persistent_state.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
5 #ifndef UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_DISTRIBUTED_PERSISTENT_STATE_HPP_INCLUDED
6 #define UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_DISTRIBUTED_PERSISTENT_STATE_HPP_INCLUDED
7 
9 #include <uavcan/debug.hpp>
14 
15 namespace uavcan
16 {
17 namespace dynamic_node_id_server
18 {
19 namespace distributed
20 {
26 {
29 
33 
34  static IStorageBackend::String getCurrentTermKey() { return "current_term"; }
35  static IStorageBackend::String getVotedForKey() { return "voted_for"; }
36 
37 public:
39  : storage_(storage)
40  , tracer_(tracer)
41  , current_term_(0)
42  , log_(storage, tracer)
43  { }
44 
53  int init()
54  {
55  /*
56  * Reading log
57  */
58  int res = log_.init();
59  if (res < 0)
60  {
61  UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState", "Log init failed: %d", res);
62  return res;
63  }
64 
65  const Entry* const last_entry = log_.getEntryAtIndex(log_.getLastIndex());
66  if (last_entry == UAVCAN_NULLPTR)
67  {
68  UAVCAN_ASSERT(0);
69  return -ErrLogic;
70  }
71 
72  const bool log_is_empty = (log_.getLastIndex() == 0) && (last_entry->term == 0);
73 
74  StorageMarshaller io(storage_);
75 
76  /*
77  * Reading currentTerm
78  */
79  if (storage_.get(getCurrentTermKey()).empty() && log_is_empty)
80  {
81  // First initialization
82  current_term_ = 0;
83  res = io.setAndGetBack(getCurrentTermKey(), current_term_);
84  if (res < 0)
85  {
86  UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState",
87  "Failed to init current term: %d", res);
88  return res;
89  }
90  if (current_term_ != 0)
91  {
92  return -ErrFailure;
93  }
94  }
95  else
96  {
97  // Restoring
98  res = io.get(getCurrentTermKey(), current_term_);
99  if (res < 0)
100  {
101  UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState",
102  "Failed to read current term: %d", res);
103  return res;
104  }
105  }
106 
107  tracer_.onEvent(TraceRaftCurrentTermRestored, current_term_);
108 
109  if (current_term_ < last_entry->term)
110  {
111  UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState",
112  "Persistent storage is damaged: current term is less than term of the last log entry (%u < %u)",
113  unsigned(current_term_), unsigned(last_entry->term));
114  return -ErrLogic;
115  }
116 
117  /*
118  * Reading votedFor
119  */
120  if (storage_.get(getVotedForKey()).empty() && log_is_empty && (current_term_ == 0))
121  {
122  // First initialization
123  voted_for_ = NodeID(0);
124  uint32_t stored_voted_for = 0;
125  res = io.setAndGetBack(getVotedForKey(), stored_voted_for);
126  if (res < 0)
127  {
128  UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState",
129  "Failed to init votedFor: %d", res);
130  return res;
131  }
132  if (stored_voted_for != 0)
133  {
134  return -ErrFailure;
135  }
136  }
137  else
138  {
139  // Restoring
140  uint32_t stored_voted_for = 0;
141  res = io.get(getVotedForKey(), stored_voted_for);
142  if (res < 0)
143  {
144  UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState",
145  "Failed to read votedFor: %d", res);
146  return res;
147  }
148  if (stored_voted_for > NodeID::Max)
149  {
150  return -ErrInvalidConfiguration;
151  }
152  voted_for_ = NodeID(uint8_t(stored_voted_for));
153  }
154 
155  tracer_.onEvent(TraceRaftVotedForRestored, voted_for_.get());
156 
157  return 0;
158  }
159 
160  Term getCurrentTerm() const { return current_term_; }
161 
162  NodeID getVotedFor() const { return voted_for_; }
163  bool isVotedForSet() const { return voted_for_.isUnicast(); }
164 
165  Log& getLog() { return log_; }
166  const Log& getLog() const { return log_; }
167 
172  {
173  if (term < current_term_)
174  {
175  UAVCAN_ASSERT(0);
176  return -ErrInvalidParam;
177  }
178 
179  tracer_.onEvent(TraceRaftCurrentTermUpdate, term);
180 
181  StorageMarshaller io(storage_);
182 
183  Term tmp = term;
184  int res = io.setAndGetBack(getCurrentTermKey(), tmp);
185  if (res < 0)
186  {
187  return res;
188  }
189 
190  if (tmp != term)
191  {
192  return -ErrFailure;
193  }
194 
195  current_term_ = term;
196  return 0;
197  }
198 
202  int setVotedFor(NodeID node_id)
203  {
204  if (!node_id.isValid())
205  {
206  UAVCAN_ASSERT(0);
207  return -ErrInvalidParam;
208  }
209 
210  tracer_.onEvent(TraceRaftVotedForUpdate, node_id.get());
211 
212  StorageMarshaller io(storage_);
213 
214  uint32_t tmp = node_id.get();
215  int res = io.setAndGetBack(getVotedForKey(), tmp);
216  if (res < 0)
217  {
218  return res;
219  }
220 
221  if (node_id.get() != tmp)
222  {
223  return -ErrFailure;
224  }
225 
226  voted_for_ = node_id;
227  return 0;
228  }
229 
230  int resetVotedFor() { return setVotedFor(NodeID(0)); }
231 };
232 
233 }
234 }
235 }
236 
237 #endif // Include guard
std::uint8_t uint8_t
Definition: std.hpp:24
bool isUnicast() const
Definition: transfer.hpp:136
bool empty() const
Definition: array.hpp:712
PersistentState(IStorageBackend &storage, IEventTracer &tracer)
virtual void onEvent(TraceCode event_code, int64_t event_argument)=0
TraceRaftVotedForUpdate
Definition: event.hpp:23
TraceRaftCurrentTermRestored
Definition: event.hpp:23
const Entry * getEntryAtIndex(Index index) const
Definition: log.hpp:285
uint8_t get() const
Definition: transfer.hpp:132
int get(const IStorageBackend::String &key, uint32_t &out_value) const
static const uint8_t Max
Definition: transfer.hpp:120
int setAndGetBack(const IStorageBackend::String &key, uint32_t &inout_value)
TraceRaftVotedForRestored
Definition: event.hpp:23
std::uint32_t uint32_t
Definition: std.hpp:26
bool isValid() const
Definition: transfer.hpp:134
TraceRaftCurrentTermUpdate
Definition: event.hpp:23
virtual String get(const String &key) const =0


uavcan_communicator
Author(s):
autogenerated on Wed Jan 11 2023 03:59:39