blob: d4a811f83a7a315d3fbcad11412936209304f9ac [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 *
Yingdi Yu9d5679a2015-02-01 00:17:58 -0800104 * @param face The face used to communication, will be shutdown in destructor
Yingdi Yuf7ede412014-08-30 20:37:52 -0700105 * @param syncPrefix The prefix of the sync group
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800106 * @param defaultUserPrefix The prefix of the first user added to this session
Yingdi Yuf7ede412014-08-30 20:37:52 -0700107 * @param onUpdate The callback function to handle state updates
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800108 * @param defaultSigningId The signing Id of the default user
Yingdi Yucd339022014-11-05 17:51:19 -0800109 * @param validator The validator for packet validation
Yingdi Yuf7ede412014-08-30 20:37:52 -0700110 * @param resetTimer The timer to periodically send Reset Interest
111 * @param syncReplyFreshness The FreshnessPeriod of sync reply
112 * @param resetInterestLifetime The lifetime of sync interest
113 * @param resetInterestLifetime The lifetime of Reset Interest
114 * @param cancelResetTimer The timer to exit from Reset state
115 */
116 Logic(ndn::Face& face,
117 const Name& syncPrefix,
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800118 const Name& defaultUserPrefix,
Yingdi Yuf7ede412014-08-30 20:37:52 -0700119 const UpdateCallback& onUpdate,
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800120 const Name& defaultSigningId = DEFAULT_NAME,
Yingdi Yucd339022014-11-05 17:51:19 -0800121 ndn::shared_ptr<ndn::Validator> validator = DEFAULT_VALIDATOR,
Yingdi Yuf7ede412014-08-30 20:37:52 -0700122 const time::steady_clock::Duration& resetTimer = DEFAULT_RESET_TIMER,
123 const time::steady_clock::Duration& cancelResetTimer = DEFAULT_CANCEL_RESET_TIMER,
124 const time::milliseconds& resetInterestLifetime = DEFAULT_RESET_INTEREST_LIFETIME,
125 const time::milliseconds& syncInterestLifetime = DEFAULT_SYNC_INTEREST_LIFETIME,
126 const time::milliseconds& syncReplyFreshness = DEFAULT_SYNC_REPLY_FRESHNESS);
127
128 ~Logic();
129
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800130 /**
131 * @brief Reset the sync tree (and restart synchronization again)
132 *
133 * @param isOnInterest a flag that tells whether the reset is called by reset interest.
134 */
Yingdi Yuf7ede412014-08-30 20:37:52 -0700135 void
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800136 reset(bool isOnInterest = false);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700137
138 /**
139 * @brief Set user prefix
140 *
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800141 * This method will also change the default user and signing Id of that user.
Yingdi Yuf7ede412014-08-30 20:37:52 -0700142 *
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800143 * @param defaultUserPrefix The prefix of user.
Yingdi Yuf7ede412014-08-30 20:37:52 -0700144 */
145 void
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800146 setDefaultUserPrefix(const Name& defaultUserPrefix);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700147
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800148 /// @brief Get the name of default user.
Yingdi Yuf7ede412014-08-30 20:37:52 -0700149 const Name&
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800150 getDefaultUserPrefix() const
Yingdi Yuf7ede412014-08-30 20:37:52 -0700151 {
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800152 return m_defaultUserPrefix;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700153 }
154
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800155 /**
156 * @brief Add user node into the local session.
157 *
158 * This method also reset after adding
159 *
160 * @param userPrefix prefix of the added node
161 * @param signingId signing Id of the added node
162 */
163 void
164 addUserNode(const Name& userPrefix, const Name& signingId = DEFAULT_NAME);
165
166 /// @brief remove the node from the local session
167 void
168 removeUserNode(const Name& userPrefix);
169
170 /**
171 * @brief Get the name of the local session.
172 *
173 * This method gets the session name according to prefix, if prefix is not specified,
174 * it returns the session name of default user.
175 *
176 * @param prefix prefix of the node
177 */
178 const Name&
179 getSessionName(Name prefix = EMPTY_NAME);
180
181 /**
182 * @brief Get current seqNo of the local session.
183 *
184 * This method gets the seqNo according to prefix, if prefix is not specified,
185 * it returns the seqNo of default user.
186 *
187 * @param prefix prefix of the node
188 */
Yingdi Yuf7ede412014-08-30 20:37:52 -0700189 const SeqNo&
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800190 getSeqNo(Name prefix = EMPTY_NAME);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700191
192 /**
193 * @brief Update the seqNo of the local session
194 *
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800195 * The method updates the existing seqNo with the supplied seqNo and prefix.
Yingdi Yuf7ede412014-08-30 20:37:52 -0700196 *
197 * @param seq The new seqNo.
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800198 * @param updatePrefix The prefix of node to update.
Yingdi Yuf7ede412014-08-30 20:37:52 -0700199 */
200 void
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800201 updateSeqNo(const SeqNo& seq, const Name& updatePrefix = EMPTY_NAME);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700202
203 /// @brief Get root digest of current sync tree
204 ndn::ConstBufferPtr
205 getRootDigest() const;
206
207 /// @brief Get the name of all sessions
208 std::set<Name>
209 getSessionNames() const;
210
Yingdi Yu906c2ea2014-10-31 11:24:50 -0700211CHRONOSYNC_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Yingdi Yuf7ede412014-08-30 20:37:52 -0700212 void
213 printState(std::ostream& os) const;
214
215 ndn::Scheduler&
216 getScheduler()
217 {
218 return m_scheduler;
219 }
220
221 State&
222 getState()
223 {
224 return m_state;
225 }
226
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800227
Yingdi Yuf7ede412014-08-30 20:37:52 -0700228private:
229 /**
230 * @brief Callback to handle Sync Interest
231 *
232 * This method checks whether an incoming interest is a normal one or a reset
233 * and dispatches the incoming interest to corresponding processing methods.
234 *
235 * @param prefix The prefix of the sync group.
236 * @param interest The incoming sync interest.
237 */
238 void
239 onSyncInterest(const Name& prefix, const Interest& interest);
240
241 /**
242 * @brief Callback to handle Sync prefix registration failure
243 *
244 * This method does nothing for now.
245 *
246 * @param prefix The prefix of the sync group.
247 * @param msg The error message.
248 */
249 void
250 onSyncRegisterFailed(const Name& prefix, const std::string& msg);
251
252 /**
253 * @brief Callback to handle Sync Reply
254 *
255 * This method calls validator to validate Sync Reply.
256 * For now, validation is disabled, Logic::onSyncDataValidated is called
257 * directly.
258 *
259 * @param interest The Sync Interest
260 * @param data The reply to the Sync Interest
261 */
262 void
263 onSyncData(const Interest& interest, Data& data);
264
265 /**
266 * @brief Callback to handle reply to Reset Interest.
267 *
268 * This method does nothing, since reply to Reset Interest is not useful for now.
269 *
270 * @param interest The Reset Interest
271 * @param data The reply to the Reset Interest
272 */
273 void
274 onResetData(const Interest& interest, Data& data);
275
276 /**
277 * @brief Callback to handle Sync Interest timeout.
278 *
279 * This method does nothing, since Logic per se handles timeout explicitly.
280 *
281 * @param interest The Sync Interest
282 */
283 void
284 onSyncTimeout(const Interest& interest);
285
286 /**
287 * @brief Callback to invalid Sync Reply.
288 *
289 * This method does nothing but drops the invalid reply.
290 *
291 * @param data The invalid Sync Reply
292 */
293 void
294 onSyncDataValidationFailed(const shared_ptr<const Data>& data);
295
296 /**
297 * @brief Callback to valid Sync Reply.
298 *
299 * This method simply passes the valid reply to processSyncData.
300 *
301 * @param data The valid Sync Reply.
302 */
303 void
304 onSyncDataValidated(const shared_ptr<const Data>& data);
305
306 /**
307 * @brief Process normal Sync Interest
308 *
309 * This method extracts the digest from the incoming Sync Interest,
310 * compares it against current local digest, and process the Sync
311 * Interest according to the comparison result. See docs/design.rst
312 * for more details.
313 *
314 * @param interest The incoming interest
315 * @param isTimedProcessing True if the interest needs an immediate reply,
316 * otherwise hold the interest for a while before
317 * making a reply (to avoid unnecessary recovery)
318 */
319 void
320 processSyncInterest(const shared_ptr<const Interest>& interest,
321 bool isTimedProcessing = false);
322
323 /**
324 * @brief Process reset Sync Interest
325 *
326 * This method simply call Logic::reset()
327 *
328 * @param interest The incoming interest.
329 */
330 void
331 processResetInterest(const Interest& interest);
332
333 /**
334 * @brief Process Sync Reply.
335 *
336 * This method extracts state update information from Sync Reply and applies
337 * it to the Sync Tree and re-express Sync Interest.
338 *
339 * @param name The data name of the Sync Reply.
340 * @param digest The digest in the data name.
341 * @param syncReplyBlock The content of the Sync Reply.
342 */
343 void
344 processSyncData(const Name& name,
345 ndn::ConstBufferPtr digest,
346 const Block& syncReplyBlock);
347
348 /**
349 * @brief Insert state diff into log
350 *
351 * @param diff The diff .
352 * @param previousRoot The root digest before state changes.
353 */
354 void
355 insertToDiffLog(DiffStatePtr diff,
356 ndn::ConstBufferPtr previousRoot);
357
358 /**
359 * @brief Reply to all pending Sync Interests with a particular commit (or diff)
360 *
361 * @param commit The diff.
362 */
363 void
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800364 satisfyPendingSyncInterests(const Name& updatedPrefix, ConstDiffStatePtr commit);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700365
366 /// @brief Helper method to send normal Sync Interest
367 void
368 sendSyncInterest();
369
370 /// @brief Helper method to send reset Sync Interest
371 void
372 sendResetInterest();
373
374 /// @brief Helper method to send Sync Reply
375 void
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800376 sendSyncData(const Name& nodePrefix, const Name& name, const State& state);
Yingdi Yuf7ede412014-08-30 20:37:52 -0700377
378 /**
379 * @brief Unset reset status
380 *
381 * By invoking this method, one can add its own state into the Sync Tree, thus
382 * jumping out of the reset status
383 */
384 void
385 cancelReset();
386
387 void
388 printDigest(ndn::ConstBufferPtr digest);
389
Yingdi Yucd339022014-11-05 17:51:19 -0800390public:
391 static const ndn::Name DEFAULT_NAME;
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800392 static const ndn::Name EMPTY_NAME;
Yingdi Yucd339022014-11-05 17:51:19 -0800393 static const ndn::shared_ptr<ndn::Validator> DEFAULT_VALIDATOR;
394
Yingdi Yuf7ede412014-08-30 20:37:52 -0700395private:
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800396 typedef std::unordered_map<ndn::Name, NodeInfo> NodeList;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700397
398 static const ndn::ConstBufferPtr EMPTY_DIGEST;
399 static const ndn::name::Component RESET_COMPONENT;
400
401 // Communication
402 ndn::Face& m_face;
403 Name m_syncPrefix;
404 const ndn::RegisteredPrefixId* m_syncRegisteredPrefixId;
405 Name m_syncReset;
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800406 Name m_defaultUserPrefix;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700407
408 // State
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800409 NodeList m_nodeList;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700410 State m_state;
411 DiffStateContainer m_log;
412 InterestTable m_interestTable;
413 Name m_outstandingInterestName;
414 const ndn::PendingInterestId* m_outstandingInterestId;
415 bool m_isInReset;
416 bool m_needPeriodReset;
417
418 // Callback
419 UpdateCallback m_onUpdate;
420
421 // Event
422 ndn::Scheduler m_scheduler;
423 ndn::EventId m_delayedInterestProcessingId;
424 ndn::EventId m_reexpressingInterestId;
425 ndn::EventId m_resetInterestId;
426
427 // Timer
428 boost::mt19937 m_randomGenerator;
429 boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_rangeUniformRandom;
430 boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_reexpressionJitter;
431 /// @brief Timer to send next reset 0 for no reset
432 time::steady_clock::Duration m_resetTimer;
433 /// @brief Timer to cancel reset state
434 time::steady_clock::Duration m_cancelResetTimer;
435 /// @brief Lifetime of reset interest
436 time::milliseconds m_resetInterestLifetime;
437 /// @brief Lifetime of sync interest
438 time::milliseconds m_syncInterestLifetime;
439 /// @brief FreshnessPeriod of SyncReply
440 time::milliseconds m_syncReplyFreshness;
441
Yingdi Yucd339022014-11-05 17:51:19 -0800442 // Security
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800443 ndn::Name m_defaultSigningId;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700444 ndn::KeyChain m_keyChain;
Yingdi Yucd339022014-11-05 17:51:19 -0800445 ndn::shared_ptr<ndn::Validator> m_validator;
Yingdi Yuf7ede412014-08-30 20:37:52 -0700446
Qiuhan Ding8c095fd2014-11-19 17:38:32 -0800447
Yingdi Yuf7ede412014-08-30 20:37:52 -0700448#ifdef _DEBUG
449 int m_instanceId;
450 static int m_instanceCounter;
451#endif
452};
453
454
455} // namespace chronosync
456
457#endif // CHRONOSYNC_LOGIC_HPP