31struct OPENDHT_PUBLIC Prefix
36 , content_(h.begin(), h.end())
38 Prefix(
const Blob& d,
const Blob& f = {})
44 Prefix(
const Prefix& p,
size_t first)
45 : size_(std::min(first, p.content_.size() * 8))
46 , content_(
Blob(p.content_.begin(), p.content_.begin() + size_ / 8))
49 if (not p.flags_.empty()) {
50 flags_ =
Blob(p.flags_.begin(), p.flags_.begin() + size_ / 8);
52 flags_.push_back(p.flags_[size_ / 8] & (0xFF << (8 - rem)));
56 content_.push_back(p.content_[size_ / 8] & (0xFF << (8 - rem)));
73 if ((
size_t) std::abs(len) >= content_.size() * 8)
74 throw std::out_of_range(
"len larger than prefix size.");
78 return Prefix(*
this, len);
87 bool isFlagActive(
size_t pos)
const {
return flags_.empty() or isActiveBit(flags_, pos); }
94 Prefix getFullSize() {
return Prefix(*
this, content_.size() * 8); }
110 InfoHash hash()
const
113 copy.push_back(size_);
114 return InfoHash::get(copy);
124 static inline unsigned commonBits(
const Prefix& p1,
const Prefix& p2)
128 auto longest_prefix_size = std::min(p1.size_, p2.size_);
130 for (i = 0; i < longest_prefix_size; i++) {
136 if (i == longest_prefix_size)
137 return 8 * longest_prefix_size;
139 x = p1.content_.data()[i] ^ p2.content_.data()[i];
142 while ((x & 0x80) == 0) {
168 auto csize = size_ - flags_.size() * 8;
170 flags_.push_back(0xFF);
176 flags_.push_back(0xFF << (8 - csize));
179 for (
auto i = flags_.size(); i < content_.size(); i++)
180 flags_.push_back(0xFF);
183 std::string toString()
const;
202 Blob addPadding(Blob toP,
size_t size)
205 for (
auto i = copy.size(); i < size; i++)
208 swapBit(copy, size_ + 1);
222 bool isActiveBit(
const Blob& b,
size_t pos)
const
224 if (pos >= content_.size() * 8)
225 throw std::out_of_range(
"Can't detect active bit at pos, pos larger than prefix size or empty prefix");
227 return ((b[pos / 8] >> (7 - (pos % 8))) & 1) == 1;
240 void swapBit(Blob& b,
size_t bit)
242 if (bit >= b.size() * 8)
243 throw std::out_of_range(
"bit larger than prefix size.");
245 size_t offset_bit = (8 - bit) % 8;
246 b[bit / 8] ^= (1 << offset_bit);
274class OPENDHT_PUBLIC Pht
276 static constexpr const char* INVALID_KEY =
"Key does not match the PHT key spec.";
279 static constexpr const char* INDEX_PREFIX =
"index.pht.";
285 static constexpr const size_t MAX_NODE_ENTRY_COUNT {16};
288 using Key = std::map<std::string, Blob>;
292 using KeySpec = std::map<std::string, size_t>;
293 using LookupCallback = std::function<void(std::vector<std::shared_ptr<Value>>& values,
const Prefix& p)>;
295 typedef void (*LookupCallbackRaw)(std::vector<std::shared_ptr<Value>>* values,
Prefix* p,
void* user_data);
296 static LookupCallback bindLookupCb(LookupCallbackRaw raw_cb,
void* user_data)
300 return [=](std::vector<std::shared_ptr<Value>>& values,
const Prefix& p) {
301 raw_cb((std::vector<std::shared_ptr<Value>>*) &values, (
Prefix*) &p, user_data);
304 using LookupCallbackSimple = std::function<void(std::vector<std::shared_ptr<Value>>& values)>;
305 typedef void (*LookupCallbackSimpleRaw)(std::vector<std::shared_ptr<Value>>* values,
void* user_data);
306 static LookupCallbackSimple bindLookupCbSimple(LookupCallbackSimpleRaw raw_cb,
void* user_data)
310 return [=](std::vector<std::shared_ptr<Value>>& values) {
311 raw_cb((std::vector<std::shared_ptr<Value>>*) &values, user_data);
315 Pht(std::string name, KeySpec k_spec, std::shared_ptr<DhtRunner>
dht)
316 : name_(INDEX_PREFIX + name)
317 , canary_(name_ +
".canary")
327 void lookup(Key k, LookupCallback cb = {}, DoneCallbackSimple done_cb = {},
bool exact_match =
true);
328 void lookup(Key k, LookupCallbackSimple cb = {}, DoneCallbackSimple done_cb = {},
bool exact_match =
true)
332 [cb = std::move(cb)](std::vector<std::shared_ptr<Value>>& values, Prefix) { cb(values); },
344 void insert(Key k, Value v, DoneCallbackSimple done_cb = {})
348 auto lo = std::make_shared<int>(0);
349 auto hi = std::make_shared<int>(p.size_);
353 entry.prefix = p.content_;
356 Pht::insert(p, entry, lo, hi, clock::now(),
true, done_cb);
372 void insert(
const Prefix& kp,
374 std::shared_ptr<int> lo,
375 std::shared_ptr<int> hi,
378 DoneCallbackSimple done_cb = {});
387 void insert(
const Prefix& p);
397 int lookup(
const Prefix& p);
400 static constexpr const size_t MAX_ELEMENT {1024};
401 static constexpr const std::chrono::minutes NODE_EXPIRE_TIME {5};
405 time_point last_reply;
406 std::shared_ptr<Node> parent;
407 std::weak_ptr<Node> left_child;
408 std::weak_ptr<Node> right_child;
411 std::weak_ptr<Node> root_;
418 std::multimap<time_point, std::shared_ptr<Node>> leaves_;
422 using RealInsertCallback = std::function<void(
const Prefix& p, IndexEntry entry)>;
423 using LookupCallbackWrapper = std::function<void(std::vector<std::shared_ptr<IndexEntry>>& values,
const Prefix& p)>;
440 void lookupStep(Prefix k,
441 std::shared_ptr<int> lo,
442 std::shared_ptr<int> hi,
443 std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals,
444 LookupCallbackWrapper cb,
445 DoneCallbackSimple done_cb,
446 std::shared_ptr<unsigned> max_common_prefix_len,
448 bool all_values =
false);
457 Prefix zcurve(
const std::vector<Prefix>& all_prefix)
const;
467 virtual Prefix linearize(Key k)
const;
477 void getRealPrefix(
const std::shared_ptr<Prefix>& p, IndexEntry entry, RealInsertCallback end_cb);
487 void checkPhtUpdate(Prefix p, IndexEntry entry, time_point time_p);
496 static size_t findSplitLocation(
const Prefix& compared,
const std::vector<std::shared_ptr<IndexEntry>>& vals)
498 for (
size_t i = 0; i < compared.content_.size() * 8 - 1; i++)
499 for (
auto const& v : vals)
500 if (Prefix(v->prefix).isContentBitActive(i) != compared.isContentBitActive(i))
502 return compared.content_.size() * 8 - 1;
513 void split(
const Prefix& insert,
514 const std::vector<std::shared_ptr<IndexEntry>>& vals,
516 RealInsertCallback end_cb);
521 bool validKey(
const Key& k)
const
523 return k.size() == keySpec_.size()
524 and std::equal(k.begin(),
527 [&](
const Key::value_type& key,
const KeySpec::value_type& key_spec) {
528 return key.first == key_spec.first and key.second.size() <= key_spec.second;
536 void updateCanary(Prefix p);
538 const std::string name_;
539 const std::string canary_;
540 const KeySpec keySpec_;
542 std::shared_ptr<DhtRunner> dht_;