Skip to content

Commit 470f430

Browse files
committed
chore: expose SBF via compact_object
Signed-off-by: Roman Gershman <[email protected]>
1 parent 5d998d0 commit 470f430

File tree

11 files changed

+114
-36
lines changed

11 files changed

+114
-36
lines changed

src/core/bloom.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,17 @@ SBF::~SBF() {
146146
f.Destroy(mr);
147147
}
148148

149+
SBF& SBF::operator=(SBF&& src) {
150+
filters_.clear();
151+
filters_.swap(src.filters_);
152+
grow_factor_ = src.grow_factor_;
153+
fp_prob_ = src.fp_prob_;
154+
current_size_ = src.current_size_;
155+
max_capacity_ = src.max_capacity_;
156+
157+
return *this;
158+
}
159+
149160
bool SBF::Add(std::string_view str) {
150161
DCHECK_LT(current_size_, max_capacity_);
151162

src/core/bloom.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,14 @@ class Bloom {
7272
* TODO: to test the actual rate of this filter.
7373
*/
7474
class SBF {
75+
SBF(const SBF&) = delete;
76+
7577
public:
7678
SBF(uint64_t initial_capacity, double fp_prob, double grow_factor, PMR_NS::memory_resource* mr);
7779
~SBF();
7880

81+
SBF& operator=(SBF&& src);
82+
7983
bool Add(std::string_view str);
8084
bool Exists(std::string_view str) const;
8185

src/core/compact_object.cc

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ extern "C" {
2525
#include "base/flags.h"
2626
#include "base/logging.h"
2727
#include "base/pod_array.h"
28+
#include "core/bloom.h"
2829
#include "core/detail/bitpacking.h"
2930
#include "core/sorted_map.h"
3031
#include "core/string_map.h"
@@ -631,6 +632,10 @@ unsigned CompactObj::ObjType() const {
631632
return OBJ_JSON;
632633
}
633634

635+
if (taglen_ == SBF_TAG) {
636+
return OBJ_SBF;
637+
}
638+
634639
LOG(FATAL) << "TBD " << int(taglen_);
635640
return 0;
636641
}
@@ -649,6 +654,7 @@ string_view CompactObj::ObjTypeToString(unsigned type) {
649654
OBJECT_TYPE_CASE(OBJ_MODULE);
650655
OBJECT_TYPE_CASE(OBJ_STREAM);
651656
OBJECT_TYPE_CASE(OBJ_JSON);
657+
OBJECT_TYPE_CASE(OBJ_SBF);
652658
default:
653659
DCHECK(false) << "Unknown object type " << type;
654660
return "OTHER";
@@ -707,6 +713,16 @@ void CompactObj::SetJson(JsonType&& j) {
707713
}
708714
}
709715

716+
void CompactObj::SetSBF(uint64_t initial_capacity, double fp_prob, double grow_factor) {
717+
if (taglen_ == SBF_TAG) { // already json
718+
*u_.sbf = SBF(initial_capacity, fp_prob, grow_factor, tl.local_mr);
719+
} else {
720+
SetMeta(SBF_TAG);
721+
void* ptr = tl.local_mr->allocate(sizeof(SBF));
722+
u_.sbf = new (ptr) SBF(initial_capacity, fp_prob, grow_factor, tl.local_mr);
723+
}
724+
}
725+
710726
void CompactObj::SetString(std::string_view str) {
711727
uint8_t mask = mask_ & ~kEncMask;
712728
CHECK(!IsExternal());
@@ -876,7 +892,7 @@ bool CompactObj::HasAllocated() const {
876892
(taglen_ == ROBJ_TAG && u_.r_obj.inner_obj() == nullptr))
877893
return false;
878894

879-
DCHECK(taglen_ == ROBJ_TAG || taglen_ == SMALL_TAG || taglen_ == JSON_TAG);
895+
DCHECK(taglen_ == ROBJ_TAG || taglen_ == SMALL_TAG || taglen_ == JSON_TAG || taglen_ == SBF_TAG);
880896
return true;
881897
}
882898

@@ -991,6 +1007,8 @@ void CompactObj::Free() {
9911007
VLOG(1) << "Freeing JSON object";
9921008
u_.json_obj.json_ptr->~JsonType();
9931009
tl.local_mr->deallocate(u_.json_obj.json_ptr, sizeof(JsonType), kAlignSize);
1010+
} else if (taglen_ == SBF_TAG) {
1011+
DeleteMR<SBF>(u_.sbf);
9941012
} else {
9951013
LOG(FATAL) << "Unsupported tag " << int(taglen_);
9961014
}
@@ -1015,6 +1033,9 @@ size_t CompactObj::MallocUsed() const {
10151033
return u_.small_str.MallocUsed();
10161034
}
10171035

1036+
if (taglen_ == SBF_TAG) {
1037+
return 0; // TODO: to track SBF memory utilization.
1038+
}
10181039
LOG(DFATAL) << "should not reach";
10191040
return 0;
10201041
}

src/core/compact_object.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ constexpr unsigned kEncodingStrMap = 1; // for set/map encodings of strings
1919
constexpr unsigned kEncodingStrMap2 = 2; // for set/map encodings of strings using DenseSet
2020
constexpr unsigned kEncodingListPack = 3;
2121

22+
class SBF;
23+
2224
namespace detail {
2325

2426
// redis objects or blobs of upto 4GB size.
@@ -101,6 +103,7 @@ class CompactObj {
101103
ROBJ_TAG = 19,
102104
EXTERNAL_TAG = 20,
103105
JSON_TAG = 21,
106+
SBF_TAG = 22,
104107
};
105108

106109
enum MaskBit {
@@ -297,6 +300,8 @@ class CompactObj {
297300
// pre condition - the type here is OBJ_JSON and was set with SetJson
298301
JsonType* GetJson() const;
299302

303+
void SetSBF(uint64_t initial_capacity, double fp_prob, double grow_factor);
304+
300305
// dest must have at least Size() bytes available
301306
void GetString(char* dest) const;
302307

@@ -388,6 +393,7 @@ class CompactObj {
388393
SmallString small_str;
389394
detail::RobjWrapper r_obj;
390395
JsonWrapper json_obj;
396+
SBF* sbf __attribute__((packed));
391397
int64_t ival __attribute__((packed));
392398
ExternalPtr ext_ptr;
393399

src/core/compact_object_test.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,12 @@ TEST_F(CompactObjectTest, Hash) {
366366
EXPECT_EQ(1, cobj_.Size());
367367
}
368368

369+
TEST_F(CompactObjectTest, SBF) {
370+
cobj_.SetSBF(1000, 0.001, 2);
371+
EXPECT_EQ(cobj_.ObjType(), OBJ_SBF);
372+
EXPECT_EQ(0, cobj_.MallocUsed());
373+
}
374+
369375
TEST_F(CompactObjectTest, MimallocUnderutilzation) {
370376
// We are testing with the same object size allocation here
371377
// This test is for https://github.com/dragonflydb/dragonfly/issues/448

src/redis/redis_aux.h

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,10 @@
77
/* the last one in object.h is OBJ_STREAM and it is 6,
88
* this will add enough place for Redis types to grow */
99
#define OBJ_JSON 15U
10+
#define OBJ_SBF 16U
1011

1112
/* How many types of objects exist */
12-
#define OBJ_TYPE_MAX 16U
13-
14-
#define HASHTABLE_MIN_FILL 10 /* Minimal hash table fill 10% */
15-
#define HASHTABLE_MAX_LOAD_FACTOR 1.618 /* Maximum hash table load factor. */
16-
17-
/* Redis maxmemory strategies. Instead of using just incremental number
18-
* for this defines, we use a set of flags so that testing for certain
19-
* properties common to multiple policies is faster. */
20-
#define MAXMEMORY_FLAG_LRU (1 << 0)
21-
#define MAXMEMORY_FLAG_LFU (1 << 1)
22-
#define MAXMEMORY_FLAG_ALLKEYS (1 << 2)
23-
#define MAXMEMORY_FLAG_NO_SHARED_INTEGERS (MAXMEMORY_FLAG_LRU | MAXMEMORY_FLAG_LFU)
24-
25-
#define LFU_INIT_VAL 5
26-
27-
#define MAXMEMORY_VOLATILE_LRU ((0 << 8) | MAXMEMORY_FLAG_LRU)
28-
#define MAXMEMORY_VOLATILE_LFU ((1 << 8) | MAXMEMORY_FLAG_LFU)
29-
#define MAXMEMORY_VOLATILE_TTL (2 << 8)
30-
#define MAXMEMORY_VOLATILE_RANDOM (3 << 8)
31-
#define MAXMEMORY_ALLKEYS_LRU ((4 << 8) | MAXMEMORY_FLAG_LRU | MAXMEMORY_FLAG_ALLKEYS)
32-
#define MAXMEMORY_ALLKEYS_LFU ((5 << 8) | MAXMEMORY_FLAG_LFU | MAXMEMORY_FLAG_ALLKEYS)
33-
#define MAXMEMORY_ALLKEYS_RANDOM ((6 << 8) | MAXMEMORY_FLAG_ALLKEYS)
34-
#define MAXMEMORY_NO_EVICTION (7 << 8)
13+
#define OBJ_TYPE_MAX 17U
3514

3615
#define CONFIG_RUN_ID_SIZE 40U
3716

src/server/bloom_family.cc

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,64 @@
88
#include "facade/error.h"
99
#include "server/command_registry.h"
1010
#include "server/conn_context.h"
11+
#include "server/engine_shard_set.h"
12+
#include "server/transaction.h"
1113

1214
namespace dfly {
1315

14-
// Bloom interface based on SBFs:
15-
// https://www.sciencedirect.com/science/article/abs/pii/S0020019006003127 See
16-
// https://www.alibabacloud.com/help/en/tair/developer-reference/bloom for the API documentation.
17-
// See c-project for the implementation of bloom filters
18-
// https://github.com/armon/bloomd as well as https://github.com/jvirkki/libbloom
19-
2016
using namespace facade;
17+
using namespace std;
18+
19+
namespace {
20+
21+
struct SbfParams {
22+
uint32_t init_capacity;
23+
double error;
24+
double grow_factor = 2.0;
25+
26+
bool ok() const {
27+
return error > 0 and error < 0.5;
28+
}
29+
};
30+
31+
OpStatus OpReserve(const SbfParams& params, const OpArgs& op_args, string_view key) {
32+
auto& db_slice = op_args.shard->db_slice();
33+
OpResult op_res = db_slice.AddOrFind(op_args.db_cntx, key);
34+
if (!op_res)
35+
return op_res.status();
36+
if (!op_res->is_new)
37+
return OpStatus::KEY_EXISTS;
2138

22-
namespace {} // namespace
39+
PrimeValue& pv = op_res->it->second;
40+
pv.SetSBF(params.init_capacity, params.error, params.grow_factor);
41+
42+
return OpStatus::OK;
43+
}
44+
45+
} // namespace
2346

2447
void BloomFamily::Reserve(CmdArgList args, ConnectionContext* cntx) {
25-
cntx->SendError(kSyntaxErr);
48+
CmdArgParser parser(args);
49+
string_view key = parser.Next();
50+
SbfParams params;
51+
52+
tie(params.error, params.init_capacity) = parser.Next<double, uint32_t>();
53+
54+
if (parser.Error())
55+
return cntx->SendError(kSyntaxErr);
56+
57+
if (!params.ok())
58+
return cntx->SendError("error rate is out of range", kSyntaxErrType);
59+
60+
const auto cb = [&](Transaction* t, EngineShard* shard) {
61+
return OpReserve(params, t->GetOpArgs(shard), key);
62+
};
63+
64+
OpStatus res = cntx->transaction->ScheduleSingleHop(std::move(cb));
65+
if (res == OpStatus::KEY_EXISTS) {
66+
return cntx->SendError("item exists");
67+
}
68+
return cntx->SendError(res);
2669
}
2770

2871
void BloomFamily::Add(CmdArgList args, ConnectionContext* cntx) {

src/server/bloom_family_test.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "server/bloom_family.h"
66

7+
#include "facade/facade_test.h"
78
#include "server/test_utils.h"
89

910
namespace dfly {
@@ -13,6 +14,10 @@ class BloomFamilyTest : public BaseFamilyTest {
1314
};
1415

1516
TEST_F(BloomFamilyTest, Basic) {
17+
auto resp = Run({"bf.reserve", "b1", "0.1", "32"});
18+
EXPECT_EQ(resp, "OK");
19+
resp = Run({"type", "b1"});
20+
EXPECT_EQ(resp, "MBbloom--");
1621
}
1722

1823
} // namespace dfly

src/server/common.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ const char* ObjTypeName(int type) {
9999
return "stream";
100100
case OBJ_JSON:
101101
return "rejson-rl";
102+
case OBJ_SBF:
103+
return "MBbloom--";
104+
102105
default:
103106
LOG(ERROR) << "Unsupported type " << type;
104107
}

src/server/db_slice.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,8 @@ unsigned PrimeEvictionPolicy::Evict(const PrimeTable::HotspotBuckets& eb, PrimeT
218218
#define ADD(x) (x) += o.x
219219

220220
DbStats& DbStats::operator+=(const DbStats& o) {
221-
constexpr size_t kDbSz = sizeof(DbStats);
222-
static_assert(kDbSz == 208);
221+
constexpr size_t kDbSz = sizeof(DbStats) - sizeof(DbTableStats);
222+
static_assert(kDbSz == 32);
223223

224224
DbTableStats::operator+=(o);
225225

0 commit comments

Comments
 (0)