@@ -32,7 +32,7 @@ struct FixedKVNode : ChildableCachedExtent {
3232 using FixedKVNodeRef = TCachedExtentRef<FixedKVNode>;
3333 fixed_kv_node_meta_t <node_key_t > range;
3434
35- struct copy_source_cmp_t {
35+ struct fixedkv_node_cmp_t {
3636 using is_transparent = node_key_t ;
3737 bool operator ()(const FixedKVNodeRef &l, const FixedKVNodeRef &r) const {
3838 assert (l->range .end <= r->range .begin
@@ -84,11 +84,78 @@ struct FixedKVNode : ChildableCachedExtent {
8484 * cannot be rewritten) because their parents must be mutated upon remapping.
8585 */
8686 std::vector<ChildableCachedExtent*> children;
87- std::set<FixedKVNodeRef, copy_source_cmp_t > copy_sources;
87+ std::set<FixedKVNodeRef, fixedkv_node_cmp_t > copy_sources;
8888 uint16_t capacity = 0 ;
8989 parent_tracker_t * my_tracker = nullptr ;
9090 RootBlockRef root_block;
9191
92+ // copy dests points from a stable node back to its pending nodes
93+ // having copy sources at the same tree level, it serves as a two-level index:
94+ // transaction-id then node-key to the pending node.
95+ //
96+ // The copy dest pointers must be symmetric to the copy source pointers.
97+ //
98+ // copy_dests_t will be automatically unregisterred upon transaction destruction,
99+ // see Transaction::views
100+ struct copy_dests_t : trans_spec_view_t {
101+ std::set<FixedKVNodeRef, fixedkv_node_cmp_t > dests_by_key;
102+ copy_dests_t (Transaction &t) : trans_spec_view_t {t.get_trans_id ()} {}
103+ ~copy_dests_t () {
104+ LOG_PREFIX (~copy_dests_t );
105+ SUBTRACE (seastore_fixedkv_tree, " copy_dests_t destroyed" );
106+ }
107+ };
108+
109+ trans_view_set_t copy_dests_by_trans;
110+
111+ void add_copy_dest (Transaction &t, FixedKVNodeRef dest) {
112+ ceph_assert (is_stable ());
113+ ceph_assert (dest->is_pending ());
114+ auto tid = t.get_trans_id ();
115+ auto iter = copy_dests_by_trans.lower_bound (
116+ tid, trans_spec_view_t::cmp_t ());
117+ if (iter == copy_dests_by_trans.end () ||
118+ iter->pending_for_transaction != tid) {
119+ iter = copy_dests_by_trans.insert_before (
120+ iter, t.add_transactional_view <copy_dests_t >(t));
121+ }
122+ auto ©_dests = static_cast <copy_dests_t &>(*iter);
123+ auto [it, inserted] = copy_dests.dests_by_key .insert (dest);
124+ assert (inserted || it->get () == dest.get ());
125+ }
126+
127+ void del_copy_dest (Transaction &t, FixedKVNodeRef dest) {
128+ auto iter = copy_dests_by_trans.find (
129+ t.get_trans_id (), trans_spec_view_t::cmp_t ());
130+ ceph_assert (iter != copy_dests_by_trans.end ());
131+ auto ©_dests = static_cast <copy_dests_t &>(*iter);
132+ auto it = copy_dests.dests_by_key .find (dest);
133+ ceph_assert (it != copy_dests.dests_by_key .end ());
134+ copy_dests.dests_by_key .erase (dest);
135+ }
136+
137+ FixedKVNodeRef find_pending_version (Transaction &t, node_key_t key) {
138+ assert (is_stable ());
139+ auto mut_iter = mutation_pendings.find (
140+ t.get_trans_id (), trans_spec_view_t::cmp_t ());
141+ if (mut_iter != mutation_pendings.end ()) {
142+ assert (copy_dests_by_trans.find (t.get_trans_id ()) ==
143+ copy_dests_by_trans.end ());
144+ return (FixedKVNode*)(&(*mut_iter));
145+ }
146+ auto iter = copy_dests_by_trans.find (
147+ t.get_trans_id (), trans_spec_view_t::cmp_t ());
148+ ceph_assert (iter != copy_dests_by_trans.end ());
149+ auto ©_dests = static_cast <copy_dests_t &>(*iter);
150+ auto it = copy_dests.dests_by_key .lower_bound (key);
151+ if ((*it)->range .begin > key) {
152+ ceph_assert (it != copy_dests.dests_by_key .begin ());
153+ --it;
154+ }
155+ ceph_assert ((*it)->range .begin <= key && key < (*it)->range .end );
156+ return *it;
157+ }
158+
92159 bool is_linked () {
93160 assert (!has_parent_tracker () || !(bool )root_block);
94161 return (bool )has_parent_tracker () || (bool )root_block;
@@ -161,19 +228,22 @@ struct FixedKVNode : ChildableCachedExtent {
161228
162229 virtual bool have_children () const = 0;
163230
164- void on_rewrite (CachedExtent &extent, extent_len_t off) final {
231+ void on_rewrite (Transaction &t, CachedExtent &extent, extent_len_t off) final {
165232 assert (get_type () == extent.get_type ());
166233 assert (off == 0 );
167234 auto &foreign_extent = (FixedKVNode&)extent;
168235 range = get_node_meta ();
169236
170237 if (have_children ()) {
171238 if (!foreign_extent.is_pending ()) {
239+ foreign_extent.add_copy_dest (t, this );
172240 copy_sources.emplace (&foreign_extent);
173241 } else {
174242 ceph_assert (foreign_extent.is_mutation_pending ());
175- copy_sources.emplace (
176- foreign_extent.get_prior_instance ()->template cast <FixedKVNode>());
243+ auto copy_source =
244+ foreign_extent.get_prior_instance ()->template cast <FixedKVNode>();
245+ copy_source->add_copy_dest (t, this );
246+ copy_sources.emplace (copy_source);
177247 children = std::move (foreign_extent.children );
178248 adjust_ptracker_for_children ();
179249 }
@@ -211,17 +281,24 @@ struct FixedKVNode : ChildableCachedExtent {
211281 }
212282
213283 static void push_copy_sources (
284+ Transaction &t,
214285 FixedKVNode &dest,
215286 FixedKVNode &src)
216287 {
217288 ceph_assert (dest.is_initial_pending ());
218289 if (!src.is_pending ()) {
290+ src.add_copy_dest (t, &dest);
219291 dest.copy_sources .emplace (&src);
220292 } else if (src.is_mutation_pending ()) {
221- dest.copy_sources .emplace (
222- src.get_prior_instance ()->template cast <FixedKVNode>());
293+ auto copy_src =
294+ src.get_prior_instance ()->template cast <FixedKVNode>();
295+ copy_src->add_copy_dest (t, &dest);
296+ dest.copy_sources .emplace (copy_src);
223297 } else {
224298 ceph_assert (src.is_initial_pending ());
299+ for (auto &cs : src.copy_sources ) {
300+ cs->add_copy_dest (t, &dest);
301+ }
225302 dest.copy_sources .insert (
226303 src.copy_sources .begin (),
227304 src.copy_sources .end ());
@@ -306,13 +383,20 @@ struct FixedKVNode : ChildableCachedExtent {
306383 }
307384
308385 void split_child_ptrs (
386+ Transaction &t,
309387 FixedKVNode &left,
310388 FixedKVNode &right)
311389 {
312390 assert (!left.my_tracker );
313391 assert (!right.my_tracker );
314- push_copy_sources (left, *this );
315- push_copy_sources (right, *this );
392+ if (is_initial_pending ()) {
393+ for (auto &cs : copy_sources) {
394+ cs->del_copy_dest (t, this );
395+ }
396+ }
397+
398+ push_copy_sources (t, left, *this );
399+ push_copy_sources (t, right, *this );
316400 if (is_pending ()) {
317401 uint16_t pivot = get_node_split_pivot ();
318402 move_child_ptrs (left, *this , 0 , 0 , pivot);
@@ -322,12 +406,24 @@ struct FixedKVNode : ChildableCachedExtent {
322406 }
323407
324408 void merge_child_ptrs (
409+ Transaction &t,
325410 FixedKVNode &left,
326411 FixedKVNode &right)
327412 {
328413 ceph_assert (!my_tracker);
329- push_copy_sources (*this , left);
330- push_copy_sources (*this , right);
414+
415+ if (left.is_initial_pending ()) {
416+ for (auto &cs : left.copy_sources ) {
417+ cs->del_copy_dest (t, &left);
418+ }
419+ }
420+ if (right.is_initial_pending ()) {
421+ for (auto &cs : right.copy_sources ) {
422+ cs->del_copy_dest (t, &right);
423+ }
424+ }
425+ push_copy_sources (t, *this , left);
426+ push_copy_sources (t, *this , right);
331427
332428 if (left.is_pending ()) {
333429 move_child_ptrs (*this , left, 0 , 0 , left.get_node_size ());
@@ -341,6 +437,7 @@ struct FixedKVNode : ChildableCachedExtent {
341437 }
342438
343439 static void balance_child_ptrs (
440+ Transaction &t,
344441 FixedKVNode &left,
345442 FixedKVNode &right,
346443 bool prefer_left,
@@ -355,35 +452,46 @@ struct FixedKVNode : ChildableCachedExtent {
355452 pivot_idx++;
356453 }
357454
455+ if (left.is_initial_pending ()) {
456+ for (auto &cs : left.copy_sources ) {
457+ cs->del_copy_dest (t, &left);
458+ }
459+ }
460+ if (right.is_initial_pending ()) {
461+ for (auto &cs : right.copy_sources ) {
462+ cs->del_copy_dest (t, &right);
463+ }
464+ }
465+
358466 assert (!replacement_left.my_tracker );
359467 assert (!replacement_right.my_tracker );
360468 if (pivot_idx < l_size) {
361469 // deal with left
362- push_copy_sources (replacement_left, left);
363- push_copy_sources (replacement_right, left);
470+ push_copy_sources (t, replacement_left, left);
471+ push_copy_sources (t, replacement_right, left);
364472 if (left.is_pending ()) {
365473 move_child_ptrs (replacement_left, left, 0 , 0 , pivot_idx);
366474 move_child_ptrs (replacement_right, left, 0 , pivot_idx, l_size);
367475 left.my_tracker = nullptr ;
368476 }
369477
370478 // deal with right
371- push_copy_sources (replacement_right, right);
479+ push_copy_sources (t, replacement_right, right);
372480 if (right.is_pending ()) {
373481 move_child_ptrs (replacement_right, right, l_size - pivot_idx, 0 , r_size);
374482 right.my_tracker = nullptr ;
375483 }
376484 } else {
377485 // deal with left
378- push_copy_sources (replacement_left, left);
486+ push_copy_sources (t, replacement_left, left);
379487 if (left.is_pending ()) {
380488 move_child_ptrs (replacement_left, left, 0 , 0 , l_size);
381489 left.my_tracker = nullptr ;
382490 }
383491
384492 // deal with right
385- push_copy_sources (replacement_left, right);
386- push_copy_sources (replacement_right, right);
493+ push_copy_sources (t, replacement_left, right);
494+ push_copy_sources (t, replacement_right, right);
387495 if (right.is_pending ()) {
388496 move_child_ptrs (replacement_left, right, l_size, 0 , pivot_idx - l_size);
389497 move_child_ptrs (replacement_right, right, 0 , pivot_idx - l_size, r_size);
@@ -821,10 +929,10 @@ struct FixedKVInternalNode
821929 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
822930 auto right = c.cache .template alloc_new_non_data_extent <node_type_t >(
823931 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
824- this ->split_child_ptrs (*left, *right);
825932 auto pivot = this ->split_into (*left, *right);
826933 left->range = left->get_meta ();
827934 right->range = right->get_meta ();
935+ this ->split_child_ptrs (c.trans , *left, *right);
828936 return std::make_tuple (
829937 left,
830938 right,
@@ -836,9 +944,9 @@ struct FixedKVInternalNode
836944 Ref &right) {
837945 auto replacement = c.cache .template alloc_new_non_data_extent <node_type_t >(
838946 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
839- replacement->merge_child_ptrs (*this , *right);
840947 replacement->merge_from (*this , *right->template cast <node_type_t >());
841948 replacement->range = replacement->get_meta ();
949+ replacement->merge_child_ptrs (c.trans , *this , *right);
842950 return replacement;
843951 }
844952
@@ -860,15 +968,15 @@ struct FixedKVInternalNode
860968 prefer_left,
861969 *replacement_left,
862970 *replacement_right);
971+ replacement_left->range = replacement_left->get_meta ();
972+ replacement_right->range = replacement_right->get_meta ();
863973 this ->balance_child_ptrs (
974+ c.trans ,
864975 *this ,
865976 right,
866977 prefer_left,
867978 *replacement_left,
868979 *replacement_right);
869-
870- replacement_left->range = replacement_left->get_meta ();
871- replacement_right->range = replacement_right->get_meta ();
872980 return std::make_tuple (
873981 replacement_left,
874982 replacement_right,
@@ -1231,12 +1339,12 @@ struct FixedKVLeafNode
12311339 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
12321340 auto right = c.cache .template alloc_new_non_data_extent <node_type_t >(
12331341 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
1234- if constexpr (has_children) {
1235- this ->split_child_ptrs (*left, *right);
1236- }
12371342 auto pivot = this ->split_into (*left, *right);
12381343 left->range = left->get_meta ();
12391344 right->range = right->get_meta ();
1345+ if constexpr (has_children) {
1346+ this ->split_child_ptrs (c.trans , *left, *right);
1347+ }
12401348 return std::make_tuple (
12411349 left,
12421350 right,
@@ -1248,11 +1356,11 @@ struct FixedKVLeafNode
12481356 Ref &right) {
12491357 auto replacement = c.cache .template alloc_new_non_data_extent <node_type_t >(
12501358 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
1251- if constexpr (has_children) {
1252- replacement->merge_child_ptrs (*this , *right);
1253- }
12541359 replacement->merge_from (*this , *right->template cast <node_type_t >());
12551360 replacement->range = replacement->get_meta ();
1361+ if constexpr (has_children) {
1362+ replacement->merge_child_ptrs (c.trans , *this , *right);
1363+ }
12561364 return replacement;
12571365 }
12581366
@@ -1274,17 +1382,17 @@ struct FixedKVLeafNode
12741382 prefer_left,
12751383 *replacement_left,
12761384 *replacement_right);
1385+ replacement_left->range = replacement_left->get_meta ();
1386+ replacement_right->range = replacement_right->get_meta ();
12771387 if constexpr (has_children) {
12781388 this ->balance_child_ptrs (
1389+ c.trans ,
12791390 *this ,
12801391 right,
12811392 prefer_left,
12821393 *replacement_left,
12831394 *replacement_right);
12841395 }
1285-
1286- replacement_left->range = replacement_left->get_meta ();
1287- replacement_right->range = replacement_right->get_meta ();
12881396 return std::make_tuple (
12891397 replacement_left,
12901398 replacement_right,
0 commit comments