Skip to content

Commit 2548a42

Browse files
committed
FT-307 Add a 'memcmp magic' API, where users can specify that a
particular value for the first byte of a key means it may be compared with memcmp and a length check. FT-50 Implement toku_builtin_cmp_fun with memcmp and a length check
1 parent 17c5b4d commit 2548a42

File tree

9 files changed

+93
-61
lines changed

9 files changed

+93
-61
lines changed

buildheader/make_tdb.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ static void print_db_struct (void) {
545545
"int (*change_fanout)(DB *db, uint32_t fanout)",
546546
"int (*get_fanout)(DB *db, uint32_t *fanout)",
547547
"int (*set_fanout)(DB *db, uint32_t fanout)",
548+
"int (*set_memcmp_magic)(DB *db, uint8_t magic)",
548549
"int (*set_indexer)(DB*, DB_INDEXER*)",
549550
"void (*get_indexer)(DB*, DB_INDEXER**)",
550551
"int (*verify_with_progress)(DB *, int (*progress_callback)(void *progress_extra, float progress), void *progress_extra, int verbose, int keep_going)",

ft/comparator.h

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,16 @@ namespace toku {
110110
// that points may be positive or negative infinity.
111111

112112
class comparator {
113-
public:
114-
void create(ft_compare_func cmp, DESCRIPTOR desc) {
113+
void init(ft_compare_func cmp, DESCRIPTOR desc, uint8_t memcmp_magic) {
115114
_cmp = cmp;
116-
XCALLOC(_fake_db);
117115
_fake_db->cmp_descriptor = desc;
118-
_builtin = _cmp == &toku_builtin_compare_fun;
116+
_memcmp_magic = memcmp_magic;
117+
}
118+
119+
public:
120+
void create(ft_compare_func cmp, DESCRIPTOR desc, uint8_t memcmp_magic = 0) {
121+
XCALLOC(_fake_db);
122+
init(cmp, desc, memcmp_magic);
119123
}
120124

121125
// inherit the attributes of another comparator, but keep our own
@@ -124,9 +128,7 @@ namespace toku {
124128
invariant_notnull(_fake_db);
125129
invariant_notnull(cmp._cmp);
126130
invariant_notnull(cmp._fake_db);
127-
_cmp = cmp._cmp;
128-
_fake_db->cmp_descriptor = cmp._fake_db->cmp_descriptor;
129-
_builtin = cmp._builtin;
131+
init(cmp._cmp, cmp._fake_db->cmp_descriptor, cmp._memcmp_magic);
130132
}
131133

132134
// like inherit, but doesn't require that the this comparator
@@ -148,14 +150,24 @@ namespace toku {
148150
return _cmp;
149151
}
150152

153+
uint8_t get_memcmp_magic() const {
154+
return _memcmp_magic;
155+
}
156+
151157
bool valid() const {
152158
return _cmp != nullptr;
153159
}
154160

161+
inline bool dbt_has_memcmp_magic(const DBT *dbt) const {
162+
return *reinterpret_cast<const char *>(dbt->data) == _memcmp_magic;
163+
}
164+
155165
int operator()(const DBT *a, const DBT *b) const {
156-
if (__builtin_expect(!!(toku_dbt_is_infinite(a) || toku_dbt_is_infinite(b)), 0)) {
166+
if (__builtin_expect(toku_dbt_is_infinite(a) || toku_dbt_is_infinite(b), 0)) {
157167
return toku_dbt_infinite_compare(a, b);
158-
} else if (_builtin) {
168+
} else if (_memcmp_magic && dbt_has_memcmp_magic(a)
169+
// At this point we expect b to also have the memcmp magic
170+
&& __builtin_expect(dbt_has_memcmp_magic(b), 1)) {
159171
return toku_builtin_compare_fun(nullptr, a, b);
160172
} else {
161173
// yikes, const sadness here
@@ -166,7 +178,7 @@ namespace toku {
166178
private:
167179
DB *_fake_db;
168180
ft_compare_func _cmp;
169-
bool _builtin;
181+
uint8_t _memcmp_magic;
170182
};
171183

172184
} /* namespace toku */

ft/ft-internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ struct ft_options {
278278
enum toku_compression_method compression_method;
279279
unsigned int fanout;
280280
unsigned int flags;
281+
uint8_t memcmp_magic;
281282
ft_compare_func compare_fun;
282283
ft_update_func update_fun;
283284
};

ft/ft-ops.cc

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2887,6 +2887,17 @@ toku_ft_handle_get_fanout(FT_HANDLE ft_handle, unsigned int *fanout)
28872887
*fanout = ft_handle->options.fanout;
28882888
}
28892889
}
2890+
2891+
void toku_ft_handle_set_memcmp_magic(FT_HANDLE ft_handle, uint8_t magic) {
2892+
invariant(magic != 0);
2893+
if (ft_handle->ft) {
2894+
// handle is already open, application bug if memcmp magic changes
2895+
invariant(ft_handle->ft->cmp.get_memcmp_magic() == magic);
2896+
} else {
2897+
ft_handle->options.memcmp_magic = magic;
2898+
}
2899+
}
2900+
28902901
static int
28912902
verify_builtin_comparisons_consistent(FT_HANDLE t, uint32_t flags) {
28922903
if ((flags & TOKU_DB_KEYCMP_BUILTIN) && (t->options.compare_fun != toku_builtin_compare_fun))
@@ -2955,6 +2966,7 @@ toku_ft_handle_inherit_options(FT_HANDLE t, FT ft) {
29552966
.compression_method = ft->h->compression_method,
29562967
.fanout = ft->h->fanout,
29572968
.flags = ft->h->flags,
2969+
.memcmp_magic = ft->cmp.get_memcmp_magic(),
29582970
.compare_fun = ft->cmp.get_compare_func(),
29592971
.update_fun = ft->update_fun
29602972
};
@@ -4721,32 +4733,23 @@ int toku_ft_strerror_r(int error, char *buf, size_t buflen)
47214733
}
47224734
}
47234735

4724-
// when a and b are chars, return a-b is safe here because return type is int. No over/underflow possible.
4725-
int toku_keycompare (const void *key1, uint32_t key1len, const void *key2, uint32_t key2len) {
4726-
int comparelen = key1len<key2len ? key1len : key2len;
4727-
const unsigned char *k1;
4728-
const unsigned char *k2;
4729-
for (CAST_FROM_VOIDP(k1, key1), CAST_FROM_VOIDP(k2, key2);
4730-
comparelen>4;
4731-
k1+=4, k2+=4, comparelen-=4) {
4732-
{ int v1=k1[0], v2=k2[0]; if (v1!=v2) return v1-v2; }
4733-
{ int v1=k1[1], v2=k2[1]; if (v1!=v2) return v1-v2; }
4734-
{ int v1=k1[2], v2=k2[2]; if (v1!=v2) return v1-v2; }
4735-
{ int v1=k1[3], v2=k2[3]; if (v1!=v2) return v1-v2; }
4736-
}
4737-
for (;
4738-
comparelen>0;
4739-
k1++, k2++, comparelen--) {
4740-
if (*k1 != *k2) {
4741-
return (int)*k1-(int)*k2;
4742-
}
4743-
}
4744-
if (key1len<key2len) return -1;
4745-
if (key1len>key2len) return 1;
4746-
return 0;
4736+
int toku_keycompare(const void *key1, uint32_t key1len, const void *key2, uint32_t key2len) {
4737+
int comparelen = key1len < key2len ? key1len : key2len;
4738+
int c = memcmp(key1, key2, comparelen);
4739+
if (__builtin_expect(c != 0, 1)) {
4740+
return c;
4741+
} else {
4742+
if (key1len < key2len) {
4743+
return -1;
4744+
} else if (key1len > key2len) {
4745+
return 1;
4746+
} else {
4747+
return 0;
4748+
}
4749+
}
47474750
}
47484751

4749-
int toku_builtin_compare_fun (DB *db __attribute__((__unused__)), const DBT *a, const DBT*b) {
4752+
int toku_builtin_compare_fun(DB *db __attribute__((__unused__)), const DBT *a, const DBT*b) {
47504753
return toku_keycompare(a->data, a->size, b->data, b->size);
47514754
}
47524755

ft/ft-ops.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ void toku_ft_handle_set_compression_method(FT_HANDLE, enum toku_compression_meth
126126
void toku_ft_handle_get_compression_method(FT_HANDLE, enum toku_compression_method *);
127127
void toku_ft_handle_set_fanout(FT_HANDLE, unsigned int fanout);
128128
void toku_ft_handle_get_fanout(FT_HANDLE, unsigned int *fanout);
129+
void toku_ft_handle_set_memcmp_magic(FT_HANDLE, uint8_t magic);
129130

130131
void toku_ft_set_bt_compare(FT_HANDLE ft_handle, ft_compare_func cmp_func);
131132
const toku::comparator &toku_ft_get_comparator(FT_HANDLE ft_handle);

ft/ft.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ static void ft_init(FT ft, FT_OPTIONS options, CACHEFILE cf) {
384384
toku_list_init(&ft->live_ft_handles);
385385

386386
// intuitively, the comparator points to the FT's cmp descriptor
387-
ft->cmp.create(options->compare_fun, &ft->cmp_descriptor);
387+
ft->cmp.create(options->compare_fun, &ft->cmp_descriptor, options->memcmp_magic);
388388
ft->update_fun = options->update_fun;
389389

390390
if (ft->cf != NULL) {
@@ -486,7 +486,7 @@ int toku_read_ft_and_store_in_cachefile (FT_HANDLE ft_handle, CACHEFILE cf, LSN
486486

487487
invariant_notnull(ft);
488488
// intuitively, the comparator points to the FT's cmp descriptor
489-
ft->cmp.create(ft_handle->options.compare_fun, &ft->cmp_descriptor);
489+
ft->cmp.create(ft_handle->options.compare_fun, &ft->cmp_descriptor, ft_handle->options.memcmp_magic);
490490
ft->update_fun = ft_handle->options.update_fun;
491491
ft->cf = cf;
492492
toku_cachefile_set_userdata(cf,
@@ -611,6 +611,7 @@ toku_ft_init(FT ft,
611611
.compression_method = compression_method,
612612
.fanout = fanout,
613613
.flags = 0,
614+
.memcmp_magic = 0,
614615
.compare_fun = NULL,
615616
.update_fun = NULL
616617
};

src/ydb.cc

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -465,27 +465,6 @@ needs_recovery (DB_ENV *env) {
465465

466466
static int toku_env_txn_checkpoint(DB_ENV * env, uint32_t kbyte, uint32_t min, uint32_t flags);
467467

468-
// Instruct db to use the default (built-in) key comparison function
469-
// by setting the flag bits in the db and ft structs
470-
static int
471-
db_use_builtin_key_cmp(DB *db) {
472-
HANDLE_PANICKED_DB(db);
473-
int r = 0;
474-
if (db_opened(db))
475-
r = toku_ydb_do_error(db->dbenv, EINVAL, "Comparison functions cannot be set after DB open.\n");
476-
else if (db->i->key_compare_was_set)
477-
r = toku_ydb_do_error(db->dbenv, EINVAL, "Key comparison function already set.\n");
478-
else {
479-
uint32_t tflags;
480-
toku_ft_get_flags(db->i->ft_handle, &tflags);
481-
482-
tflags |= TOKU_DB_KEYCMP_BUILTIN;
483-
toku_ft_set_flags(db->i->ft_handle, tflags);
484-
db->i->key_compare_was_set = true;
485-
}
486-
return r;
487-
}
488-
489468
// Keys used in persistent environment dictionary:
490469
// Following keys added in version 12
491470
static const char * orig_env_ver_key = "original_version";
@@ -1025,7 +1004,7 @@ env_open(DB_ENV * env, const char *home, uint32_t flags, int mode) {
10251004
{
10261005
r = toku_db_create(&env->i->persistent_environment, env, 0);
10271006
assert_zero(r);
1028-
r = db_use_builtin_key_cmp(env->i->persistent_environment);
1007+
r = toku_db_use_builtin_key_cmp(env->i->persistent_environment);
10291008
assert_zero(r);
10301009
r = toku_db_open_iname(env->i->persistent_environment, txn, toku_product_name_strings.environmentdictionary, DB_CREATE, mode);
10311010
if (r != 0) {
@@ -1063,7 +1042,7 @@ env_open(DB_ENV * env, const char *home, uint32_t flags, int mode) {
10631042
{
10641043
r = toku_db_create(&env->i->directory, env, 0);
10651044
assert_zero(r);
1066-
r = db_use_builtin_key_cmp(env->i->directory);
1045+
r = toku_db_use_builtin_key_cmp(env->i->directory);
10671046
assert_zero(r);
10681047
r = toku_db_open_iname(env->i->directory, txn, toku_product_name_strings.fileopsdirectory, DB_CREATE, mode);
10691048
if (r != 0) {

src/ydb_db.cc

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -431,8 +431,27 @@ void toku_db_lt_on_destroy_callback(toku::locktree *lt) {
431431
toku_ft_handle_close(ft_handle);
432432
}
433433

434-
int
435-
toku_db_open_iname(DB * db, DB_TXN * txn, const char *iname_in_env, uint32_t flags, int mode) {
434+
// Instruct db to use the default (built-in) key comparison function
435+
// by setting the flag bits in the db and ft structs
436+
int toku_db_use_builtin_key_cmp(DB *db) {
437+
HANDLE_PANICKED_DB(db);
438+
int r = 0;
439+
if (db_opened(db)) {
440+
r = toku_ydb_do_error(db->dbenv, EINVAL, "Comparison functions cannot be set after DB open.\n");
441+
} else if (db->i->key_compare_was_set) {
442+
r = toku_ydb_do_error(db->dbenv, EINVAL, "Key comparison function already set.\n");
443+
} else {
444+
uint32_t tflags;
445+
toku_ft_get_flags(db->i->ft_handle, &tflags);
446+
447+
tflags |= TOKU_DB_KEYCMP_BUILTIN;
448+
toku_ft_set_flags(db->i->ft_handle, tflags);
449+
db->i->key_compare_was_set = true;
450+
}
451+
return r;
452+
}
453+
454+
int toku_db_open_iname(DB * db, DB_TXN * txn, const char *iname_in_env, uint32_t flags, int mode) {
436455
//Set comparison functions if not yet set.
437456
HANDLE_READ_ONLY_TXN(txn);
438457
if (!db->i->key_compare_was_set && db->dbenv->i->bt_compare) {
@@ -704,6 +723,19 @@ toku_db_get_fanout(DB *db, unsigned int *fanout) {
704723
return 0;
705724
}
706725

726+
static int
727+
toku_db_set_memcmp_magic(DB *db, uint8_t magic) {
728+
HANDLE_PANICKED_DB(db);
729+
if (db_opened(db)) {
730+
return EINVAL;
731+
}
732+
if (magic == 0) {
733+
return EINVAL;
734+
}
735+
toku_ft_handle_set_memcmp_magic(db->i->ft_handle, magic);
736+
return 0;
737+
}
738+
707739
static int
708740
toku_db_get_fractal_tree_info64(DB *db, uint64_t *num_blocks_allocated, uint64_t *num_blocks_in_use, uint64_t *size_allocated, uint64_t *size_in_use) {
709741
HANDLE_PANICKED_DB(db);
@@ -1101,6 +1133,7 @@ toku_db_create(DB ** db, DB_ENV * env, uint32_t flags) {
11011133
USDB(change_compression_method);
11021134
USDB(set_fanout);
11031135
USDB(get_fanout);
1136+
USDB(set_memcmp_magic);
11041137
USDB(change_fanout);
11051138
USDB(set_flags);
11061139
USDB(get_flags);

src/ydb_db.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ static inline const toku::comparator &toku_db_get_comparator(DB *db) {
131131
return toku_ft_get_comparator(db->i->ft_handle);
132132
}
133133

134+
int toku_db_use_builtin_key_cmp(DB *db);
134135
int toku_db_pre_acquire_fileops_lock(DB *db, DB_TXN *txn);
135136
int toku_db_open_iname(DB * db, DB_TXN * txn, const char *iname, uint32_t flags, int mode);
136137
int toku_db_pre_acquire_table_lock(DB *db, DB_TXN *txn);

0 commit comments

Comments
 (0)