@@ -192,4 +192,142 @@ struct __attribute__((packed)) backref_map_val_le_t {
192192
193193} // namespace backerf
194194
195+ /* *
196+ * BtreeCursor
197+ *
198+ * BtreeCursor is the type-erased wrapper for FixedKVBtree::iterator, stores
199+ * a key-value mapping's location and the snapshot of its data at construction
200+ * time.
201+ */
202+ template <typename key_t , typename val_t >
203+ struct BtreeCursor {
204+ BtreeCursor (
205+ op_context_t &ctx,
206+ CachedExtentRef parent,
207+ uint64_t modifications,
208+ key_t key,
209+ std::optional<val_t > val,
210+ btreenode_pos_t pos)
211+ : ctx(ctx),
212+ parent (std::move(parent)),
213+ modifications(modifications),
214+ key(key),
215+ val(std::move(val)),
216+ pos(pos)
217+ {
218+ if constexpr (std::is_same_v<key_t , laddr_t >) {
219+ static_assert (std::is_same_v<val_t , lba_manager::btree::lba_map_val_t >,
220+ " the value type of laddr_t for BtreeCursor should be lba_map_val_t" );
221+ } else {
222+ static_assert (std::is_same_v<key_t , paddr_t >,
223+ " the key type of BtreeCursor should be either laddr_t or paddr_t" );
224+ static_assert (std::is_same_v<val_t , backref::backref_map_val_t >,
225+ " the value type should be either lba_map_val_t or backref_map_val_t" );
226+ }
227+ }
228+
229+ op_context_t ctx;
230+ CachedExtentRef parent;
231+ uint64_t modifications;
232+ key_t key;
233+ std::optional<val_t > val;
234+ btreenode_pos_t pos;
235+
236+ // NOTE: The overhead of calling is_viewable() might be not negligible in the
237+ // case of the parent extent is stable and shared by multiple transactions.
238+ // The best practice is to only hold cursors whose parent is pending in
239+ // current transaction in the long term.
240+ bool is_viewable () const ;
241+
242+ bool is_end () const {
243+ auto max_key = min_max_t <key_t >::max;
244+ assert ((key != max_key) == (bool )val);
245+ return key == max_key;
246+ }
247+
248+ extent_len_t get_length () const {
249+ assert (!is_end ());
250+ return val->len ;
251+ }
252+ };
253+
254+ struct LBACursor : BtreeCursor<laddr_t , lba_manager::btree::lba_map_val_t > {
255+ using Base = BtreeCursor<laddr_t , lba_manager::btree::lba_map_val_t >;
256+ using Base::BtreeCursor;
257+ bool is_indirect () const {
258+ assert (!is_end ());
259+ return val->pladdr .is_laddr ();
260+ }
261+ laddr_t get_laddr () const {
262+ return key;
263+ }
264+ paddr_t get_paddr () const {
265+ assert (!is_indirect ());
266+ assert (!is_end ());
267+ return val->pladdr .get_paddr ();
268+ }
269+ laddr_t get_intermediate_key () const {
270+ assert (is_indirect ());
271+ assert (!is_end ());
272+ return val->pladdr .get_laddr ();
273+ }
274+ checksum_t get_checksum () const {
275+ assert (!is_end ());
276+ assert (!is_indirect ());
277+ return val->checksum ;
278+ }
279+ extent_ref_count_t get_refcount () const {
280+ assert (!is_end ());
281+ assert (!is_indirect ());
282+ return val->refcount ;
283+ }
284+ std::unique_ptr<LBACursor> duplicate () const {
285+ return std::make_unique<LBACursor>(*this );
286+ }
287+ };
288+ using LBACursorRef = std::unique_ptr<LBACursor>;
289+
290+ struct BackrefCursor : BtreeCursor<paddr_t , backref::backref_map_val_t > {
291+ using Base = BtreeCursor<paddr_t , backref::backref_map_val_t >;
292+ using Base::BtreeCursor;
293+ paddr_t get_paddr () const {
294+ return key;
295+ }
296+ laddr_t get_laddr () const {
297+ assert (!is_end ());
298+ return val->laddr ;
299+ }
300+ extent_types_t get_type () const {
301+ assert (!is_end ());
302+ return val->type ;
303+ }
304+ };
305+ using BackrefCursorRef = std::unique_ptr<BackrefCursor>;
306+
307+ template <typename key_t , typename val_t >
308+ std::ostream &operator <<(
309+ std::ostream &out, const BtreeCursor<key_t , val_t > &cursor)
310+ {
311+ if constexpr (std::is_same_v<key_t , laddr_t >) {
312+ out << " LBACursor(" ;
313+ } else {
314+ out << " BackrefCursor(" ;
315+ }
316+ out << (void *)cursor.parent .get ()
317+ << " @" << cursor.pos
318+ << " #" << cursor.modifications
319+ << " ," ;
320+ if (cursor.is_end ()) {
321+ return out << " END)" ;
322+ }
323+ return out << " ," << cursor.key
324+ << " ~" << *cursor.val
325+ << " )" ;
326+ }
327+
195328} // namespace crimson::os::seastore
329+
330+ #if FMT_VERSION >= 90000
331+ template <> struct fmt ::formatter<crimson::os::seastore::LBACursor> : fmt::ostream_formatter {};
332+ template <> struct fmt ::formatter<crimson::os::seastore::BackrefCursor> : fmt::ostream_formatter {};
333+ #endif
0 commit comments