@@ -333,9 +333,9 @@ class radix_tree {
333333 static bool keys_equal (const K1 &k1, const K2 &k2);
334334 template <typename K1, typename K2>
335335 static int compare (const K1 &k1, const K2 &k2, byten_t offset = 0 );
336- template <bool Direction, typename Iterator, typename K >
337- const leaf *next_leaf (Iterator child, pointer_type parent ,
338- const K &k ) const ;
336+ template <bool Direction, typename Iterator>
337+ std::pair< bool , const leaf *> next_leaf (Iterator child,
338+ pointer_type parent ) const ;
339339 template <bool Direction>
340340 const leaf *find_leaf (pointer_type n) const ;
341341 static unsigned slice_index (char k, uint8_t shift);
@@ -619,6 +619,9 @@ struct radix_tree<Key, Value, BytesView>::radix_tree_iterator {
619619
620620 template <typename T>
621621 void replace_val (T &&rhs);
622+
623+ bool try_increment ();
624+ bool try_decrement ();
622625};
623626
624627template <typename Key, typename Value, typename BytesView>
@@ -2108,6 +2111,9 @@ radix_tree<Key, Value, BytesView>::internal_bound(const K &k) const
21082111 auto key = bytes_view (k);
21092112 auto pop = pool_base (pmemobj_pool_by_ptr (this ));
21102113
2114+ path_type path;
2115+ const_iterator result;
2116+
21112117 while (true ) {
21122118 auto r = root.load_acquire ();
21132119
@@ -2123,7 +2129,7 @@ radix_tree<Key, Value, BytesView>::internal_bound(const K &k) const
21232129 */
21242130 auto ret = descend (r, key);
21252131 auto leaf = ret.first ;
2126- auto path = ret.second ;
2132+ path = ret.second ;
21272133
21282134 if (!leaf)
21292135 continue ;
@@ -2134,10 +2140,17 @@ radix_tree<Key, Value, BytesView>::internal_bound(const K &k) const
21342140
21352141 /* Key exists. */
21362142 if (diff == key.size () && leaf_key.size () == key.size ()) {
2143+ result = const_iterator (leaf, this );
2144+
2145+ /* For lower_bound, result is looked-for element. */
21372146 if (Lower)
2138- return const_iterator (leaf, this );
2139- else
2140- return ++const_iterator (leaf, this );
2147+ break ;
2148+
2149+ /* For upper_bound, we need to find larger element. */
2150+ if (result.try_increment ())
2151+ break ;
2152+
2153+ continue ;
21412154 }
21422155
21432156 /* Descend the tree again by following the path. */
@@ -2147,8 +2160,6 @@ radix_tree<Key, Value, BytesView>::internal_bound(const K &k) const
21472160 auto slot = node_d.slot ;
21482161 auto prev = node_d.prev ;
21492162
2150- const_iterator result;
2151-
21522163 /*
21532164 * n would point to element with key which we are looking for
21542165 * (if it existed). All elements on the left are smaller and all
@@ -2160,9 +2171,12 @@ radix_tree<Key, Value, BytesView>::internal_bound(const K &k) const
21602171 auto target_leaf = next_leaf<node::direction::Forward>(
21612172 prev->template make_iterator <
21622173 node::direction::Forward>(slot),
2163- prev, k );
2174+ prev);
21642175
2165- result = const_iterator (target_leaf, this );
2176+ if (!target_leaf.first )
2177+ continue ;
2178+
2179+ result = const_iterator (target_leaf.second , this );
21662180 } else if (diff == key.size ()) {
21672181 /* The looked-for key is a prefix of the leaf key. The
21682182 * target node must be the smallest leaf within *slot's
@@ -2178,10 +2192,24 @@ radix_tree<Key, Value, BytesView>::internal_bound(const K &k) const
21782192
21792193 result = const_iterator (target_leaf, this );
21802194 } else if (diff == leaf_key.size ()) {
2195+ assert (n == leaf);
2196+
21812197 /* Leaf's key is a prefix of the looked-for key. Leaf's
21822198 * key is the biggest key less than the looked-for key.
2183- * The target node must be the next leaf. */
2184- result = ++const_iterator (leaf, this );
2199+ * The target node must be the next leaf. Note that we
2200+ * cannot just call const_iterator(leaf,
2201+ * this).try_increment() because some other element with
2202+ * key larger than leaf and smaller than k could be
2203+ * inserted concurrently. */
2204+ auto target_leaf = next_leaf<node::direction::Forward>(
2205+ prev->template make_iterator <
2206+ node::direction::Forward>(slot),
2207+ prev);
2208+
2209+ if (!target_leaf.first )
2210+ continue ;
2211+
2212+ result = const_iterator (target_leaf.second , this );
21852213 } else {
21862214 assert (diff < leaf_key.size () && diff < key.size ());
21872215
@@ -2236,21 +2264,25 @@ radix_tree<Key, Value, BytesView>::internal_bound(const K &k) const
22362264 node::direction::Forward>(
22372265 prev->template make_iterator <
22382266 node::direction::Forward>(slot),
2239- prev, k );
2267+ prev);
22402268
2241- result = const_iterator (target_leaf, this );
2269+ if (!target_leaf.first )
2270+ continue ;
2271+
2272+ result = const_iterator (target_leaf.second ,
2273+ this );
22422274 }
22432275 }
22442276
22452277 /* If some node on the path was modified, the calculated result
22462278 * might not be correct. */
2247- if (!validate_path (path))
2248- continue ;
2279+ if (validate_path (path))
2280+ break ;
2281+ }
22492282
2250- assert (validate_bound<Lower>(result, k));
2283+ assert (validate_bound<Lower>(result, k));
22512284
2252- return result;
2253- }
2285+ return result;
22542286}
22552287
22562288/* *
@@ -2938,35 +2970,69 @@ template <bool IsConst>
29382970typename radix_tree<Key, Value,
29392971 BytesView>::template radix_tree_iterator<IsConst> &
29402972radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::operator ++()
2973+ {
2974+ /* Fallback to top-down search. */
2975+ if (!try_increment ())
2976+ *this = tree->upper_bound (leaf_->key ());
2977+
2978+ return *this ;
2979+ }
2980+
2981+ /*
2982+ * Tries to increment iterator. Returns true on success, false otherwise.
2983+ * Increment can fail in case of concurrent, conflicting operation.
2984+ */
2985+ template <typename Key, typename Value, typename BytesView>
2986+ template <bool IsConst>
2987+ bool
2988+ radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::try_increment()
29412989{
29422990 assert (leaf_);
29432991
29442992 constexpr auto direction = radix_tree::node::direction::Forward;
29452993 auto parent_ptr = leaf_->parent .load_acquire ();
29462994
29472995 /* leaf is root, there is no other leaf in the tree */
2948- if (!parent_ptr)
2996+ if (!parent_ptr) {
29492997 leaf_ = nullptr ;
2950- else {
2998+ } else {
29512999 auto it = parent_ptr->template find_child <direction>(leaf_);
29523000
2953- if (it == parent_ptr->template end <direction>()) {
2954- *this = tree->upper_bound (leaf_->key ());
2955- } else {
2956- leaf_ = const_cast <leaf_ptr>(
2957- tree->template next_leaf <direction>(
2958- it, parent_ptr, leaf_->key ()));
2959- }
3001+ if (it == parent_ptr->template end <direction>())
3002+ return false ;
3003+
3004+ auto ret = tree->template next_leaf <direction>(it, parent_ptr);
3005+
3006+ if (!ret.first )
3007+ return false ;
3008+
3009+ leaf_ = const_cast <leaf_ptr>(ret.second );
29603010 }
29613011
2962- return * this ;
3012+ return true ;
29633013}
29643014
29653015template <typename Key, typename Value, typename BytesView>
29663016template <bool IsConst>
29673017typename radix_tree<Key, Value,
29683018 BytesView>::template radix_tree_iterator<IsConst> &
29693019radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::operator --()
3020+ {
3021+ while (!try_decrement ()) {
3022+ *this = tree->lower_bound (leaf_->key ());
3023+ }
3024+
3025+ return *this ;
3026+ }
3027+
3028+ /*
3029+ * Tries to decrement iterator. Returns true on success, false otherwise.
3030+ * Decrement can fail in case of concurrent, conflicting operation.
3031+ */
3032+ template <typename Key, typename Value, typename BytesView>
3033+ template <bool IsConst>
3034+ bool
3035+ radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::try_decrement()
29703036{
29713037 constexpr auto direction = radix_tree::node::direction::Reverse;
29723038
@@ -2982,7 +3048,7 @@ radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::operator--()
29823048 tree->template find_leaf <direction>(r));
29833049
29843050 if (leaf_)
2985- return * this ;
3051+ return true ;
29863052 } else {
29873053 auto parent_ptr = leaf_->parent .load_acquire ();
29883054
@@ -2992,18 +3058,17 @@ radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::operator--()
29923058 auto it = parent_ptr->template find_child <direction>(
29933059 leaf_);
29943060
2995- if (it == parent_ptr->template end <direction>()) {
2996- /* Search the tree from top - this iterator
2997- * might point to detached leaf. */
2998- *this = --tree->lower_bound (leaf_->key ());
2999- return *this ;
3000- }
3061+ if (it == parent_ptr->template end <direction>())
3062+ return false ;
30013063
3002- leaf_ = const_cast <leaf_ptr>(
3003- tree->template next_leaf <direction>(
3004- it, parent_ptr, leaf_->key ()));
3064+ auto ret = tree->template next_leaf <direction>(
3065+ it, parent_ptr);
3066+
3067+ if (!ret.first )
3068+ return false ;
30053069
3006- return *this ;
3070+ leaf_ = const_cast <leaf_ptr>(ret.second );
3071+ return true ;
30073072 }
30083073 }
30093074}
@@ -3055,42 +3120,36 @@ radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::operator==(
30553120}
30563121
30573122/*
3058- * Returns next leaf (either with smaller or larger key than k, depending on
3123+ * Returns a pair consisting of a bool and a leaf pointer to the
3124+ * next leaf (either with smaller or larger key than k, depending on
30593125 * ChildIterator type). This function might need to traverse the
3060- * tree upwards. Return value can be null if there is no such leaf.
3126+ * tree upwards. Pointer can be null if there is no such leaf.
30613127 *
3062- * Parameter k is only used in case of confliciting, concurrent operation
3063- * to restart from the top .
3128+ * Bool variable is set to true on success, false otherwise.
3129+ * Failure can occur in case of a concurrent, conflicting operation .
30643130 */
30653131template <typename Key, typename Value, typename BytesView>
3066- template <bool Direction, typename Iterator, typename K >
3067- const typename radix_tree<Key, Value, BytesView>::leaf *
3068- radix_tree<Key, Value, BytesView>::next_leaf(Iterator node, pointer_type parent,
3069- const K &k ) const
3132+ template <bool Direction, typename Iterator>
3133+ std::pair< bool , const typename radix_tree<Key, Value, BytesView>::leaf *>
3134+ radix_tree<Key, Value, BytesView>::next_leaf(Iterator node,
3135+ pointer_type parent ) const
30703136{
3071- auto fallback = [&] {
3072- if (Direction == node::direction::Forward)
3073- return upper_bound (k).leaf_ ;
3074- else
3075- return (--lower_bound (k)).leaf_ ;
3076- };
3077-
30783137 while (true ) {
30793138 ++node;
30803139
30813140 /* No more children on this level, need to go up. */
30823141 if (node == parent->template end <Direction>()) {
30833142 auto p = parent->parent .load_acquire ();
3084- if (!p) // parent == root
3085- return nullptr ;
3143+ if (!p) /* parent == root */
3144+ return { true , nullptr } ;
30863145
30873146 auto p_it = p->template find_child <Direction>(parent);
30883147 if (p_it == p->template end <Direction>()) {
3089- /* Detached leaf, need to start from the top . */
3090- return fallback () ;
3148+ /* Detached leaf, cannot advance . */
3149+ return { false , nullptr } ;
30913150 }
30923151
3093- return next_leaf<Direction>(p_it, p, k );
3152+ return next_leaf<Direction>(p_it, p);
30943153 }
30953154
30963155 auto n = node->load_acquire ();
@@ -3099,9 +3158,9 @@ radix_tree<Key, Value, BytesView>::next_leaf(Iterator node, pointer_type parent,
30993158
31003159 auto leaf = find_leaf<Direction>(n);
31013160 if (!leaf)
3102- return fallback () ;
3161+ return { false , nullptr } ;
31033162
3104- return leaf;
3163+ return { true , leaf} ;
31053164 }
31063165}
31073166
0 commit comments