Browse Source

Bloom Filter initial version reviewed

cl-refactor
Vlad Gluhovsky 10 years ago
parent
commit
255f81e2cc
  1. 49
      libwhisper/BloomFilter.cpp
  2. 48
      libwhisper/BloomFilter.h
  3. 2
      libwhisper/WhisperHost.h
  4. 249
      test/libwhisper/bloomFilter.cpp

49
libwhisper/BloomFilter.cpp

@ -25,48 +25,45 @@ using namespace std;
using namespace dev;
using namespace dev::shh;
bool BloomFilter::matches(AbridgedTopic const& _t) const
{
static unsigned const c_match = ~unsigned(0);
unsigned topic = AbridgedTopic::Arith(_t).convert_to<unsigned>();
unsigned matchingBits = m_filter & topic;
matchingBits |= ~topic;
return (c_match == matchingBits);
}
static unsigned const c_mask[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
void SharedBloomFilter::add(AbridgedTopic const& _t)
void TopicBloomFilter::add(AbridgedTopic const& _h)
{
unsigned const topic = AbridgedTopic::Arith(_t).convert_to<unsigned>();
m_filter |= topic;
unsigned nextBit = 1;
for (unsigned i = 0; i < ArrSize; ++i, nextBit <<= 1)
if (topic & nextBit)
if (m_refCounter[i] != numeric_limits<unsigned short>::max())
*this |= _h;
unsigned count = 0;
for (unsigned i = 0; i < CounterSize; ++i)
if (isBitSet(_h, i))
{
if (m_refCounter[i] != numeric_limits<uint16_t>::max())
m_refCounter[i]++;
//else: overflow
// in order to encounter overflow, you have to set at least 65536 filters simultaneously.
// even then, the problem will only arise after at least 65536 filters will be be removed.
// we assume, it will never happen.
// in order to encounter overflow, you have to set at least 65536 filters simultaneously.
// even then, the problem will only arise after at least 65536 filters will be be removed.
// we assume, it will never happen.
}
}
void SharedBloomFilter::remove(AbridgedTopic const& _t)
void TopicBloomFilter::remove(AbridgedTopic const& _h)
{
unsigned const topic = AbridgedTopic::Arith(_t).convert_to<unsigned>();
unsigned nextBit = 1;
for (unsigned i = 0; i < ArrSize; ++i, nextBit <<= 1)
if (topic & nextBit)
unsigned count = 0;
for (unsigned i = 0; i < CounterSize; ++i)
if (isBitSet(_h, i))
{
if (m_refCounter[i])
m_refCounter[i]--;
if (!m_refCounter[i])
m_filter &= ~nextBit;
(*this)[i/8] &= ~c_mask[i%8];
}
}
bool TopicBloomFilter::isBitSet(AbridgedTopic const& _h, unsigned _index)
{
unsigned iByte = _index / 8;
unsigned iBit = _index % 8;
return (_h[iByte] & c_mask[iBit]) != 0;
}

48
libwhisper/BloomFilter.h

@ -28,44 +28,26 @@ namespace dev
namespace shh
{
class BloomFilter
class TopicBloomFilter: public AbridgedTopic
{
public:
virtual ~BloomFilter() {}
BloomFilter(): m_filter(0) {}
BloomFilter(unsigned _i): m_filter(_i) {}
BloomFilter(AbridgedTopic const& _t): m_filter(AbridgedTopic::Arith(_t).convert_to<unsigned>()) {}
unsigned getUnsigned() const { return m_filter; }
AbridgedTopic getAbridgedTopic() const { return AbridgedTopic(m_filter); }
bool matches(AbridgedTopic const& _t) const;
virtual void add(Topic const& _t) { add(abridge(_t)); }
virtual void add(Topics const& _topics) { for (Topic t : _topics) add(abridge(t)); }
virtual void add(AbridgedTopic const& _t) { m_filter |= AbridgedTopic::Arith(_t).convert_to<unsigned>(); }
virtual void remove(AbridgedTopic const&) {} // not implemented in this class, use derived class instead.
protected:
unsigned m_filter;
};
class SharedBloomFilter: public BloomFilter
{
public:
virtual ~SharedBloomFilter() {}
SharedBloomFilter() { init(); }
SharedBloomFilter(unsigned _i): BloomFilter(_i) { init(); }
SharedBloomFilter(AbridgedTopic const& _t): BloomFilter(_t) { init(); }
void add(AbridgedTopic const& _t) override;
void remove(AbridgedTopic const& _t) override;
TopicBloomFilter() { init(); }
TopicBloomFilter(AbridgedTopic const& _h): AbridgedTopic(_h) { init(); }
protected:
void init() { for (unsigned i = 0; i < ArrSize; ++i) m_refCounter[i] = 0; }
void addBloom(AbridgedTopic const& _h) { add(_h.template bloom<BitsPerBloom, 4>()); }
void removeBloom(AbridgedTopic const& _h) { remove(_h.template bloom<BitsPerBloom, 4>()); }
void add(AbridgedTopic const& _h);
void remove(AbridgedTopic const& _h);
bool containsBloom(AbridgedTopic const& _h) const { return contains(_h.template bloom<BitsPerBloom, 4>()); }
enum { BitsPerBloom = 3 };
private:
enum { ArrSize = 8 * AbridgedTopic::size };
unsigned short m_refCounter[ArrSize];
void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; }
static bool isBitSet(AbridgedTopic const& _h, unsigned _index);
enum { CounterSize = 8 * AbridgedTopic::size };
std::array<uint16_t, CounterSize> m_refCounter;
};
}

