1 /* Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2 Use of this source code is governed by a BSD-style license that can be
3 found in the LICENSE file. See the AUTHORS file for names of contributors. */
7 #ifndef ROCKSDB_LITE // Lite does not support C API
14 #include <sys/types.h>
20 // Can not use port/port.h macros as this is a c file
25 #define snprintf _snprintf
31 result
= ((int)GetCurrentProcessId() << 16);
32 result
|= (int)GetCurrentThreadId();
39 const char* phase
= "";
40 static char dbname
[200];
41 static char sstfilename
[200];
42 static char dbbackupname
[200];
44 static void StartPhase(const char* name
) {
45 fprintf(stderr
, "=== Test %s\n", name
);
48 static const char* GetTempDir(void) {
49 const char* ret
= getenv("TEST_TMPDIR");
50 if (ret
== NULL
|| ret
[0] == '\0')
55 #define CheckNoError(err) \
56 if ((err) != NULL) { \
57 fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \
61 #define CheckCondition(cond) \
63 fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \
67 static void CheckEqual(const char* expected
, const char* v
, size_t n
) {
68 if (expected
== NULL
&& v
== NULL
) {
70 } else if (expected
!= NULL
&& v
!= NULL
&& n
== strlen(expected
) &&
71 memcmp(expected
, v
, n
) == 0) {
75 fprintf(stderr
, "%s: expected '%s', got '%s'\n",
77 (expected
? expected
: "(null)"),
83 static void Free(char** ptr
) {
90 static void CheckValue(
94 size_t actual_length
) {
96 CheckEqual(expected
, *actual
, actual_length
);
100 static void CheckGet(
102 const rocksdb_readoptions_t
* options
,
104 const char* expected
) {
108 val
= rocksdb_get(db
, options
, key
, strlen(key
), &val_len
, &err
);
110 CheckEqual(expected
, val
, val_len
);
114 static void CheckGetCF(
116 const rocksdb_readoptions_t
* options
,
117 rocksdb_column_family_handle_t
* handle
,
119 const char* expected
) {
123 val
= rocksdb_get_cf(db
, options
, handle
, key
, strlen(key
), &val_len
, &err
);
125 CheckEqual(expected
, val
, val_len
);
130 static void CheckIter(rocksdb_iterator_t
* iter
,
131 const char* key
, const char* val
) {
134 str
= rocksdb_iter_key(iter
, &len
);
135 CheckEqual(key
, str
, len
);
136 str
= rocksdb_iter_value(iter
, &len
);
137 CheckEqual(val
, str
, len
);
140 // Callback from rocksdb_writebatch_iterate()
141 static void CheckPut(void* ptr
,
142 const char* k
, size_t klen
,
143 const char* v
, size_t vlen
) {
144 int* state
= (int*) ptr
;
145 CheckCondition(*state
< 2);
148 CheckEqual("bar", k
, klen
);
149 CheckEqual("b", v
, vlen
);
152 CheckEqual("box", k
, klen
);
153 CheckEqual("c", v
, vlen
);
159 // Callback from rocksdb_writebatch_iterate()
160 static void CheckDel(void* ptr
, const char* k
, size_t klen
) {
161 int* state
= (int*) ptr
;
162 CheckCondition(*state
== 2);
163 CheckEqual("bar", k
, klen
);
167 static void CmpDestroy(void* arg
) { }
169 static int CmpCompare(void* arg
, const char* a
, size_t alen
,
170 const char* b
, size_t blen
) {
171 size_t n
= (alen
< blen
) ? alen
: blen
;
172 int r
= memcmp(a
, b
, n
);
174 if (alen
< blen
) r
= -1;
175 else if (alen
> blen
) r
= +1;
180 static const char* CmpName(void* arg
) {
184 // Custom filter policy
185 static unsigned char fake_filter_result
= 1;
186 static void FilterDestroy(void* arg
) { }
187 static const char* FilterName(void* arg
) {
190 static char* FilterCreate(
192 const char* const* key_array
, const size_t* key_length_array
,
194 size_t* filter_length
) {
196 char* result
= malloc(4);
197 memcpy(result
, "fake", 4);
200 static unsigned char FilterKeyMatch(
202 const char* key
, size_t length
,
203 const char* filter
, size_t filter_length
) {
204 CheckCondition(filter_length
== 4);
205 CheckCondition(memcmp(filter
, "fake", 4) == 0);
206 return fake_filter_result
;
209 // Custom compaction filter
210 static void CFilterDestroy(void* arg
) {}
211 static const char* CFilterName(void* arg
) { return "foo"; }
212 static unsigned char CFilterFilter(void* arg
, int level
, const char* key
,
214 const char* existing_value
,
215 size_t value_length
, char** new_value
,
216 size_t* new_value_length
,
217 unsigned char* value_changed
) {
218 if (key_length
== 3) {
219 if (memcmp(key
, "bar", key_length
) == 0) {
221 } else if (memcmp(key
, "baz", key_length
) == 0) {
223 *new_value
= "newbazvalue";
224 *new_value_length
= 11;
231 static void CFilterFactoryDestroy(void* arg
) {}
232 static const char* CFilterFactoryName(void* arg
) { return "foo"; }
233 static rocksdb_compactionfilter_t
* CFilterCreate(
234 void* arg
, rocksdb_compactionfiltercontext_t
* context
) {
235 return rocksdb_compactionfilter_create(NULL
, CFilterDestroy
, CFilterFilter
,
239 static rocksdb_t
* CheckCompaction(rocksdb_t
* db
, rocksdb_options_t
* options
,
240 rocksdb_readoptions_t
* roptions
,
241 rocksdb_writeoptions_t
* woptions
) {
243 db
= rocksdb_open(options
, dbname
, &err
);
245 rocksdb_put(db
, woptions
, "foo", 3, "foovalue", 8, &err
);
247 CheckGet(db
, roptions
, "foo", "foovalue");
248 rocksdb_put(db
, woptions
, "bar", 3, "barvalue", 8, &err
);
250 CheckGet(db
, roptions
, "bar", "barvalue");
251 rocksdb_put(db
, woptions
, "baz", 3, "bazvalue", 8, &err
);
253 CheckGet(db
, roptions
, "baz", "bazvalue");
256 rocksdb_compact_range(db
, NULL
, 0, NULL
, 0);
257 // should have filtered bar, but not foo
258 CheckGet(db
, roptions
, "foo", "foovalue");
259 CheckGet(db
, roptions
, "bar", NULL
);
260 CheckGet(db
, roptions
, "baz", "newbazvalue");
264 // Custom merge operator
265 static void MergeOperatorDestroy(void* arg
) { }
266 static const char* MergeOperatorName(void* arg
) {
267 return "TestMergeOperator";
269 static char* MergeOperatorFullMerge(
271 const char* key
, size_t key_length
,
272 const char* existing_value
, size_t existing_value_length
,
273 const char* const* operands_list
, const size_t* operands_list_length
,
275 unsigned char* success
, size_t* new_value_length
) {
276 *new_value_length
= 4;
278 char* result
= malloc(4);
279 memcpy(result
, "fake", 4);
282 static char* MergeOperatorPartialMerge(
284 const char* key
, size_t key_length
,
285 const char* const* operands_list
, const size_t* operands_list_length
,
287 unsigned char* success
, size_t* new_value_length
) {
288 *new_value_length
= 4;
290 char* result
= malloc(4);
291 memcpy(result
, "fake", 4);
295 int main(int argc
, char** argv
) {
297 rocksdb_comparator_t
* cmp
;
298 rocksdb_cache_t
* cache
;
300 rocksdb_options_t
* options
;
301 rocksdb_compactoptions_t
* coptions
;
302 rocksdb_block_based_table_options_t
* table_options
;
303 rocksdb_readoptions_t
* roptions
;
304 rocksdb_writeoptions_t
* woptions
;
305 rocksdb_ratelimiter_t
* rate_limiter
;
309 snprintf(dbname
, sizeof(dbname
),
310 "%s/rocksdb_c_test-%d",
314 snprintf(dbbackupname
, sizeof(dbbackupname
),
315 "%s/rocksdb_c_test-%d-backup",
319 snprintf(sstfilename
, sizeof(sstfilename
),
320 "%s/rocksdb_c_test-%d-sst",
324 StartPhase("create_objects");
325 cmp
= rocksdb_comparator_create(NULL
, CmpDestroy
, CmpCompare
, CmpName
);
326 env
= rocksdb_create_default_env();
327 cache
= rocksdb_cache_create_lru(100000);
329 options
= rocksdb_options_create();
330 rocksdb_options_set_comparator(options
, cmp
);
331 rocksdb_options_set_error_if_exists(options
, 1);
332 rocksdb_options_set_env(options
, env
);
333 rocksdb_options_set_info_log(options
, NULL
);
334 rocksdb_options_set_write_buffer_size(options
, 100000);
335 rocksdb_options_set_paranoid_checks(options
, 1);
336 rocksdb_options_set_max_open_files(options
, 10);
337 rocksdb_options_set_base_background_compactions(options
, 1);
338 table_options
= rocksdb_block_based_options_create();
339 rocksdb_block_based_options_set_block_cache(table_options
, cache
);
340 rocksdb_options_set_block_based_table_factory(options
, table_options
);
342 rocksdb_options_set_compression(options
, rocksdb_no_compression
);
343 rocksdb_options_set_compression_options(options
, -14, -1, 0, 0);
344 int compression_levels
[] = {rocksdb_no_compression
, rocksdb_no_compression
,
345 rocksdb_no_compression
, rocksdb_no_compression
};
346 rocksdb_options_set_compression_per_level(options
, compression_levels
, 4);
347 rate_limiter
= rocksdb_ratelimiter_create(1000 * 1024 * 1024, 100 * 1000, 10);
348 rocksdb_options_set_ratelimiter(options
, rate_limiter
);
349 rocksdb_ratelimiter_destroy(rate_limiter
);
351 roptions
= rocksdb_readoptions_create();
352 rocksdb_readoptions_set_verify_checksums(roptions
, 1);
353 rocksdb_readoptions_set_fill_cache(roptions
, 1);
355 woptions
= rocksdb_writeoptions_create();
356 rocksdb_writeoptions_set_sync(woptions
, 1);
358 coptions
= rocksdb_compactoptions_create();
359 rocksdb_compactoptions_set_exclusive_manual_compaction(coptions
, 1);
361 StartPhase("destroy");
362 rocksdb_destroy_db(options
, dbname
, &err
);
365 StartPhase("open_error");
366 rocksdb_open(options
, dbname
, &err
);
367 CheckCondition(err
!= NULL
);
371 rocksdb_options_set_create_if_missing(options
, 1);
372 db
= rocksdb_open(options
, dbname
, &err
);
374 CheckGet(db
, roptions
, "foo", NULL
);
377 rocksdb_put(db
, woptions
, "foo", 3, "hello", 5, &err
);
379 CheckGet(db
, roptions
, "foo", "hello");
381 StartPhase("backup_and_restore");
383 rocksdb_destroy_db(options
, dbbackupname
, &err
);
386 rocksdb_backup_engine_t
*be
= rocksdb_backup_engine_open(options
, dbbackupname
, &err
);
389 rocksdb_backup_engine_create_new_backup(be
, db
, &err
);
392 // need a change to trigger a new backup
393 rocksdb_delete(db
, woptions
, "does-not-exist", 14, &err
);
396 rocksdb_backup_engine_create_new_backup(be
, db
, &err
);
399 const rocksdb_backup_engine_info_t
* bei
= rocksdb_backup_engine_get_backup_info(be
);
400 CheckCondition(rocksdb_backup_engine_info_count(bei
) > 1);
401 rocksdb_backup_engine_info_destroy(bei
);
403 rocksdb_backup_engine_purge_old_backups(be
, 1, &err
);
406 bei
= rocksdb_backup_engine_get_backup_info(be
);
407 CheckCondition(rocksdb_backup_engine_info_count(bei
) == 1);
408 rocksdb_backup_engine_info_destroy(bei
);
410 rocksdb_delete(db
, woptions
, "foo", 3, &err
);
415 rocksdb_destroy_db(options
, dbname
, &err
);
418 rocksdb_restore_options_t
*restore_options
= rocksdb_restore_options_create();
419 rocksdb_restore_options_set_keep_log_files(restore_options
, 0);
420 rocksdb_backup_engine_restore_db_from_latest_backup(be
, dbname
, dbname
, restore_options
, &err
);
422 rocksdb_restore_options_destroy(restore_options
);
424 rocksdb_options_set_error_if_exists(options
, 0);
425 db
= rocksdb_open(options
, dbname
, &err
);
427 rocksdb_options_set_error_if_exists(options
, 1);
429 CheckGet(db
, roptions
, "foo", "hello");
431 rocksdb_backup_engine_close(be
);
434 StartPhase("compactall");
435 rocksdb_compact_range(db
, NULL
, 0, NULL
, 0);
436 CheckGet(db
, roptions
, "foo", "hello");
438 StartPhase("compactrange");
439 rocksdb_compact_range(db
, "a", 1, "z", 1);
440 CheckGet(db
, roptions
, "foo", "hello");
442 StartPhase("compactallopt");
443 rocksdb_compact_range_opt(db
, coptions
, NULL
, 0, NULL
, 0);
444 CheckGet(db
, roptions
, "foo", "hello");
446 StartPhase("compactrangeopt");
447 rocksdb_compact_range_opt(db
, coptions
, "a", 1, "z", 1);
448 CheckGet(db
, roptions
, "foo", "hello");
450 // Simple check cache usage
451 StartPhase("cache_usage");
453 rocksdb_readoptions_set_pin_data(roptions
, 1);
454 rocksdb_iterator_t
* iter
= rocksdb_create_iterator(db
, roptions
);
455 rocksdb_iter_seek(iter
, "foo", 3);
457 size_t usage
= rocksdb_cache_get_usage(cache
);
458 CheckCondition(usage
> 0);
460 size_t pin_usage
= rocksdb_cache_get_pinned_usage(cache
);
461 CheckCondition(pin_usage
> 0);
463 rocksdb_iter_next(iter
);
464 rocksdb_iter_destroy(iter
);
465 rocksdb_readoptions_set_pin_data(roptions
, 0);
468 StartPhase("addfile");
470 rocksdb_envoptions_t
* env_opt
= rocksdb_envoptions_create();
471 rocksdb_options_t
* io_options
= rocksdb_options_create();
472 rocksdb_sstfilewriter_t
* writer
=
473 rocksdb_sstfilewriter_create(env_opt
, io_options
);
476 rocksdb_sstfilewriter_open(writer
, sstfilename
, &err
);
478 rocksdb_sstfilewriter_add(writer
, "sstk1", 5, "v1", 2, &err
);
480 rocksdb_sstfilewriter_add(writer
, "sstk2", 5, "v2", 2, &err
);
482 rocksdb_sstfilewriter_add(writer
, "sstk3", 5, "v3", 2, &err
);
484 rocksdb_sstfilewriter_finish(writer
, &err
);
487 rocksdb_ingestexternalfileoptions_t
* ing_opt
=
488 rocksdb_ingestexternalfileoptions_create();
489 const char* file_list
[1] = {sstfilename
};
490 rocksdb_ingest_external_file(db
, file_list
, 1, ing_opt
, &err
);
492 CheckGet(db
, roptions
, "sstk1", "v1");
493 CheckGet(db
, roptions
, "sstk2", "v2");
494 CheckGet(db
, roptions
, "sstk3", "v3");
497 rocksdb_sstfilewriter_open(writer
, sstfilename
, &err
);
499 rocksdb_sstfilewriter_add(writer
, "sstk2", 5, "v4", 2, &err
);
501 rocksdb_sstfilewriter_add(writer
, "sstk22", 6, "v5", 2, &err
);
503 rocksdb_sstfilewriter_add(writer
, "sstk3", 5, "v6", 2, &err
);
505 rocksdb_sstfilewriter_finish(writer
, &err
);
508 rocksdb_ingest_external_file(db
, file_list
, 1, ing_opt
, &err
);
510 CheckGet(db
, roptions
, "sstk1", "v1");
511 CheckGet(db
, roptions
, "sstk2", "v4");
512 CheckGet(db
, roptions
, "sstk22", "v5");
513 CheckGet(db
, roptions
, "sstk3", "v6");
515 rocksdb_ingestexternalfileoptions_destroy(ing_opt
);
516 rocksdb_sstfilewriter_destroy(writer
);
517 rocksdb_options_destroy(io_options
);
518 rocksdb_envoptions_destroy(env_opt
);
520 // Delete all keys we just ingested
521 rocksdb_delete(db
, woptions
, "sstk1", 5, &err
);
523 rocksdb_delete(db
, woptions
, "sstk2", 5, &err
);
525 rocksdb_delete(db
, woptions
, "sstk22", 6, &err
);
527 rocksdb_delete(db
, woptions
, "sstk3", 5, &err
);
531 StartPhase("writebatch");
533 rocksdb_writebatch_t
* wb
= rocksdb_writebatch_create();
534 rocksdb_writebatch_put(wb
, "foo", 3, "a", 1);
535 rocksdb_writebatch_clear(wb
);
536 rocksdb_writebatch_put(wb
, "bar", 3, "b", 1);
537 rocksdb_writebatch_put(wb
, "box", 3, "c", 1);
538 rocksdb_writebatch_delete(wb
, "bar", 3);
539 rocksdb_write(db
, woptions
, wb
, &err
);
541 CheckGet(db
, roptions
, "foo", "hello");
542 CheckGet(db
, roptions
, "bar", NULL
);
543 CheckGet(db
, roptions
, "box", "c");
545 rocksdb_writebatch_iterate(wb
, &pos
, CheckPut
, CheckDel
);
546 CheckCondition(pos
== 3);
547 rocksdb_writebatch_clear(wb
);
548 rocksdb_writebatch_put(wb
, "bar", 3, "b", 1);
549 rocksdb_writebatch_put(wb
, "bay", 3, "d", 1);
550 rocksdb_writebatch_delete_range(wb
, "bar", 3, "bay", 3);
551 rocksdb_write(db
, woptions
, wb
, &err
);
553 CheckGet(db
, roptions
, "bar", NULL
);
554 CheckGet(db
, roptions
, "bay", "d");
555 rocksdb_writebatch_clear(wb
);
556 const char* start_list
[1] = {"bay"};
557 const size_t start_sizes
[1] = {3};
558 const char* end_list
[1] = {"baz"};
559 const size_t end_sizes
[1] = {3};
560 rocksdb_writebatch_delete_rangev(wb
, 1, start_list
, start_sizes
, end_list
,
562 rocksdb_write(db
, woptions
, wb
, &err
);
564 CheckGet(db
, roptions
, "bay", NULL
);
565 rocksdb_writebatch_destroy(wb
);
568 StartPhase("writebatch_vectors");
570 rocksdb_writebatch_t
* wb
= rocksdb_writebatch_create();
571 const char* k_list
[2] = { "z", "ap" };
572 const size_t k_sizes
[2] = { 1, 2 };
573 const char* v_list
[3] = { "x", "y", "z" };
574 const size_t v_sizes
[3] = { 1, 1, 1 };
575 rocksdb_writebatch_putv(wb
, 2, k_list
, k_sizes
, 3, v_list
, v_sizes
);
576 rocksdb_write(db
, woptions
, wb
, &err
);
578 CheckGet(db
, roptions
, "zap", "xyz");
579 rocksdb_writebatch_delete(wb
, "zap", 3);
580 rocksdb_write(db
, woptions
, wb
, &err
);
582 CheckGet(db
, roptions
, "zap", NULL
);
583 rocksdb_writebatch_destroy(wb
);
586 StartPhase("writebatch_savepoint");
588 rocksdb_writebatch_t
* wb
= rocksdb_writebatch_create();
589 rocksdb_writebatch_set_save_point(wb
);
590 const char* k_list
[2] = {"z", "ap"};
591 const size_t k_sizes
[2] = {1, 2};
592 const char* v_list
[3] = {"x", "y", "z"};
593 const size_t v_sizes
[3] = {1, 1, 1};
594 rocksdb_writebatch_putv(wb
, 2, k_list
, k_sizes
, 3, v_list
, v_sizes
);
595 rocksdb_writebatch_rollback_to_save_point(wb
, &err
);
597 rocksdb_write(db
, woptions
, wb
, &err
);
599 CheckGet(db
, roptions
, "zap", NULL
);
600 rocksdb_writebatch_destroy(wb
);
603 StartPhase("writebatch_rep");
605 rocksdb_writebatch_t
* wb1
= rocksdb_writebatch_create();
606 rocksdb_writebatch_put(wb1
, "baz", 3, "d", 1);
607 rocksdb_writebatch_put(wb1
, "quux", 4, "e", 1);
608 rocksdb_writebatch_delete(wb1
, "quux", 4);
610 const char* rep
= rocksdb_writebatch_data(wb1
, &repsize1
);
611 rocksdb_writebatch_t
* wb2
= rocksdb_writebatch_create_from(rep
, repsize1
);
612 CheckCondition(rocksdb_writebatch_count(wb1
) ==
613 rocksdb_writebatch_count(wb2
));
616 memcmp(rep
, rocksdb_writebatch_data(wb2
, &repsize2
), repsize1
) == 0);
617 rocksdb_writebatch_destroy(wb1
);
618 rocksdb_writebatch_destroy(wb2
);
621 StartPhase("writebatch_wi");
623 rocksdb_writebatch_wi_t
* wbi
= rocksdb_writebatch_wi_create(0, 1);
624 rocksdb_writebatch_wi_put(wbi
, "foo", 3, "a", 1);
625 rocksdb_writebatch_wi_clear(wbi
);
626 rocksdb_writebatch_wi_put(wbi
, "bar", 3, "b", 1);
627 rocksdb_writebatch_wi_put(wbi
, "box", 3, "c", 1);
628 rocksdb_writebatch_wi_delete(wbi
, "bar", 3);
629 int count
= rocksdb_writebatch_wi_count(wbi
);
630 CheckCondition(count
== 3);
633 value
= rocksdb_writebatch_wi_get_from_batch(wbi
, options
, "box", 3, &size
, &err
);
634 CheckValue(err
, "c", &value
, size
);
635 value
= rocksdb_writebatch_wi_get_from_batch(wbi
, options
, "bar", 3, &size
, &err
);
636 CheckValue(err
, NULL
, &value
, size
);
637 value
= rocksdb_writebatch_wi_get_from_batch_and_db(wbi
, db
, roptions
, "foo", 3, &size
, &err
);
638 CheckValue(err
, "hello", &value
, size
);
639 value
= rocksdb_writebatch_wi_get_from_batch_and_db(wbi
, db
, roptions
, "box", 3, &size
, &err
);
640 CheckValue(err
, "c", &value
, size
);
641 rocksdb_write_writebatch_wi(db
, woptions
, wbi
, &err
);
643 CheckGet(db
, roptions
, "foo", "hello");
644 CheckGet(db
, roptions
, "bar", NULL
);
645 CheckGet(db
, roptions
, "box", "c");
647 rocksdb_writebatch_wi_iterate(wbi
, &pos
, CheckPut
, CheckDel
);
648 CheckCondition(pos
== 3);
649 rocksdb_writebatch_wi_clear(wbi
);
650 rocksdb_writebatch_wi_put(wbi
, "bar", 3, "b", 1);
651 rocksdb_writebatch_wi_put(wbi
, "bay", 3, "d", 1);
652 rocksdb_writebatch_wi_delete_range(wbi
, "bar", 3, "bay", 3);
653 rocksdb_write_writebatch_wi(db
, woptions
, wbi
, &err
);
655 CheckGet(db
, roptions
, "bar", NULL
);
656 CheckGet(db
, roptions
, "bay", "d");
657 rocksdb_writebatch_wi_clear(wbi
);
658 const char* start_list
[1] = {"bay"};
659 const size_t start_sizes
[1] = {3};
660 const char* end_list
[1] = {"baz"};
661 const size_t end_sizes
[1] = {3};
662 rocksdb_writebatch_wi_delete_rangev(wbi
, 1, start_list
, start_sizes
, end_list
,
664 rocksdb_write_writebatch_wi(db
, woptions
, wbi
, &err
);
666 CheckGet(db
, roptions
, "bay", NULL
);
667 rocksdb_writebatch_wi_destroy(wbi
);
670 StartPhase("writebatch_wi_vectors");
672 rocksdb_writebatch_wi_t
* wb
= rocksdb_writebatch_wi_create(0, 1);
673 const char* k_list
[2] = { "z", "ap" };
674 const size_t k_sizes
[2] = { 1, 2 };
675 const char* v_list
[3] = { "x", "y", "z" };
676 const size_t v_sizes
[3] = { 1, 1, 1 };
677 rocksdb_writebatch_wi_putv(wb
, 2, k_list
, k_sizes
, 3, v_list
, v_sizes
);
678 rocksdb_write_writebatch_wi(db
, woptions
, wb
, &err
);
680 CheckGet(db
, roptions
, "zap", "xyz");
681 rocksdb_writebatch_wi_delete(wb
, "zap", 3);
682 rocksdb_write_writebatch_wi(db
, woptions
, wb
, &err
);
684 CheckGet(db
, roptions
, "zap", NULL
);
685 rocksdb_writebatch_wi_destroy(wb
);
688 StartPhase("writebatch_wi_savepoint");
690 rocksdb_writebatch_wi_t
* wb
= rocksdb_writebatch_wi_create(0, 1);
691 rocksdb_writebatch_wi_set_save_point(wb
);
692 const char* k_list
[2] = {"z", "ap"};
693 const size_t k_sizes
[2] = {1, 2};
694 const char* v_list
[3] = {"x", "y", "z"};
695 const size_t v_sizes
[3] = {1, 1, 1};
696 rocksdb_writebatch_wi_putv(wb
, 2, k_list
, k_sizes
, 3, v_list
, v_sizes
);
697 rocksdb_writebatch_wi_rollback_to_save_point(wb
, &err
);
699 rocksdb_write_writebatch_wi(db
, woptions
, wb
, &err
);
701 CheckGet(db
, roptions
, "zap", NULL
);
702 rocksdb_writebatch_wi_destroy(wb
);
707 rocksdb_iterator_t
* iter
= rocksdb_create_iterator(db
, roptions
);
708 CheckCondition(!rocksdb_iter_valid(iter
));
709 rocksdb_iter_seek_to_first(iter
);
710 CheckCondition(rocksdb_iter_valid(iter
));
711 CheckIter(iter
, "box", "c");
712 rocksdb_iter_next(iter
);
713 CheckIter(iter
, "foo", "hello");
714 rocksdb_iter_prev(iter
);
715 CheckIter(iter
, "box", "c");
716 rocksdb_iter_prev(iter
);
717 CheckCondition(!rocksdb_iter_valid(iter
));
718 rocksdb_iter_seek_to_last(iter
);
719 CheckIter(iter
, "foo", "hello");
720 rocksdb_iter_seek(iter
, "b", 1);
721 CheckIter(iter
, "box", "c");
722 rocksdb_iter_seek_for_prev(iter
, "g", 1);
723 CheckIter(iter
, "foo", "hello");
724 rocksdb_iter_seek_for_prev(iter
, "box", 3);
725 CheckIter(iter
, "box", "c");
726 rocksdb_iter_get_error(iter
, &err
);
728 rocksdb_iter_destroy(iter
);
731 StartPhase("wbwi_iter");
733 rocksdb_iterator_t
* base_iter
= rocksdb_create_iterator(db
, roptions
);
734 rocksdb_writebatch_wi_t
* wbi
= rocksdb_writebatch_wi_create(0, 1);
735 rocksdb_writebatch_wi_put(wbi
, "bar", 3, "b", 1);
736 rocksdb_writebatch_wi_delete(wbi
, "foo", 3);
737 rocksdb_iterator_t
* iter
= rocksdb_writebatch_wi_create_iterator_with_base(wbi
, base_iter
);
738 CheckCondition(!rocksdb_iter_valid(iter
));
739 rocksdb_iter_seek_to_first(iter
);
740 CheckCondition(rocksdb_iter_valid(iter
));
741 CheckIter(iter
, "bar", "b");
742 rocksdb_iter_next(iter
);
743 CheckIter(iter
, "box", "c");
744 rocksdb_iter_prev(iter
);
745 CheckIter(iter
, "bar", "b");
746 rocksdb_iter_prev(iter
);
747 CheckCondition(!rocksdb_iter_valid(iter
));
748 rocksdb_iter_seek_to_last(iter
);
749 CheckIter(iter
, "box", "c");
750 rocksdb_iter_seek(iter
, "b", 1);
751 CheckIter(iter
, "bar", "b");
752 rocksdb_iter_seek_for_prev(iter
, "c", 1);
753 CheckIter(iter
, "box", "c");
754 rocksdb_iter_seek_for_prev(iter
, "box", 3);
755 CheckIter(iter
, "box", "c");
756 rocksdb_iter_get_error(iter
, &err
);
758 rocksdb_iter_destroy(iter
);
759 rocksdb_writebatch_wi_destroy(wbi
);
762 StartPhase("multiget");
764 const char* keys
[3] = { "box", "foo", "notfound" };
765 const size_t keys_sizes
[3] = { 3, 3, 8 };
767 size_t vals_sizes
[3];
769 rocksdb_multi_get(db
, roptions
, 3, keys
, keys_sizes
, vals
, vals_sizes
, errs
);
772 for (i
= 0; i
< 3; i
++) {
773 CheckEqual(NULL
, errs
[i
], 0);
776 CheckEqual("c", vals
[i
], vals_sizes
[i
]);
779 CheckEqual("hello", vals
[i
], vals_sizes
[i
]);
782 CheckEqual(NULL
, vals
[i
], vals_sizes
[i
]);
789 StartPhase("approximate_sizes");
796 const char* start
[2] = { "a", "k00000000000000010000" };
797 size_t start_len
[2] = { 1, 21 };
798 const char* limit
[2] = { "k00000000000000010000", "z" };
799 size_t limit_len
[2] = { 21, 1 };
800 rocksdb_writeoptions_set_sync(woptions
, 0);
801 for (i
= 0; i
< n
; i
++) {
802 snprintf(keybuf
, sizeof(keybuf
), "k%020d", i
);
803 snprintf(valbuf
, sizeof(valbuf
), "v%020d", i
);
804 rocksdb_put(db
, woptions
, keybuf
, strlen(keybuf
), valbuf
, strlen(valbuf
),
808 rocksdb_approximate_sizes(db
, 2, start
, start_len
, limit
, limit_len
, sizes
);
809 CheckCondition(sizes
[0] > 0);
810 CheckCondition(sizes
[1] > 0);
813 StartPhase("property");
815 char* prop
= rocksdb_property_value(db
, "nosuchprop");
816 CheckCondition(prop
== NULL
);
817 prop
= rocksdb_property_value(db
, "rocksdb.stats");
818 CheckCondition(prop
!= NULL
);
822 StartPhase("snapshot");
824 const rocksdb_snapshot_t
* snap
;
825 snap
= rocksdb_create_snapshot(db
);
826 rocksdb_delete(db
, woptions
, "foo", 3, &err
);
828 rocksdb_readoptions_set_snapshot(roptions
, snap
);
829 CheckGet(db
, roptions
, "foo", "hello");
830 rocksdb_readoptions_set_snapshot(roptions
, NULL
);
831 CheckGet(db
, roptions
, "foo", NULL
);
832 rocksdb_release_snapshot(db
, snap
);
835 StartPhase("repair");
837 // If we do not compact here, then the lazy deletion of
838 // files (https://reviews.facebook.net/D6123) would leave
839 // around deleted files and the repair process will find
840 // those files and put them back into the database.
841 rocksdb_compact_range(db
, NULL
, 0, NULL
, 0);
843 rocksdb_options_set_create_if_missing(options
, 0);
844 rocksdb_options_set_error_if_exists(options
, 0);
845 rocksdb_options_set_wal_recovery_mode(options
, 2);
846 rocksdb_repair_db(options
, dbname
, &err
);
848 db
= rocksdb_open(options
, dbname
, &err
);
850 CheckGet(db
, roptions
, "foo", NULL
);
851 CheckGet(db
, roptions
, "bar", NULL
);
852 CheckGet(db
, roptions
, "box", "c");
853 rocksdb_options_set_create_if_missing(options
, 1);
854 rocksdb_options_set_error_if_exists(options
, 1);
857 StartPhase("filter");
858 for (run
= 0; run
< 2; run
++) {
859 // First run uses custom filter, second run uses bloom filter
861 rocksdb_filterpolicy_t
* policy
;
863 policy
= rocksdb_filterpolicy_create(
864 NULL
, FilterDestroy
, FilterCreate
, FilterKeyMatch
, NULL
, FilterName
);
866 policy
= rocksdb_filterpolicy_create_bloom(10);
869 rocksdb_block_based_options_set_filter_policy(table_options
, policy
);
871 // Create new database
873 rocksdb_destroy_db(options
, dbname
, &err
);
874 rocksdb_options_set_block_based_table_factory(options
, table_options
);
875 db
= rocksdb_open(options
, dbname
, &err
);
877 rocksdb_put(db
, woptions
, "foo", 3, "foovalue", 8, &err
);
879 rocksdb_put(db
, woptions
, "bar", 3, "barvalue", 8, &err
);
881 rocksdb_compact_range(db
, NULL
, 0, NULL
, 0);
883 fake_filter_result
= 1;
884 CheckGet(db
, roptions
, "foo", "foovalue");
885 CheckGet(db
, roptions
, "bar", "barvalue");
887 // Must not find value when custom filter returns false
888 fake_filter_result
= 0;
889 CheckGet(db
, roptions
, "foo", NULL
);
890 CheckGet(db
, roptions
, "bar", NULL
);
891 fake_filter_result
= 1;
893 CheckGet(db
, roptions
, "foo", "foovalue");
894 CheckGet(db
, roptions
, "bar", "barvalue");
897 rocksdb_block_based_options_set_filter_policy(table_options
, NULL
);
898 rocksdb_options_set_block_based_table_factory(options
, table_options
);
901 StartPhase("compaction_filter");
903 rocksdb_options_t
* options_with_filter
= rocksdb_options_create();
904 rocksdb_options_set_create_if_missing(options_with_filter
, 1);
905 rocksdb_compactionfilter_t
* cfilter
;
906 cfilter
= rocksdb_compactionfilter_create(NULL
, CFilterDestroy
,
907 CFilterFilter
, CFilterName
);
908 // Create new database
910 rocksdb_destroy_db(options_with_filter
, dbname
, &err
);
911 rocksdb_options_set_compaction_filter(options_with_filter
, cfilter
);
912 db
= CheckCompaction(db
, options_with_filter
, roptions
, woptions
);
914 rocksdb_options_set_compaction_filter(options_with_filter
, NULL
);
915 rocksdb_compactionfilter_destroy(cfilter
);
916 rocksdb_options_destroy(options_with_filter
);
919 StartPhase("compaction_filter_factory");
921 rocksdb_options_t
* options_with_filter_factory
= rocksdb_options_create();
922 rocksdb_options_set_create_if_missing(options_with_filter_factory
, 1);
923 rocksdb_compactionfilterfactory_t
* factory
;
924 factory
= rocksdb_compactionfilterfactory_create(
925 NULL
, CFilterFactoryDestroy
, CFilterCreate
, CFilterFactoryName
);
926 // Create new database
928 rocksdb_destroy_db(options_with_filter_factory
, dbname
, &err
);
929 rocksdb_options_set_compaction_filter_factory(options_with_filter_factory
,
931 db
= CheckCompaction(db
, options_with_filter_factory
, roptions
, woptions
);
933 rocksdb_options_set_compaction_filter_factory(
934 options_with_filter_factory
, NULL
);
935 rocksdb_options_destroy(options_with_filter_factory
);
938 StartPhase("merge_operator");
940 rocksdb_mergeoperator_t
* merge_operator
;
941 merge_operator
= rocksdb_mergeoperator_create(
942 NULL
, MergeOperatorDestroy
, MergeOperatorFullMerge
,
943 MergeOperatorPartialMerge
, NULL
, MergeOperatorName
);
944 // Create new database
946 rocksdb_destroy_db(options
, dbname
, &err
);
947 rocksdb_options_set_merge_operator(options
, merge_operator
);
948 db
= rocksdb_open(options
, dbname
, &err
);
950 rocksdb_put(db
, woptions
, "foo", 3, "foovalue", 8, &err
);
952 CheckGet(db
, roptions
, "foo", "foovalue");
953 rocksdb_merge(db
, woptions
, "foo", 3, "barvalue", 8, &err
);
955 CheckGet(db
, roptions
, "foo", "fake");
957 // Merge of a non-existing value
958 rocksdb_merge(db
, woptions
, "bar", 3, "barvalue", 8, &err
);
960 CheckGet(db
, roptions
, "bar", "fake");
964 StartPhase("columnfamilies");
967 rocksdb_destroy_db(options
, dbname
, &err
);
970 rocksdb_options_t
* db_options
= rocksdb_options_create();
971 rocksdb_options_set_create_if_missing(db_options
, 1);
972 db
= rocksdb_open(db_options
, dbname
, &err
);
974 rocksdb_column_family_handle_t
* cfh
;
975 cfh
= rocksdb_create_column_family(db
, db_options
, "cf1", &err
);
976 rocksdb_column_family_handle_destroy(cfh
);
981 char** column_fams
= rocksdb_list_column_families(db_options
, dbname
, &cflen
, &err
);
983 CheckEqual("default", column_fams
[0], 7);
984 CheckEqual("cf1", column_fams
[1], 3);
985 CheckCondition(cflen
== 2);
986 rocksdb_list_column_families_destroy(column_fams
, cflen
);
988 rocksdb_options_t
* cf_options
= rocksdb_options_create();
990 const char* cf_names
[2] = {"default", "cf1"};
991 const rocksdb_options_t
* cf_opts
[2] = {cf_options
, cf_options
};
992 rocksdb_column_family_handle_t
* handles
[2];
993 db
= rocksdb_open_column_families(db_options
, dbname
, 2, cf_names
, cf_opts
, handles
, &err
);
996 rocksdb_put_cf(db
, woptions
, handles
[1], "foo", 3, "hello", 5, &err
);
999 CheckGetCF(db
, roptions
, handles
[1], "foo", "hello");
1001 rocksdb_delete_cf(db
, woptions
, handles
[1], "foo", 3, &err
);
1004 CheckGetCF(db
, roptions
, handles
[1], "foo", NULL
);
1006 rocksdb_writebatch_t
* wb
= rocksdb_writebatch_create();
1007 rocksdb_writebatch_put_cf(wb
, handles
[1], "baz", 3, "a", 1);
1008 rocksdb_writebatch_clear(wb
);
1009 rocksdb_writebatch_put_cf(wb
, handles
[1], "bar", 3, "b", 1);
1010 rocksdb_writebatch_put_cf(wb
, handles
[1], "box", 3, "c", 1);
1011 rocksdb_writebatch_delete_cf(wb
, handles
[1], "bar", 3);
1012 rocksdb_write(db
, woptions
, wb
, &err
);
1014 CheckGetCF(db
, roptions
, handles
[1], "baz", NULL
);
1015 CheckGetCF(db
, roptions
, handles
[1], "bar", NULL
);
1016 CheckGetCF(db
, roptions
, handles
[1], "box", "c");
1017 rocksdb_writebatch_destroy(wb
);
1019 const char* keys
[3] = { "box", "box", "barfooxx" };
1020 const rocksdb_column_family_handle_t
* get_handles
[3] = { handles
[0], handles
[1], handles
[1] };
1021 const size_t keys_sizes
[3] = { 3, 3, 8 };
1023 size_t vals_sizes
[3];
1025 rocksdb_multi_get_cf(db
, roptions
, get_handles
, 3, keys
, keys_sizes
, vals
, vals_sizes
, errs
);
1028 for (i
= 0; i
< 3; i
++) {
1029 CheckEqual(NULL
, errs
[i
], 0);
1032 CheckEqual(NULL
, vals
[i
], vals_sizes
[i
]); // wrong cf
1035 CheckEqual("c", vals
[i
], vals_sizes
[i
]); // bingo
1038 CheckEqual(NULL
, vals
[i
], vals_sizes
[i
]); // normal not found
1044 rocksdb_iterator_t
* iter
= rocksdb_create_iterator_cf(db
, roptions
, handles
[1]);
1045 CheckCondition(!rocksdb_iter_valid(iter
));
1046 rocksdb_iter_seek_to_first(iter
);
1047 CheckCondition(rocksdb_iter_valid(iter
));
1049 for (i
= 0; rocksdb_iter_valid(iter
) != 0; rocksdb_iter_next(iter
)) {
1052 CheckCondition(i
== 1);
1053 rocksdb_iter_get_error(iter
, &err
);
1055 rocksdb_iter_destroy(iter
);
1057 rocksdb_column_family_handle_t
* iters_cf_handles
[2] = { handles
[0], handles
[1] };
1058 rocksdb_iterator_t
* iters_handles
[2];
1059 rocksdb_create_iterators(db
, roptions
, iters_cf_handles
, iters_handles
, 2, &err
);
1062 iter
= iters_handles
[0];
1063 CheckCondition(!rocksdb_iter_valid(iter
));
1064 rocksdb_iter_seek_to_first(iter
);
1065 CheckCondition(!rocksdb_iter_valid(iter
));
1066 rocksdb_iter_destroy(iter
);
1068 iter
= iters_handles
[1];
1069 CheckCondition(!rocksdb_iter_valid(iter
));
1070 rocksdb_iter_seek_to_first(iter
);
1071 CheckCondition(rocksdb_iter_valid(iter
));
1073 for (i
= 0; rocksdb_iter_valid(iter
) != 0; rocksdb_iter_next(iter
)) {
1076 CheckCondition(i
== 1);
1077 rocksdb_iter_get_error(iter
, &err
);
1079 rocksdb_iter_destroy(iter
);
1081 rocksdb_drop_column_family(db
, handles
[1], &err
);
1083 for (i
= 0; i
< 2; i
++) {
1084 rocksdb_column_family_handle_destroy(handles
[i
]);
1087 rocksdb_destroy_db(options
, dbname
, &err
);
1088 rocksdb_options_destroy(db_options
);
1089 rocksdb_options_destroy(cf_options
);
1092 StartPhase("prefix");
1094 // Create new database
1095 rocksdb_options_set_allow_mmap_reads(options
, 1);
1096 rocksdb_options_set_prefix_extractor(options
, rocksdb_slicetransform_create_fixed_prefix(3));
1097 rocksdb_options_set_hash_skip_list_rep(options
, 5000, 4, 4);
1098 rocksdb_options_set_plain_table_factory(options
, 4, 10, 0.75, 16);
1099 rocksdb_options_set_allow_concurrent_memtable_write(options
, 0);
1101 db
= rocksdb_open(options
, dbname
, &err
);
1104 rocksdb_put(db
, woptions
, "foo1", 4, "foo", 3, &err
);
1106 rocksdb_put(db
, woptions
, "foo2", 4, "foo", 3, &err
);
1108 rocksdb_put(db
, woptions
, "foo3", 4, "foo", 3, &err
);
1110 rocksdb_put(db
, woptions
, "bar1", 4, "bar", 3, &err
);
1112 rocksdb_put(db
, woptions
, "bar2", 4, "bar", 3, &err
);
1114 rocksdb_put(db
, woptions
, "bar3", 4, "bar", 3, &err
);
1117 rocksdb_iterator_t
* iter
= rocksdb_create_iterator(db
, roptions
);
1118 CheckCondition(!rocksdb_iter_valid(iter
));
1120 rocksdb_iter_seek(iter
, "bar", 3);
1121 rocksdb_iter_get_error(iter
, &err
);
1123 CheckCondition(rocksdb_iter_valid(iter
));
1125 CheckIter(iter
, "bar1", "bar");
1126 rocksdb_iter_next(iter
);
1127 CheckIter(iter
, "bar2", "bar");
1128 rocksdb_iter_next(iter
);
1129 CheckIter(iter
, "bar3", "bar");
1130 rocksdb_iter_get_error(iter
, &err
);
1132 rocksdb_iter_destroy(iter
);
1134 rocksdb_readoptions_set_total_order_seek(roptions
, 1);
1135 iter
= rocksdb_create_iterator(db
, roptions
);
1136 CheckCondition(!rocksdb_iter_valid(iter
));
1138 rocksdb_iter_seek(iter
, "ba", 2);
1139 rocksdb_iter_get_error(iter
, &err
);
1141 CheckCondition(rocksdb_iter_valid(iter
));
1142 CheckIter(iter
, "bar1", "bar");
1144 rocksdb_iter_destroy(iter
);
1145 rocksdb_readoptions_set_total_order_seek(roptions
, 0);
1148 rocksdb_destroy_db(options
, dbname
, &err
);
1151 StartPhase("cuckoo_options");
1153 rocksdb_cuckoo_table_options_t
* cuckoo_options
;
1154 cuckoo_options
= rocksdb_cuckoo_options_create();
1155 rocksdb_cuckoo_options_set_hash_ratio(cuckoo_options
, 0.5);
1156 rocksdb_cuckoo_options_set_max_search_depth(cuckoo_options
, 200);
1157 rocksdb_cuckoo_options_set_cuckoo_block_size(cuckoo_options
, 10);
1158 rocksdb_cuckoo_options_set_identity_as_first_hash(cuckoo_options
, 1);
1159 rocksdb_cuckoo_options_set_use_module_hash(cuckoo_options
, 0);
1160 rocksdb_options_set_cuckoo_table_factory(options
, cuckoo_options
);
1162 db
= rocksdb_open(options
, dbname
, &err
);
1165 rocksdb_cuckoo_options_destroy(cuckoo_options
);
1168 StartPhase("iterate_upper_bound");
1170 // Create new empty database
1172 rocksdb_destroy_db(options
, dbname
, &err
);
1175 rocksdb_options_set_prefix_extractor(options
, NULL
);
1176 db
= rocksdb_open(options
, dbname
, &err
);
1179 rocksdb_put(db
, woptions
, "a", 1, "0", 1, &err
); CheckNoError(err
);
1180 rocksdb_put(db
, woptions
, "foo", 3, "bar", 3, &err
); CheckNoError(err
);
1181 rocksdb_put(db
, woptions
, "foo1", 4, "bar1", 4, &err
); CheckNoError(err
);
1182 rocksdb_put(db
, woptions
, "g1", 2, "0", 1, &err
); CheckNoError(err
);
1184 // testing basic case with no iterate_upper_bound and no prefix_extractor
1186 rocksdb_readoptions_set_iterate_upper_bound(roptions
, NULL
, 0);
1187 rocksdb_iterator_t
* iter
= rocksdb_create_iterator(db
, roptions
);
1189 rocksdb_iter_seek(iter
, "foo", 3);
1190 CheckCondition(rocksdb_iter_valid(iter
));
1191 CheckIter(iter
, "foo", "bar");
1193 rocksdb_iter_next(iter
);
1194 CheckCondition(rocksdb_iter_valid(iter
));
1195 CheckIter(iter
, "foo1", "bar1");
1197 rocksdb_iter_next(iter
);
1198 CheckCondition(rocksdb_iter_valid(iter
));
1199 CheckIter(iter
, "g1", "0");
1201 rocksdb_iter_destroy(iter
);
1204 // testing iterate_upper_bound and forward iterator
1205 // to make sure it stops at bound
1207 // iterate_upper_bound points beyond the last expected entry
1208 rocksdb_readoptions_set_iterate_upper_bound(roptions
, "foo2", 4);
1210 rocksdb_iterator_t
* iter
= rocksdb_create_iterator(db
, roptions
);
1212 rocksdb_iter_seek(iter
, "foo", 3);
1213 CheckCondition(rocksdb_iter_valid(iter
));
1214 CheckIter(iter
, "foo", "bar");
1216 rocksdb_iter_next(iter
);
1217 CheckCondition(rocksdb_iter_valid(iter
));
1218 CheckIter(iter
, "foo1", "bar1");
1220 rocksdb_iter_next(iter
);
1221 // should stop here...
1222 CheckCondition(!rocksdb_iter_valid(iter
));
1224 rocksdb_iter_destroy(iter
);
1228 // Simple sanity check that setting memtable rep works.
1229 StartPhase("memtable_reps");
1231 // Create database with vector memtable.
1233 rocksdb_destroy_db(options
, dbname
, &err
);
1236 rocksdb_options_set_memtable_vector_rep(options
);
1237 db
= rocksdb_open(options
, dbname
, &err
);
1240 // Create database with hash skiplist memtable.
1242 rocksdb_destroy_db(options
, dbname
, &err
);
1245 rocksdb_options_set_hash_skip_list_rep(options
, 5000, 4, 4);
1246 db
= rocksdb_open(options
, dbname
, &err
);
1250 StartPhase("cleanup");
1252 rocksdb_options_destroy(options
);
1253 rocksdb_block_based_options_destroy(table_options
);
1254 rocksdb_readoptions_destroy(roptions
);
1255 rocksdb_writeoptions_destroy(woptions
);
1256 rocksdb_compactoptions_destroy(coptions
);
1257 rocksdb_cache_destroy(cache
);
1258 rocksdb_comparator_destroy(cmp
);
1259 rocksdb_env_destroy(env
);
1261 fprintf(stderr
, "PASS\n");
1268 fprintf(stderr
, "SKIPPED\n");
1272 #endif // !ROCKSDB_LITE