STXXL  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
node_cache.h
Go to the documentation of this file.
1 /***************************************************************************
2  * include/stxxl/bits/containers/btree/node_cache.h
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 2006 Roman Dementiev <[email protected]>
7  *
8  * Distributed under the Boost Software License, Version 1.0.
9  * (See accompanying file LICENSE_1_0.txt or copy at
10  * http://www.boost.org/LICENSE_1_0.txt)
11  **************************************************************************/
12 
13 #ifndef STXXL_CONTAINERS_BTREE_NODE_CACHE_HEADER
14 #define STXXL_CONTAINERS_BTREE_NODE_CACHE_HEADER
15 
16 #include <stxxl/bits/config.h>
18 #include <stxxl/bits/io/request.h>
23 
24 
26 
27 // TODO: speedup BID2node_ access using search result iterator in the methods
28 
29 namespace btree {
30 
31 template <class NodeType, class BTreeType>
32 class node_cache : private noncopyable
33 {
34 public:
35  typedef BTreeType btree_type;
36  typedef NodeType node_type;
37  typedef typename node_type::block_type block_type;
38  typedef typename node_type::bid_type bid_type;
39  typedef typename btree_type::key_compare key_compare;
40 
41  typedef typename btree_type::alloc_strategy_type alloc_strategy_type;
43 
44 private:
47 
48 /*
49  struct bid_comp
50  {
51  bool operator () (const bid_type & a, const bid_type & b) const
52  {
53  return (a.storage < b.storage) || ( a.storage == b.storage && a.offset < b.offset);
54  }
55  };
56 */
57 
58  struct bid_hash
59  {
60  size_t operator () (const bid_type& bid) const
61  {
62  size_t result =
63  longhash1(bid.offset + uint64(unsigned_type(bid.storage)));
64  return result;
65  }
66 #if STXXL_MSVC
67  bool operator () (const bid_type& a, const bid_type& b) const
68  {
69  return (a.storage < b.storage) || (a.storage == b.storage && a.offset < b.offset);
70  }
71  enum
72  { // parameters for hash table
73  bucket_size = 4, // 0 < bucket_size
74  min_buckets = 8 // min_buckets = 2 ^^ N, 0 < N
75  };
76 #endif
77  };
78 
79  std::vector<node_type*> nodes_;
80  std::vector<request_ptr> reqs_;
81  std::vector<bool> fixed_;
82  std::vector<bool> dirty_;
83  std::vector<int_type> free_nodes_;
85 
86  //typedef std::map<bid_type,int_type,bid_comp> BID2node_type;
88 
93 
101 
102  // changes btree pointer in all contained iterators
104  {
105  typename std::vector<node_type*>::const_iterator it = nodes_.begin();
106  for ( ; it != nodes_.end(); ++it)
107  {
108  (*it)->btree_ = b;
109  }
110  }
111 
112 public:
113  node_cache(unsigned_type cache_size_in_bytes,
114  btree_type* btree__,
115  key_compare comp__
116  ) :
117  btree_(btree__),
118  comp_(comp__),
119  bm(block_manager::get_instance()),
120  n_found(0),
121  n_not_found(0),
122  n_created(0),
123  n_deleted(0),
124  n_read(0),
125  n_written(0),
126  n_clean_forced(0)
127  {
128  const unsigned_type nnodes = cache_size_in_bytes / block_type::raw_size;
129  STXXL_VERBOSE1("btree::node_cache constructor nodes=" << nnodes);
130  if (nnodes < 3)
131  {
132  STXXL_THROW2(std::runtime_error, "btree::node_cache::node_cache", "Too few memory for a node cache (<3)");
133  }
134  nodes_.reserve(nnodes);
135  reqs_.resize(nnodes);
136  free_nodes_.reserve(nnodes);
137  fixed_.resize(nnodes, false);
138  dirty_.resize(nnodes, true);
139  for (unsigned_type i = 0; i < nnodes; ++i)
140  {
141  nodes_.push_back(new node_type(btree_, comp_));
142  free_nodes_.push_back(i);
143  }
144 
145  pager_type tmp_pager(nnodes);
146  std::swap(pager_, tmp_pager);
147  }
148 
150  {
151  return nodes_.size();
152  }
153 
154  // returns the number of fixed pages
156  {
157  typename BID2node_type::const_iterator i = BID2node_.begin();
158  typename BID2node_type::const_iterator end = BID2node_.end();
159  unsigned_type cnt = 0;
160  for ( ; i != end; ++i)
161  {
162  if (fixed_[(*i).second])
163  ++cnt;
164  }
165  return cnt;
166  }
167 
169  {
170  STXXL_VERBOSE1("btree::node_cache destructor addr=" << this);
171  typename BID2node_type::const_iterator i = BID2node_.begin();
172  typename BID2node_type::const_iterator end = BID2node_.end();
173  for ( ; i != end; ++i)
174  {
175  const unsigned_type p = (*i).second;
176  if (reqs_[p].valid())
177  reqs_[p]->wait();
178 
179  if (dirty_[p])
180  nodes_[p]->save();
181  }
182  for (unsigned_type i = 0; i < size(); ++i)
183  delete nodes_[i];
184  }
185 
187  {
188  ++n_created;
189 
190  if (free_nodes_.empty())
191  {
192  // need to kick a node
193  int_type node2kick;
194  unsigned_type i = 0;
195  const unsigned_type max_tries = size() + 1;
196  do
197  {
198  ++i;
199  node2kick = pager_.kick();
200  if (i == max_tries)
201  {
202  STXXL_ERRMSG(
203  "The node cache is too small, no node can be kicked out (all nodes are fixed) !");
204  STXXL_ERRMSG("Returning NULL node.");
205  return NULL;
206  }
207  pager_.hit(node2kick);
208  } while (fixed_[node2kick]);
209 
210 
211  if (reqs_[node2kick].valid())
212  reqs_[node2kick]->wait();
213 
214 
215  node_type& Node = *(nodes_[node2kick]);
216 
217  if (dirty_[node2kick])
218  {
219  Node.save();
220  ++n_written;
221  }
222  else
223  ++n_clean_forced;
224 
225 
226  //reqs_[node2kick] = request_ptr(); // reset request
227 
228  assert(BID2node_.find(Node.my_bid()) != BID2node_.end());
229  BID2node_.erase(Node.my_bid());
230  bm->new_block(alloc_strategy_, new_bid);
231 
232  BID2node_[new_bid] = node2kick;
233 
234  Node.init(new_bid);
235 
236  dirty_[node2kick] = true;
237 
238  assert(size() == BID2node_.size() + free_nodes_.size());
239 
240  STXXL_VERBOSE1("btree::node_cache get_new_node, need to kick node " << node2kick);
241 
242  return &Node;
243  }
244 
245 
246  int_type free_node = free_nodes_.back();
247  free_nodes_.pop_back();
248  assert(fixed_[free_node] == false);
249 
250  bm->new_block(alloc_strategy_, new_bid);
251  BID2node_[new_bid] = free_node;
252  node_type& Node = *(nodes_[free_node]);
253  Node.init(new_bid);
254 
255  // assert(!(reqs_[free_node].valid()));
256 
257  pager_.hit(free_node);
258 
259  dirty_[free_node] = true;
260 
261  assert(size() == BID2node_.size() + free_nodes_.size());
262 
263  STXXL_VERBOSE1("btree::node_cache get_new_node, free node " << free_node << "available");
264 
265  return &Node;
266  }
267 
268 
269  node_type * get_node(const bid_type& bid, bool fix = false)
270  {
271  typename BID2node_type::const_iterator it = BID2node_.find(bid);
272  ++n_read;
273 
274  if (it != BID2node_.end())
275  {
276  // the node is in cache
277  const int_type nodeindex = it->second;
278  STXXL_VERBOSE1("btree::node_cache get_node, the node " << nodeindex << "is in cache , fix=" << fix);
279  fixed_[nodeindex] = fix;
280  pager_.hit(nodeindex);
281  dirty_[nodeindex] = true;
282 
283  if (reqs_[nodeindex].valid() && !reqs_[nodeindex]->poll())
284  reqs_[nodeindex]->wait();
285 
286 
287  ++n_found;
288  return nodes_[nodeindex];
289  }
290 
291  ++n_not_found;
292 
293  // the node is not in cache
294  if (free_nodes_.empty())
295  {
296  // need to kick a node
297  int_type node2kick;
298  unsigned_type i = 0;
299  const unsigned_type max_tries = size() + 1;
300  do
301  {
302  ++i;
303  node2kick = pager_.kick();
304  if (i == max_tries)
305  {
306  STXXL_ERRMSG(
307  "The node cache is too small, no node can be kicked out (all nodes are fixed) !");
308  STXXL_ERRMSG("Returning NULL node.");
309  return NULL;
310  }
311  pager_.hit(node2kick);
312  } while (fixed_[node2kick]);
313 
314  if (reqs_[node2kick].valid())
315  reqs_[node2kick]->wait();
316 
317 
318  node_type& Node = *(nodes_[node2kick]);
319 
320  if (dirty_[node2kick])
321  {
322  Node.save();
323  ++n_written;
324  }
325  else
326  ++n_clean_forced;
327 
328 
329  BID2node_.erase(Node.my_bid());
330 
331  reqs_[node2kick] = Node.load(bid);
332  BID2node_[bid] = node2kick;
333 
334  fixed_[node2kick] = fix;
335 
336  dirty_[node2kick] = true;
337 
338  assert(size() == BID2node_.size() + free_nodes_.size());
339 
340  STXXL_VERBOSE1("btree::node_cache get_node, need to kick node" << node2kick << " fix=" << fix);
341 
342  return &Node;
343  }
344 
345  int_type free_node = free_nodes_.back();
346  free_nodes_.pop_back();
347  assert(fixed_[free_node] == false);
348 
349  node_type& Node = *(nodes_[free_node]);
350  reqs_[free_node] = Node.load(bid);
351  BID2node_[bid] = free_node;
352 
353  pager_.hit(free_node);
354 
355  fixed_[free_node] = fix;
356 
357  dirty_[free_node] = true;
358 
359  assert(size() == BID2node_.size() + free_nodes_.size());
360 
361  STXXL_VERBOSE1("btree::node_cache get_node, free node " << free_node << "available, fix=" << fix);
362 
363  return &Node;
364  }
365 
366  node_type const * get_const_node(const bid_type& bid, bool fix = false)
367  {
368  typename BID2node_type::const_iterator it = BID2node_.find(bid);
369  ++n_read;
370 
371  if (it != BID2node_.end())
372  {
373  // the node is in cache
374  const int_type nodeindex = it->second;
375  STXXL_VERBOSE1("btree::node_cache get_node, the node " << nodeindex << "is in cache , fix=" << fix);
376  fixed_[nodeindex] = fix;
377  pager_.hit(nodeindex);
378 
379  if (reqs_[nodeindex].valid() && !reqs_[nodeindex]->poll())
380  reqs_[nodeindex]->wait();
381 
382 
383  ++n_found;
384  return nodes_[nodeindex];
385  }
386 
387  ++n_not_found;
388 
389  // the node is not in cache
390  if (free_nodes_.empty())
391  {
392  // need to kick a node
393  int_type node2kick;
394  unsigned_type i = 0;
395  const unsigned_type max_tries = size() + 1;
396  do
397  {
398  ++i;
399  node2kick = pager_.kick();
400  if (i == max_tries)
401  {
402  STXXL_ERRMSG(
403  "The node cache is too small, no node can be kicked out (all nodes are fixed) !");
404  STXXL_ERRMSG("Returning NULL node.");
405  return NULL;
406  }
407  pager_.hit(node2kick);
408  } while (fixed_[node2kick]);
409 
410  if (reqs_[node2kick].valid())
411  reqs_[node2kick]->wait();
412 
413 
414  node_type& Node = *(nodes_[node2kick]);
415  if (dirty_[node2kick])
416  {
417  Node.save();
418  ++n_written;
419  }
420  else
421  ++n_clean_forced;
422 
423 
424  BID2node_.erase(Node.my_bid());
425 
426  reqs_[node2kick] = Node.load(bid);
427  BID2node_[bid] = node2kick;
428 
429  fixed_[node2kick] = fix;
430 
431  dirty_[node2kick] = false;
432 
433  assert(size() == BID2node_.size() + free_nodes_.size());
434 
435  STXXL_VERBOSE1("btree::node_cache get_node, need to kick node" << node2kick << " fix=" << fix);
436 
437  return &Node;
438  }
439 
440  int_type free_node = free_nodes_.back();
441  free_nodes_.pop_back();
442  assert(fixed_[free_node] == false);
443 
444  node_type& Node = *(nodes_[free_node]);
445  reqs_[free_node] = Node.load(bid);
446  BID2node_[bid] = free_node;
447 
448  pager_.hit(free_node);
449 
450  fixed_[free_node] = fix;
451 
452  dirty_[free_node] = false;
453 
454  assert(size() == BID2node_.size() + free_nodes_.size());
455 
456  STXXL_VERBOSE1("btree::node_cache get_node, free node " << free_node << "available, fix=" << fix);
457 
458  return &Node;
459  }
460 
461  void delete_node(const bid_type& bid)
462  {
463  typename BID2node_type::const_iterator it = BID2node_.find(bid);
464  try
465  {
466  if (it != BID2node_.end())
467  {
468  // the node is in the cache
469  const int_type nodeindex = it->second;
470  STXXL_VERBOSE1("btree::node_cache delete_node " << nodeindex << " from cache.");
471  if (reqs_[nodeindex].valid())
472  reqs_[nodeindex]->wait();
473 
474  //reqs_[nodeindex] = request_ptr(); // reset request
475  free_nodes_.push_back(nodeindex);
476  BID2node_.erase(bid);
477  fixed_[nodeindex] = false;
478  }
479  ++n_deleted;
480  } catch (const io_error& ex)
481  {
482  bm->delete_block(bid);
483  throw io_error(ex.what());
484  }
485  bm->delete_block(bid);
486  }
487 
488 
489  void prefetch_node(const bid_type& bid)
490  {
491  if (BID2node_.find(bid) != BID2node_.end())
492  return;
493 
494 
495  // the node is not in cache
496  if (free_nodes_.empty())
497  {
498  // need to kick a node
499  int_type node2kick;
500  unsigned_type i = 0;
501  const unsigned_type max_tries = size() + 1;
502  do
503  {
504  ++i;
505  node2kick = pager_.kick();
506  if (i == max_tries)
507  {
508  STXXL_ERRMSG(
509  "The node cache is too small, no node can be kicked out (all nodes are fixed) !");
510  STXXL_ERRMSG("Returning NULL node.");
511  return;
512  }
513  pager_.hit(node2kick);
514  } while (fixed_[node2kick]);
515 
516  if (reqs_[node2kick].valid())
517  reqs_[node2kick]->wait();
518 
519 
520  node_type& Node = *(nodes_[node2kick]);
521 
522  if (dirty_[node2kick])
523  {
524  Node.save();
525  ++n_written;
526  }
527  else
528  ++n_clean_forced;
529 
530 
531  BID2node_.erase(Node.my_bid());
532 
533  reqs_[node2kick] = Node.prefetch(bid);
534  BID2node_[bid] = node2kick;
535 
536  fixed_[node2kick] = false;
537 
538  dirty_[node2kick] = false;
539 
540  assert(size() == BID2node_.size() + free_nodes_.size());
541 
542  STXXL_VERBOSE1("btree::node_cache prefetch_node, need to kick node" << node2kick << " ");
543 
544  return;
545  }
546 
547  int_type free_node = free_nodes_.back();
548  free_nodes_.pop_back();
549  assert(fixed_[free_node] == false);
550 
551  node_type& Node = *(nodes_[free_node]);
552  reqs_[free_node] = Node.prefetch(bid);
553  BID2node_[bid] = free_node;
554 
555  pager_.hit(free_node);
556 
557  fixed_[free_node] = false;
558 
559  dirty_[free_node] = false;
560 
561  assert(size() == BID2node_.size() + free_nodes_.size());
562 
563  STXXL_VERBOSE1("btree::node_cache prefetch_node, free node " << free_node << "available");
564 
565  return;
566  }
567 
568  void unfix_node(const bid_type& bid)
569  {
570  assert(BID2node_.find(bid) != BID2node_.end());
571  fixed_[BID2node_[bid]] = false;
572  STXXL_VERBOSE1("btree::node_cache unfix_node, node " << BID2node_[bid]);
573  }
574 
575  void swap(node_cache& obj)
576  {
577  std::swap(comp_, obj.comp_);
578  std::swap(nodes_, obj.nodes_);
579  std::swap(reqs_, obj.reqs_);
580  change_btree_pointers(btree_);
581  obj.change_btree_pointers(obj.btree_);
582  std::swap(fixed_, obj.fixed_);
583  std::swap(free_nodes_, obj.free_nodes_);
584  std::swap(BID2node_, obj.BID2node_);
585  std::swap(pager_, obj.pager_);
586  std::swap(alloc_strategy_, obj.alloc_strategy_);
587  std::swap(n_found, obj.n_found);
588  std::swap(n_not_found, obj.n_found);
589  std::swap(n_created, obj.n_created);
590  std::swap(n_deleted, obj.n_deleted);
591  std::swap(n_read, obj.n_read);
592  std::swap(n_written, obj.n_written);
593  std::swap(n_clean_forced, obj.n_clean_forced);
594  }
595 
596  void print_statistics(std::ostream& o) const
597  {
598  if (n_read)
599  o << "Found blocks : " << n_found << " (" <<
600  100. * double(n_found) / double(n_read) << "%)" << std::endl;
601 
602  else
603  o << "Found blocks : " << n_found << " (" <<
604  100 << "%)" << std::endl;
605 
606  o << "Not found blocks : " << n_not_found << std::endl;
607  o << "Created in the cache blocks : " << n_created << std::endl;
608  o << "Deleted blocks : " << n_deleted << std::endl;
609  o << "Read blocks : " << n_read << std::endl;
610  o << "Written blocks : " << n_written << std::endl;
611  o << "Clean blocks forced from the cache: " << n_clean_forced << std::endl;
612  }
614  {
615  n_found = 0;
616  n_not_found = 0;
617  n_created = 0;
618  n_deleted = 0;
619  n_read = 0;
620  n_written = 0;
621  n_clean_forced = 0;
622  }
623 };
624 
625 } // namespace btree
626 
628 
629 
630 namespace std {
631 
632 template <class NodeType, class BTreeType>
635 {
636  a.swap(b);
637 }
638 
639 } // namespace std
640 
641 #endif // !STXXL_CONTAINERS_BTREE_NODE_CACHE_HEADER
stxxl::lru_pager pager_type
Definition: node_cache.h:42
std::vector< bool > dirty_
Definition: node_cache.h:82
Block manager class.
Definition: block_manager.h:63
long long int int64
Definition: types.h:40
node_type const * get_const_node(const bid_type &bid, bool fix=false)
Definition: node_cache.h:366
unsigned long long int uint64
Definition: types.h:41
void change_btree_pointers(btree_type *b)
Definition: node_cache.h:103
void swap(node_cache &obj)
Definition: node_cache.h:575
node_type::block_type block_type
Definition: node_cache.h:37
void prefetch_node(const bid_type &bid)
Definition: node_cache.h:489
uint64 longhash1(uint64 key_)
Definition: utils.h:231
void print_statistics(std::ostream &o) const
Definition: node_cache.h:596
btree_type::alloc_strategy_type alloc_strategy_type
Definition: node_cache.h:41
block_manager * bm
Definition: node_cache.h:91
void unfix_node(const bid_type &bid)
Definition: node_cache.h:568
btree_type::key_compare key_compare
Definition: node_cache.h:39
choose_int_types< my_pointer_size >::int_type int_type
Definition: types.h:66
std::vector< bool > fixed_
Definition: node_cache.h:81
unsigned_type nfixed() const
Definition: node_cache.h:155
compat_hash_map< bid_type, int_type, bid_hash >::result hash_map_type
Definition: node_cache.h:84
#define STXXL_BEGIN_NAMESPACE
Definition: namespace.h:16
#define STXXL_VERBOSE1(x)
Definition: verbose.h:99
hash_map_type BID2node_type
Definition: node_cache.h:87
std::vector< request_ptr > reqs_
Definition: node_cache.h:80
#define STXXL_THROW2(exception_type, location, error_message)
Throws exception_type with &quot;Error in [location] : [error_message]&quot;.
alloc_strategy_type alloc_strategy_
Definition: node_cache.h:92
BID2node_type BID2node_
Definition: node_cache.h:89
#define STXXL_ERRMSG(x)
Definition: verbose.h:79
std::vector< node_type * > nodes_
Definition: node_cache.h:79
Pager with LRU replacement strategy.
Definition: pager.h:67
void delete_node(const bid_type &bid)
Definition: node_cache.h:461
node_type * get_new_node(bid_type &new_bid)
Definition: node_cache.h:186
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
Definition: types.h:67
node_type::bid_type bid_type
Definition: node_cache.h:38
std::vector< int_type > free_nodes_
Definition: node_cache.h:83
unsigned_type size() const
Definition: node_cache.h:149
node_type * get_node(const bid_type &bid, bool fix=false)
Definition: node_cache.h:269
__gnu_cxx::hash_map< _Key, _Tp, _Hash > result
Definition: hash_map.h:59
#define STXXL_END_NAMESPACE
Definition: namespace.h:17
node_cache(unsigned_type cache_size_in_bytes, btree_type *btree__, key_compare comp__)
Definition: node_cache.h:113