2
libwhisper/WhisperHost.h

@ -87,7 +87,7 @@ private:
mutable dev::Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches;
SharedBloomFilter m_bloom;
TopicBloomFilter m_bloom;
};
}

249
test/libwhisper/bloomFilter.cpp

@ -20,122 +20,163 @@ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
#include <boost/test/unit_test.hpp>
#include <libdevcore/SHA3.h>
#include <libwhisper/BloomFilter.h>
using namespace std;
using namespace dev;
using namespace dev::shh;
void testAddNonExisting(TopicBloomFilter& _f, AbridgedTopic const& _h)
{
BOOST_REQUIRE(!_f.contains(_h));
_f.add(_h);
BOOST_REQUIRE(_f.contains(_h));
}
void testRemoveExisting(TopicBloomFilter& _f, AbridgedTopic const& _h)
{
BOOST_REQUIRE(_f.contains(_h));
_f.remove(_h);
BOOST_REQUIRE(!_f.contains(_h));
}
void testAddNonExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h)
{
BOOST_REQUIRE(!_f.containsBloom(_h));
_f.addBloom(_h);
BOOST_REQUIRE(_f.containsBloom(_h));
}
void testRemoveExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h)
{
BOOST_REQUIRE(_f.containsBloom(_h));
_f.removeBloom(_h);
BOOST_REQUIRE(!_f.containsBloom(_h));
}
BOOST_AUTO_TEST_SUITE(bloomFilter)
BOOST_AUTO_TEST_CASE(match)
BOOST_AUTO_TEST_CASE(bloomFilterRandom)
{
VerbosityHolder setTemporaryLevel(10);
cnote << "Testing Bloom Filter matching...";
SharedBloomFilter f;
unsigned b00000001 = 0x01;
unsigned b00010000 = 0x10;
unsigned b00011000 = 0x18;
unsigned b00110000 = 0x30;
unsigned b00110010 = 0x32;
unsigned b00111000 = 0x38;
unsigned b00000110 = 0x06;
unsigned b00110110 = 0x36;
unsigned b00110111 = 0x37;
AbridgedTopic x(b00111000);
SharedBloomFilter f1(b00111000);
SharedBloomFilter f2(x);
BOOST_REQUIRE_EQUAL(x, f1.getAbridgedTopic());
BOOST_REQUIRE_EQUAL(x, f2.getAbridgedTopic());
BOOST_REQUIRE_EQUAL(b00111000, f1.getUnsigned());
BOOST_REQUIRE_EQUAL(b00111000, f2.getUnsigned());
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001)));
f.add(AbridgedTopic(b00000001));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00010000)));
f.add(AbridgedTopic(b00010000));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000)));
f.add(AbridgedTopic(b00011000));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000)));
f.add(AbridgedTopic(b00110000));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010)));
f.add(AbridgedTopic(b00110010));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110)));
f.add(AbridgedTopic(b00000110));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110111)));
f.remove(AbridgedTopic(b00000001));
f.remove(AbridgedTopic(b00000001));
f.remove(AbridgedTopic(b00000001));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00011000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111)));
f.remove(AbridgedTopic(b00010000));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00011000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111)));
f.remove(AbridgedTopic(b00111000));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111)));
f.add(AbridgedTopic(b00000001));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00000001)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00110111)));
f.remove(AbridgedTopic(b00110111));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001)));
BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110110)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111)));
f.remove(AbridgedTopic(b00110111));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00010000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110110)));
BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111)));
TopicBloomFilter f;
vector<AbridgedTopic> vec;
Topic x(0xDEADBEEF);
int const c_rounds = 4;
for (int i = 0; i < c_rounds; ++i, x = sha3(x))
vec.push_back(abridge(x));
for (int i = 0; i < c_rounds; ++i)
testAddNonExisting(f, vec[i]);
for (int i = 0; i < c_rounds; ++i)
testRemoveExisting(f, vec[i]);
for (int i = 0; i < c_rounds; ++i)
testAddNonExistingBloom(f, vec[i]);
for (int i = 0; i < c_rounds; ++i)
testRemoveExistingBloom(f, vec[i]);
}
BOOST_AUTO_TEST_CASE(bloomFilterRaw)
{
VerbosityHolder setTemporaryLevel(10);
cnote << "Testing Raw Bloom matching...";
TopicBloomFilter f;
AbridgedTopic b00000001(0x01);
AbridgedTopic b00010000(0x10);
AbridgedTopic b00011000(0x18);
AbridgedTopic b00110000(0x30);
AbridgedTopic b00110010(0x32);
AbridgedTopic b00111000(0x38);
AbridgedTopic b00000110(0x06);
AbridgedTopic b00110110(0x36);
AbridgedTopic b00110111(0x37);
testAddNonExisting(f, b00000001);
testAddNonExisting(f, b00010000);
testAddNonExisting(f, b00011000);
testAddNonExisting(f, b00110000);
BOOST_REQUIRE(f.contains(b00111000));
testAddNonExisting(f, b00110010);
testAddNonExisting(f, b00000110);
BOOST_REQUIRE(f.contains(b00110110));
BOOST_REQUIRE(f.contains(b00110111));
f.remove(b00000001);
f.remove(b00000001);
f.remove(b00000001);
BOOST_REQUIRE(!f.contains(b00000001));
BOOST_REQUIRE(f.contains(b00010000));
BOOST_REQUIRE(f.contains(b00011000));
BOOST_REQUIRE(f.contains(b00110000));
BOOST_REQUIRE(f.contains(b00110010));
BOOST_REQUIRE(f.contains(b00111000));
BOOST_REQUIRE(f.contains(b00000110));
BOOST_REQUIRE(f.contains(b00110110));
BOOST_REQUIRE(!f.contains(b00110111));
f.remove(b00010000);
BOOST_REQUIRE(!f.contains(b00000001));
BOOST_REQUIRE(f.contains(b00010000));
BOOST_REQUIRE(f.contains(b00011000));
BOOST_REQUIRE(f.contains(b00110000));
BOOST_REQUIRE(f.contains(b00110010));
BOOST_REQUIRE(f.contains(b00111000));
BOOST_REQUIRE(f.contains(b00000110));
BOOST_REQUIRE(f.contains(b00110110));
BOOST_REQUIRE(!f.contains(b00110111));
f.remove(b00111000);
BOOST_REQUIRE(!f.contains(b00000001));
BOOST_REQUIRE(f.contains(b00010000));
BOOST_REQUIRE(!f.contains(b00011000));
BOOST_REQUIRE(f.contains(b00110000));
BOOST_REQUIRE(f.contains(b00110010));
BOOST_REQUIRE(!f.contains(b00111000));
BOOST_REQUIRE(f.contains(b00000110));
BOOST_REQUIRE(f.contains(b00110110));
BOOST_REQUIRE(!f.contains(b00110111));
f.add(b00000001);
BOOST_REQUIRE(f.contains(b00000001));
BOOST_REQUIRE(f.contains(b00010000));
BOOST_REQUIRE(!f.contains(b00011000));
BOOST_REQUIRE(f.contains(b00110000));
BOOST_REQUIRE(f.contains(b00110010));
BOOST_REQUIRE(!f.contains(b00111000));
BOOST_REQUIRE(f.contains(b00000110));
BOOST_REQUIRE(f.contains(b00110110));
BOOST_REQUIRE(f.contains(b00110111));
f.remove(b00110111);
BOOST_REQUIRE(!f.contains(b00000001));
BOOST_REQUIRE(f.contains(b00010000));
BOOST_REQUIRE(!f.contains(b00011000));
BOOST_REQUIRE(!f.contains(b00110000));
BOOST_REQUIRE(!f.contains(b00110010));
BOOST_REQUIRE(!f.contains(b00111000));
BOOST_REQUIRE(!f.contains(b00000110));
BOOST_REQUIRE(!f.contains(b00110110));
BOOST_REQUIRE(!f.contains(b00110111));
f.remove(b00110111);
BOOST_REQUIRE(!f.contains(b00000001));
BOOST_REQUIRE(!f.contains(b00010000));
BOOST_REQUIRE(!f.contains(b00011000));
BOOST_REQUIRE(!f.contains(b00110000));
BOOST_REQUIRE(!f.contains(b00110010));
BOOST_REQUIRE(!f.contains(b00111000));
BOOST_REQUIRE(!f.contains(b00000110));
BOOST_REQUIRE(!f.contains(b00110110));
BOOST_REQUIRE(!f.contains(b00110111));
}
BOOST_AUTO_TEST_SUITE_END()
Loading…
Cancel
Save