log.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_LOG_HPP_INCLUDED
6 #define UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_DISTRIBUTED_LOG_HPP_INCLUDED
7 
9 #include <uavcan/debug.hpp>
13 
14 namespace uavcan
15 {
16 namespace dynamic_node_id_server
17 {
18 namespace distributed
19 {
25 class Log
26 {
27 public:
28  typedef uint8_t Index;
29 
30  enum { Capacity = NodeID::Max + 1 };
31 
32 private:
36  Index last_index_; // Index zero always contains an empty entry
37 
38  static IStorageBackend::String getLastIndexKey() { return "log_last_index"; }
39 
40  static IStorageBackend::String makeEntryKey(Index index, const char* postfix)
41  {
43  // "log0_foobar"
44  str += "log";
45  str.appendFormatted("%d", int(index));
46  str += "_";
47  str += postfix;
48  return str;
49  }
50 
51  int readEntryFromStorage(Index index, Entry& out_entry)
52  {
53  const StorageMarshaller io(storage_);
54 
55  // Term
56  if (io.get(makeEntryKey(index, "term"), out_entry.term) < 0)
57  {
58  return -ErrFailure;
59  }
60 
61  // Unique ID
62  if (io.get(makeEntryKey(index, "unique_id"), out_entry.unique_id) < 0)
63  {
64  return -ErrFailure;
65  }
66 
67  // Node ID
68  uint32_t node_id = 0;
69  if (io.get(makeEntryKey(index, "node_id"), node_id) < 0)
70  {
71  return -ErrFailure;
72  }
73  if (node_id > NodeID::Max)
74  {
75  return -ErrFailure;
76  }
77  out_entry.node_id = static_cast<uint8_t>(node_id);
78 
79  return 0;
80  }
81 
82  int writeEntryToStorage(Index index, const Entry& entry)
83  {
84  Entry temp = entry;
85 
87 
88  // Term
89  if (io.setAndGetBack(makeEntryKey(index, "term"), temp.term) < 0)
90  {
91  return -ErrFailure;
92  }
93 
94  // Unique ID
95  if (io.setAndGetBack(makeEntryKey(index, "unique_id"), temp.unique_id) < 0)
96  {
97  return -ErrFailure;
98  }
99 
100  // Node ID
101  uint32_t node_id = entry.node_id;
102  if (io.setAndGetBack(makeEntryKey(index, "node_id"), node_id) < 0)
103  {
104  return -ErrFailure;
105  }
106  temp.node_id = static_cast<uint8_t>(node_id);
107 
108  return (temp == entry) ? 0 : -ErrFailure;
109  }
110 
112  {
114 
115  /*
116  * Writing the zero entry - it must always be default-initialized
117  */
118  entries_[0] = Entry();
119  int res = writeEntryToStorage(0, entries_[0]);
120  if (res < 0)
121  {
122  return res;
123  }
124 
125  /*
126  * Initializing last index
127  * Last index must be written AFTER the zero entry, otherwise if the write fails here the storage will be
128  * left in an inconsistent state.
129  */
130  last_index_ = 0;
131  uint32_t stored_index = 0;
132  res = io.setAndGetBack(getLastIndexKey(), stored_index);
133  if (res < 0)
134  {
135  return res;
136  }
137  if (stored_index != 0)
138  {
139  return -ErrFailure;
140  }
141 
142  return 0;
143  }
144 
145 public:
146  Log(IStorageBackend& storage, IEventTracer& tracer)
147  : storage_(storage)
148  , tracer_(tracer)
149  , last_index_(0)
150  { }
151 
152  int init()
153  {
155 
156  // Reading max index
157  {
158  uint32_t value = 0;
159  if (io.get(getLastIndexKey(), value) < 0)
160  {
161  if (storage_.get(getLastIndexKey()).empty())
162  {
163  UAVCAN_TRACE("dynamic_node_id_server::distributed::Log", "Initializing empty storage");
164  return initEmptyLogStorage();
165  }
166  else
167  {
168  // There's some data in the storage, but it cannot be parsed - reporting an error
169  UAVCAN_TRACE("dynamic_node_id_server::distributed::Log", "Failed to read last index");
170  return -ErrFailure;
171  }
172  }
173  if (value >= Capacity)
174  {
175  return -ErrFailure;
176  }
177  last_index_ = Index(value);
178  }
179 
181 
182  // Restoring log entries - note that index 0 always exists
183  for (Index index = 0; index <= last_index_; index++)
184  {
185  const int result = readEntryFromStorage(index, entries_[index]);
186  if (result < 0)
187  {
188  UAVCAN_TRACE("dynamic_node_id_server::distributed::Log", "Failed to read entry at index %u: %d",
189  unsigned(index), result);
190  return result;
191  }
192  }
193 
194  UAVCAN_TRACE("dynamic_node_id_server::distributed::Log", "Restored %u log entries", unsigned(last_index_));
195  return 0;
196  }
197 
202  int append(const Entry& entry)
203  {
204  if ((last_index_ + 1) >= Capacity)
205  {
206  return -ErrLogic;
207  }
208 
210 
211  // If next operations fail, we'll get a dangling entry, but it's absolutely OK.
212  int res = writeEntryToStorage(Index(last_index_ + 1), entry);
213  if (res < 0)
214  {
215  return res;
216  }
217 
218  // Updating the last index
220  uint32_t new_last_index = last_index_ + 1U;
221  res = io.setAndGetBack(getLastIndexKey(), new_last_index);
222  if (res < 0)
223  {
224  return res;
225  }
226  if (new_last_index != last_index_ + 1U)
227  {
228  return -ErrFailure;
229  }
230  entries_[new_last_index] = entry;
231  last_index_ = Index(new_last_index);
232 
233  UAVCAN_TRACE("dynamic_node_id_server::distributed::Log", "New entry, index %u, node ID %u, term %u",
234  unsigned(last_index_), unsigned(entry.node_id), unsigned(entry.term));
235  return 0;
236  }
237 
243  {
245 
246  if (((index) >= Capacity) || (index <= 0))
247  {
248  return -ErrLogic;
249  }
250 
251  uint32_t new_last_index = index - 1U;
252 
253  tracer_.onEvent(TraceRaftLogRemove, new_last_index);
254 
255  if (new_last_index != last_index_)
256  {
258  int res = io.setAndGetBack(getLastIndexKey(), new_last_index);
259  if (res < 0)
260  {
261  return res;
262  }
263  if (new_last_index != index - 1U)
264  {
265  return -ErrFailure;
266  }
267  UAVCAN_TRACE("dynamic_node_id_server::distributed::Log", "Entries removed, last index %u --> %u",
268  unsigned(last_index_), unsigned(new_last_index));
269  last_index_ = Index(new_last_index);
270  }
271 
272  // Removal operation leaves dangling entries in storage, it's OK
273  return 0;
274  }
275 
277  {
278  return removeEntriesWhereIndexGreaterOrEqual(Index(index + 1U));
279  }
280 
285  const Entry* getEntryAtIndex(Index index) const
286  {
288  return (index <= last_index_) ? &entries_[index] : UAVCAN_NULLPTR;
289  }
290 
291  Index getLastIndex() const { return last_index_; }
292 
293  bool isOtherLogUpToDate(Index other_last_index, Term other_last_term) const
294  {
296  // Terms are different - the one with higher term is more up-to-date
297  if (other_last_term != entries_[last_index_].term)
298  {
299  return other_last_term > entries_[last_index_].term;
300  }
301  // Terms are equal - longer log wins
302  return other_last_index >= last_index_;
303  }
304 };
305 
306 }
307 }
308 }
309 
310 #endif // Include guard
UAVCAN_NULLPTR
#define UAVCAN_NULLPTR
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:51
uavcan::dynamic_node_id_server::distributed::Log::initEmptyLogStorage
int initEmptyLogStorage()
Definition: log.hpp:111
uavcan::dynamic_node_id_server::distributed::Log::init
int init()
Definition: log.hpp:152
debug.hpp
uavcan::dynamic_node_id_server::distributed::Term
StorageType< Entry::FieldTypes::term >::Type Term
Definition: protocol/dynamic_node_id_server/distributed/types.hpp:23
uavcan::dynamic_node_id_server::distributed::Log::last_index_
Index last_index_
Definition: log.hpp:36
uavcan::dynamic_node_id_server::distributed::Log::isOtherLogUpToDate
bool isOtherLogUpToDate(Index other_last_index, Term other_last_term) const
Definition: log.hpp:293
uavcan::uint32_t
std::uint32_t uint32_t
Definition: std.hpp:26
uavcan::dynamic_node_id_server::distributed::Log::Index
uint8_t Index
Definition: log.hpp:28
uavcan::dynamic_node_id_server::distributed::Log::writeEntryToStorage
int writeEntryToStorage(Index index, const Entry &entry)
Definition: log.hpp:82
uavcan::dynamic_node_id_server::distributed::Log::makeEntryKey
static IStorageBackend::String makeEntryKey(Index index, const char *postfix)
Definition: log.hpp:40
uavcan::dynamic_node_id_server::distributed::Log::getEntryAtIndex
const Entry * getEntryAtIndex(Index index) const
Definition: log.hpp:285
uavcan::dynamic_node_id_server::StorageMarshaller
Definition: storage_marshaller.hpp:25
uavcan::dynamic_node_id_server::distributed::Log::tracer_
IEventTracer & tracer_
Definition: log.hpp:34
event.hpp
uavcan::dynamic_node_id_server::StorageMarshaller::setAndGetBack
int setAndGetBack(const IStorageBackend::String &key, uint32_t &inout_value)
Definition: storage_marshaller.hpp:62
TraceRaftLogRemove
TraceRaftLogRemove
Definition: event.hpp:26
uavcan::dynamic_node_id_server::StorageMarshaller::get
int get(const IStorageBackend::String &key, uint32_t &out_value) const
Definition: storage_marshaller.hpp:90
UAVCAN_TRACE
#define UAVCAN_TRACE(...)
Definition: libuavcan/libuavcan/include/uavcan/debug.hpp:31
uavcan::dynamic_node_id_server::distributed::Log::getLastIndexKey
static IStorageBackend::String getLastIndexKey()
Definition: log.hpp:38
types.hpp
TraceRaftLogLastIndexRestored
TraceRaftLogLastIndexRestored
Definition: event.hpp:24
uavcan::dynamic_node_id_server::distributed::Log::append
int append(const Entry &entry)
Definition: log.hpp:202
uavcan::dynamic_node_id_server::distributed::Log::entries_
Entry entries_[Capacity]
Definition: log.hpp:35
libuavcan_dsdl_compiler.str
str
Definition: libuavcan_dsdl_compiler/__init__.py:22
uavcan::Array
Definition: array.hpp:424
uavcan_kinetis::ErrLogic
static const uavcan::int16_t ErrLogic
Internal logic error.
Definition: platform_specific_components/kinetis/libuavcan/driver/include/uavcan_kinetis/can.hpp:22
uavcan::dynamic_node_id_server::distributed::Log::removeEntriesWhereIndexGreaterOrEqual
int removeEntriesWhereIndexGreaterOrEqual(Index index)
Definition: log.hpp:242
uavcan::uint8_t
std::uint8_t uint8_t
Definition: std.hpp:24
uavcan::dynamic_node_id_server::IStorageBackend
Definition: storage_backend.hpp:22
uavcan::dynamic_node_id_server::distributed::Log::readEntryFromStorage
int readEntryFromStorage(Index index, Entry &out_entry)
Definition: log.hpp:51
build_config.hpp
Entry
Definition: avl_tree.cpp:12
uavcan::dynamic_node_id_server::IEventTracer::onEvent
virtual void onEvent(TraceCode event_code, int64_t event_argument)=0
uavcan::dynamic_node_id_server::IEventTracer
Definition: event.hpp:90
uavcan::dynamic_node_id_server::distributed::Log::removeEntriesWhereIndexGreater
int removeEntriesWhereIndexGreater(Index index)
Definition: log.hpp:276
uavcan::dynamic_node_id_server::distributed::Log::Capacity
@ Capacity
Definition: log.hpp:30
uavcan::dynamic_node_id_server::distributed::Log::Log
Log(IStorageBackend &storage, IEventTracer &tracer)
Definition: log.hpp:146
uavcan::NodeID::Max
static const uint8_t Max
Definition: transfer.hpp:120
uavcan::dynamic_node_id_server::distributed::Log
Definition: log.hpp:25
uavcan::dynamic_node_id_server::distributed::Log::storage_
IStorageBackend & storage_
Definition: log.hpp:33
uavcan
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:204
uavcan::dynamic_node_id_server::IStorageBackend::get
virtual String get(const String &key) const =0
storage_marshaller.hpp
TraceRaftLogAppend
TraceRaftLogAppend
Definition: event.hpp:25
UAVCAN_ASSERT
#define UAVCAN_ASSERT(x)
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:184
uavcan::dynamic_node_id_server::distributed::Log::getLastIndex
Index getLastIndex() const
Definition: log.hpp:291


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:02