blob: a7f2dc040bc31a6834616480a11f51d3d31a4653 [file] [log] [blame]
peizhen guo410e0e12014-08-12 13:24:14 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014, Regents of the University of California
4 *
5 * This file is part of NSL (NDN Signature Logger).
6 * See AUTHORS.md for complete list of NSL authors and contributors.
7 *
8 * NSL is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * NSL, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @author Peizhen Guo <patrick.guopz@gmail.com>
20 */
21
22#include "merkle-tree-cache.hpp"
23
24
25
26namespace nsl {
27
28typedef std::map<Index, int>::iterator tree_iter;
29typedef std::map<uint64_t, ndn::ConstBufferPtr>::iterator leaf_iter;
30
31Index
32MerkleTreeCache::findSubTree(Index nodeIndex)
33{
34 if(nodeIndex.level % 6 == 0 && nodeIndex.level != 0)
35 {
36 return nodeIndex;
37 }
38 else
39 {
40 uint8_t step = (uint64_t(nodeIndex.level / 6) + 1) * 6 - nodeIndex.level;
41 for (int i = 0; i < step; i++)
42 {
43 nodeIndex.number -= nodeIndex.number % int(pow(2, nodeIndex.level + 1));
44 nodeIndex.level += 1;
45 }
46 return nodeIndex;
47 }
48}
49
50Index
51MerkleTreeCache::getParentRootIndex(Index thisRootIndex)
52{
53 Index parentIndex;
54 parentIndex.number = thisRootIndex.number;
55 parentIndex.level = thisRootIndex.level;
56 for (int i = 0; i < 6; i++)
57 {
58 parentIndex.number -= parentIndex.number%int(pow(2, parentIndex.level + 1));
59 parentIndex.level += 1;
60 }
61 return parentIndex;
62}
63
64
65void
66MerkleTreeCache::removeSubTree()
67{
68 if (doesCacheFull() > 1)
69 {
70 // find out the least recent used subtree
71 tree_iter _i = m_timeFromLastUse.begin();
72 int idle_time_max = -1;
73 Index rm_index_max = _i->first;
74 int idle_time_min = _i->second;
75 Index rm_index_min = _i->first;
76 for (_i = m_timeFromLastUse.begin(); _i != m_timeFromLastUse.end(); _i++)
77 {
78 if (_i->second > idle_time_max && m_cachedTree[_i->first]->getRemainPosition() == 0)
79 {
80 idle_time_max = _i->second;
81 rm_index_max = _i->first;
82 }
83 if (_i->second < idle_time_min)
84 {
85 idle_time_min = _i->second;
86 rm_index_min = _i->first;
87 }
88 }
89
90 // refresh the timer
91 for (_i = m_timeFromLastUse.begin(); _i != m_timeFromLastUse.end(); _i++)
92 {
93 _i->second -= idle_time_min;
94 }
95 // update to database and remove subtree from cache and timer,only when there is full subtree
96 if (m_cachedTree[rm_index_max]->getRemainPosition() == 0 && idle_time_max >= 0)
97 {
98 m_database.addSubTree(m_cachedTree[rm_index_max]);
99 m_cachedTree.erase(rm_index_max);
100 m_timeFromLastUse.erase(rm_index_max);
101 }
102 }
103}
104
105void
106MerkleTreeCache::removeLeaf()
107{
108 if (doesCacheFull() % 2 != 0)
109 {
110 // randomly pick a old leaf to remove
111 leaf_iter _i = m_leavesData.begin();
112 while (_i->first == m_nLeaves - 1)
113 {
114 _i++;
115 }
116 m_database.addLeafInfo(_i->first, _i->second);
117 m_leavesData.erase(_i->first);
118 }
119}
120
121
122
123
124
125// Do not have to deal with NOT-IN-MEMORY issue because not full tree will not in database
126void
127MerkleTreeCache::addLeaf(Leaf newLeaf)
128{
129 ndn::ConstBufferPtr data = newLeaf.getData();
130 removeLeaf(); // test whether is full, if so, delete an old item
131 m_leavesData[newLeaf.getIndex().number] = data;
132 Index leafIndex = newLeaf.getIndex();
133 ndn::ConstBufferPtr hash = newLeaf.getHash();
134
135 Index subTreeRoot = findSubTree(leafIndex);
136 if (m_nLeaves > 0)
137 {
138 // Not full so that always in memory
139 m_cachedTree[subTreeRoot]->addNode(hash);
140 m_nLeaves += 1;
141 }
142 else
143 {
144 SubTreePtr newTree(new SubTree(subTreeRoot,
145 ndn::bind(&MerkleTreeCache::update, this,
146 subTreeRoot, _1, _2)));
147 newTree->addNode(hash);
148 removeSubTree();
149 m_cachedTree[subTreeRoot] = newTree;
150 m_nLeaves = 1;
151 m_nLevels = 1;
152 }
153
154 for (tree_iter _i = m_timeFromLastUse.begin(); _i != m_timeFromLastUse.end(); _i++)
155 {
156 _i->second += 1;
157 }
158 m_timeFromLastUse[subTreeRoot] = 0; // if not exist, automatically create one and set to 0
159}
160
161
162// Deal with loading from database
163// database update
164// consider add to database when a subtree is full
165void
166MerkleTreeCache::update(Index subRootIndex, uint8_t subRemainNum, ndn::ConstBufferPtr subRootHash)
167{
168 if ((subRootIndex.level / 6) < m_nLevels)
169 {
170 Index parentRoot = getParentRootIndex(subRootIndex);
171
172 // bring in memory if parentRoot not in
173 if (m_cachedTree.count(parentRoot) <= 0)
174 {
175 loadSubTreeFromDatabase(parentRoot);
176 }
177 m_cachedTree[parentRoot]->updateLeafHash(subRootIndex, subRootHash);
178 m_timeFromLastUse[parentRoot] = 0;
179 }
180
181 if (subRemainNum == 0) // add the current full subtree into the database
182 {
183 Index parentRoot = getParentRootIndex(subRootIndex);
184 if ((subRootIndex.level / 6) >= m_nLevels) // if it is the top subtree
185 {
186 SubTreePtr newTree(new SubTree(parentRoot,
187 ndn::bind(&MerkleTreeCache::update, this,
188 parentRoot, _1, _2)));
189 removeSubTree();
190 m_cachedTree[parentRoot] = newTree;
191 m_nLevels += 1;
192 m_timeFromLastUse[parentRoot] = 0;
193 m_cachedTree[parentRoot]->updateLeafHash(subRootIndex, subRootHash);
194 }
195 Index newRoot;
196 newRoot.level = subRootIndex.level;
197 newRoot.number = subRootIndex.number + int(pow(2, subRootIndex.level));
198 // whether the updated subtree is already full,
199 // but its child subtree is not full.
200 // To avoid create multiple sibling new subtree
201 if (m_cachedTree.count(newRoot) == 0)
202 {
203 SubTreePtr newTree(new SubTree(newRoot,
204 ndn::bind(&MerkleTreeCache::update, this,
205 newRoot, _1, _2)));
206 removeSubTree();
207 m_cachedTree[newRoot] = newTree;
208 m_timeFromLastUse[newRoot] = 0;
209 }
210 }
211}
212
213
214NodePtr
215MerkleTreeCache::queryNode(Index nodeIndex)
216{
217 // update timer
218 for (tree_iter _i = m_timeFromLastUse.begin(); _i != m_timeFromLastUse.end(); _i++)
219 {
220 _i->second += 1;
221 }
222
223 Index rootIndex = findSubTree(nodeIndex);
224 ndn::ConstBufferPtr hash;
225 if (m_cachedTree.count(rootIndex) == 0)
226 {
227 loadSubTreeFromDatabase(rootIndex);
228 }
229 hash = m_cachedTree[rootIndex]->getHash(nodeIndex);
230
231 if (nodeIndex.level == 0)
232 {
233 if (m_leavesData.count(nodeIndex.number) == 0)
234 {
235 loadLeafFromDatabase(nodeIndex.number);
236 }
237 NodePtr node_ptr(new Leaf(m_leavesData[nodeIndex.number],
238 nodeIndex.number, nodeIndex.level, 0));
239 node_ptr->setHash(hash);
240 return node_ptr;
241 }
242 else
243 {
244 NodePtr node_ptr(new IntermediateNode(nodeIndex.number, nodeIndex.level, 0));
245 node_ptr->setHash(hash);
246 ((IntermediateNode*)node_ptr.get())->setIsFull(m_nLeaves);
247 return node_ptr;
248 }
249}
250
251
252bool
253MerkleTreeCache::doesNodeExist(Index nodeIndex)
254{
255 Index rootIndex = findSubTree(nodeIndex);
256 if (m_cachedTree.count(rootIndex) > 0)
257 {
258 return true;
259 }
260 else
261 {
262 bool result = m_database.doesSubTreeExist(rootIndex);
263 return result;
264 }
265}
266
267
268
269SubTreePtr
270MerkleTreeCache::decoding(std::string subTreeInfo)
271{
272 uint64_t seq = 0;
273 unsigned char tmp = 0;
274 for (int i = 7; i >= 0; i--)
275 {
276 tmp = subTreeInfo[i];
277 seq += tmp;
278 seq = seq << 8;
279 }
280 seq = seq >> 8;
281 uint64_t lev = 0;
282 for (int i = 15; i >= 8; i--)
283 {
284 tmp = subTreeInfo[i];
285 lev += tmp;
286 lev = lev << 8;
287 }
288 lev = lev >> 8;
289 Index rootIndex;
290 rootIndex.number = seq;
291 rootIndex.level = lev;
292 SubTreePtr newTree(new SubTree(rootIndex,
293 ndn::bind(&MerkleTreeCache::update, this,
294 rootIndex, _1, _2)));
295 uint8_t remain = subTreeInfo[16]; // not useful
296 if (remain == 0)
297 {
298 std::vector<ndn::BufferPtr> hashes;
299 for (int i = 0; i < 127; i++)
300 {
301 ndn::Buffer buf;
302 for(int j = 17 + 32 * i; j < 49 + 32 * i; j++)
303 {
304 buf.push_back(subTreeInfo[j]);
305 }
306 ndn::BufferPtr thisBuf = ndn::make_shared<ndn::Buffer>(buf);
307 hashes.push_back(thisBuf);
308 }
309 newTree->resumeFromString(remain, hashes);
310 return newTree;
311 }
312 else
313 {
314 std::vector<ndn::BufferPtr> hashes;
315 uint8_t lastNo = 126 - remain;
316 for (int i = 63; i <= lastNo; i++)
317 {
318 ndn::Buffer buf;
319 for(int j = 17 + 32 * i; j < 49 + 32 * i; j++)
320 {
321 buf.push_back(subTreeInfo[j]);
322 }
323 ndn::BufferPtr thisBuf = ndn::make_shared<ndn::Buffer>(buf);
324 hashes.push_back(thisBuf);
325 }
326 newTree->resumeFromString(remain, hashes);
327 return newTree;
328 }
329}
330
331
332void
333MerkleTreeCache::loadSubTreeFromDatabase(Index rootIndex)
334{
335 // Detect the cache limitation
336 removeSubTree();
337 std::string tmp_str = m_database.getSubTree(rootIndex);
338 SubTreePtr newtree = decoding(tmp_str);
339 m_cachedTree[rootIndex] = newtree;
340 m_timeFromLastUse[rootIndex] = 0;
341}
342
343void
344MerkleTreeCache::loadLeafFromDatabase(uint64_t sequence)
345{
346 // Detect the cache limitation
347 removeLeaf();
348 ndn::ConstBufferPtr newleaf = m_database.getLeafInfo(sequence);
349 m_leavesData[sequence] = newleaf;
350}
351
352
353} // namespace nsl