diff --git a/src/diff-state-container.cpp b/src/diff-state-container.cpp new file mode 100644 index 0000000..38a67f3 --- /dev/null +++ b/src/diff-state-container.cpp @@ -0,0 +1,25 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2012-2014 University of California, Los Angeles + * + * This file is part of ChronoSync, synchronization library for distributed realtime + * applications for NDN. + * + * ChronoSync 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. + * + * ChronoSync 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 + * ChronoSync, e.g., in COPYING.md file. If not, see . + * + * @author Zhenkai Zhu + * @author Chaoyi Bian + * @author Alexander Afanasyev + * @author Yingdi Yu + */ + +#include "diff-state-container.hpp" diff --git a/src/sync-diff-state-container.h b/src/diff-state-container.hpp similarity index 71% rename from src/sync-diff-state-container.h rename to src/diff-state-container.hpp index 428877e..d20fbee 100644 --- a/src/sync-diff-state-container.h +++ b/src/diff-state-container.hpp @@ -19,35 +19,47 @@ * @author Zhenkai Zhu * @author Chaoyi Bian * @author Alexander Afanasyev + * @author Yingdi Yu */ -#ifndef SYNC_DIFF_STATE_CONTAINER_H -#define SYNC_DIFF_STATE_CONTAINER_H +#ifndef CHRONOSYNC_DIFF_STATE_CONTAINER_HPP +#define CHRONOSYNC_DIFF_STATE_CONTAINER_HPP -#include "sync-diff-state.h" -#include "sync-digest.h" +#include "mi-tag.hpp" +#include "diff-state.hpp" #include #include -// #include -// #include #include #include -// #include #include #include +namespace chronosync { + namespace mi = boost::multi_index; -namespace Sync { +struct DigestPtrHash +{ + std::size_t + operator()(ndn::ConstBufferPtr digest) const + { + BOOST_ASSERT(digest->size() > sizeof(std::size_t)); -/// @cond include_hidden -struct sequenced { }; -struct timed { }; -/// @endcond + return *reinterpret_cast(digest->buf()); + } +}; + +struct DigestPtrEqual +{ + bool + operator()(ndn::ConstBufferPtr digest1, ndn::ConstBufferPtr digest2) const + { + return *digest1 == *digest2; + } +}; /** - * \ingroup sync * @brief Container for differential states */ struct DiffStateContainer : public mi::multi_index_container< @@ -56,11 +68,11 @@ struct DiffStateContainer : public mi::multi_index_container< // For fast access to elements using DiffState hashes mi::hashed_unique< mi::tag, - mi::const_mem_fun, + mi::const_mem_fun, DigestPtrHash, DigestPtrEqual - > - , + >, + // sequenced index to access older/newer element (like in list) mi::sequenced > > @@ -68,6 +80,6 @@ struct DiffStateContainer : public mi::multi_index_container< { }; -} // Sync +} // namespace chronosync -#endif // SYNC_DIFF_STATE_CONTAINER_H +#endif // CHRONOSYNC_DIFF_STATE_CONTAINER_HPP diff --git a/src/diff-state.cpp b/src/diff-state.cpp new file mode 100644 index 0000000..f5813bf --- /dev/null +++ b/src/diff-state.cpp @@ -0,0 +1,43 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2012-2014 University of California, Los Angeles + * + * This file is part of ChronoSync, synchronization library for distributed realtime + * applications for NDN. + * + * ChronoSync 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. + * + * ChronoSync 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 + * ChronoSync, e.g., in COPYING.md file. If not, see . + * + * @author Zhenkai Zhu + * @author Chaoyi Bian + * @author Alexander Afanasyev + * @author Yingdi Yu + */ + +#include "diff-state.hpp" + +namespace chronosync { + +ConstStatePtr +DiffState::diff() const +{ + StatePtr result = make_shared(); + + ConstDiffStatePtr state = m_next; + while (static_cast(state)) { + *result += *state; + state = state->m_next; + } + + return result; +} + +} // namespace chronosync diff --git a/src/diff-state.hpp b/src/diff-state.hpp new file mode 100644 index 0000000..46ed412 --- /dev/null +++ b/src/diff-state.hpp @@ -0,0 +1,104 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2012-2014 University of California, Los Angeles + * + * This file is part of ChronoSync, synchronization library for distributed realtime + * applications for NDN. + * + * ChronoSync 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. + * + * ChronoSync 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 + * ChronoSync, e.g., in COPYING.md file. If not, see . + * + * @author Zhenkai Zhu + * @author Chaoyi Bian + * @author Alexander Afanasyev + * @author Yingdi Yu + */ + +#ifndef CHRONOSYNC_DIFF_STATE_HPP +#define CHRONOSYNC_DIFF_STATE_HPP + +#include "state.hpp" + +namespace chronosync { + +class DiffState; +typedef shared_ptr DiffStatePtr; +typedef shared_ptr ConstDiffStatePtr; + +/** + * @brief Contains the diff info between two states. + * + * DiffState is used to construct DiffLog. It serves as + * a log entry. Each log entry contains the updates between + * two states, and is indexed by the digest of the second state + * which is the result when the updates have been applied. + * + * DiffLog is a chain of DiffStates. Each DiffState connects to + * the next DiffState (a newer diff) through member m_next. The + * m_next of the last DiffState in a log should be empty. And the + * root digest of the last DiffState in the log should be the most + * current state. + */ +class DiffState : public State +{ +public: + /** + * @brief Set successor for the diff state + * + * @param next successor state + */ + void + setNext(ConstDiffStatePtr next) + { + m_next = next; + } + + /** + * @brief Set digest for the diff state (obtained from a corresponding full state) + * + * @param digest root digest of the full state + */ + void + setRootDigest(ndn::ConstBufferPtr digest) + { + m_digest = digest; + } + + /** + * @brief Get root digest of the full state after applying the diff state + */ + ndn::ConstBufferPtr + getRootDigest() const + { + return m_digest; + } + + /** + * @brief Accumulate differences from this state to the most current state + * + * This method assumes that the DiffState is in a log. It will iterate the all + * the DiffState between its m_next DiffState and the last DiffState in the log, + * and aggregate all the differences into one diff, which is represented as a + * State object. + * + * @returns Accumulated differences from this state to the most current state + */ + ConstStatePtr + diff() const; + +private: + ConstDiffStatePtr m_next; + ndn::ConstBufferPtr m_digest; +}; + +} // chronosync + +#endif // CHRONOSYNC_DIFF_STATE_HPP diff --git a/src/sync-diff-state.cc b/src/sync-diff-state.cc deleted file mode 100644 index 5ddaace..0000000 --- a/src/sync-diff-state.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */ -/* - * Copyright (c) 2012-2014 University of California, Los Angeles - * - * This file is part of ChronoSync, synchronization library for distributed realtime - * applications for NDN. - * - * ChronoSync 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. - * - * ChronoSync 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 - * ChronoSync, e.g., in COPYING.md file. If not, see . - * - * @author Zhenkai Zhu - * @author Chaoyi Bian - * @author Alexander Afanasyev - */ - -#include "sync-diff-state.h" -#include "sync-diff-leaf.h" - -#include -#include -#include - -using namespace boost; - -namespace Sync { - -DiffState::DiffState () -{ -} - -DiffState::~DiffState () -{ -} - -DiffStatePtr -DiffState::diff () const -{ - DiffStatePtr ret = make_shared (); - - DiffStatePtr state = m_next; - while (state != 0) - { - *ret += *state; - state = state->m_next; - } - - return ret; -} - -DiffState & -DiffState::operator += (const DiffState &state) -{ - BOOST_FOREACH (LeafConstPtr _leaf, state.getLeaves ()) - { - DiffLeafConstPtr leaf = dynamic_pointer_cast (_leaf); - BOOST_ASSERT (leaf != 0); - - if (leaf->getOperation () == UPDATE) - update (leaf->getInfo (), leaf->getSeq ()); - else if (leaf->getOperation () == REMOVE) - remove (leaf->getInfo ()); - else - { - BOOST_ASSERT (false); - } - } - - return *this; -} - -// from State -boost::tuple -DiffState::update (NameInfoConstPtr info, const SeqNo &seq) -{ - m_leaves.erase (info); - - DiffLeafPtr leaf = make_shared (info, cref (seq)); - m_leaves.insert (leaf); - - return make_tuple (true, false, SeqNo ()); -} - -bool -DiffState::remove (NameInfoConstPtr info) -{ - m_leaves.erase (info); - - DiffLeafPtr leaf = make_shared (info); - m_leaves.insert (leaf); - - return true; -} - -} // ns3 diff --git a/src/sync-diff-state.h b/src/sync-diff-state.h deleted file mode 100644 index da0d649..0000000 --- a/src/sync-diff-state.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */ -/* - * Copyright (c) 2012-2014 University of California, Los Angeles - * - * This file is part of ChronoSync, synchronization library for distributed realtime - * applications for NDN. - * - * ChronoSync 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. - * - * ChronoSync 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 - * ChronoSync, e.g., in COPYING.md file. If not, see . - * - * @author Zhenkai Zhu - * @author Chaoyi Bian - * @author Alexander Afanasyev - */ - -#ifndef SYNC_DIFF_STATE_H -#define SYNC_DIFF_STATE_H - -#include "sync-state.h" -#include - -namespace Sync { - -class DiffState; -typedef boost::shared_ptr DiffStatePtr; -typedef boost::shared_ptr DiffStateConstPtr; - -/** - * @ingroup ccnx - * @brief Differential SYNC state - */ -class DiffState : public State -{ -public: - /** - * @see Default constructor - */ - DiffState (); - virtual ~DiffState (); - - /** - * @brief Set successor for the diff state - * @param next successor state - */ - void - setNext (DiffStatePtr next) - { - m_next = next; - } - - /** - * @brief Set digest for the diff state (obtained from a corresponding full state) - * @param digest A read only smart pointer to a digest object (that should be unmodified anywhere else) - */ - void - setDigest (DigestConstPtr digest) { m_digest = digest; } - - /** - * @brief Get digest for the diff state - */ - DigestConstPtr - getDigest () const { return m_digest; } - - /** - * @brief Accumulate differences from `this' state to the most current state - * @returns Accumulated differences from `this' state to the most current state - */ - DiffStatePtr - diff () const; - - /** - * @brief Combine differences from `this' and `state' - * @param state Differential state to combine with - * @return Combined differences - * - * In case of collisions, `this' leaf will be replaced with the leaf of `state' - */ - DiffState& - operator += (const DiffState &state); - - // from State - virtual boost::tuple - update (NameInfoConstPtr info, const SeqNo &seq); - - virtual bool - remove (NameInfoConstPtr info); - -private: - DiffStatePtr m_next; - DigestConstPtr m_digest; -}; - -} // Sync - -#endif // SYNC_DIFF_STATE_H diff --git a/tests/unit-tests/test-diff-state.cpp b/tests/unit-tests/test-diff-state.cpp new file mode 100644 index 0000000..a4b740f --- /dev/null +++ b/tests/unit-tests/test-diff-state.cpp @@ -0,0 +1,140 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2012-2014 University of California, Los Angeles + * + * This file is part of ChronoSync, synchronization library for distributed realtime + * applications for NDN. + * + * ChronoSync 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. + * + * ChronoSync 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 + * ChronoSync, e.g., in COPYING.md file. If not, see . + */ + +#include "diff-state.hpp" +#include "diff-state-container.hpp" +#include "boost-test.hpp" + +namespace chronosync { +namespace test { + +BOOST_AUTO_TEST_SUITE(DiffStateTests) + +BOOST_AUTO_TEST_CASE(Diff) +{ + State state; + + Name info1("/test/name"); + info1.appendNumber(0); + + Name info2("/test/name"); + info2.appendNumber(1); + + Name info3("/test/name"); + info3.appendNumber(2); + + DiffStatePtr root = make_shared(); + DiffStatePtr action1 = make_shared(); + root->setNext(action1); + + state.update(info1, 1); + action1->update(info1, 1); + action1->setRootDigest(state.getRootDigest()); + + DiffStatePtr action2 = make_shared(); + action1->setNext(action2); + + state.update(info2, 1); + state.update(info3, 2); + action2->update(info2, 1); + action2->update(info3, 2); + action2->setRootDigest(state.getRootDigest()); + + LeafContainer::index::type::iterator it; + ConstStatePtr diff0 = root->diff(); + BOOST_CHECK_EQUAL(diff0->getLeaves().size(), 3); + it = diff0->getLeaves().get().begin(); + BOOST_CHECK_EQUAL((*it)->getSessionName(), info1); + BOOST_CHECK_EQUAL((*it)->getSeq(), 1); + it++; + BOOST_CHECK_EQUAL((*it)->getSessionName(), info2); + BOOST_CHECK_EQUAL((*it)->getSeq(), 1); + it++; + BOOST_CHECK_EQUAL((*it)->getSessionName(), info3); + BOOST_CHECK_EQUAL((*it)->getSeq(), 2); + + ConstStatePtr diff1 = action1->diff(); + BOOST_CHECK_EQUAL(diff1->getLeaves().size(), 2); + it = diff1->getLeaves().get().begin(); + BOOST_CHECK_EQUAL((*it)->getSessionName(), info2); + BOOST_CHECK_EQUAL((*it)->getSeq(), 1); + it++; + BOOST_CHECK_EQUAL((*it)->getSessionName(), info3); + BOOST_CHECK_EQUAL((*it)->getSeq(), 2); +} + +BOOST_AUTO_TEST_CASE(Container) +{ + DiffStateContainer container; + + State state; + + Name info1("/test/name"); + info1.appendNumber(0); + + Name info2("/test/name"); + info2.appendNumber(1); + + Name info3("/test/name"); + info3.appendNumber(2); + + DiffStatePtr root = make_shared(); + DiffStatePtr action1 = make_shared(); + root->setNext(action1); + + state.update(info1, 1); + action1->update(info1, 1); + ndn::ConstBufferPtr digest1 = state.getRootDigest(); + action1->setRootDigest(digest1); + + DiffStatePtr action2 = make_shared(); + action1->setNext(action2); + + state.update(info2, 1); + state.update(info3, 2); + action2->update(info2, 1); + action2->update(info3, 2); + ndn::ConstBufferPtr digest2 = state.getRootDigest(); + action2->setRootDigest(digest2); + + DiffStatePtr action3 = make_shared(); + state.update(info1, 3); + state.update(info3, 4); + action3->update(info1, 3); + action3->update(info3, 4); + ndn::ConstBufferPtr digest3 = state.getRootDigest(); + action3->setRootDigest(digest3); + + container.insert(action3); + container.insert(action2); + container.insert(action1); + BOOST_CHECK_EQUAL(container.size(), 3); + + DiffStateContainer::index::type::iterator it = container.get().begin(); + BOOST_CHECK(*(*it)->getRootDigest() == *digest3); + it++; + BOOST_CHECK(*(*it)->getRootDigest() == *digest2); + it++; + BOOST_CHECK(*(*it)->getRootDigest() == *digest1); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace test +} // namespace chronosync