Stxxl  1.4.0
include/stxxl/bits/containers/btree/btree.h
Go to the documentation of this file.
00001 /***************************************************************************
00002  *  include/stxxl/bits/containers/btree/btree.h
00003  *
00004  *  Part of the STXXL. See http://stxxl.sourceforge.net
00005  *
00006  *  Copyright (C) 2006, 2008 Roman Dementiev <dementiev@ira.uka.de>
00007  *
00008  *  Distributed under the Boost Software License, Version 1.0.
00009  *  (See accompanying file LICENSE_1_0.txt or copy at
00010  *  http://www.boost.org/LICENSE_1_0.txt)
00011  **************************************************************************/
00012 
00013 #ifndef STXXL_CONTAINERS_BTREE__BTREE_H
00014 #define STXXL_CONTAINERS_BTREE__BTREE_H
00015 
00016 #include <limits>
00017 #include <stxxl/bits/namespace.h>
00018 #include <stxxl/bits/containers/btree/iterator.h>
00019 #include <stxxl/bits/containers/btree/iterator_map.h>
00020 #include <stxxl/bits/containers/btree/leaf.h>
00021 #include <stxxl/bits/containers/btree/node_cache.h>
00022 #include <stxxl/bits/containers/btree/root_node.h>
00023 #include <stxxl/bits/containers/btree/node.h>
00024 #include <stxxl/vector>
00025 
00026 
00027 __STXXL_BEGIN_NAMESPACE
00028 
00029 namespace btree
00030 {
00031     template <class KeyType,
00032               class DataType,
00033               class CompareType,
00034               unsigned RawNodeSize,
00035               unsigned RawLeafSize,
00036               class PDAllocStrategy
00037               >
00038     class btree : private noncopyable
00039     {
00040     public:
00041         typedef KeyType key_type;
00042         typedef DataType data_type;
00043         typedef CompareType key_compare;
00044 
00045         typedef btree<KeyType, DataType, CompareType, RawNodeSize, RawLeafSize, PDAllocStrategy> SelfType;
00046 
00047         typedef PDAllocStrategy alloc_strategy_type;
00048 
00049         typedef stxxl::uint64 size_type;
00050         typedef stxxl::int64 difference_type;
00051         typedef std::pair<const key_type, data_type> value_type;
00052         typedef value_type & reference;
00053         typedef const value_type & const_reference;
00054         typedef value_type * pointer;
00055         typedef value_type const * const_pointer;
00056 
00057 
00058         // leaf type declarations
00059         typedef normal_leaf<key_type, data_type, key_compare, RawLeafSize, SelfType> leaf_type;
00060         friend class normal_leaf<key_type, data_type, key_compare, RawLeafSize, SelfType>;
00061         typedef typename leaf_type::block_type leaf_block_type;
00062         typedef typename leaf_type::bid_type leaf_bid_type;
00063         typedef node_cache<leaf_type, SelfType> leaf_cache_type;
00064         friend class node_cache<leaf_type, SelfType>;
00065         // iterator types
00066         typedef btree_iterator<SelfType> iterator;
00067         typedef btree_const_iterator<SelfType> const_iterator;
00068         friend class btree_iterator_base<SelfType>;
00069         // iterator map type
00070         typedef iterator_map<SelfType> iterator_map_type;
00071         // node type declarations
00072         typedef normal_node<key_type, key_compare, RawNodeSize, SelfType> node_type;
00073         typedef typename node_type::block_type node_block_type;
00074         friend class normal_node<key_type, key_compare, RawNodeSize, SelfType>;
00075         typedef typename node_type::bid_type node_bid_type;
00076         typedef node_cache<node_type, SelfType> node_cache_type;
00077         friend class node_cache<node_type, SelfType>;
00078 
00079         typedef typename leaf_type::value_compare value_compare;
00080 
00081         enum {
00082             min_node_size = node_type::min_size,
00083             max_node_size = node_type::max_size,
00084             min_leaf_size = leaf_type::min_size,
00085             max_leaf_size = leaf_type::max_size
00086         };
00087 
00088     private:
00089         key_compare key_compare_;
00090         mutable node_cache_type node_cache_;
00091         mutable leaf_cache_type leaf_cache_;
00092         iterator_map_type iterator_map_;
00093         size_type size_;
00094         unsigned_type height_;
00095         bool prefetching_enabled_;
00096         block_manager * bm_;
00097         alloc_strategy_type alloc_strategy_;
00098 
00099         typedef std::map<key_type, node_bid_type, key_compare> root_node_type;
00100         typedef typename root_node_type::iterator root_node_iterator_type;
00101         typedef typename root_node_type::const_iterator root_node_const_iterator_type;
00102         typedef std::pair<key_type, node_bid_type> root_node_pair_type;
00103 
00104 
00105         root_node_type root_node_;
00106         iterator end_iterator;
00107 
00108 
00109         void insert_into_root(const std::pair<key_type, node_bid_type> & splitter)
00110         {
00111             std::pair<root_node_iterator_type, bool> result =
00112                 root_node_.insert(splitter);
00113             assert(result.second == true);
00114             if (root_node_.size() > max_node_size)      // root overflow
00115             {
00116                 STXXL_VERBOSE1("btree::insert_into_root, overflow happened, splitting");
00117 
00118                 node_bid_type LeftBid;
00119                 node_type * LeftNode = node_cache_.get_new_node(LeftBid);
00120                 assert(LeftNode);
00121                 node_bid_type RightBid;
00122                 node_type * RightNode = node_cache_.get_new_node(RightBid);
00123                 assert(RightNode);
00124 
00125                 const unsigned_type old_size = root_node_.size();
00126                 const unsigned_type half = root_node_.size() / 2;
00127                 unsigned_type i = 0;
00128                 root_node_iterator_type it = root_node_.begin();
00129                 typename node_block_type::iterator block_it = LeftNode->block().begin();
00130                 while (i < half)                // copy smaller part
00131                 {
00132                     *block_it = *it;
00133                     ++i;
00134                     ++block_it;
00135                     ++it;
00136                 }
00137                 LeftNode->block().info.cur_size = half;
00138                 key_type LeftKey = (LeftNode->block()[half - 1]).first;
00139 
00140                 block_it = RightNode->block().begin();
00141                 while (i < old_size)            // copy larger part
00142                 {
00143                     *block_it = *it;
00144                     ++i;
00145                     ++block_it;
00146                     ++it;
00147                 }
00148                 unsigned_type right_size = RightNode->block().info.cur_size = old_size - half;
00149                 key_type RightKey = (RightNode->block()[right_size - 1]).first;
00150 
00151                 assert(old_size == RightNode->size() + LeftNode->size());
00152 
00153                 // create new root node
00154                 root_node_.clear();
00155                 root_node_.insert(root_node_pair_type(LeftKey, LeftBid));
00156                 root_node_.insert(root_node_pair_type(RightKey, RightBid));
00157 
00158 
00159                 ++height_;
00160                 STXXL_VERBOSE1("btree Increasing height to " << height_);
00161                 if (node_cache_.size() < (height_ - 1))
00162                 {
00163                     STXXL_THROW(std::runtime_error, "btree::bulk_construction", "The height of the tree (" << height_ << ") has exceeded the required capacity ("
00164                                                                                                            << (node_cache_.size() + 1) << ") of the node cache. " <<
00165                                 "Increase the node cache size.");
00166                 }
00167             }
00168         }
00169 
00170         template <class CacheType>
00171         void fuse_or_balance(root_node_iterator_type UIt, CacheType & cache_)
00172         {
00173             typedef typename CacheType::node_type local_node_type;
00174             typedef typename local_node_type::bid_type local_bid_type;
00175 
00176             root_node_iterator_type leftIt, rightIt;
00177             if (UIt->first == key_compare::max_value())         // UIt is the last entry in the root
00178             {
00179                 assert(UIt != root_node_.begin());
00180                 rightIt = UIt;
00181                 leftIt = --UIt;
00182             }
00183             else
00184             {
00185                 leftIt = UIt;
00186                 rightIt = ++UIt;
00187                 assert(rightIt != root_node_.end());
00188             }
00189 
00190             // now fuse or balance nodes pointed by leftIt and rightIt
00191             local_bid_type LeftBid = (local_bid_type)leftIt->second;
00192             local_bid_type RightBid = (local_bid_type)rightIt->second;
00193             local_node_type * LeftNode = cache_.get_node(LeftBid, true);
00194             local_node_type * RightNode = cache_.get_node(RightBid, true);
00195 
00196             const unsigned_type TotalSize = LeftNode->size() + RightNode->size();
00197             if (TotalSize <= RightNode->max_nelements())
00198             {
00199                 // fuse
00200                 RightNode->fuse(*LeftNode);             // add the content of LeftNode to RightNode
00201 
00202                 cache_.unfix_node(RightBid);
00203                 cache_.delete_node(LeftBid);            // 'delete_node' unfixes LeftBid also
00204 
00205                 root_node_.erase(leftIt);               // delete left BID from the root
00206             }
00207             else
00208             {
00209                 // balance
00210 
00211                 key_type NewSplitter = RightNode->balance(*LeftNode);
00212 
00213                 root_node_.erase(leftIt);               // delete left BID from the root
00214                 // reinsert with the new key
00215                 root_node_.insert(root_node_pair_type(NewSplitter, (node_bid_type)LeftBid));
00216 
00217                 cache_.unfix_node(LeftBid);
00218                 cache_.unfix_node(RightBid);
00219             }
00220         }
00221 
00222         void create_empty_leaf()
00223         {
00224             leaf_bid_type NewBid;
00225             leaf_type * NewLeaf = leaf_cache_.get_new_node(NewBid);
00226             assert(NewLeaf);
00227             end_iterator = NewLeaf->end();              // initialize end() iterator
00228             root_node_.insert(root_node_pair_type(key_compare::max_value(), (node_bid_type)NewBid));
00229         }
00230 
00231         void deallocate_children()
00232         {
00233             if (height_ == 2)
00234             {
00235                 // we have children leaves here
00236                 root_node_const_iterator_type it = root_node_.begin();
00237                 for ( ; it != root_node_.end(); ++it)
00238                 {
00239                     // delete from leaf cache and deallocate bid
00240                     leaf_cache_.delete_node((leaf_bid_type)it->second);
00241                 }
00242             }
00243             else
00244             {
00245                 root_node_const_iterator_type it = root_node_.begin();
00246                 for ( ; it != root_node_.end(); ++it)
00247                 {
00248                     node_type * Node = node_cache_.get_node((node_bid_type)it->second);
00249                     assert(Node);
00250                     Node->deallocate_children(height_ - 1);
00251                     // delete from node cache and deallocate bid
00252                     node_cache_.delete_node((node_bid_type)it->second);
00253                 }
00254             }
00255         }
00256 
00257         template <class InputIterator>
00258         void bulk_construction(InputIterator b, InputIterator e, double node_fill_factor, double leaf_fill_factor)
00259         {
00260             assert(node_fill_factor >= 0.5);
00261             assert(leaf_fill_factor >= 0.5);
00262             key_type lastKey = key_compare::max_value();
00263 
00264             typedef std::pair<key_type, node_bid_type> key_bid_pair;
00265             typedef typename stxxl::VECTOR_GENERATOR<key_bid_pair, 1, 1,
00266                                                      node_block_type::raw_size>::result key_bid_vector_type;
00267 
00268             key_bid_vector_type Bids;
00269 
00270             leaf_bid_type NewBid;
00271             leaf_type * Leaf = leaf_cache_.get_new_node(NewBid);
00272             const unsigned_type max_leaf_elements = unsigned_type(double(Leaf->max_nelements()) * leaf_fill_factor);
00273 
00274             while (b != e)
00275             {
00276                 // write data in leaves
00277 
00278                 // if *b not equal to the last element
00279                 if (key_compare_(b->first, lastKey) || key_compare_(lastKey, b->first))
00280                 {
00281                     ++size_;
00282                     if (Leaf->size() == max_leaf_elements)
00283                     {
00284                         // overflow, need a new block
00285                         Bids.push_back(key_bid_pair(Leaf->back().first, (node_bid_type)NewBid));
00286 
00287                         leaf_type * NewLeaf = leaf_cache_.get_new_node(NewBid);
00288                         assert(NewLeaf);
00289                         // Setting links
00290                         Leaf->succ() = NewLeaf->my_bid();
00291                         NewLeaf->pred() = Leaf->my_bid();
00292 
00293                         Leaf = NewLeaf;
00294                     }
00295                     Leaf->push_back(*b);
00296                     lastKey = b->first;
00297                 }
00298                 ++b;
00299             }
00300 
00301             // rebalance the last leaf
00302             if (Leaf->underflows() && !Bids.empty())
00303             {
00304                 leaf_type * LeftLeaf = leaf_cache_.get_node((leaf_bid_type)(Bids.back().second));
00305                 assert(LeftLeaf);
00306                 if (LeftLeaf->size() + Leaf->size() <= Leaf->max_nelements()) // can fuse
00307                 {
00308                     Leaf->fuse(*LeftLeaf);
00309                     leaf_cache_.delete_node((leaf_bid_type)(Bids.back().second));
00310                     Bids.pop_back();
00311                     assert(!Leaf->overflows() && !Leaf->underflows());
00312                 }
00313                 else
00314                 {
00315                     // need to rebalance
00316                     const key_type NewSplitter = Leaf->balance(*LeftLeaf);
00317                     Bids.back().first = NewSplitter;
00318                     assert(!LeftLeaf->overflows() && !LeftLeaf->underflows());
00319                 }
00320             }
00321 
00322             assert(!Leaf->overflows() && (!Leaf->underflows() || size_ <= max_leaf_size));
00323 
00324             end_iterator = Leaf->end();             // initialize end() iterator
00325 
00326             Bids.push_back(key_bid_pair(key_compare::max_value(), (node_bid_type)NewBid));
00327 
00328             const unsigned_type max_node_elements = unsigned_type(double(max_node_size) * node_fill_factor);
00329 
00330             while (Bids.size() > max_node_elements)
00331             {
00332                 key_bid_vector_type ParentBids;
00333 
00334                 stxxl::uint64 nparents = div_ceil(Bids.size(), max_node_elements);
00335                 assert(nparents >= 2);
00336                 STXXL_VERBOSE1("btree bulk constructBids.size() " << Bids.size() << " nparents: " << nparents << " max_ns: "
00337                                                                   << max_node_elements);
00338                 STXXL_UNUSED(nparents);
00339                 typename key_bid_vector_type::const_iterator it = Bids.begin();
00340 
00341                 do
00342                 {
00343                     node_bid_type NewBid;
00344                     node_type * Node = node_cache_.get_new_node(NewBid);
00345                     assert(Node);
00346                     unsigned_type cnt = 0;
00347                     for ( ; cnt < max_node_elements && it != Bids.end(); ++cnt, ++it)
00348                     {
00349                         Node->push_back(*it);
00350                     }
00351                     STXXL_VERBOSE1("btree bulk construct Node size : " << Node->size() << " limits: " <<
00352                                    Node->min_nelements() << " " << Node->max_nelements() << " max_node_elements: " << max_node_elements);
00353 
00354                     if (Node->underflows())
00355                     {
00356                         assert(it == Bids.end());                       // this can happen only at the end
00357                         assert(!ParentBids.empty());
00358 
00359                         node_type * LeftNode = node_cache_.get_node(ParentBids.back().second);
00360                         assert(LeftNode);
00361                         if (LeftNode->size() + Node->size() <= Node->max_nelements()) // can fuse
00362                         {
00363                             Node->fuse(*LeftNode);
00364                             node_cache_.delete_node(ParentBids.back().second);
00365                             ParentBids.pop_back();
00366                         }
00367                         else
00368                         {   // need to rebalance
00369                             const key_type NewSplitter = Node->balance(*LeftNode);
00370                             ParentBids.back().first = NewSplitter;
00371                             assert(!LeftNode->overflows() && !LeftNode->underflows());
00372                         }
00373                     }
00374                     assert(!Node->overflows() && !Node->underflows());
00375 
00376                     ParentBids.push_back(key_bid_pair(Node->back().first, NewBid));
00377                 } while (it != Bids.end());
00378 
00379                 std::swap(ParentBids, Bids);
00380 
00381                 assert(nparents == Bids.size() || (nparents - 1) == Bids.size());
00382 
00383                 ++height_;
00384                 STXXL_VERBOSE1("Increasing height to " << height_);
00385                 if (node_cache_.size() < (height_ - 1))
00386                 {
00387                     STXXL_THROW(std::runtime_error, "btree::bulk_construction", "The height of the tree (" << height_ << ") has exceeded the required capacity ("
00388                                                                                                            << (node_cache_.size() + 1) << ") of the node cache. " <<
00389                                 "Increase the node cache size.");
00390                 }
00391             }
00392 
00393             root_node_.insert(Bids.begin(), Bids.end());
00394         }
00395 
00396     public:
00397         btree(unsigned_type node_cache_size_in_bytes,
00398               unsigned_type leaf_cache_size_in_bytes
00399               ) :
00400             node_cache_(node_cache_size_in_bytes, this, key_compare_),
00401             leaf_cache_(leaf_cache_size_in_bytes, this, key_compare_),
00402             iterator_map_(this),
00403             size_(0),
00404             height_(2),
00405             prefetching_enabled_(true),
00406             bm_(block_manager::get_instance())
00407         {
00408             STXXL_VERBOSE1("Creating a btree, addr=" << this);
00409             STXXL_VERBOSE1(" bytes in a node: " << node_bid_type::size);
00410             STXXL_VERBOSE1(" bytes in a leaf: " << leaf_bid_type::size);
00411             STXXL_VERBOSE1(" elements in a node: " << node_block_type::size);
00412             STXXL_VERBOSE1(" elements in a leaf: " << leaf_block_type::size);
00413             STXXL_VERBOSE1(" size of a node element: " << sizeof(typename node_block_type::value_type));
00414             STXXL_VERBOSE1(" size of a leaf element: " << sizeof(typename leaf_block_type::value_type));
00415 
00416 
00417             create_empty_leaf();
00418         }
00419 
00420         btree(const key_compare & c_,
00421               unsigned_type node_cache_size_in_bytes,
00422               unsigned_type leaf_cache_size_in_bytes
00423               ) :
00424             key_compare_(c_),
00425             node_cache_(node_cache_size_in_bytes, this, key_compare_),
00426             leaf_cache_(leaf_cache_size_in_bytes, this, key_compare_),
00427             iterator_map_(this),
00428             size_(0),
00429             height_(2),
00430             prefetching_enabled_(true),
00431             bm_(block_manager::get_instance())
00432         {
00433             STXXL_VERBOSE1("Creating a btree, addr=" << this);
00434             STXXL_VERBOSE1(" bytes in a node: " << node_bid_type::size);
00435             STXXL_VERBOSE1(" bytes in a leaf: " << leaf_bid_type::size);
00436 
00437             create_empty_leaf();
00438         }
00439 
00440         virtual ~btree()
00441         {
00442             try
00443             {
00444                 deallocate_children();
00445             } catch (...)
00446             {
00447                 // no exceptions in destructor
00448             }
00449         }
00450 
00451         size_type size() const
00452         {
00453             return size_;
00454         }
00455 
00456         size_type max_size() const
00457         {
00458             return (std::numeric_limits<size_type>::max)();
00459         }
00460 
00461         bool empty() const
00462         {
00463             return !size_;
00464         }
00465 
00466         std::pair<iterator, bool> insert(const value_type & x)
00467         {
00468             root_node_iterator_type it = root_node_.lower_bound(x.first);
00469             assert(!root_node_.empty());
00470             assert(it != root_node_.end());
00471             if (height_ == 2)            // 'it' points to a leaf
00472             {
00473                 STXXL_VERBOSE1("Inserting new value into a leaf");
00474                 leaf_type * Leaf = leaf_cache_.get_node((leaf_bid_type)it->second, true);
00475                 assert(Leaf);
00476                 std::pair<key_type, leaf_bid_type> Splitter;
00477                 std::pair<iterator, bool> result = Leaf->insert(x, Splitter);
00478                 if (result.second)
00479                     ++size_;
00480 
00481                 leaf_cache_.unfix_node((leaf_bid_type)it->second);
00482                 //if(key_compare::max_value() == Splitter.first)
00483                 if (!(key_compare_(key_compare::max_value(), Splitter.first) ||
00484                       key_compare_(Splitter.first, key_compare::max_value())))
00485                     return result;
00486                 // no overflow/splitting happened
00487 
00488                 STXXL_VERBOSE1("Inserting new value into root node");
00489 
00490                 insert_into_root(std::make_pair(Splitter.first, node_bid_type(Splitter.second)));
00491 
00492                 assert(leaf_cache_.nfixed() == 0);
00493                 assert(node_cache_.nfixed() == 0);
00494                 return result;
00495             }
00496 
00497             // 'it' points to a node
00498             STXXL_VERBOSE1("Inserting new value into a node");
00499             node_type * Node = node_cache_.get_node((node_bid_type)it->second, true);
00500             assert(Node);
00501             std::pair<key_type, node_bid_type> Splitter;
00502             std::pair<iterator, bool> result = Node->insert(x, height_ - 1, Splitter);
00503             if (result.second)
00504                 ++size_;
00505 
00506             node_cache_.unfix_node((node_bid_type)it->second);
00507             //if(key_compare::max_value() == Splitter.first)
00508             if (!(key_compare_(key_compare::max_value(), Splitter.first) ||
00509                   key_compare_(Splitter.first, key_compare::max_value())))
00510                 return result;
00511             // no overflow/splitting happened
00512 
00513             STXXL_VERBOSE1("Inserting new value into root node");
00514 
00515             insert_into_root(Splitter);
00516 
00517             assert(leaf_cache_.nfixed() == 0);
00518             assert(node_cache_.nfixed() == 0);
00519 
00520             return result;
00521         }
00522 
00523         iterator begin()
00524         {
00525             root_node_iterator_type it = root_node_.begin();
00526             assert(it != root_node_.end());
00527 
00528             if (height_ == 2)            // 'it' points to a leaf
00529             {
00530                 STXXL_VERBOSE1("btree: retrieving begin() from the first leaf");
00531                 leaf_type * Leaf = leaf_cache_.get_node((leaf_bid_type)it->second);
00532                 assert(Leaf);
00533 
00534                 assert(leaf_cache_.nfixed() == 0);
00535                 assert(node_cache_.nfixed() == 0);
00536                 return Leaf->begin();
00537             }
00538 
00539             // 'it' points to a node
00540             STXXL_VERBOSE1("btree: retrieving begin() from the first node");
00541             node_type * Node = node_cache_.get_node((node_bid_type)it->second, true);
00542             assert(Node);
00543             iterator result = Node->begin(height_ - 1);
00544             node_cache_.unfix_node((node_bid_type)it->second);
00545 
00546             assert(leaf_cache_.nfixed() == 0);
00547             assert(node_cache_.nfixed() == 0);
00548 
00549             return result;
00550         }
00551 
00552         const_iterator begin() const
00553         {
00554             root_node_const_iterator_type it = root_node_.begin();
00555             assert(it != root_node_.end());
00556 
00557             if (height_ == 2)            // 'it' points to a leaf
00558             {
00559                 STXXL_VERBOSE1("btree: retrieving begin() from the first leaf");
00560                 leaf_type const * Leaf = leaf_cache_.get_const_node((leaf_bid_type)it->second);
00561                 assert(Leaf);
00562                 assert(leaf_cache_.nfixed() == 0);
00563                 assert(node_cache_.nfixed() == 0);
00564                 return Leaf->begin();
00565             }
00566 
00567             // 'it' points to a node
00568             STXXL_VERBOSE1("btree: retrieving begin() from the first node");
00569             node_type const * Node = node_cache_.get_const_node((node_bid_type)it->second, true);
00570             assert(Node);
00571             const_iterator result = Node->begin(height_ - 1);
00572             node_cache_.unfix_node((node_bid_type)it->second);
00573             assert(leaf_cache_.nfixed() == 0);
00574             assert(node_cache_.nfixed() == 0);
00575             return result;
00576         }
00577 
00578         iterator end()
00579         {
00580             return end_iterator;
00581         }
00582 
00583         const_iterator end() const
00584         {
00585             return end_iterator;
00586         }
00587 
00588         data_type & operator [] (const key_type & k)
00589         {
00590             return (*((insert(value_type(k, data_type()))).first)).second;
00591         }
00592 
00593         iterator find(const key_type & k)
00594         {
00595             root_node_iterator_type it = root_node_.lower_bound(k);
00596             assert(it != root_node_.end());
00597 
00598             if (height_ == 2)            // 'it' points to a leaf
00599             {
00600                 STXXL_VERBOSE1("Searching in a leaf");
00601                 leaf_type * Leaf = leaf_cache_.get_node((leaf_bid_type)it->second, true);
00602                 assert(Leaf);
00603                 iterator result = Leaf->find(k);
00604                 leaf_cache_.unfix_node((leaf_bid_type)it->second);
00605                 assert(result == end() || result->first == k);
00606                 assert(leaf_cache_.nfixed() == 0);
00607                 assert(node_cache_.nfixed() == 0);
00608                 return result;
00609             }
00610 
00611             // 'it' points to a node
00612             STXXL_VERBOSE1("Searching in a node");
00613             node_type * Node = node_cache_.get_node((node_bid_type)it->second, true);
00614             assert(Node);
00615             iterator result = Node->find(k, height_ - 1);
00616             node_cache_.unfix_node((node_bid_type)it->second);
00617 
00618             assert(result == end() || result->first == k);
00619             assert(leaf_cache_.nfixed() == 0);
00620             assert(node_cache_.nfixed() == 0);
00621             return result;
00622         }
00623 
00624         const_iterator find(const key_type & k) const
00625         {
00626             root_node_const_iterator_type it = root_node_.lower_bound(k);
00627             assert(it != root_node_.end());
00628 
00629             if (height_ == 2)            // 'it' points to a leaf
00630             {
00631                 STXXL_VERBOSE1("Searching in a leaf");
00632                 leaf_type const * Leaf = leaf_cache_.get_const_node((leaf_bid_type)it->second, true);
00633                 assert(Leaf);
00634                 const_iterator result = Leaf->find(k);
00635                 leaf_cache_.unfix_node((leaf_bid_type)it->second);
00636                 assert(result == end() || result->first == k);
00637                 assert(leaf_cache_.nfixed() == 0);
00638                 assert(node_cache_.nfixed() == 0);
00639                 return result;
00640             }
00641 
00642             // 'it' points to a node
00643             STXXL_VERBOSE1("Searching in a node");
00644             node_type const * Node = node_cache_.get_const_node((node_bid_type)it->second, true);
00645             assert(Node);
00646             const_iterator result = Node->find(k, height_ - 1);
00647             node_cache_.unfix_node((node_bid_type)it->second);
00648 
00649             assert(result == end() || result->first == k);
00650             assert(leaf_cache_.nfixed() == 0);
00651             assert(node_cache_.nfixed() == 0);
00652             return result;
00653         }
00654 
00655         iterator lower_bound(const key_type & k)
00656         {
00657             root_node_iterator_type it = root_node_.lower_bound(k);
00658             assert(it != root_node_.end());
00659 
00660             if (height_ == 2)            // 'it' points to a leaf
00661             {
00662                 STXXL_VERBOSE1("Searching lower bound in a leaf");
00663                 leaf_type * Leaf = leaf_cache_.get_node((leaf_bid_type)it->second, true);
00664                 assert(Leaf);
00665                 iterator result = Leaf->lower_bound(k);
00666                 leaf_cache_.unfix_node((leaf_bid_type)it->second);
00667                 assert(leaf_cache_.nfixed() == 0);
00668                 assert(node_cache_.nfixed() == 0);
00669                 return result;
00670             }
00671 
00672             // 'it' points to a node
00673             STXXL_VERBOSE1("Searching lower bound in a node");
00674             node_type * Node = node_cache_.get_node((node_bid_type)it->second, true);
00675             assert(Node);
00676             iterator result = Node->lower_bound(k, height_ - 1);
00677             node_cache_.unfix_node((node_bid_type)it->second);
00678 
00679             assert(leaf_cache_.nfixed() == 0);
00680             assert(node_cache_.nfixed() == 0);
00681             return result;
00682         }
00683 
00684         const_iterator lower_bound(const key_type & k) const
00685         {
00686             root_node_const_iterator_type it = root_node_.lower_bound(k);
00687             assert(it != root_node_.end());
00688 
00689             if (height_ == 2)            // 'it' points to a leaf
00690             {
00691                 STXXL_VERBOSE1("Searching lower bound in a leaf");
00692                 leaf_type const * Leaf = leaf_cache_.get_const_node((leaf_bid_type)it->second, true);
00693                 assert(Leaf);
00694                 const_iterator result = Leaf->lower_bound(k);
00695                 leaf_cache_.unfix_node((leaf_bid_type)it->second);
00696 
00697                 assert(leaf_cache_.nfixed() == 0);
00698                 assert(node_cache_.nfixed() == 0);
00699                 return result;
00700             }
00701 
00702             // 'it' points to a node
00703             STXXL_VERBOSE1("Searching lower bound in a node");
00704             node_type const * Node = node_cache_.get_const_node((node_bid_type)it->second, true);
00705             assert(Node);
00706             const_iterator result = Node->lower_bound(k, height_ - 1);
00707             node_cache_.unfix_node((node_bid_type)it->second);
00708 
00709             assert(leaf_cache_.nfixed() == 0);
00710             assert(node_cache_.nfixed() == 0);
00711             return result;
00712         }
00713 
00714         iterator upper_bound(const key_type & k)
00715         {
00716             root_node_iterator_type it = root_node_.upper_bound(k);
00717             assert(it != root_node_.end());
00718 
00719             if (height_ == 2)            // 'it' points to a leaf
00720             {
00721                 STXXL_VERBOSE1("Searching upper bound in a leaf");
00722                 leaf_type * Leaf = leaf_cache_.get_node((leaf_bid_type)it->second, true);
00723                 assert(Leaf);
00724                 iterator result = Leaf->upper_bound(k);
00725                 leaf_cache_.unfix_node((leaf_bid_type)it->second);
00726 
00727                 assert(leaf_cache_.nfixed() == 0);
00728                 assert(node_cache_.nfixed() == 0);
00729                 return result;
00730             }
00731 
00732             // 'it' points to a node
00733             STXXL_VERBOSE1("Searching upper bound in a node");
00734             node_type * Node = node_cache_.get_node((node_bid_type)it->second, true);
00735             assert(Node);
00736             iterator result = Node->upper_bound(k, height_ - 1);
00737             node_cache_.unfix_node((node_bid_type)it->second);
00738 
00739             assert(leaf_cache_.nfixed() == 0);
00740             assert(node_cache_.nfixed() == 0);
00741             return result;
00742         }
00743 
00744         const_iterator upper_bound(const key_type & k) const
00745         {
00746             root_node_const_iterator_type it = root_node_.upper_bound(k);
00747             assert(it != root_node_.end());
00748 
00749             if (height_ == 2)            // 'it' points to a leaf
00750             {
00751                 STXXL_VERBOSE1("Searching upper bound in a leaf");
00752                 leaf_type const * Leaf = leaf_cache_.get_const_node((leaf_bid_type)it->second, true);
00753                 assert(Leaf);
00754                 const_iterator result = Leaf->upper_bound(k);
00755                 leaf_cache_.unfix_node((leaf_bid_type)it->second);
00756 
00757                 assert(leaf_cache_.nfixed() == 0);
00758                 assert(node_cache_.nfixed() == 0);
00759                 return result;
00760             }
00761 
00762             // 'it' points to a node
00763             STXXL_VERBOSE1("Searching upper bound in a node");
00764             node_type const * Node = node_cache_.get_const_node((node_bid_type)it->second, true);
00765             assert(Node);
00766             const_iterator result = Node->upper_bound(k, height_ - 1);
00767             node_cache_.unfix_node((node_bid_type)it->second);
00768 
00769             assert(leaf_cache_.nfixed() == 0);
00770             assert(node_cache_.nfixed() == 0);
00771             return result;
00772         }
00773 
00774         std::pair<iterator, iterator> equal_range(const key_type & k)
00775         {
00776             iterator l = lower_bound(k);                                // l->first >= k
00777 
00778             if (l == end() || key_compare_(k, l->first))                // if (k < l->first)
00779                 return std::pair<iterator, iterator>(l, l);
00780             // then upper_bound == lower_bound
00781 
00782             iterator u = l;
00783             ++u;                                                        // only one element ==k can exist
00784 
00785             assert(leaf_cache_.nfixed() == 0);
00786             assert(node_cache_.nfixed() == 0);
00787 
00788             return std::pair<iterator, iterator>(l, u);                 // then upper_bound == (lower_bound+1)
00789         }
00790 
00791         std::pair<const_iterator, const_iterator> equal_range(const key_type & k) const
00792         {
00793             const_iterator l = lower_bound(k);                          // l->first >= k
00794 
00795             if (l == end() || key_compare_(k, l->first))                // if (k < l->first)
00796                 return std::pair<const_iterator, const_iterator>(l, l);
00797             // then upper_bound == lower_bound
00798 
00799             const_iterator u = l;
00800             ++u;                                                        // only one element ==k can exist
00801 
00802             assert(leaf_cache_.nfixed() == 0);
00803             assert(node_cache_.nfixed() == 0);
00804             return std::pair<const_iterator, const_iterator>(l, u);     // then upper_bound == (lower_bound+1)
00805         }
00806 
00807         size_type erase(const key_type & k)
00808         {
00809             root_node_iterator_type it = root_node_.lower_bound(k);
00810             assert(it != root_node_.end());
00811             if (height_ == 2)            // 'it' points to a leaf
00812             {
00813                 STXXL_VERBOSE1("Deleting key from a leaf");
00814                 leaf_type * Leaf = leaf_cache_.get_node((leaf_bid_type)it->second, true);
00815                 assert(Leaf);
00816                 size_type result = Leaf->erase(k);
00817                 size_ -= result;
00818                 leaf_cache_.unfix_node((leaf_bid_type)it->second);
00819                 assert(leaf_cache_.nfixed() == 0);
00820                 assert(node_cache_.nfixed() == 0);
00821 
00822                 if ((!Leaf->underflows()) || root_node_.size() == 1)
00823                     return result;
00824                 // no underflow or root has a special degree 1 (too few elements)
00825 
00826                 STXXL_VERBOSE1("btree: Fusing or rebalancing a leaf");
00827                 fuse_or_balance(it, leaf_cache_);
00828 
00829                 assert(leaf_cache_.nfixed() == 0);
00830                 assert(node_cache_.nfixed() == 0);
00831 
00832                 return result;
00833             }
00834 
00835             // 'it' points to a node
00836             STXXL_VERBOSE1("Deleting key from a node");
00837             assert(root_node_.size() >= 2);
00838             node_type * Node = node_cache_.get_node((node_bid_type)it->second, true);
00839             assert(Node);
00840             size_type result = Node->erase(k, height_ - 1);
00841             size_ -= result;
00842             node_cache_.unfix_node((node_bid_type)it->second);
00843             assert(leaf_cache_.nfixed() == 0);
00844             assert(node_cache_.nfixed() == 0);
00845             if (!Node->underflows())
00846                 return result;
00847             // no underflow happened
00848 
00849             STXXL_VERBOSE1("Fusing or rebalancing a node");
00850             fuse_or_balance(it, node_cache_);
00851 
00852             if (root_node_.size() == 1)
00853             {
00854                 STXXL_VERBOSE1("btree Root has size 1 and height > 2");
00855                 STXXL_VERBOSE1("btree Deallocate root and decrease height");
00856                 it = root_node_.begin();
00857                 node_bid_type RootBid = it->second;
00858                 assert(it->first == key_compare::max_value());
00859                 node_type * RootNode = node_cache_.get_node(RootBid);
00860                 assert(RootNode);
00861                 assert(RootNode->back().first == key_compare::max_value());
00862                 root_node_.clear();
00863                 root_node_.insert(RootNode->block().begin(),
00864                                   RootNode->block().begin() + RootNode->size());
00865 
00866                 node_cache_.delete_node(RootBid);
00867                 --height_;
00868                 STXXL_VERBOSE1("btree Decreasing height to " << height_);
00869             }
00870 
00871             assert(leaf_cache_.nfixed() == 0);
00872             assert(node_cache_.nfixed() == 0);
00873 
00874             return result;
00875         }
00876 
00877         size_type count(const key_type & k)
00878         {
00879             if (find(k) == end())
00880                 return 0;
00881 
00882             return 1;
00883         }
00884 
00885         void erase(iterator pos)
00886         {
00887             assert(pos != end());
00888 #ifndef NDEBUG
00889             size_type old_size = size();
00890 #endif
00891 
00892             erase(pos->first);
00893 
00894             assert(size() == old_size - 1);
00895         }
00896 
00897         iterator insert(iterator /*pos*/, const value_type & x)
00898         {
00899             return insert(x).first;             // pos ignored in the current version
00900         }
00901 
00902         void clear()
00903         {
00904             deallocate_children();
00905 
00906             root_node_.clear();
00907 
00908             size_ = 0;
00909             height_ = 2,
00910 
00911             create_empty_leaf();
00912             assert(leaf_cache_.nfixed() == 0);
00913             assert(node_cache_.nfixed() == 0);
00914         }
00915 
00916         template <class InputIterator>
00917         void insert(InputIterator b, InputIterator e)
00918         {
00919             while (b != e)
00920             {
00921                 insert(*(b++));
00922             }
00923         }
00924 
00925         template <class InputIterator>
00926         btree(InputIterator b,
00927               InputIterator e,
00928               const key_compare & c_,
00929               unsigned_type node_cache_size_in_bytes,
00930               unsigned_type leaf_cache_size_in_bytes,
00931               bool range_sorted = false,
00932               double node_fill_factor = 0.75,
00933               double leaf_fill_factor = 0.6
00934               ) :
00935             key_compare_(c_),
00936             node_cache_(node_cache_size_in_bytes, this, key_compare_),
00937             leaf_cache_(leaf_cache_size_in_bytes, this, key_compare_),
00938             iterator_map_(this),
00939             size_(0),
00940             height_(2),
00941             prefetching_enabled_(true),
00942             bm_(block_manager::get_instance())
00943         {
00944             STXXL_VERBOSE1("Creating a btree, addr=" << this);
00945             STXXL_VERBOSE1(" bytes in a node: " << node_bid_type::size);
00946             STXXL_VERBOSE1(" bytes in a leaf: " << leaf_bid_type::size);
00947 
00948             if (range_sorted == false)
00949             {
00950                 create_empty_leaf();
00951                 insert(b, e);
00952                 assert(leaf_cache_.nfixed() == 0);
00953                 assert(node_cache_.nfixed() == 0);
00954                 return;
00955             }
00956 
00957             bulk_construction(b, e, node_fill_factor, leaf_fill_factor);
00958             assert(leaf_cache_.nfixed() == 0);
00959             assert(node_cache_.nfixed() == 0);
00960         }
00961 
00962 
00963         template <class InputIterator>
00964         btree(InputIterator b,
00965               InputIterator e,
00966               unsigned_type node_cache_size_in_bytes,
00967               unsigned_type leaf_cache_size_in_bytes,
00968               bool range_sorted = false,
00969               double node_fill_factor = 0.75,
00970               double leaf_fill_factor = 0.6
00971               ) :
00972             node_cache_(node_cache_size_in_bytes, this, key_compare_),
00973             leaf_cache_(leaf_cache_size_in_bytes, this, key_compare_),
00974             iterator_map_(this),
00975             size_(0),
00976             height_(2),
00977             prefetching_enabled_(true),
00978             bm_(block_manager::get_instance())
00979         {
00980             STXXL_VERBOSE1("Creating a btree, addr=" << this);
00981             STXXL_VERBOSE1(" bytes in a node: " << node_bid_type::size);
00982             STXXL_VERBOSE1(" bytes in a leaf: " << leaf_bid_type::size);
00983 
00984             if (range_sorted == false)
00985             {
00986                 create_empty_leaf();
00987                 insert(b, e);
00988                 assert(leaf_cache_.nfixed() == 0);
00989                 assert(node_cache_.nfixed() == 0);
00990                 return;
00991             }
00992 
00993             bulk_construction(b, e, node_fill_factor, leaf_fill_factor);
00994             assert(leaf_cache_.nfixed() == 0);
00995             assert(node_cache_.nfixed() == 0);
00996         }
00997 
00998         void erase(iterator first, iterator last)
00999         {
01000             if (first == begin() && last == end())
01001                 clear();
01002 
01003             else
01004                 while (first != last)
01005                     erase(first++);
01006         }
01007 
01008         key_compare key_comp() const
01009         {
01010             return key_compare_;
01011         }
01012         value_compare value_comp() const
01013         {
01014             return value_compare(key_compare_);
01015         }
01016 
01017         void swap(btree & obj)
01018         {
01019             std::swap(key_compare_, obj.key_compare_);          // OK
01020 
01021             std::swap(node_cache_, obj.node_cache_);            // OK
01022             std::swap(leaf_cache_, obj.leaf_cache_);            // OK
01023 
01024 
01025             std::swap(iterator_map_, obj.iterator_map_);        // must update all iterators
01026 
01027             std::swap(end_iterator, obj.end_iterator);
01028             std::swap(size_, obj.size_);
01029             std::swap(height_, obj.height_);
01030             std::swap(alloc_strategy_, obj.alloc_strategy_);
01031             std::swap(root_node_, obj.root_node_);
01032         }
01033 
01034         void enable_prefetching()
01035         {
01036             prefetching_enabled_ = true;
01037         }
01038         void disable_prefetching()
01039         {
01040             prefetching_enabled_ = false;
01041         }
01042         bool prefetching_enabled()
01043         {
01044             return prefetching_enabled_;
01045         }
01046 
01047         void print_statistics(std::ostream & o) const
01048         {
01049             o << "Node cache statistics:" << std::endl;
01050             node_cache_.print_statistics(o);
01051             o << "Leaf cache statistics:" << std::endl;
01052             leaf_cache_.print_statistics(o);
01053         }
01054         void reset_statistics()
01055         {
01056             node_cache_.reset_statistics();
01057             leaf_cache_.reset_statistics();
01058         }
01059     };
01060 
01061     template <class KeyType,
01062               class DataType,
01063               class CompareType,
01064               unsigned LogNodeSize,
01065               unsigned LogLeafSize,
01066               class PDAllocStrategy
01067               >
01068     inline bool operator == (const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & a,
01069                              const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & b)
01070     {
01071         return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
01072     }
01073 
01074     template <class KeyType,
01075               class DataType,
01076               class CompareType,
01077               unsigned LogNodeSize,
01078               unsigned LogLeafSize,
01079               class PDAllocStrategy
01080               >
01081     inline bool operator != (const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & a,
01082                              const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & b)
01083     {
01084         return !(a == b);
01085     }
01086 
01087 
01088     template <class KeyType,
01089               class DataType,
01090               class CompareType,
01091               unsigned LogNodeSize,
01092               unsigned LogLeafSize,
01093               class PDAllocStrategy
01094               >
01095     inline bool operator < (const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & a,
01096                             const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & b)
01097     {
01098         return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
01099     }
01100 
01101 
01102     template <class KeyType,
01103               class DataType,
01104               class CompareType,
01105               unsigned LogNodeSize,
01106               unsigned LogLeafSize,
01107               class PDAllocStrategy
01108               >
01109     inline bool operator > (const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & a,
01110                             const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & b)
01111     {
01112         return b < a;
01113     }
01114 
01115 
01116     template <class KeyType,
01117               class DataType,
01118               class CompareType,
01119               unsigned LogNodeSize,
01120               unsigned LogLeafSize,
01121               class PDAllocStrategy
01122               >
01123     inline bool operator <= (const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & a,
01124                              const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & b)
01125     {
01126         return !(b < a);
01127     }
01128 
01129     template <class KeyType,
01130               class DataType,
01131               class CompareType,
01132               unsigned LogNodeSize,
01133               unsigned LogLeafSize,
01134               class PDAllocStrategy
01135               >
01136     inline bool operator >= (const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & a,
01137                              const btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & b)
01138     {
01139         return !(a < b);
01140     }
01141 }
01142 
01143 __STXXL_END_NAMESPACE
01144 
01145 
01146 namespace std
01147 {
01148     template <class KeyType,
01149               class DataType,
01150               class CompareType,
01151               unsigned LogNodeSize,
01152               unsigned LogLeafSize,
01153               class PDAllocStrategy
01154               >
01155     void swap(stxxl::btree::btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & a,
01156               stxxl::btree::btree<KeyType, DataType, CompareType, LogNodeSize, LogLeafSize, PDAllocStrategy> & b)
01157     {
01158         if (&a != &b)
01159             a.swap(b);
01160     }
01161 }
01162 
01163 #endif /* STXXL_CONTAINERS_BTREE__BTREE_H */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines