Skip to content

Commit

Permalink
iblt: rewrite encode, decode, and operator==
Browse files Browse the repository at this point in the history
refs #4825

Change-Id: I207dc56cc39a6c66bd3165745d2e00c3779eedbd
  • Loading branch information
yoursunny committed Jan 9, 2024
1 parent 69bcaef commit c052d89
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 98 deletions.
99 changes: 26 additions & 73 deletions PSync/detail/iblt.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, The University of Memphis
* Copyright (c) 2014-2024, The University of Memphis
*
* This file is part of PSync.
* See AUTHORS.md for complete list of PSync authors and contributors.
Expand Down Expand Up @@ -52,6 +52,9 @@ namespace psync::detail {

namespace be = boost::endian;

constexpr size_t ENTRY_SIZE = sizeof(HashTableEntry::count) + sizeof(HashTableEntry::keySum) +
sizeof(HashTableEntry::keyCheck);

bool
HashTableEntry::isPure() const
{
Expand Down Expand Up @@ -86,19 +89,21 @@ IBLT::IBLT(size_t expectedNumEntries, CompressionScheme scheme)
void
IBLT::initialize(const ndn::name::Component& ibltName)
{
const auto& values = extractValueFromName(ibltName);

if (3 * m_hashTable.size() != values.size()) {
auto decompressed = decompress(m_compressionScheme, ibltName.value_bytes());
if (decompressed->size() != ENTRY_SIZE * m_hashTable.size()) {
NDN_THROW(Error("Received IBF cannot be decoded!"));
}

for (size_t i = 0; i < m_hashTable.size(); i++) {
HashTableEntry& entry = m_hashTable.at(i);
if (values[i * 3] != 0) {
entry.count = values[i * 3];
entry.keySum = values[(i * 3) + 1];
entry.keyCheck = values[(i * 3) + 2];
}
const uint8_t* input = decompressed->data();
for (auto& entry : m_hashTable) {
entry.count = be::endian_load<int32_t, sizeof(int32_t), be::order::big>(input);
input += sizeof(entry.count);

entry.keySum = be::endian_load<uint32_t, sizeof(uint32_t), be::order::big>(input);
input += sizeof(entry.keySum);

entry.keyCheck = be::endian_load<uint32_t, sizeof(uint32_t), be::order::big>(input);
input += sizeof(entry.keyCheck);
}
}

Expand Down Expand Up @@ -182,75 +187,23 @@ IBLT::operator-(const IBLT& other) const
void
IBLT::appendToName(ndn::Name& name) const
{
constexpr size_t unitSize = sizeof(m_hashTable[0].count) +
sizeof(m_hashTable[0].keySum) +
sizeof(m_hashTable[0].keyCheck);
std::vector<uint8_t> buffer(ENTRY_SIZE * m_hashTable.size());
uint8_t* output = buffer.data();
for (const auto& entry : m_hashTable) {
be::endian_store<int32_t, sizeof(int32_t), be::order::big>(output, entry.count);
output += sizeof(entry.count);

size_t tableSize = unitSize * m_hashTable.size();
std::vector<uint8_t> table(tableSize);

for (size_t i = 0; i < m_hashTable.size(); i++) {
uint32_t count = be::native_to_big(static_cast<uint32_t>(m_hashTable[i].count));
uint32_t keySum = be::native_to_big(static_cast<uint32_t>(m_hashTable[i].keySum));
uint32_t keyCheck = be::native_to_big(static_cast<uint32_t>(m_hashTable[i].keyCheck));
be::endian_store<uint32_t, sizeof(uint32_t), be::order::big>(output, entry.keySum);
output += sizeof(entry.keySum);

std::memcpy(&table[i * unitSize], &count, sizeof(count));
std::memcpy(&table[(i * unitSize) + 4], &keySum, sizeof(keySum));
std::memcpy(&table[(i * unitSize) + 8], &keyCheck, sizeof(keyCheck));
be::endian_store<uint32_t, sizeof(uint32_t), be::order::big>(output, entry.keyCheck);
output += sizeof(entry.keyCheck);
}

auto compressed = compress(m_compressionScheme, table);
auto compressed = compress(m_compressionScheme, buffer);
name.append(ndn::name::Component(std::move(compressed)));
}

std::vector<uint32_t>
IBLT::extractValueFromName(const ndn::name::Component& ibltName) const
{
auto decompressedBuf = decompress(m_compressionScheme, ibltName.value_bytes());

if (decompressedBuf->size() % 4 != 0) {
NDN_THROW(Error("Received IBF cannot be decompressed correctly!"));
}

size_t n = decompressedBuf->size() / 4;
std::vector<uint32_t> values(n, 0);

for (size_t i = 0; i < n; i++) {
uint32_t t;
std::memcpy(&t, &(*decompressedBuf)[i * 4], sizeof(t));
values[i] = be::big_to_native(t);
}

return values;
}

bool
operator==(const IBLT& iblt1, const IBLT& iblt2)
{
auto iblt1HashTable = iblt1.getHashTable();
auto iblt2HashTable = iblt2.getHashTable();
if (iblt1HashTable.size() != iblt2HashTable.size()) {
return false;
}

size_t N = iblt1HashTable.size();

for (size_t i = 0; i < N; i++) {
if (iblt1HashTable[i].count != iblt2HashTable[i].count ||
iblt1HashTable[i].keySum != iblt2HashTable[i].keySum ||
iblt1HashTable[i].keyCheck != iblt2HashTable[i].keyCheck)
return false;
}

return true;
}

bool
operator!=(const IBLT& iblt1, const IBLT& iblt2)
{
return !(iblt1 == iblt2);
}

std::ostream&
operator<<(std::ostream& os, const IBLT& iblt)
{
Expand Down
57 changes: 32 additions & 25 deletions PSync/detail/iblt.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, The University of Memphis
* Copyright (c) 2014-2024, The University of Memphis
*
* This file is part of PSync.
* See AUTHORS.md for complete list of PSync authors and contributors.
Expand Down Expand Up @@ -50,23 +50,37 @@

#include <ndn-cxx/name.hpp>

#include <boost/operators.hpp>

#include <set>
#include <string>

namespace psync::detail {

class HashTableEntry
class HashTableEntry : private boost::equality_comparable<HashTableEntry>
{
public:
int32_t count;
uint32_t keySum;
uint32_t keyCheck;

bool
isPure() const;

bool
isEmpty() const;

private: // non-member operators
// NOTE: the following "hidden friend" operators are available via
// argument-dependent lookup only and must be defined inline.
// boost::equality_comparable provides != operator.

friend bool
operator==(const HashTableEntry& lhs, const HashTableEntry& rhs) noexcept
{
return lhs.count == rhs.count && lhs.keySum == rhs.keySum && lhs.keyCheck == rhs.keyCheck;
}

public:
int32_t count = 0;
uint32_t keySum = 0;
uint32_t keyCheck = 0;
};

inline constexpr size_t N_HASH = 3;
Expand All @@ -77,7 +91,7 @@ inline constexpr size_t N_HASHCHECK = 11;
*
* Used by Partial Sync (PartialProducer) and Full Sync (Full Producer)
*/
class IBLT
class IBLT : private boost::equality_comparable<IBLT>
{
public:
class Error : public std::runtime_error
Expand Down Expand Up @@ -143,35 +157,28 @@ class IBLT
void
appendToName(ndn::Name& name) const;

/**
* @brief Extracts IBLT from name component
*
* Converts the name into a uint8_t vector which is then decoded to a
* a uint32_t vector.
*
* @param ibltName IBLT represented as a Name Component
* @return a uint32_t vector representing the hash table of the IBLT
*/
std::vector<uint32_t>
extractValueFromName(const ndn::name::Component& ibltName) const;

private:
void
update(int plusOrMinus, uint32_t key);

private: // non-member operators
// NOTE: the following "hidden friend" operators are available via
// argument-dependent lookup only and must be defined inline.
// boost::equality_comparable provides != operator.

friend bool
operator==(const IBLT& lhs, const IBLT& rhs)
{
return lhs.m_hashTable == rhs.m_hashTable;
}

private:
std::vector<HashTableEntry> m_hashTable;
static constexpr int INSERT = 1;
static constexpr int ERASE = -1;
CompressionScheme m_compressionScheme;
};

bool
operator==(const IBLT& iblt1, const IBLT& iblt2);

bool
operator!=(const IBLT& iblt1, const IBLT& iblt2);

std::ostream&
operator<<(std::ostream& os, const IBLT& iblt);

Expand Down

0 comments on commit c052d89

Please sign in to comment.