@@ -159,21 +159,34 @@ class Transaction {
159159 }
160160
161161 // Returns true if added, false if already added or weak
162- bool maybe_add_to_read_set (CachedExtentRef ref) {
163- assert (ref->get_paddr ().is_absolute ());
162+ struct maybe_add_readset_ret {
163+ bool added;
164+ bool is_paddr_known;
165+ };
166+ maybe_add_readset_ret maybe_add_to_read_set (CachedExtentRef ref) {
167+ assert (ref->get_paddr ().is_absolute ()
168+ || ref->get_paddr ().is_record_relative ());
164169 if (is_weak ()) {
165- return false ;
170+ return {false , true /* meaningless */ };
171+ }
172+ if (ref->get_paddr ().is_absolute ()) {
173+ // paddr is known
174+ bool added = do_add_to_read_set (ref);
175+ return {added, true };
176+ } else {
177+ // paddr is unknown until wait_io() finished
178+ // to call maybe_add_to_read_set_step_2(ref)
179+ ceph_assert (ref->get_paddr ().is_record_relative ());
180+ bool added = maybe_add_to_read_set_step_1 (ref);
181+ return {added, false };
166182 }
167- return do_add_to_read_set (ref);
168183 }
169184
170185 bool is_in_read_set (CachedExtentRef extent) const {
171- return lookup_read_set (extent).first ;
186+ return lookup_trans_from_read_extent (extent).first ;
172187 }
173188
174189 void add_to_read_set (CachedExtentRef ref) {
175- assert (ref->get_paddr ().is_absolute ()
176- || ref->get_paddr ().is_root ());
177190 if (is_weak ()) {
178191 return ;
179192 }
@@ -292,9 +305,9 @@ class Transaction {
292305 auto where = read_set.find (placeholder.get_paddr (), extent_cmp_t {});
293306 assert (where != read_set.end ());
294307 assert (where->ref .get () == &placeholder);
295- where = read_set.erase (where);
296308 placeholder.read_transactions .erase (
297309 read_trans_set_t <Transaction>::s_iterator_to (*where));
310+ where = read_set.erase (where);
298311 // Note, the retired-placeholder is not removed from read_items after replace.
299312 read_items.emplace_back (this , &extent);
300313 auto it = read_set.insert_before (where, read_items.back ());
@@ -436,7 +449,7 @@ class Transaction {
436449 root.reset ();
437450 offset = 0 ;
438451 delayed_temp_offset = 0 ;
439- read_items. clear ();
452+ clear_read_set ();
440453 fresh_backref_extents = 0 ;
441454 invalidate_clear_write_set ();
442455 mutated_block_list.clear ();
@@ -579,6 +592,15 @@ class Transaction {
579592 friend class Cache ;
580593 friend Ref make_test_transaction ();
581594
595+ void clear_read_set () {
596+ read_items.clear ();
597+ assert (read_set.empty ());
598+ #ifndef NDEBUG
599+ num_replace_placeholder = 0 ;
600+ #endif
601+ // Automatically unlink this transaction from CachedExtent::read_transactions
602+ }
603+
582604 std::pair<get_extent_ret, CachedExtentRef> do_get_extent (paddr_t addr) {
583605 LOG_PREFIX (Transaction::do_get_extent);
584606 // it's possible that both write_set and retired_set contain
@@ -606,8 +628,8 @@ class Transaction {
606628 }
607629 }
608630
609- auto lookup_read_set (CachedExtentRef ref) const
610- -> std::pair<bool, read_trans_set_t<Transaction>::const_iterator> {
631+ std::pair< bool , read_trans_set_t <Transaction>::iterator>
632+ lookup_trans_from_read_extent (CachedExtentRef ref) const {
611633 assert (ref->is_valid ());
612634 assert (!is_weak ());
613635 auto it = ref->read_transactions .lower_bound (
@@ -617,19 +639,67 @@ class Transaction {
617639 return std::make_pair (exists, it);
618640 }
619641
620- bool do_add_to_read_set (CachedExtentRef ref) {
642+ bool maybe_add_to_read_set_step_1 (CachedExtentRef ref) {
621643 assert (!is_weak ());
622644 assert (ref->is_stable ());
623- auto [exists, it] = lookup_read_set (ref);
645+ auto [exists, it] = lookup_trans_from_read_extent (ref);
624646 if (exists) {
647+ // not added
625648 return false ;
626649 }
627650
651+ // step 1: create read_item and attach transaction to extent
652+ // so that transaction invalidation can populate
653+ assert (!read_set.count (ref->get_paddr (), extent_cmp_t {}));
628654 read_items.emplace_back (this , ref);
629- auto [iter, inserted] = read_set.insert (read_items.back ());
630- ceph_assert (inserted);
631655 ref->read_transactions .insert_before (
632- it, const_cast <read_set_item_t <Transaction>&>(*iter));
656+ it, read_items.back ());
657+
658+ // added
659+ return true ;
660+ }
661+
662+ void maybe_add_to_read_set_step_2 (CachedExtentRef ref) {
663+ // paddr must be known for read_set
664+ ceph_assert (ref->get_paddr ().is_absolute ());
665+ if (is_weak ()) {
666+ return ;
667+ }
668+ auto [exists, it] = lookup_trans_from_read_extent (ref);
669+ // step 1 must be complete
670+ assert (exists);
671+ // step 2 may be reordered after wait_io(),
672+ // so the extent may already be attached to the transaction.
673+ if (it->is_extent_attached_to_trans ()) {
674+ assert (read_set.count (ref->get_paddr (), extent_cmp_t {}));
675+ return ;
676+ }
677+
678+ // step 2: attach extent to transaction to become visible
679+ assert (!read_set.count (ref->get_paddr (), extent_cmp_t {}));
680+ auto [iter, inserted] = read_set.insert (*it);
681+ assert (inserted);
682+ }
683+
684+ bool do_add_to_read_set (CachedExtentRef ref) {
685+ assert (!is_weak ());
686+ assert (ref->is_stable ());
687+ // paddr must be known for read_set
688+ assert (ref->get_paddr ().is_absolute ()
689+ || ref->get_paddr ().is_root ());
690+
691+ if (!maybe_add_to_read_set_step_1 (ref)) {
692+ // step 2 must be complete if exist
693+ assert (read_set.count (ref->get_paddr (), extent_cmp_t {}));
694+ // not added
695+ return false ;
696+ }
697+
698+ // step 2: attach extent to transaction to become visible
699+ auto [iter, inserted] = read_set.insert (read_items.back ());
700+ assert (inserted);
701+
702+ // added
633703 return true ;
634704 }
635705
0 commit comments