@@ -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
@@ -2181,7 +2195,9 @@ radix_tree<Key, Value, BytesView>::internal_bound(const K &k) const
21812195 /* Leaf's key is a prefix of the looked-for key. Leaf's
21822196 * key is the biggest key less than the looked-for key.
21832197 * The target node must be the next leaf. */
2184- result = ++const_iterator (leaf, this );
2198+ result = const_iterator (leaf, this );
2199+ if (!result.try_increment ())
2200+ continue ;
21852201 } else {
21862202 assert (diff < leaf_key.size () && diff < key.size ());
21872203
@@ -2236,21 +2252,25 @@ radix_tree<Key, Value, BytesView>::internal_bound(const K &k) const
22362252 node::direction::Forward>(
22372253 prev->template make_iterator <
22382254 node::direction::Forward>(slot),
2239- prev, k );
2255+ prev);
22402256
2241- result = const_iterator (target_leaf, this );
2257+ if (!target_leaf.first )
2258+ continue ;
2259+
2260+ result = const_iterator (target_leaf.second ,
2261+ this );
22422262 }
22432263 }
22442264
22452265 /* If some node on the path was modified, the calculated result
22462266 * might not be correct. */
2247- if (!validate_path (path))
2248- continue ;
2267+ if (validate_path (path))
2268+ break ;
2269+ }
22492270
2250- assert (validate_bound<Lower>(result, k));
2271+ assert (validate_bound<Lower>(result, k));
22512272
2252- return result;
2253- }
2273+ return result;
22542274}
22552275
22562276/* *
@@ -2938,35 +2958,69 @@ template <bool IsConst>
29382958typename radix_tree<Key, Value,
29392959 BytesView>::template radix_tree_iterator<IsConst> &
29402960radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::operator ++()
2961+ {
2962+ /* Fallback to top-down search. */
2963+ if (!try_increment ())
2964+ *this = tree->upper_bound (leaf_->key ());
2965+
2966+ return *this ;
2967+ }
2968+
2969+ /*
2970+ * Tries to increment iterator. Returns true on success, false otherwise.
2971+ * Increment can fail in case of concurrent, conflicting operation.
2972+ */
2973+ template <typename Key, typename Value, typename BytesView>
2974+ template <bool IsConst>
2975+ bool
2976+ radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::try_increment()
29412977{
29422978 assert (leaf_);
29432979
29442980 constexpr auto direction = radix_tree::node::direction::Forward;
29452981 auto parent_ptr = leaf_->parent .load_acquire ();
29462982
29472983 /* leaf is root, there is no other leaf in the tree */
2948- if (!parent_ptr)
2984+ if (!parent_ptr) {
29492985 leaf_ = nullptr ;
2950- else {
2986+ } else {
29512987 auto it = parent_ptr->template find_child <direction>(leaf_);
29522988
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- }
2989+ if (it == parent_ptr->template end <direction>())
2990+ return false ;
2991+
2992+ auto ret = tree->template next_leaf <direction>(it, parent_ptr);
2993+
2994+ if (!ret.first )
2995+ return false ;
2996+
2997+ leaf_ = const_cast <leaf_ptr>(ret.second );
29602998 }
29612999
2962- return * this ;
3000+ return true ;
29633001}
29643002
29653003template <typename Key, typename Value, typename BytesView>
29663004template <bool IsConst>
29673005typename radix_tree<Key, Value,
29683006 BytesView>::template radix_tree_iterator<IsConst> &
29693007radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::operator --()
3008+ {
3009+ while (!try_decrement ()) {
3010+ *this = tree->lower_bound (leaf_->key ());
3011+ }
3012+
3013+ return *this ;
3014+ }
3015+
3016+ /*
3017+ * Tries to decrement iterator. Returns true on success, false otherwise.
3018+ * Decrement can fail in case of concurrent, conflicting operation.
3019+ */
3020+ template <typename Key, typename Value, typename BytesView>
3021+ template <bool IsConst>
3022+ bool
3023+ radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::try_decrement()
29703024{
29713025 constexpr auto direction = radix_tree::node::direction::Reverse;
29723026
@@ -2982,7 +3036,7 @@ radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::operator--()
29823036 tree->template find_leaf <direction>(r));
29833037
29843038 if (leaf_)
2985- return * this ;
3039+ return true ;
29863040 } else {
29873041 auto parent_ptr = leaf_->parent .load_acquire ();
29883042
@@ -2992,18 +3046,17 @@ radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::operator--()
29923046 auto it = parent_ptr->template find_child <direction>(
29933047 leaf_);
29943048
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- }
3049+ if (it == parent_ptr->template end <direction>())
3050+ return false ;
30013051
3002- leaf_ = const_cast <leaf_ptr>(
3003- tree->template next_leaf <direction>(
3004- it, parent_ptr, leaf_->key ()));
3052+ auto ret = tree->template next_leaf <direction>(
3053+ it, parent_ptr);
30053054
3006- return *this ;
3055+ if (!ret.first )
3056+ return false ;
3057+
3058+ leaf_ = const_cast <leaf_ptr>(ret.second );
3059+ return true ;
30073060 }
30083061 }
30093062}
@@ -3055,42 +3108,36 @@ radix_tree<Key, Value, BytesView>::radix_tree_iterator<IsConst>::operator==(
30553108}
30563109
30573110/*
3058- * Returns next leaf (either with smaller or larger key than k, depending on
3111+ * Returns a pair consisting of a bool and a leaf pointer to the
3112+ * next leaf (either with smaller or larger key than k, depending on
30593113 * ChildIterator type). This function might need to traverse the
3060- * tree upwards. Return value can be null if there is no such leaf.
3114+ * tree upwards. Pointer can be null if there is no such leaf.
30613115 *
3062- * Parameter k is only used in case of confliciting, concurrent operation
3063- * to restart from the top .
3116+ * Bool variable is set to true on success, false otherwise.
3117+ * Failure can occur in case of a concurrent, conflicting operation .
30643118 */
30653119template <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
3120+ template <bool Direction, typename Iterator>
3121+ std::pair< bool , const typename radix_tree<Key, Value, BytesView>::leaf *>
3122+ radix_tree<Key, Value, BytesView>::next_leaf(Iterator node,
3123+ pointer_type parent ) const
30703124{
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-
30783125 while (true ) {
30793126 ++node;
30803127
30813128 /* No more children on this level, need to go up. */
30823129 if (node == parent->template end <Direction>()) {
30833130 auto p = parent->parent .load_acquire ();
3084- if (!p) // parent == root
3085- return nullptr ;
3131+ if (!p) /* parent == root */
3132+ return { true , nullptr } ;
30863133
30873134 auto p_it = p->template find_child <Direction>(parent);
30883135 if (p_it == p->template end <Direction>()) {
3089- /* Detached leaf, need to start from the top . */
3090- return fallback () ;
3136+ /* Detached leaf, cannot advance . */
3137+ return { false , nullptr } ;
30913138 }
30923139
3093- return next_leaf<Direction>(p_it, p, k );
3140+ return next_leaf<Direction>(p_it, p);
30943141 }
30953142
30963143 auto n = node->load_acquire ();
@@ -3099,9 +3146,9 @@ radix_tree<Key, Value, BytesView>::next_leaf(Iterator node, pointer_type parent,
30993146
31003147 auto leaf = find_leaf<Direction>(n);
31013148 if (!leaf)
3102- return fallback () ;
3149+ return { false , nullptr } ;
31033150
3104- return leaf;
3151+ return { true , leaf} ;
31053152 }
31063153}
31073154
0 commit comments