13 #ifndef STXXL_CONTAINERS_BTREE__NODE_CACHE_H
14 #define STXXL_CONTAINERS_BTREE__NODE_CACHE_H
16 #ifdef STXXL_BOOST_CONFIG
17 #include <boost/config.hpp>
20 #include <stxxl/bits/compat_hash_map.h>
21 #include <stxxl/bits/io/request_ptr.h>
22 #include <stxxl/bits/mng/mng.h>
23 #include <stxxl/bits/mng/typed_block.h>
24 #include <stxxl/bits/containers/pager.h>
25 #include <stxxl/bits/common/error_handling.h>
28 __STXXL_BEGIN_NAMESPACE
34 template <
class NodeType,
class BTreeType>
35 class node_cache :
private noncopyable
38 typedef BTreeType btree_type;
39 typedef NodeType node_type;
40 typedef typename node_type::block_type block_type;
41 typedef typename node_type::bid_type bid_type;
42 typedef typename btree_type::key_compare key_compare;
44 typedef typename btree_type::alloc_strategy_type alloc_strategy_type;
45 typedef stxxl::lru_pager<> pager_type;
63 size_t operator () (
const bid_type & bid)
const
66 longhash1(bid.offset + uint64(unsigned_type(bid.storage)));
70 bool operator () (
const bid_type & a,
const bid_type & b)
const
72 return (a.storage < b.storage) || (a.storage == b.storage && a.offset < b.offset);
82 std::vector<node_type *> nodes_;
83 std::vector<request_ptr> reqs_;
84 std::vector<bool> fixed_;
85 std::vector<bool> dirty_;
86 std::vector<int_type> free_nodes_;
87 typedef typename compat_hash_map<bid_type, int_type, bid_hash>::result hash_map_type;
90 typedef hash_map_type BID2node_type;
92 BID2node_type BID2node_;
95 alloc_strategy_type alloc_strategy_;
103 int64 n_clean_forced;
106 void change_btree_pointers(btree_type * b)
108 typename std::vector<node_type *>::const_iterator it = nodes_.begin();
109 for ( ; it != nodes_.end(); ++it)
116 node_cache(unsigned_type cache_size_in_bytes,
117 btree_type * btree__,
131 const unsigned_type nnodes = cache_size_in_bytes / block_type::raw_size;
132 STXXL_VERBOSE1(
"btree::node_cache constructor nodes=" << nnodes);
135 STXXL_THROW(std::runtime_error,
"btree::node_cache::node_cache",
"Too few memory for a node cache (<3)");
137 nodes_.reserve(nnodes);
138 reqs_.resize(nnodes);
139 free_nodes_.reserve(nnodes);
140 fixed_.resize(nnodes,
false);
141 dirty_.resize(nnodes,
true);
142 for (unsigned_type i = 0; i < nnodes; ++i)
144 nodes_.push_back(
new node_type(btree_, comp_));
145 free_nodes_.push_back(i);
148 pager_type tmp_pager(nnodes);
149 std::swap(pager_, tmp_pager);
152 unsigned_type size()
const
154 return nodes_.size();
158 unsigned_type nfixed()
const
160 typename BID2node_type::const_iterator i = BID2node_.begin();
161 typename BID2node_type::const_iterator end = BID2node_.end();
162 unsigned_type cnt = 0;
163 for ( ; i != end; ++i)
165 if (fixed_[(*i).second])
173 STXXL_VERBOSE1(
"btree::node_cache destructor addr=" <<
this);
174 typename BID2node_type::const_iterator i = BID2node_.begin();
175 typename BID2node_type::const_iterator end = BID2node_.end();
176 for ( ; i != end; ++i)
178 const unsigned_type p = (*i).second;
179 if (reqs_[p].valid())
185 for (unsigned_type i = 0; i < size(); ++i)
189 node_type * get_new_node(bid_type & new_bid)
193 if (free_nodes_.empty())
198 const unsigned_type max_tries = size() + 1;
202 node2kick = pager_.kick();
206 "The node cache is too small, no node can be kicked out (all nodes are fixed) !");
207 STXXL_ERRMSG(
"Returning NULL node.");
210 pager_.hit(node2kick);
211 }
while (fixed_[node2kick]);
214 if (reqs_[node2kick].valid())
215 reqs_[node2kick]->wait();
218 node_type & Node = *(nodes_[node2kick]);
220 if (dirty_[node2kick])
231 assert(BID2node_.find(Node.my_bid()) != BID2node_.end());
232 BID2node_.erase(Node.my_bid());
233 bm->new_block(alloc_strategy_, new_bid);
235 BID2node_[new_bid] = node2kick;
239 dirty_[node2kick] =
true;
241 assert(size() == BID2node_.size() + free_nodes_.size());
243 STXXL_VERBOSE1(
"btree::node_cache get_new_node, need to kick node " << node2kick);
249 int_type free_node = free_nodes_.back();
250 free_nodes_.pop_back();
251 assert(fixed_[free_node] ==
false);
253 bm->new_block(alloc_strategy_, new_bid);
254 BID2node_[new_bid] = free_node;
255 node_type & Node = *(nodes_[free_node]);
260 pager_.hit(free_node);
262 dirty_[free_node] =
true;
264 assert(size() == BID2node_.size() + free_nodes_.size());
266 STXXL_VERBOSE1(
"btree::node_cache get_new_node, free node " << free_node <<
"available");
272 node_type * get_node(
const bid_type & bid,
bool fix =
false)
274 typename BID2node_type::const_iterator it = BID2node_.find(bid);
277 if (it != BID2node_.end())
280 const int_type nodeindex = it->second;
281 STXXL_VERBOSE1(
"btree::node_cache get_node, the node " << nodeindex <<
"is in cache , fix=" << fix);
282 fixed_[nodeindex] = fix;
283 pager_.hit(nodeindex);
284 dirty_[nodeindex] =
true;
286 if (reqs_[nodeindex].valid() && !reqs_[nodeindex]->poll())
287 reqs_[nodeindex]->wait();
291 return nodes_[nodeindex];
297 if (free_nodes_.empty())
302 const unsigned_type max_tries = size() + 1;
306 node2kick = pager_.kick();
310 "The node cache is too small, no node can be kicked out (all nodes are fixed) !");
311 STXXL_ERRMSG(
"Returning NULL node.");
314 pager_.hit(node2kick);
315 }
while (fixed_[node2kick]);
317 if (reqs_[node2kick].valid())
318 reqs_[node2kick]->wait();
321 node_type & Node = *(nodes_[node2kick]);
323 if (dirty_[node2kick])
332 BID2node_.erase(Node.my_bid());
334 reqs_[node2kick] = Node.load(bid);
335 BID2node_[bid] = node2kick;
337 fixed_[node2kick] = fix;
339 dirty_[node2kick] =
true;
341 assert(size() == BID2node_.size() + free_nodes_.size());
343 STXXL_VERBOSE1(
"btree::node_cache get_node, need to kick node" << node2kick <<
" fix=" << fix);
348 int_type free_node = free_nodes_.back();
349 free_nodes_.pop_back();
350 assert(fixed_[free_node] ==
false);
352 node_type & Node = *(nodes_[free_node]);
353 reqs_[free_node] = Node.load(bid);
354 BID2node_[bid] = free_node;
356 pager_.hit(free_node);
358 fixed_[free_node] = fix;
360 dirty_[free_node] =
true;
362 assert(size() == BID2node_.size() + free_nodes_.size());
364 STXXL_VERBOSE1(
"btree::node_cache get_node, free node " << free_node <<
"available, fix=" << fix);
369 node_type
const * get_const_node(
const bid_type & bid,
bool fix =
false)
371 typename BID2node_type::const_iterator it = BID2node_.find(bid);
374 if (it != BID2node_.end())
377 const int_type nodeindex = it->second;
378 STXXL_VERBOSE1(
"btree::node_cache get_node, the node " << nodeindex <<
"is in cache , fix=" << fix);
379 fixed_[nodeindex] = fix;
380 pager_.hit(nodeindex);
382 if (reqs_[nodeindex].valid() && !reqs_[nodeindex]->poll())
383 reqs_[nodeindex]->wait();
387 return nodes_[nodeindex];
393 if (free_nodes_.empty())
398 const unsigned_type max_tries = size() + 1;
402 node2kick = pager_.kick();
406 "The node cache is too small, no node can be kicked out (all nodes are fixed) !");
407 STXXL_ERRMSG(
"Returning NULL node.");
410 pager_.hit(node2kick);
411 }
while (fixed_[node2kick]);
413 if (reqs_[node2kick].valid())
414 reqs_[node2kick]->wait();
417 node_type & Node = *(nodes_[node2kick]);
418 if (dirty_[node2kick])
427 BID2node_.erase(Node.my_bid());
429 reqs_[node2kick] = Node.load(bid);
430 BID2node_[bid] = node2kick;
432 fixed_[node2kick] = fix;
434 dirty_[node2kick] =
false;
436 assert(size() == BID2node_.size() + free_nodes_.size());
438 STXXL_VERBOSE1(
"btree::node_cache get_node, need to kick node" << node2kick <<
" fix=" << fix);
443 int_type free_node = free_nodes_.back();
444 free_nodes_.pop_back();
445 assert(fixed_[free_node] ==
false);
447 node_type & Node = *(nodes_[free_node]);
448 reqs_[free_node] = Node.load(bid);
449 BID2node_[bid] = free_node;
451 pager_.hit(free_node);
453 fixed_[free_node] = fix;
455 dirty_[free_node] =
false;
457 assert(size() == BID2node_.size() + free_nodes_.size());
459 STXXL_VERBOSE1(
"btree::node_cache get_node, free node " << free_node <<
"available, fix=" << fix);
464 void delete_node(
const bid_type & bid)
466 typename BID2node_type::const_iterator it = BID2node_.find(bid);
469 if (it != BID2node_.end())
472 const int_type nodeindex = it->second;
473 STXXL_VERBOSE1(
"btree::node_cache delete_node " << nodeindex <<
" from cache.");
474 if (reqs_[nodeindex].valid())
475 reqs_[nodeindex]->wait();
478 free_nodes_.push_back(nodeindex);
479 BID2node_.erase(bid);
480 fixed_[nodeindex] =
false;
483 }
catch (
const io_error & ex)
485 bm->delete_block(bid);
486 throw io_error(ex.what());
488 bm->delete_block(bid);
492 void prefetch_node(
const bid_type & bid)
494 if (BID2node_.find(bid) != BID2node_.end())
499 if (free_nodes_.empty())
504 const unsigned_type max_tries = size() + 1;
508 node2kick = pager_.kick();
512 "The node cache is too small, no node can be kicked out (all nodes are fixed) !");
513 STXXL_ERRMSG(
"Returning NULL node.");
516 pager_.hit(node2kick);
517 }
while (fixed_[node2kick]);
519 if (reqs_[node2kick].valid())
520 reqs_[node2kick]->wait();
523 node_type & Node = *(nodes_[node2kick]);
525 if (dirty_[node2kick])
534 BID2node_.erase(Node.my_bid());
536 reqs_[node2kick] = Node.prefetch(bid);
537 BID2node_[bid] = node2kick;
539 fixed_[node2kick] =
false;
541 dirty_[node2kick] =
false;
543 assert(size() == BID2node_.size() + free_nodes_.size());
545 STXXL_VERBOSE1(
"btree::node_cache prefetch_node, need to kick node" << node2kick <<
" ");
550 int_type free_node = free_nodes_.back();
551 free_nodes_.pop_back();
552 assert(fixed_[free_node] ==
false);
554 node_type & Node = *(nodes_[free_node]);
555 reqs_[free_node] = Node.prefetch(bid);
556 BID2node_[bid] = free_node;
558 pager_.hit(free_node);
560 fixed_[free_node] =
false;
562 dirty_[free_node] =
false;
564 assert(size() == BID2node_.size() + free_nodes_.size());
566 STXXL_VERBOSE1(
"btree::node_cache prefetch_node, free node " << free_node <<
"available");
571 void unfix_node(
const bid_type & bid)
573 assert(BID2node_.find(bid) != BID2node_.end());
574 fixed_[BID2node_[bid]] =
false;
575 STXXL_VERBOSE1(
"btree::node_cache unfix_node, node " << BID2node_[bid]);
578 void swap(node_cache & obj)
580 std::swap(comp_, obj.comp_);
581 std::swap(nodes_, obj.nodes_);
582 std::swap(reqs_, obj.reqs_);
583 change_btree_pointers(btree_);
584 obj.change_btree_pointers(obj.btree_);
585 std::swap(fixed_, obj.fixed_);
586 std::swap(free_nodes_, obj.free_nodes_);
587 std::swap(BID2node_, obj.BID2node_);
588 std::swap(pager_, obj.pager_);
589 std::swap(alloc_strategy_, obj.alloc_strategy_);
590 std::swap(n_found, obj.n_found);
591 std::swap(n_not_found, obj.n_found);
592 std::swap(n_created, obj.n_created);
593 std::swap(n_deleted, obj.n_deleted);
594 std::swap(n_read, obj.n_read);
595 std::swap(n_written, obj.n_written);
596 std::swap(n_clean_forced, obj.n_clean_forced);
599 void print_statistics(std::ostream & o)
const
602 o <<
"Found blocks : " << n_found <<
" (" <<
603 100. * double(n_found) / double(n_read) <<
"%)" << std::endl;
606 o <<
"Found blocks : " << n_found <<
" (" <<
607 100 <<
"%)" << std::endl;
609 o <<
"Not found blocks : " << n_not_found << std::endl;
610 o <<
"Created in the cache blocks : " << n_created << std::endl;
611 o <<
"Deleted blocks : " << n_deleted << std::endl;
612 o <<
"Read blocks : " << n_read << std::endl;
613 o <<
"Written blocks : " << n_written << std::endl;
614 o <<
"Clean blocks forced from the cache: " << n_clean_forced << std::endl;
616 void reset_statistics()
629 __STXXL_END_NAMESPACE
634 template <
class NodeType,
class BTreeType>
635 void swap(stxxl::btree::node_cache<NodeType, BTreeType> & a,
636 stxxl::btree::node_cache<NodeType, BTreeType> & b)
Block manager class.
Definition: mng.h:59