@@ -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,56 @@ 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+
92137 bool is_linked () {
93138 assert (!has_parent_tracker () || !(bool )root_block);
94139 return (bool )has_parent_tracker () || (bool )root_block;
@@ -161,19 +206,22 @@ struct FixedKVNode : ChildableCachedExtent {
161206
162207 virtual bool have_children () const = 0;
163208
164- void on_rewrite (CachedExtent &extent, extent_len_t off) final {
209+ void on_rewrite (Transaction &t, CachedExtent &extent, extent_len_t off) final {
165210 assert (get_type () == extent.get_type ());
166211 assert (off == 0 );
167212 auto &foreign_extent = (FixedKVNode&)extent;
168213 range = get_node_meta ();
169214
170215 if (have_children ()) {
171216 if (!foreign_extent.is_pending ()) {
217+ foreign_extent.add_copy_dest (t, this );
172218 copy_sources.emplace (&foreign_extent);
173219 } else {
174220 ceph_assert (foreign_extent.is_mutation_pending ());
175- copy_sources.emplace (
176- foreign_extent.get_prior_instance ()->template cast <FixedKVNode>());
221+ auto copy_source =
222+ foreign_extent.get_prior_instance ()->template cast <FixedKVNode>();
223+ copy_source->add_copy_dest (t, this );
224+ copy_sources.emplace (copy_source);
177225 children = std::move (foreign_extent.children );
178226 adjust_ptracker_for_children ();
179227 }
@@ -211,17 +259,24 @@ struct FixedKVNode : ChildableCachedExtent {
211259 }
212260
213261 static void push_copy_sources (
262+ Transaction &t,
214263 FixedKVNode &dest,
215264 FixedKVNode &src)
216265 {
217266 ceph_assert (dest.is_initial_pending ());
218267 if (!src.is_pending ()) {
268+ src.add_copy_dest (t, &dest);
219269 dest.copy_sources .emplace (&src);
220270 } else if (src.is_mutation_pending ()) {
221- dest.copy_sources .emplace (
222- src.get_prior_instance ()->template cast <FixedKVNode>());
271+ auto copy_src =
272+ src.get_prior_instance ()->template cast <FixedKVNode>();
273+ copy_src->add_copy_dest (t, &dest);
274+ dest.copy_sources .emplace (copy_src);
223275 } else {
224276 ceph_assert (src.is_initial_pending ());
277+ for (auto &cs : src.copy_sources ) {
278+ cs->add_copy_dest (t, &dest);
279+ }
225280 dest.copy_sources .insert (
226281 src.copy_sources .begin (),
227282 src.copy_sources .end ());
@@ -306,13 +361,20 @@ struct FixedKVNode : ChildableCachedExtent {
306361 }
307362
308363 void split_child_ptrs (
364+ Transaction &t,
309365 FixedKVNode &left,
310366 FixedKVNode &right)
311367 {
312368 assert (!left.my_tracker );
313369 assert (!right.my_tracker );
314- push_copy_sources (left, *this );
315- push_copy_sources (right, *this );
370+ if (is_initial_pending ()) {
371+ for (auto &cs : copy_sources) {
372+ cs->del_copy_dest (t, this );
373+ }
374+ }
375+
376+ push_copy_sources (t, left, *this );
377+ push_copy_sources (t, right, *this );
316378 if (is_pending ()) {
317379 uint16_t pivot = get_node_split_pivot ();
318380 move_child_ptrs (left, *this , 0 , 0 , pivot);
@@ -322,12 +384,24 @@ struct FixedKVNode : ChildableCachedExtent {
322384 }
323385
324386 void merge_child_ptrs (
387+ Transaction &t,
325388 FixedKVNode &left,
326389 FixedKVNode &right)
327390 {
328391 ceph_assert (!my_tracker);
329- push_copy_sources (*this , left);
330- push_copy_sources (*this , right);
392+
393+ if (left.is_initial_pending ()) {
394+ for (auto &cs : left.copy_sources ) {
395+ cs->del_copy_dest (t, &left);
396+ }
397+ }
398+ if (right.is_initial_pending ()) {
399+ for (auto &cs : right.copy_sources ) {
400+ cs->del_copy_dest (t, &right);
401+ }
402+ }
403+ push_copy_sources (t, *this , left);
404+ push_copy_sources (t, *this , right);
331405
332406 if (left.is_pending ()) {
333407 move_child_ptrs (*this , left, 0 , 0 , left.get_node_size ());
@@ -341,6 +415,7 @@ struct FixedKVNode : ChildableCachedExtent {
341415 }
342416
343417 static void balance_child_ptrs (
418+ Transaction &t,
344419 FixedKVNode &left,
345420 FixedKVNode &right,
346421 bool prefer_left,
@@ -355,35 +430,46 @@ struct FixedKVNode : ChildableCachedExtent {
355430 pivot_idx++;
356431 }
357432
433+ if (left.is_initial_pending ()) {
434+ for (auto &cs : left.copy_sources ) {
435+ cs->del_copy_dest (t, &left);
436+ }
437+ }
438+ if (right.is_initial_pending ()) {
439+ for (auto &cs : right.copy_sources ) {
440+ cs->del_copy_dest (t, &right);
441+ }
442+ }
443+
358444 assert (!replacement_left.my_tracker );
359445 assert (!replacement_right.my_tracker );
360446 if (pivot_idx < l_size) {
361447 // deal with left
362- push_copy_sources (replacement_left, left);
363- push_copy_sources (replacement_right, left);
448+ push_copy_sources (t, replacement_left, left);
449+ push_copy_sources (t, replacement_right, left);
364450 if (left.is_pending ()) {
365451 move_child_ptrs (replacement_left, left, 0 , 0 , pivot_idx);
366452 move_child_ptrs (replacement_right, left, 0 , pivot_idx, l_size);
367453 left.my_tracker = nullptr ;
368454 }
369455
370456 // deal with right
371- push_copy_sources (replacement_right, right);
457+ push_copy_sources (t, replacement_right, right);
372458 if (right.is_pending ()) {
373459 move_child_ptrs (replacement_right, right, l_size - pivot_idx, 0 , r_size);
374460 right.my_tracker = nullptr ;
375461 }
376462 } else {
377463 // deal with left
378- push_copy_sources (replacement_left, left);
464+ push_copy_sources (t, replacement_left, left);
379465 if (left.is_pending ()) {
380466 move_child_ptrs (replacement_left, left, 0 , 0 , l_size);
381467 left.my_tracker = nullptr ;
382468 }
383469
384470 // deal with right
385- push_copy_sources (replacement_left, right);
386- push_copy_sources (replacement_right, right);
471+ push_copy_sources (t, replacement_left, right);
472+ push_copy_sources (t, replacement_right, right);
387473 if (right.is_pending ()) {
388474 move_child_ptrs (replacement_left, right, l_size, 0 , pivot_idx - l_size);
389475 move_child_ptrs (replacement_right, right, 0 , pivot_idx - l_size, r_size);
@@ -821,10 +907,10 @@ struct FixedKVInternalNode
821907 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
822908 auto right = c.cache .template alloc_new_non_data_extent <node_type_t >(
823909 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
824- this ->split_child_ptrs (*left, *right);
825910 auto pivot = this ->split_into (*left, *right);
826911 left->range = left->get_meta ();
827912 right->range = right->get_meta ();
913+ this ->split_child_ptrs (c.trans , *left, *right);
828914 return std::make_tuple (
829915 left,
830916 right,
@@ -836,9 +922,9 @@ struct FixedKVInternalNode
836922 Ref &right) {
837923 auto replacement = c.cache .template alloc_new_non_data_extent <node_type_t >(
838924 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
839- replacement->merge_child_ptrs (*this , *right);
840925 replacement->merge_from (*this , *right->template cast <node_type_t >());
841926 replacement->range = replacement->get_meta ();
927+ replacement->merge_child_ptrs (c.trans , *this , *right);
842928 return replacement;
843929 }
844930
@@ -860,15 +946,15 @@ struct FixedKVInternalNode
860946 prefer_left,
861947 *replacement_left,
862948 *replacement_right);
949+ replacement_left->range = replacement_left->get_meta ();
950+ replacement_right->range = replacement_right->get_meta ();
863951 this ->balance_child_ptrs (
952+ c.trans ,
864953 *this ,
865954 right,
866955 prefer_left,
867956 *replacement_left,
868957 *replacement_right);
869-
870- replacement_left->range = replacement_left->get_meta ();
871- replacement_right->range = replacement_right->get_meta ();
872958 return std::make_tuple (
873959 replacement_left,
874960 replacement_right,
@@ -1231,12 +1317,12 @@ struct FixedKVLeafNode
12311317 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
12321318 auto right = c.cache .template alloc_new_non_data_extent <node_type_t >(
12331319 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
1234- if constexpr (has_children) {
1235- this ->split_child_ptrs (*left, *right);
1236- }
12371320 auto pivot = this ->split_into (*left, *right);
12381321 left->range = left->get_meta ();
12391322 right->range = right->get_meta ();
1323+ if constexpr (has_children) {
1324+ this ->split_child_ptrs (c.trans , *left, *right);
1325+ }
12401326 return std::make_tuple (
12411327 left,
12421328 right,
@@ -1248,11 +1334,11 @@ struct FixedKVLeafNode
12481334 Ref &right) {
12491335 auto replacement = c.cache .template alloc_new_non_data_extent <node_type_t >(
12501336 c.trans , node_size, placement_hint_t ::HOT, INIT_GENERATION);
1251- if constexpr (has_children) {
1252- replacement->merge_child_ptrs (*this , *right);
1253- }
12541337 replacement->merge_from (*this , *right->template cast <node_type_t >());
12551338 replacement->range = replacement->get_meta ();
1339+ if constexpr (has_children) {
1340+ replacement->merge_child_ptrs (c.trans , *this , *right);
1341+ }
12561342 return replacement;
12571343 }
12581344
@@ -1274,17 +1360,17 @@ struct FixedKVLeafNode
12741360 prefer_left,
12751361 *replacement_left,
12761362 *replacement_right);
1363+ replacement_left->range = replacement_left->get_meta ();
1364+ replacement_right->range = replacement_right->get_meta ();
12771365 if constexpr (has_children) {
12781366 this ->balance_child_ptrs (
1367+ c.trans ,
12791368 *this ,
12801369 right,
12811370 prefer_left,
12821371 *replacement_left,
12831372 *replacement_right);
12841373 }
1285-
1286- replacement_left->range = replacement_left->get_meta ();
1287- replacement_right->range = replacement_right->get_meta ();
12881374 return std::make_tuple (
12891375 replacement_left,
12901376 replacement_right,
0 commit comments