Skip to content

Commit a844b45

Browse files
authored
Hamt bit width (#99)
Signed-off-by: turuslan <[email protected]>
1 parent f3b5caa commit a844b45

File tree

3 files changed

+57
-15
lines changed

3 files changed

+57
-15
lines changed

core/storage/hamt/hamt.cpp

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,24 @@ OUTCOME_CPP_DEFINE_CATEGORY(fc::storage::hamt, HamtError, e) {
2424
namespace fc::storage::hamt {
2525
using fc::common::which;
2626

27-
// assuming 8-bit indices
28-
auto keyToIndices(const std::string &key, int n = -1) {
29-
std::vector<uint8_t> key_bytes(key.begin(), key.end());
30-
auto hash = crypto::murmur::hash(key_bytes);
31-
return std::vector<size_t>(n == -1 ? hash.begin() : hash.end() - n + 1,
32-
hash.end());
33-
}
34-
3527
auto consumeIndex(gsl::span<const size_t> indices) {
3628
return indices.subspan(1);
3729
}
3830

39-
Hamt::Hamt(std::shared_ptr<ipfs::IpfsDatastore> store)
40-
: store_(std::move(store)), root_(std::make_shared<Node>()) {}
31+
Hamt::Hamt(std::shared_ptr<ipfs::IpfsDatastore> store, size_t bit_width)
32+
: store_{std::move(store)},
33+
root_{std::make_shared<Node>()},
34+
bit_width_{bit_width} {}
4135

4236
Hamt::Hamt(std::shared_ptr<ipfs::IpfsDatastore> store, Node::Ptr root)
43-
: store_(std::move(store)), root_(std::move(root)) {}
37+
: store_{std::move(store)},
38+
root_{std::move(root)},
39+
bit_width_{kDefaultBitWidth} {}
4440

45-
Hamt::Hamt(std::shared_ptr<ipfs::IpfsDatastore> store, const CID &root)
46-
: store_(std::move(store)), root_(root) {}
41+
Hamt::Hamt(std::shared_ptr<ipfs::IpfsDatastore> store,
42+
const CID &root,
43+
size_t bit_width)
44+
: store_{std::move(store)}, root_{root}, bit_width_{bit_width} {}
4745

4846
outcome::result<void> Hamt::set(const std::string &key,
4947
gsl::span<const uint8_t> value) {
@@ -84,6 +82,30 @@ namespace fc::storage::hamt {
8482
return boost::get<CID>(root_);
8583
}
8684

85+
std::vector<size_t> Hamt::keyToIndices(const std::string &key, int n) const {
86+
std::vector<uint8_t> key_bytes(key.begin(), key.end());
87+
auto hash = crypto::murmur::hash(key_bytes);
88+
std::vector<size_t> indices;
89+
constexpr auto byte_bits = 8;
90+
auto max_bits = byte_bits * hash.size();
91+
max_bits -= max_bits % bit_width_;
92+
auto offset = 0;
93+
if (n != -1) {
94+
offset = max_bits - (n - 1) * bit_width_;
95+
}
96+
while (offset + bit_width_ <= max_bits) {
97+
size_t index = 0;
98+
for (auto i = 0u; i < bit_width_; ++i, ++offset) {
99+
index <<= 1;
100+
index |= 1
101+
& (hash[offset / byte_bits]
102+
>> (byte_bits - 1 - offset % byte_bits));
103+
}
104+
indices.push_back(index);
105+
}
106+
return indices;
107+
}
108+
87109
outcome::result<void> Hamt::set(Node &node,
88110
gsl::span<const size_t> indices,
89111
const std::string &key,

core/storage/hamt/hamt.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace fc::storage::hamt {
2525
using Value = ipfs::IpfsDatastore::Value;
2626

2727
constexpr size_t kLeafMax = 3;
28+
constexpr size_t kDefaultBitWidth = 8;
2829

2930
/** Hamt node representation */
3031
struct Node {
@@ -107,9 +108,12 @@ namespace fc::storage::hamt {
107108
using Visitor = std::function<outcome::result<void>(const std::string &,
108109
const Value &)>;
109110

110-
explicit Hamt(std::shared_ptr<ipfs::IpfsDatastore> store);
111+
Hamt(std::shared_ptr<ipfs::IpfsDatastore> store,
112+
size_t bit_width = kDefaultBitWidth);
111113
Hamt(std::shared_ptr<ipfs::IpfsDatastore> store, Node::Ptr root);
112-
Hamt(std::shared_ptr<ipfs::IpfsDatastore> store, const CID &root);
114+
Hamt(std::shared_ptr<ipfs::IpfsDatastore> store,
115+
const CID &root,
116+
size_t bit_width = kDefaultBitWidth);
113117
/** Set value by key, does not write to storage */
114118
outcome::result<void> set(const std::string &key,
115119
gsl::span<const uint8_t> value);
@@ -143,6 +147,7 @@ namespace fc::storage::hamt {
143147
}
144148

145149
private:
150+
std::vector<size_t> keyToIndices(const std::string &key, int n = -1) const;
146151
outcome::result<void> set(Node &node,
147152
gsl::span<const size_t> indices,
148153
const std::string &key,
@@ -157,6 +162,7 @@ namespace fc::storage::hamt {
157162

158163
std::shared_ptr<ipfs::IpfsDatastore> store_;
159164
Node::Item root_;
165+
size_t bit_width_;
160166
};
161167
} // namespace fc::storage::hamt
162168

test/core/storage/hamt/hamt_test.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,20 @@ TEST_F(HamtTest, FlushCollisionChild) {
199199
EXPECT_OUTCOME_EQ(store_->contains(cidShard), true);
200200
}
201201

202+
/** Go cid compatibility with bit width of 5 */
203+
TEST_F(HamtTest, CollisionChildBitWidth5) {
204+
hamt_ = {store_, 5};
205+
EXPECT_OUTCOME_EQ(hamt_.flush(), "0171a0e4022018fe6acc61a3a36b0c373c4a3a8ea64b812bf2ca9b528050909c78d408558a0c"_cid);
206+
EXPECT_OUTCOME_TRUE_1(hamt_.set("ails", "01"_unhex));
207+
EXPECT_OUTCOME_EQ(hamt_.flush(), "0171a0e40220963f12f112adbaa0e56ad77152a259224ac41eed6e5d909eaeb714f65add029f"_cid);
208+
EXPECT_OUTCOME_TRUE_1(hamt_.set("aufx", "02"_unhex));
209+
EXPECT_OUTCOME_EQ(hamt_.flush(), "0171a0e402207df36ed88d694b1bfe7161dd598bdfac05426a9beab0bf828d3e838d2c198e16"_cid);
210+
EXPECT_OUTCOME_TRUE_1(hamt_.set("bmvm", "03"_unhex));
211+
EXPECT_OUTCOME_EQ(hamt_.flush(), "0171a0e40220823751c22261961ca5a97917c9ce6c681e44a8265873d66ae2dadf3908c12357"_cid);
212+
EXPECT_OUTCOME_TRUE_1(hamt_.set("cnyh", "04"_unhex));
213+
EXPECT_OUTCOME_EQ(hamt_.flush(), "0171a0e40220f77809a02565e12cbadbab9ab8713958c5bb66b061508bbb01b37d73923f8c2b"_cid);
214+
}
215+
202216
/** Visit all key value pairs */
203217
TEST_F(HamtTest, Visitor) {
204218
auto n = 0;

0 commit comments

Comments
 (0)