summaryrefslogtreecommitdiffstats
path: root/src/crimson/os/seastore/onode_manager/staged-fltree/super.h
blob: 5eefee9ffb438ffbccd32aabebd86e439d008c34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
// vim: ts=8 sw=2 smarttab

#pragma once

#include <memory>

#include "crimson/common/type_helpers.h"

#include "fwd.h"

namespace crimson::os::seastore::onode {

class Node;
class Super;

/**
 * RootNodeTracker
 *
 * An abstracted tracker to get the root node by Transaction.
 */
class RootNodeTracker {
 public:
  virtual ~RootNodeTracker() = default;
  virtual bool is_clean() const = 0;
  virtual Ref<Node> get_root(Transaction&) const = 0;
  static RootNodeTrackerURef create(bool read_isolated);
 protected:
  RootNodeTracker() = default;
  RootNodeTracker(const RootNodeTracker&) = delete;
  RootNodeTracker(RootNodeTracker&&) = delete;
  RootNodeTracker& operator=(const RootNodeTracker&) = delete;
  RootNodeTracker& operator=(RootNodeTracker&&) = delete;
  virtual void do_track_super(Transaction&, Super&) = 0;
  virtual void do_untrack_super(Transaction&, Super&) = 0;
  friend class Super;
};

/**
 * Super
 *
 * The parent of root node. It contains the relationship between a Transaction
 * and a root node address.
 */
class Super {
 public:
  using URef = std::unique_ptr<Super>;
  Super(const Super&) = delete;
  Super(Super&&) = delete;
  Super& operator=(const Super&) = delete;
  Super& operator=(Super&&) = delete;
  virtual ~Super() {
    assert(tracked_root_node == nullptr);
    tracker.do_untrack_super(t, *this);
  }

  virtual laddr_t get_root_laddr() const = 0;
  virtual void write_root_laddr(context_t, laddr_t) = 0;

  void do_track_root(Node& root) {
    assert(tracked_root_node == nullptr);
    tracked_root_node = &root;
  }
  void do_untrack_root(Node& root) {
    assert(tracked_root_node == &root);
    tracked_root_node = nullptr;
  }
  Node* get_p_root() const {
    assert(tracked_root_node != nullptr);
    return tracked_root_node;
  }

 protected:
  Super(Transaction& t, RootNodeTracker& tracker)
      : t{t}, tracker{tracker} {
    tracker.do_track_super(t, *this);
  }

 private:
  Transaction& t;
  RootNodeTracker& tracker;
  Node* tracked_root_node = nullptr;
};

/**
 * RootNodeTrackerIsolated
 *
 * A concrete RootNodeTracker implementation which provides root node isolation
 * between Transactions for Seastore backend.
 */
class RootNodeTrackerIsolated final : public RootNodeTracker {
 public:
  ~RootNodeTrackerIsolated() override { assert(is_clean()); }
 protected:
  bool is_clean() const override {
    return tracked_supers.empty();
  }
  void do_track_super(Transaction& t, Super& super) override {
    assert(tracked_supers.find(&t) == tracked_supers.end());
    tracked_supers[&t] = &super;
  }
  void do_untrack_super(Transaction& t, Super& super) override {
    [[maybe_unused]] auto removed = tracked_supers.erase(&t);
    assert(removed);
  }
  ::Ref<Node> get_root(Transaction& t) const override;
  std::map<Transaction*, Super*> tracked_supers;
};

/**
 * RootNodeTrackerShared
 *
 * A concrete RootNodeTracker implementation which has no isolation between
 * Transactions for Dummy backend.
 */
class RootNodeTrackerShared final : public RootNodeTracker {
 public:
  ~RootNodeTrackerShared() override { assert(is_clean()); }
 protected:
  bool is_clean() const override {
    return tracked_super == nullptr;
  }
  void do_track_super(Transaction&, Super& super) override {
    assert(is_clean());
    tracked_super = &super;
  }
  void do_untrack_super(Transaction&, Super& super) override {
    assert(tracked_super == &super);
    tracked_super = nullptr;
  }
  ::Ref<Node> get_root(Transaction&) const override;
  Super* tracked_super = nullptr;
};

inline RootNodeTrackerURef RootNodeTracker::create(bool read_isolated) {
  if (read_isolated) {
    return RootNodeTrackerURef(new RootNodeTrackerIsolated());
  } else {
    return RootNodeTrackerURef(new RootNodeTrackerShared());
  }
}

}