libuav original
Dependents: UAVCAN UAVCAN_Subscriber
persistent_state.hpp
00001 /* 00002 * Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com> 00003 */ 00004 00005 #ifndef UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_DISTRIBUTED_PERSISTENT_STATE_HPP_INCLUDED 00006 #define UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_DISTRIBUTED_PERSISTENT_STATE_HPP_INCLUDED 00007 00008 #include <uavcan/build_config.hpp> 00009 #include <uavcan/debug.hpp> 00010 #include <uavcan/protocol/dynamic_node_id_server/distributed/types.hpp> 00011 #include <uavcan/protocol/dynamic_node_id_server/distributed/log.hpp> 00012 #include <uavcan/protocol/dynamic_node_id_server/storage_marshaller.hpp> 00013 #include <uavcan/protocol/dynamic_node_id_server/event.hpp> 00014 00015 namespace uavcan 00016 { 00017 namespace dynamic_node_id_server 00018 { 00019 namespace distributed 00020 { 00021 /** 00022 * This class is a convenient container for persistent state variables defined by Raft. 00023 * Writes are slow, reads are instantaneous. 00024 */ 00025 class PersistentState 00026 { 00027 IStorageBackend& storage_; 00028 IEventTracer& tracer_; 00029 00030 Term current_term_; 00031 NodeID voted_for_; 00032 Log log_; 00033 00034 static IStorageBackend::String getCurrentTermKey() { return "current_term"; } 00035 static IStorageBackend::String getVotedForKey() { return "voted_for"; } 00036 00037 public: 00038 PersistentState(IStorageBackend& storage, IEventTracer& tracer) 00039 : storage_(storage) 00040 , tracer_(tracer) 00041 , current_term_(0) 00042 , log_(storage, tracer) 00043 { } 00044 00045 /** 00046 * Initialization is performed as follows (every step may fail and return an error): 00047 * 1. Log is restored or initialized. 00048 * 2. Current term is restored. If there was no current term stored and the log is empty, it will be initialized 00049 * with zero. 00050 * 3. VotedFor value is restored. If there was no VotedFor value stored, the log is empty, and the current term is 00051 * zero, the value will be initialized with zero. 00052 */ 00053 int init() 00054 { 00055 /* 00056 * Reading log 00057 */ 00058 int res = log_.init(); 00059 if (res < 0) 00060 { 00061 UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState", "Log init failed: %d", res); 00062 return res; 00063 } 00064 00065 const Entry* const last_entry = log_.getEntryAtIndex(log_.getLastIndex()); 00066 if (last_entry == UAVCAN_NULLPTR) 00067 { 00068 UAVCAN_ASSERT(0); 00069 return -ErrLogic; 00070 } 00071 00072 const bool log_is_empty = (log_.getLastIndex() == 0) && (last_entry->term == 0); 00073 00074 StorageMarshaller io(storage_); 00075 00076 /* 00077 * Reading currentTerm 00078 */ 00079 if (storage_.get(getCurrentTermKey()).empty() && log_is_empty) 00080 { 00081 // First initialization 00082 current_term_ = 0; 00083 res = io.setAndGetBack(getCurrentTermKey(), current_term_); 00084 if (res < 0) 00085 { 00086 UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState", 00087 "Failed to init current term: %d", res); 00088 return res; 00089 } 00090 if (current_term_ != 0) 00091 { 00092 return -ErrFailure; 00093 } 00094 } 00095 else 00096 { 00097 // Restoring 00098 res = io.get(getCurrentTermKey(), current_term_); 00099 if (res < 0) 00100 { 00101 UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState", 00102 "Failed to read current term: %d", res); 00103 return res; 00104 } 00105 } 00106 00107 tracer_.onEvent(TraceRaftCurrentTermRestored, current_term_); 00108 00109 if (current_term_ < last_entry->term) 00110 { 00111 UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState", 00112 "Persistent storage is damaged: current term is less than term of the last log entry (%u < %u)", 00113 unsigned(current_term_), unsigned(last_entry->term)); 00114 return -ErrLogic; 00115 } 00116 00117 /* 00118 * Reading votedFor 00119 */ 00120 if (storage_.get(getVotedForKey()).empty() && log_is_empty && (current_term_ == 0)) 00121 { 00122 // First initialization 00123 voted_for_ = NodeID(0); 00124 uint32_t stored_voted_for = 0; 00125 res = io.setAndGetBack(getVotedForKey(), stored_voted_for); 00126 if (res < 0) 00127 { 00128 UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState", 00129 "Failed to init votedFor: %d", res); 00130 return res; 00131 } 00132 if (stored_voted_for != 0) 00133 { 00134 return -ErrFailure; 00135 } 00136 } 00137 else 00138 { 00139 // Restoring 00140 uint32_t stored_voted_for = 0; 00141 res = io.get(getVotedForKey(), stored_voted_for); 00142 if (res < 0) 00143 { 00144 UAVCAN_TRACE("dynamic_node_id_server::distributed::PersistentState", 00145 "Failed to read votedFor: %d", res); 00146 return res; 00147 } 00148 if (stored_voted_for > NodeID::Max) 00149 { 00150 return -ErrInvalidConfiguration; 00151 } 00152 voted_for_ = NodeID(uint8_t(stored_voted_for)); 00153 } 00154 00155 tracer_.onEvent(TraceRaftVotedForRestored, voted_for_.get()); 00156 00157 return 0; 00158 } 00159 00160 Term getCurrentTerm() const { return current_term_; } 00161 00162 NodeID getVotedFor() const { return voted_for_; } 00163 bool isVotedForSet() const { return voted_for_.isUnicast(); } 00164 00165 Log& getLog() { return log_; } 00166 const Log& getLog() const { return log_; } 00167 00168 /** 00169 * Invokes storage IO. 00170 */ 00171 int setCurrentTerm(Term term) 00172 { 00173 if (term < current_term_) 00174 { 00175 UAVCAN_ASSERT(0); 00176 return -ErrInvalidParam; 00177 } 00178 00179 tracer_.onEvent(TraceRaftCurrentTermUpdate, term); 00180 00181 StorageMarshaller io(storage_); 00182 00183 Term tmp = term; 00184 int res = io.setAndGetBack(getCurrentTermKey(), tmp); 00185 if (res < 0) 00186 { 00187 return res; 00188 } 00189 00190 if (tmp != term) 00191 { 00192 return -ErrFailure; 00193 } 00194 00195 current_term_ = term; 00196 return 0; 00197 } 00198 00199 /** 00200 * Invokes storage IO. 00201 */ 00202 int setVotedFor(NodeID node_id) 00203 { 00204 if (!node_id.isValid()) 00205 { 00206 UAVCAN_ASSERT(0); 00207 return -ErrInvalidParam; 00208 } 00209 00210 tracer_.onEvent(TraceRaftVotedForUpdate, node_id.get()); 00211 00212 StorageMarshaller io(storage_); 00213 00214 uint32_t tmp = node_id.get(); 00215 int res = io.setAndGetBack(getVotedForKey(), tmp); 00216 if (res < 0) 00217 { 00218 return res; 00219 } 00220 00221 if (node_id.get() != tmp) 00222 { 00223 return -ErrFailure; 00224 } 00225 00226 voted_for_ = node_id; 00227 return 0; 00228 } 00229 00230 int resetVotedFor() { return setVotedFor(NodeID(0)); } 00231 }; 00232 00233 } 00234 } 00235 } 00236 00237 #endif // Include guard
Generated on Tue Jul 12 2022 17:17:33 by 1.7.2