PSync: initial commit
refs: #4641
Change-Id: Iabed3ad7632544d97559e6798547b7972b416784
diff --git a/src/producer-base.hpp b/src/producer-base.hpp
new file mode 100644
index 0000000..079b803
--- /dev/null
+++ b/src/producer-base.hpp
@@ -0,0 +1,188 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018, The University of Memphis
+ *
+ * This file is part of PSync.
+ * See AUTHORS.md for complete list of PSync authors and contributors.
+ *
+ * PSync is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * PSync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * PSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef PSYNC_PRODUCER_BASE_HPP
+#define PSYNC_PRODUCER_BASE_HPP
+
+#include "detail/iblt.hpp"
+#include "detail/bloom-filter.hpp"
+#include "detail/util.hpp"
+#include "detail/test-access-control.hpp"
+
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/util/scheduler.hpp>
+#include <ndn-cxx/util/time.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/security/validator-config.hpp>
+
+#include <map>
+#include <unordered_set>
+#include <random>
+
+namespace psync {
+
+using namespace ndn::literals::time_literals;
+
+const ndn::time::milliseconds SYNC_REPLY_FRESHNESS = 1_s;
+const ndn::time::milliseconds HELLO_REPLY_FRESHNESS = 1_s;
+
+/**
+ * @brief Base class for PartialProducer and FullProducer
+ *
+ * Contains code common to both
+ */
+class ProducerBase
+{
+ class Error : public std::runtime_error
+ {
+ public:
+ using std::runtime_error::runtime_error;
+ };
+
+PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+ /**
+ * @brief constructor
+ *
+ * @param expectedNumEntries expected number entries in IBF
+ * @param face application's face
+ * @param syncPrefix The prefix of the sync group
+ * @param userPrefix The prefix of the first user in the group
+ * @param syncReplyFreshness freshness of sync data
+ * @param helloReplyFreshness freshness of hello data
+ */
+ ProducerBase(size_t expectedNumEntries,
+ ndn::Face& face,
+ const ndn::Name& syncPrefix,
+ const ndn::Name& userPrefix,
+ ndn::time::milliseconds syncReplyFreshness = SYNC_REPLY_FRESHNESS,
+ ndn::time::milliseconds helloReplyFreshness = HELLO_REPLY_FRESHNESS);
+public:
+ /**
+ * @brief Returns the current sequence number of the given prefix
+ *
+ * @param prefix prefix to get the sequence number of
+ */
+ ndn::optional<uint64_t>
+ getSeqNo(const ndn::Name& prefix) const
+ {
+ auto it = m_prefixes.find(prefix);
+ if (it == m_prefixes.end()) {
+ return ndn::nullopt;
+ }
+ return it->second;
+ }
+
+ /**
+ * @brief Adds a user node for synchronization
+ *
+ * Initializes m_prefixes[prefix] to zero
+ * Does not add zero-th sequence number to IBF
+ * because if a large number of user nodes are added
+ * then decoding of the difference between own IBF and
+ * other IBF will not be possible
+ *
+ * @param prefix the user node to be added
+ */
+ bool
+ addUserNode(const ndn::Name& prefix);
+
+ /**
+ * @brief Remove the user node from synchronization
+ *
+ * Erases prefix from IBF and other maps
+ *
+ * @param prefix the user node to be removed
+ */
+ void
+ removeUserNode(const ndn::Name& prefix);
+
+PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+ /**
+ * @brief Update m_prefixes and IBF with the given prefix and seq
+ *
+ * Whoever calls this needs to make sure that prefix is in m_prefixes
+ * We remove already existing prefix/seq from IBF
+ * (unless seq is zero because we don't insert zero seq into IBF)
+ * Then we update m_prefix, m_prefix2hash, m_hash2prefix, and IBF
+ *
+ * @param prefix prefix of the update
+ * @param seq sequence number of the update
+ */
+ void
+ updateSeqNo(const ndn::Name& prefix, uint64_t seq);
+
+ bool
+ isUserNode(const ndn::Name& prefix) {
+ if (m_prefixes.find(prefix) == m_prefixes.end()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @brief Sends a data packet with content type nack
+ *
+ * Producer sends a nack to consumer if consumer has very old IBF
+ * whose differences with latest IBF can't be decoded successfully
+ *
+ * @param name send application nack with this name
+ */
+ void
+ sendApplicationNack(const ndn::Name& name);
+
+ /**
+ * @brief Logs a message if setting an interest filter fails
+ *
+ * @param prefix
+ * @param msg
+ */
+ void
+ onRegisterFailed(const ndn::Name& prefix, const std::string& msg) const;
+
+PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+ IBLT m_iblt;
+ uint32_t m_expectedNumEntries;
+ // Threshold is used check if the differences are greater
+ // than it and whether we need to update the other side.
+ uint32_t m_threshold;
+
+ // prefix and sequence number
+ std::map <ndn::Name, uint64_t> m_prefixes;
+ // Just for looking up hash faster (instead of calculating it again)
+ // Only used in updateSeqNo, prefix/seqNo is the key
+ std::map <ndn::Name, uint32_t> m_prefix2hash;
+ // Value is prefix (and not prefix/seqNo)
+ std::map <uint32_t, ndn::Name> m_hash2prefix;
+
+ ndn::Face& m_face;
+ ndn::KeyChain m_keyChain;
+ ndn::Scheduler m_scheduler;
+
+ ndn::Name m_syncPrefix;
+ ndn::Name m_userPrefix;
+
+ ndn::time::milliseconds m_syncReplyFreshness;
+ ndn::time::milliseconds m_helloReplyFreshness;
+
+ std::mt19937 m_rng;
+};
+
+} // namespace psync
+
+#endif // PSYNC_PRODUCER_BASE_HPP