blob: b7bfbdfd48593b8134dab6a7e4065925cb5ef7b6 [file] [log] [blame]
Yingdi Yuf7ede412014-08-30 20:37:52 -07001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2012-2014 University of California, Los Angeles
4 *
5 * This file is part of ChronoSync, synchronization library for distributed realtime
6 * applications for NDN.
7 *
8 * ChronoSync is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation, either
10 * version 3 of the License, or (at your option) any later version.
11 *
12 * ChronoSync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
20 * @author Chaoyi Bian <bcy@pku.edu.cn>
21 * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
22 * @author Yingdi Yu <yingdi@cs.ucla.edu>
23 */
24
25#ifndef CHRONOSYNC_LOGIC_HPP
26#define CHRONOSYNC_LOGIC_HPP
27
28#include "boost-header.h"
29#include <memory>
Qiuhan Ding8c095fd2014-11-19 17:38:32 -080030#include <unordered_map>
Yingdi Yuf7ede412014-08-30 20:37:52 -070031
32#include <ndn-cxx/face.hpp>
33#include <ndn-cxx/util/scheduler.hpp>
34#include <ndn-cxx/security/key-chain.hpp>
Yingdi Yucd339022014-11-05 17:51:19 -080035#include <ndn-cxx/security/validator.hpp>
Yingdi Yuf7ede412014-08-30 20:37:52 -070036
37#include "interest-table.hpp"
38#include "diff-state-container.hpp"
39
40namespace chronosync {
41
42/**
43 * @brief The missing sequence numbers for a session
44 *
45 * This class is used to notify the clients of Logic
46 * the details of state changes.
47 *
48 * Instances of this class is usually used as elements of some containers
49 * such as std::vector, thus it is copyable.
50 */
Qiuhan Ding8c095fd2014-11-19 17:38:32 -080051class NodeInfo {
52public:
53 Name userPrefix;
54 Name signingId;
55 Name sessionName;
56 SeqNo seqNo;
57};
58
Yingdi Yuf7ede412014-08-30 20:37:52 -070059class MissingDataInfo
60{
61public:
62 /// @brief session name
63 Name session;
64 /// @brief the lowest one of missing sequence numbers
65 SeqNo low;
66 /// @brief the highest one of missing sequence numbers
67 SeqNo high;
68};
69
70/**
71 * @brief The callback function to handle state updates
72 *
73 * The parameter is a set of MissingDataInfo, of which each corresponds to
74 * a session that has changed its state.
75 */
76typedef function<void(const std::vector<MissingDataInfo>&)> UpdateCallback;
77
78/**
79 * @brief Logic of ChronoSync
80 */
81class Logic : noncopyable
82{
83public:
Qiuhan Ding8c095fd2014-11-19 17:38:32 -080084 class Error : public std::runtime_error
85 {
86 public:
87 explicit
88 Error(const std::string& what)
89 : std::runtime_error(what)
90 {
91 }
92 };
93
94public:
Yingdi Yuf7ede412014-08-30 20:37:52 -070095 static const time::steady_clock::Duration DEFAULT_RESET_TIMER;
96 static const time::steady_clock::Duration DEFAULT_CANCEL_RESET_TIMER;
97 static const time::milliseconds DEFAULT_RESET_INTEREST_LIFETIME;
98 static const time::milliseconds DEFAULT_SYNC_INTEREST_LIFETIME;
99 static const time::milliseconds DEFAULT_SYNC_REPLY_FRESHNESS;
100
101 /**
102 * @brief Constructor
103 *
104 * @param syncPrefix The prefix of the sync group
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800105 * @param defaultUserPrefix The prefix of the first user added to this session
Yingdi Yuf7ede412014-08-30 20:37:52 -0700106 * @param onUpdate The callback function to handle state updates
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800107 * @param defaultSigningId The signing Id of the default user
Yingdi Yucd339022014-11-05 17:51:19 -0800108 * @param validator The validator for packet validation
Yingdi Yuf7ede412014-08-30 20:37:52 -0700109 * @param resetTimer The timer to periodically send Reset Interest
110 * @param syncReplyFreshness The FreshnessPeriod of sync reply
111 * @param resetInterestLifetime The lifetime of sync interest
112 * @param resetInterestLifetime The lifetime of Reset Interest
113 * @param cancelResetTimer The timer to exit from Reset state
114 */
115 Logic(ndn::Face& face,
116 const Name& syncPrefix,
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800117 const Name& defaultUserPrefix,
Yingdi Yuf7ede412014-08-30 20:37:52 -0700118 const UpdateCallback& onUpdate,
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800119 const Name& defaultSigningId = DEFAULT_NAME,
Yingdi Yucd339022014-11-05 17:51:19 -0800120 ndn::shared_ptr<ndn::Validator> validator = DEFAULT_VALIDATOR,
Yingdi Yuf7ede412014-08-30 20:37:52 -0700121 const time::steady_clock::Duration& resetTimer = DEFAULT_RESET_TIMER,
122 const time::steady_clock::Duration& cancelResetTimer = DEFAULT_CANCEL_RESET_TIMER,
123 const time::milliseconds& resetInterestLifetime = DEFAULT_RESET_INTEREST_LIFETIME,
124 const time::milliseconds& syncInterestLifetime = DEFAULT_SYNC_INTEREST_LIFETIME,
125 const time::milliseconds& syncReplyFreshness = DEFAULT_SYNC_REPLY_FRESHNESS);
126
127 ~Logic();
128
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800129 /**
130 * @brief Reset the sync tree (and restart synchronization again)
131 *
132 * @param isOnInterest a flag that tells whether the reset is called by reset interest.
133 */
Yingdi Yuf7ede412014-08-30 20:37:52 -0700134 void
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800135 reset(bool isOnInterest = false);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700136
137 /**
138 * @brief Set user prefix
139 *
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800140 * This method will also change the default user and signing Id of that user.
Yingdi Yuf7ede412014-08-30 20:37:52 -0700141 *
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800142 * @param defaultUserPrefix The prefix of user.
Yingdi Yuf7ede412014-08-30 20:37:52 -0700143 */
144 void
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800145 setDefaultUserPrefix(const Name& defaultUserPrefix);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700146
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800147 /// @brief Get the name of default user.
Yingdi Yuf7ede412014-08-30 20:37:52 -0700148 const Name&
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800149 getDefaultUserPrefix() const
Yingdi Yuf7ede412014-08-30 20:37:52 -0700150 {
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800151 return m_defaultUserPrefix;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700152 }
153
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800154 /**
155 * @brief Add user node into the local session.
156 *
157 * This method also reset after adding
158 *
159 * @param userPrefix prefix of the added node
160 * @param signingId signing Id of the added node
161 */
162 void
163 addUserNode(const Name& userPrefix, const Name& signingId = DEFAULT_NAME);
164
165 /// @brief remove the node from the local session
166 void
167 removeUserNode(const Name& userPrefix);
168
169 /**
170 * @brief Get the name of the local session.
171 *
172 * This method gets the session name according to prefix, if prefix is not specified,
173 * it returns the session name of default user.
174 *
175 * @param prefix prefix of the node
176 */
177 const Name&
178 getSessionName(Name prefix = EMPTY_NAME);
179
180 /**
181 * @brief Get current seqNo of the local session.
182 *
183 * This method gets the seqNo according to prefix, if prefix is not specified,
184 * it returns the seqNo of default user.
185 *
186 * @param prefix prefix of the node
187 */
Yingdi Yuf7ede412014-08-30 20:37:52 -0700188 const SeqNo&
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800189 getSeqNo(Name prefix = EMPTY_NAME);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700190
191 /**
192 * @brief Update the seqNo of the local session
193 *
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800194 * The method updates the existing seqNo with the supplied seqNo and prefix.
Yingdi Yuf7ede412014-08-30 20:37:52 -0700195 *
196 * @param seq The new seqNo.
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800197 * @param updatePrefix The prefix of node to update.
Yingdi Yuf7ede412014-08-30 20:37:52 -0700198 */
199 void
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800200 updateSeqNo(const SeqNo& seq, const Name& updatePrefix = EMPTY_NAME);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700201
202 /// @brief Get root digest of current sync tree
203 ndn::ConstBufferPtr
204 getRootDigest() const;
205
206 /// @brief Get the name of all sessions
207 std::set<Name>
208 getSessionNames() const;
209
Yingdi Yu906c2ea2014-10-31 11:24:50 -0700210CHRONOSYNC_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Yingdi Yuf7ede412014-08-30 20:37:52 -0700211 void
212 printState(std::ostream& os) const;
213
214 ndn::Scheduler&
215 getScheduler()
216 {
217 return m_scheduler;
218 }
219
220 State&
221 getState()
222 {
223 return m_state;
224 }
225
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800226
Yingdi Yuf7ede412014-08-30 20:37:52 -0700227private:
228 /**
229 * @brief Callback to handle Sync Interest
230 *
231 * This method checks whether an incoming interest is a normal one or a reset
232 * and dispatches the incoming interest to corresponding processing methods.
233 *
234 * @param prefix The prefix of the sync group.
235 * @param interest The incoming sync interest.
236 */
237 void
238 onSyncInterest(const Name& prefix, const Interest& interest);
239
240 /**
241 * @brief Callback to handle Sync prefix registration failure
242 *
243 * This method does nothing for now.
244 *
245 * @param prefix The prefix of the sync group.
246 * @param msg The error message.
247 */
248 void
249 onSyncRegisterFailed(const Name& prefix, const std::string& msg);
250
251 /**
252 * @brief Callback to handle Sync Reply
253 *
254 * This method calls validator to validate Sync Reply.
255 * For now, validation is disabled, Logic::onSyncDataValidated is called
256 * directly.
257 *
258 * @param interest The Sync Interest
259 * @param data The reply to the Sync Interest
260 */
261 void
262 onSyncData(const Interest& interest, Data& data);
263
264 /**
265 * @brief Callback to handle reply to Reset Interest.
266 *
267 * This method does nothing, since reply to Reset Interest is not useful for now.
268 *
269 * @param interest The Reset Interest
270 * @param data The reply to the Reset Interest
271 */
272 void
273 onResetData(const Interest& interest, Data& data);
274
275 /**
276 * @brief Callback to handle Sync Interest timeout.
277 *
278 * This method does nothing, since Logic per se handles timeout explicitly.
279 *
280 * @param interest The Sync Interest
281 */
282 void
283 onSyncTimeout(const Interest& interest);
284
285 /**
286 * @brief Callback to invalid Sync Reply.
287 *
288 * This method does nothing but drops the invalid reply.
289 *
290 * @param data The invalid Sync Reply
291 */
292 void
293 onSyncDataValidationFailed(const shared_ptr<const Data>& data);
294
295 /**
296 * @brief Callback to valid Sync Reply.
297 *
298 * This method simply passes the valid reply to processSyncData.
299 *
300 * @param data The valid Sync Reply.
301 */
302 void
303 onSyncDataValidated(const shared_ptr<const Data>& data);
304
305 /**
306 * @brief Process normal Sync Interest
307 *
308 * This method extracts the digest from the incoming Sync Interest,
309 * compares it against current local digest, and process the Sync
310 * Interest according to the comparison result. See docs/design.rst
311 * for more details.
312 *
313 * @param interest The incoming interest
314 * @param isTimedProcessing True if the interest needs an immediate reply,
315 * otherwise hold the interest for a while before
316 * making a reply (to avoid unnecessary recovery)
317 */
318 void
319 processSyncInterest(const shared_ptr<const Interest>& interest,
320 bool isTimedProcessing = false);
321
322 /**
323 * @brief Process reset Sync Interest
324 *
325 * This method simply call Logic::reset()
326 *
327 * @param interest The incoming interest.
328 */
329 void
330 processResetInterest(const Interest& interest);
331
332 /**
333 * @brief Process Sync Reply.
334 *
335 * This method extracts state update information from Sync Reply and applies
336 * it to the Sync Tree and re-express Sync Interest.
337 *
338 * @param name The data name of the Sync Reply.
339 * @param digest The digest in the data name.
340 * @param syncReplyBlock The content of the Sync Reply.
341 */
342 void
343 processSyncData(const Name& name,
344 ndn::ConstBufferPtr digest,
345 const Block& syncReplyBlock);
346
347 /**
348 * @brief Insert state diff into log
349 *
350 * @param diff The diff .
351 * @param previousRoot The root digest before state changes.
352 */
353 void
354 insertToDiffLog(DiffStatePtr diff,
355 ndn::ConstBufferPtr previousRoot);
356
357 /**
358 * @brief Reply to all pending Sync Interests with a particular commit (or diff)
359 *
360 * @param commit The diff.
361 */
362 void
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800363 satisfyPendingSyncInterests(const Name& updatedPrefix, ConstDiffStatePtr commit);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700364
365 /// @brief Helper method to send normal Sync Interest
366 void
367 sendSyncInterest();
368
369 /// @brief Helper method to send reset Sync Interest
370 void
371 sendResetInterest();
372
373 /// @brief Helper method to send Sync Reply
374 void
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800375 sendSyncData(const Name& nodePrefix, const Name& name, const State& state);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700376
377 /**
378 * @brief Unset reset status
379 *
380 * By invoking this method, one can add its own state into the Sync Tree, thus
381 * jumping out of the reset status
382 */
383 void
384 cancelReset();
385
386 void
387 printDigest(ndn::ConstBufferPtr digest);
388
Yingdi Yucd339022014-11-05 17:51:19 -0800389public:
390 static const ndn::Name DEFAULT_NAME;
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800391 static const ndn::Name EMPTY_NAME;
Yingdi Yucd339022014-11-05 17:51:19 -0800392 static const ndn::shared_ptr<ndn::Validator> DEFAULT_VALIDATOR;
393
Yingdi Yuf7ede412014-08-30 20:37:52 -0700394private:
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800395 typedef std::unordered_map<ndn::Name, NodeInfo> NodeList;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700396
397 static const ndn::ConstBufferPtr EMPTY_DIGEST;
398 static const ndn::name::Component RESET_COMPONENT;
399
400 // Communication
401 ndn::Face& m_face;
402 Name m_syncPrefix;
403 const ndn::RegisteredPrefixId* m_syncRegisteredPrefixId;
404 Name m_syncReset;
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800405 Name m_defaultUserPrefix;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700406
407 // State
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800408 NodeList m_nodeList;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700409 State m_state;
410 DiffStateContainer m_log;
411 InterestTable m_interestTable;
412 Name m_outstandingInterestName;
413 const ndn::PendingInterestId* m_outstandingInterestId;
414 bool m_isInReset;
415 bool m_needPeriodReset;
416
417 // Callback
418 UpdateCallback m_onUpdate;
419
420 // Event
421 ndn::Scheduler m_scheduler;
422 ndn::EventId m_delayedInterestProcessingId;
423 ndn::EventId m_reexpressingInterestId;
424 ndn::EventId m_resetInterestId;
425
426 // Timer
427 boost::mt19937 m_randomGenerator;
428 boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_rangeUniformRandom;
429 boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_reexpressionJitter;
430 /// @brief Timer to send next reset 0 for no reset
431 time::steady_clock::Duration m_resetTimer;
432 /// @brief Timer to cancel reset state
433 time::steady_clock::Duration m_cancelResetTimer;
434 /// @brief Lifetime of reset interest
435 time::milliseconds m_resetInterestLifetime;
436 /// @brief Lifetime of sync interest
437 time::milliseconds m_syncInterestLifetime;
438 /// @brief FreshnessPeriod of SyncReply
439 time::milliseconds m_syncReplyFreshness;
440
Yingdi Yucd339022014-11-05 17:51:19 -0800441 // Security
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800442 ndn::Name m_defaultSigningId;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700443 ndn::KeyChain m_keyChain;
Yingdi Yucd339022014-11-05 17:51:19 -0800444 ndn::shared_ptr<ndn::Validator> m_validator;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700445
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800446
Yingdi Yuf7ede412014-08-30 20:37:52 -0700447#ifdef _DEBUG
448 int m_instanceId;
449 static int m_instanceCounter;
450#endif
451};
452
453
454} // namespace chronosync
455
456#endif // CHRONOSYNC_LOGIC_HPP