blob: b89509b637898f46d5e380d53b816c00b6ecbb7c [file] [log] [blame]
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2012-2017 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 <http://www.gnu.org/licenses/>.
*
* @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
* @author Chaoyi Bian <bcy@pku.edu.cn>
* @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "state.hpp"
namespace chronosync {
State::~State()
{
}
/**
* @brief Add or update leaf to the sync tree
*
* @param info session name of the leaf
* @param seq sequence number of the leaf
* @return 3-tuple (isInserted, isUpdated, oldSeqNo)
*/
std::tuple<bool, bool, SeqNo>
State::update(const Name& info, const SeqNo& seq)
{
m_wire.reset();
LeafContainer::iterator leaf = m_leaves.find(info);
if (leaf == m_leaves.end()) {
m_leaves.insert(make_shared<Leaf>(info, cref(seq)));
return make_tuple(true, false, 0);
}
else {
if ((*leaf)->getSeq() == seq || seq < (*leaf)->getSeq()) {
return make_tuple(false, false, 0);
}
SeqNo old = (*leaf)->getSeq();
m_leaves.modify(leaf,
[=] (LeafPtr& leaf) { leaf->setSeq(seq); } );
return make_tuple(false, true, old);
}
}
ConstBufferPtr
State::getRootDigest() const
{
m_digest.reset();
BOOST_FOREACH (ConstLeafPtr leaf, m_leaves.get<ordered>())
{
BOOST_ASSERT(leaf != 0);
m_digest.update(leaf->getDigest()->buf(), leaf->getDigest()->size());
}
return m_digest.computeDigest();
}
void
State::reset()
{
m_leaves.clear();
}
State&
State::operator+=(const State& state)
{
BOOST_FOREACH (ConstLeafPtr leaf, state.getLeaves())
{
BOOST_ASSERT(leaf != 0);
update(leaf->getSessionName(), leaf->getSeq());
}
return *this;
}
template<encoding::Tag T>
size_t
State::wireEncode(encoding::EncodingImpl<T>& block) const
{
size_t totalLength = 0;
BOOST_REVERSE_FOREACH (ConstLeafPtr leaf, m_leaves.get<ordered>())
{
size_t entryLength = 0;
entryLength += prependNonNegativeIntegerBlock(block, tlv::SeqNo, leaf->getSeq());
entryLength += leaf->getSessionName().wireEncode(block);
entryLength += block.prependVarNumber(entryLength);
entryLength += block.prependVarNumber(tlv::StateLeaf);
totalLength += entryLength;
}
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::SyncReply);
return totalLength;
}
NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(State);
const Block&
State::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
ndn::EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
ndn::EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
State::wireDecode(const Block& wire)
{
if (!wire.hasWire())
BOOST_THROW_EXCEPTION(Error("The supplied block does not contain wire format"));
if (wire.type() != tlv::SyncReply)
BOOST_THROW_EXCEPTION(Error("Unexpected TLV type when decoding SyncReply: " +
boost::lexical_cast<std::string>(m_wire.type())));
wire.parse();
m_wire = wire;
for (Block::element_const_iterator it = wire.elements_begin();
it != wire.elements_end(); it++) {
if (it->type() == tlv::StateLeaf) {
it->parse();
Block::element_const_iterator val = it->elements_begin();
Name info(*val);
val++;
if (val != it->elements_end())
update(info, readNonNegativeInteger(*val));
else
BOOST_THROW_EXCEPTION(Error("No seqNo when decoding SyncReply"));
}
}
}
} // namespace chronosync