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. */
4 // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
5
6 #include <stdio.h>
7
8 #ifndef ROCKSDB_LITE // Lite does not support C API
9
10 #include "rocksdb/c.h"
11
12 #include <stddef.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #ifndef OS_WIN
17 #include <unistd.h>
18 #endif
19 #include <inttypes.h>
20
21 // Can not use port/port.h macros as this is a c file
22 #ifdef OS_WIN
23 #include <windows.h>
24
25 // Ok for uniqueness
geteuid()26 int geteuid() {
27 int result = 0;
28
29 result = ((int)GetCurrentProcessId() << 16);
30 result |= (int)GetCurrentThreadId();
31
32 return result;
33 }
34
35 // VS < 2015
36 #if defined(_MSC_VER) && (_MSC_VER < 1900)
37 #define snprintf _snprintf
38 #endif
39
40 #endif
41
42 const char* phase = "";
43 static char dbname[200];
44 static char sstfilename[200];
45 static char dbbackupname[200];
46 static char dbcheckpointname[200];
47 static char dbpathname[200];
48 static char secondary_path[200];
49
StartPhase(const char * name)50 static void StartPhase(const char* name) {
51 fprintf(stderr, "=== Test %s\n", name);
52 phase = name;
53 }
54 #ifdef _MSC_VER
55 #pragma warning(push)
56 #pragma warning (disable: 4996) // getenv security warning
57 #endif
GetTempDir(void)58 static const char* GetTempDir(void) {
59 const char* ret = getenv("TEST_TMPDIR");
60 if (ret == NULL || ret[0] == '\0')
61 ret = "/tmp";
62 return ret;
63 }
64 #ifdef _MSC_VER
65 #pragma warning(pop)
66 #endif
67
68 #define CheckNoError(err) \
69 if ((err) != NULL) { \
70 fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \
71 abort(); \
72 }
73
74 #define CheckCondition(cond) \
75 if (!(cond)) { \
76 fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \
77 abort(); \
78 }
79
CheckEqual(const char * expected,const char * v,size_t n)80 static void CheckEqual(const char* expected, const char* v, size_t n) {
81 if (expected == NULL && v == NULL) {
82 // ok
83 } else if (expected != NULL && v != NULL && n == strlen(expected) &&
84 memcmp(expected, v, n) == 0) {
85 // ok
86 return;
87 } else {
88 fprintf(stderr, "%s: expected '%s', got '%s'\n",
89 phase,
90 (expected ? expected : "(null)"),
91 (v ? v : "(null"));
92 abort();
93 }
94 }
95
Free(char ** ptr)96 static void Free(char** ptr) {
97 if (*ptr) {
98 free(*ptr);
99 *ptr = NULL;
100 }
101 }
102
CheckValue(char * err,const char * expected,char ** actual,size_t actual_length)103 static void CheckValue(
104 char* err,
105 const char* expected,
106 char** actual,
107 size_t actual_length) {
108 CheckNoError(err);
109 CheckEqual(expected, *actual, actual_length);
110 Free(actual);
111 }
112
CheckGet(rocksdb_t * db,const rocksdb_readoptions_t * options,const char * key,const char * expected)113 static void CheckGet(
114 rocksdb_t* db,
115 const rocksdb_readoptions_t* options,
116 const char* key,
117 const char* expected) {
118 char* err = NULL;
119 size_t val_len;
120 char* val;
121 val = rocksdb_get(db, options, key, strlen(key), &val_len, &err);
122 CheckNoError(err);
123 CheckEqual(expected, val, val_len);
124 Free(&val);
125 }
126
CheckGetCF(rocksdb_t * db,const rocksdb_readoptions_t * options,rocksdb_column_family_handle_t * handle,const char * key,const char * expected)127 static void CheckGetCF(
128 rocksdb_t* db,
129 const rocksdb_readoptions_t* options,
130 rocksdb_column_family_handle_t* handle,
131 const char* key,
132 const char* expected) {
133 char* err = NULL;
134 size_t val_len;
135 char* val;
136 val = rocksdb_get_cf(db, options, handle, key, strlen(key), &val_len, &err);
137 CheckNoError(err);
138 CheckEqual(expected, val, val_len);
139 Free(&val);
140 }
141
CheckPinGet(rocksdb_t * db,const rocksdb_readoptions_t * options,const char * key,const char * expected)142 static void CheckPinGet(rocksdb_t* db, const rocksdb_readoptions_t* options,
143 const char* key, const char* expected) {
144 char* err = NULL;
145 size_t val_len;
146 const char* val;
147 rocksdb_pinnableslice_t* p;
148 p = rocksdb_get_pinned(db, options, key, strlen(key), &err);
149 CheckNoError(err);
150 val = rocksdb_pinnableslice_value(p, &val_len);
151 CheckEqual(expected, val, val_len);
152 rocksdb_pinnableslice_destroy(p);
153 }
154
CheckPinGetCF(rocksdb_t * db,const rocksdb_readoptions_t * options,rocksdb_column_family_handle_t * handle,const char * key,const char * expected)155 static void CheckPinGetCF(rocksdb_t* db, const rocksdb_readoptions_t* options,
156 rocksdb_column_family_handle_t* handle,
157 const char* key, const char* expected) {
158 char* err = NULL;
159 size_t val_len;
160 const char* val;
161 rocksdb_pinnableslice_t* p;
162 p = rocksdb_get_pinned_cf(db, options, handle, key, strlen(key), &err);
163 CheckNoError(err);
164 val = rocksdb_pinnableslice_value(p, &val_len);
165 CheckEqual(expected, val, val_len);
166 rocksdb_pinnableslice_destroy(p);
167 }
168
CheckIter(rocksdb_iterator_t * iter,const char * key,const char * val)169 static void CheckIter(rocksdb_iterator_t* iter,
170 const char* key, const char* val) {
171 size_t len;
172 const char* str;
173 str = rocksdb_iter_key(iter, &len);
174 CheckEqual(key, str, len);
175 str = rocksdb_iter_value(iter, &len);
176 CheckEqual(val, str, len);
177 }
178
179 // Callback from rocksdb_writebatch_iterate()
CheckPut(void * ptr,const char * k,size_t klen,const char * v,size_t vlen)180 static void CheckPut(void* ptr,
181 const char* k, size_t klen,
182 const char* v, size_t vlen) {
183 int* state = (int*) ptr;
184 CheckCondition(*state < 2);
185 switch (*state) {
186 case 0:
187 CheckEqual("bar", k, klen);
188 CheckEqual("b", v, vlen);
189 break;
190 case 1:
191 CheckEqual("box", k, klen);
192 CheckEqual("c", v, vlen);
193 break;
194 }
195 (*state)++;
196 }
197
198 // Callback from rocksdb_writebatch_iterate()
CheckDel(void * ptr,const char * k,size_t klen)199 static void CheckDel(void* ptr, const char* k, size_t klen) {
200 int* state = (int*) ptr;
201 CheckCondition(*state == 2);
202 CheckEqual("bar", k, klen);
203 (*state)++;
204 }
205
CmpDestroy(void * arg)206 static void CmpDestroy(void* arg) { (void)arg; }
207
CmpCompare(void * arg,const char * a,size_t alen,const char * b,size_t blen)208 static int CmpCompare(void* arg, const char* a, size_t alen,
209 const char* b, size_t blen) {
210 (void)arg;
211 size_t n = (alen < blen) ? alen : blen;
212 int r = memcmp(a, b, n);
213 if (r == 0) {
214 if (alen < blen) r = -1;
215 else if (alen > blen) r = +1;
216 }
217 return r;
218 }
219
CmpName(void * arg)220 static const char* CmpName(void* arg) {
221 (void)arg;
222 return "foo";
223 }
224
225 // Custom filter policy
226 static unsigned char fake_filter_result = 1;
FilterDestroy(void * arg)227 static void FilterDestroy(void* arg) { (void)arg; }
FilterName(void * arg)228 static const char* FilterName(void* arg) {
229 (void)arg;
230 return "TestFilter";
231 }
FilterCreate(void * arg,const char * const * key_array,const size_t * key_length_array,int num_keys,size_t * filter_length)232 static char* FilterCreate(
233 void* arg,
234 const char* const* key_array, const size_t* key_length_array,
235 int num_keys,
236 size_t* filter_length) {
237 (void)arg;
238 (void)key_array;
239 (void)key_length_array;
240 (void)num_keys;
241 *filter_length = 4;
242 char* result = malloc(4);
243 memcpy(result, "fake", 4);
244 return result;
245 }
FilterKeyMatch(void * arg,const char * key,size_t length,const char * filter,size_t filter_length)246 static unsigned char FilterKeyMatch(
247 void* arg,
248 const char* key, size_t length,
249 const char* filter, size_t filter_length) {
250 (void)arg;
251 (void)key;
252 (void)length;
253 CheckCondition(filter_length == 4);
254 CheckCondition(memcmp(filter, "fake", 4) == 0);
255 return fake_filter_result;
256 }
257
258 // Custom compaction filter
CFilterDestroy(void * arg)259 static void CFilterDestroy(void* arg) { (void)arg; }
CFilterName(void * arg)260 static const char* CFilterName(void* arg) {
261 (void)arg;
262 return "foo";
263 }
CFilterFilter(void * arg,int level,const char * key,size_t key_length,const char * existing_value,size_t value_length,char ** new_value,size_t * new_value_length,unsigned char * value_changed)264 static unsigned char CFilterFilter(void* arg, int level, const char* key,
265 size_t key_length,
266 const char* existing_value,
267 size_t value_length, char** new_value,
268 size_t* new_value_length,
269 unsigned char* value_changed) {
270 (void)arg;
271 (void)level;
272 (void)existing_value;
273 (void)value_length;
274 if (key_length == 3) {
275 if (memcmp(key, "bar", key_length) == 0) {
276 return 1;
277 } else if (memcmp(key, "baz", key_length) == 0) {
278 *value_changed = 1;
279 *new_value = "newbazvalue";
280 *new_value_length = 11;
281 return 0;
282 }
283 }
284 return 0;
285 }
286
CFilterFactoryDestroy(void * arg)287 static void CFilterFactoryDestroy(void* arg) { (void)arg; }
CFilterFactoryName(void * arg)288 static const char* CFilterFactoryName(void* arg) {
289 (void)arg;
290 return "foo";
291 }
CFilterCreate(void * arg,rocksdb_compactionfiltercontext_t * context)292 static rocksdb_compactionfilter_t* CFilterCreate(
293 void* arg, rocksdb_compactionfiltercontext_t* context) {
294 (void)arg;
295 (void)context;
296 return rocksdb_compactionfilter_create(NULL, CFilterDestroy, CFilterFilter,
297 CFilterName);
298 }
299
CheckCompaction(rocksdb_t * db,rocksdb_options_t * options,rocksdb_readoptions_t * roptions,rocksdb_writeoptions_t * woptions)300 static rocksdb_t* CheckCompaction(rocksdb_t* db, rocksdb_options_t* options,
301 rocksdb_readoptions_t* roptions,
302 rocksdb_writeoptions_t* woptions) {
303 char* err = NULL;
304 db = rocksdb_open(options, dbname, &err);
305 CheckNoError(err);
306 rocksdb_put(db, woptions, "foo", 3, "foovalue", 8, &err);
307 CheckNoError(err);
308 CheckGet(db, roptions, "foo", "foovalue");
309 rocksdb_put(db, woptions, "bar", 3, "barvalue", 8, &err);
310 CheckNoError(err);
311 CheckGet(db, roptions, "bar", "barvalue");
312 rocksdb_put(db, woptions, "baz", 3, "bazvalue", 8, &err);
313 CheckNoError(err);
314 CheckGet(db, roptions, "baz", "bazvalue");
315
316 // Force compaction
317 rocksdb_compact_range(db, NULL, 0, NULL, 0);
318 // should have filtered bar, but not foo
319 CheckGet(db, roptions, "foo", "foovalue");
320 CheckGet(db, roptions, "bar", NULL);
321 CheckGet(db, roptions, "baz", "newbazvalue");
322 return db;
323 }
324
325 // Custom merge operator
MergeOperatorDestroy(void * arg)326 static void MergeOperatorDestroy(void* arg) { (void)arg; }
MergeOperatorName(void * arg)327 static const char* MergeOperatorName(void* arg) {
328 (void)arg;
329 return "TestMergeOperator";
330 }
MergeOperatorFullMerge(void * arg,const char * key,size_t key_length,const char * existing_value,size_t existing_value_length,const char * const * operands_list,const size_t * operands_list_length,int num_operands,unsigned char * success,size_t * new_value_length)331 static char* MergeOperatorFullMerge(
332 void* arg,
333 const char* key, size_t key_length,
334 const char* existing_value, size_t existing_value_length,
335 const char* const* operands_list, const size_t* operands_list_length,
336 int num_operands,
337 unsigned char* success, size_t* new_value_length) {
338 (void)arg;
339 (void)key;
340 (void)key_length;
341 (void)existing_value;
342 (void)existing_value_length;
343 (void)operands_list;
344 (void)operands_list_length;
345 (void)num_operands;
346 *new_value_length = 4;
347 *success = 1;
348 char* result = malloc(4);
349 memcpy(result, "fake", 4);
350 return result;
351 }
MergeOperatorPartialMerge(void * arg,const char * key,size_t key_length,const char * const * operands_list,const size_t * operands_list_length,int num_operands,unsigned char * success,size_t * new_value_length)352 static char* MergeOperatorPartialMerge(
353 void* arg,
354 const char* key, size_t key_length,
355 const char* const* operands_list, const size_t* operands_list_length,
356 int num_operands,
357 unsigned char* success, size_t* new_value_length) {
358 (void)arg;
359 (void)key;
360 (void)key_length;
361 (void)operands_list;
362 (void)operands_list_length;
363 (void)num_operands;
364 *new_value_length = 4;
365 *success = 1;
366 char* result = malloc(4);
367 memcpy(result, "fake", 4);
368 return result;
369 }
370
CheckTxnGet(rocksdb_transaction_t * txn,const rocksdb_readoptions_t * options,const char * key,const char * expected)371 static void CheckTxnGet(
372 rocksdb_transaction_t* txn,
373 const rocksdb_readoptions_t* options,
374 const char* key,
375 const char* expected) {
376 char* err = NULL;
377 size_t val_len;
378 char* val;
379 val = rocksdb_transaction_get(txn, options, key, strlen(key), &val_len, &err);
380 CheckNoError(err);
381 CheckEqual(expected, val, val_len);
382 Free(&val);
383 }
384
CheckTxnGetCF(rocksdb_transaction_t * txn,const rocksdb_readoptions_t * options,rocksdb_column_family_handle_t * column_family,const char * key,const char * expected)385 static void CheckTxnGetCF(rocksdb_transaction_t* txn,
386 const rocksdb_readoptions_t* options,
387 rocksdb_column_family_handle_t* column_family,
388 const char* key, const char* expected) {
389 char* err = NULL;
390 size_t val_len;
391 char* val;
392 val = rocksdb_transaction_get_cf(txn, options, column_family, key,
393 strlen(key), &val_len, &err);
394 CheckNoError(err);
395 CheckEqual(expected, val, val_len);
396 Free(&val);
397 }
398
CheckTxnDBGet(rocksdb_transactiondb_t * txn_db,const rocksdb_readoptions_t * options,const char * key,const char * expected)399 static void CheckTxnDBGet(
400 rocksdb_transactiondb_t* txn_db,
401 const rocksdb_readoptions_t* options,
402 const char* key,
403 const char* expected) {
404 char* err = NULL;
405 size_t val_len;
406 char* val;
407 val = rocksdb_transactiondb_get(txn_db, options, key, strlen(key), &val_len, &err);
408 CheckNoError(err);
409 CheckEqual(expected, val, val_len);
410 Free(&val);
411 }
412
CheckTxnDBGetCF(rocksdb_transactiondb_t * txn_db,const rocksdb_readoptions_t * options,rocksdb_column_family_handle_t * column_family,const char * key,const char * expected)413 static void CheckTxnDBGetCF(rocksdb_transactiondb_t* txn_db,
414 const rocksdb_readoptions_t* options,
415 rocksdb_column_family_handle_t* column_family,
416 const char* key, const char* expected) {
417 char* err = NULL;
418 size_t val_len;
419 char* val;
420 val = rocksdb_transactiondb_get_cf(txn_db, options, column_family, key,
421 strlen(key), &val_len, &err);
422 CheckNoError(err);
423 CheckEqual(expected, val, val_len);
424 Free(&val);
425 }
426
main(int argc,char ** argv)427 int main(int argc, char** argv) {
428 (void)argc;
429 (void)argv;
430 rocksdb_t* db;
431 rocksdb_comparator_t* cmp;
432 rocksdb_cache_t* cache;
433 rocksdb_dbpath_t *dbpath;
434 rocksdb_env_t* env;
435 rocksdb_options_t* options;
436 rocksdb_compactoptions_t* coptions;
437 rocksdb_block_based_table_options_t* table_options;
438 rocksdb_readoptions_t* roptions;
439 rocksdb_writeoptions_t* woptions;
440 rocksdb_ratelimiter_t* rate_limiter;
441 rocksdb_transactiondb_t* txn_db;
442 rocksdb_transactiondb_options_t* txn_db_options;
443 rocksdb_transaction_t* txn;
444 rocksdb_transaction_options_t* txn_options;
445 rocksdb_optimistictransactiondb_t* otxn_db;
446 rocksdb_optimistictransaction_options_t* otxn_options;
447 char* err = NULL;
448 int run = -1;
449
450 snprintf(dbname, sizeof(dbname),
451 "%s/rocksdb_c_test-%d",
452 GetTempDir(),
453 ((int) geteuid()));
454
455 snprintf(dbbackupname, sizeof(dbbackupname),
456 "%s/rocksdb_c_test-%d-backup",
457 GetTempDir(),
458 ((int) geteuid()));
459
460 snprintf(dbcheckpointname, sizeof(dbcheckpointname),
461 "%s/rocksdb_c_test-%d-checkpoint",
462 GetTempDir(),
463 ((int) geteuid()));
464
465 snprintf(sstfilename, sizeof(sstfilename),
466 "%s/rocksdb_c_test-%d-sst",
467 GetTempDir(),
468 ((int)geteuid()));
469
470 snprintf(dbpathname, sizeof(dbpathname),
471 "%s/rocksdb_c_test-%d-dbpath",
472 GetTempDir(),
473 ((int) geteuid()));
474
475 StartPhase("create_objects");
476 cmp = rocksdb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName);
477 dbpath = rocksdb_dbpath_create(dbpathname, 1024 * 1024);
478 env = rocksdb_create_default_env();
479 cache = rocksdb_cache_create_lru(100000);
480
481 options = rocksdb_options_create();
482 rocksdb_options_set_comparator(options, cmp);
483 rocksdb_options_set_error_if_exists(options, 1);
484 rocksdb_options_set_env(options, env);
485 rocksdb_options_set_info_log(options, NULL);
486 rocksdb_options_set_write_buffer_size(options, 100000);
487 rocksdb_options_set_paranoid_checks(options, 1);
488 rocksdb_options_set_max_open_files(options, 10);
489 rocksdb_options_set_base_background_compactions(options, 1);
490
491 table_options = rocksdb_block_based_options_create();
492 rocksdb_block_based_options_set_block_cache(table_options, cache);
493 rocksdb_block_based_options_set_data_block_index_type(table_options, 1);
494 rocksdb_block_based_options_set_data_block_hash_ratio(table_options, 0.75);
495 rocksdb_options_set_block_based_table_factory(options, table_options);
496
497 rocksdb_options_set_compression(options, rocksdb_no_compression);
498 rocksdb_options_set_compression_options(options, -14, -1, 0, 0);
499 int compression_levels[] = {rocksdb_no_compression, rocksdb_no_compression,
500 rocksdb_no_compression, rocksdb_no_compression};
501 rocksdb_options_set_compression_per_level(options, compression_levels, 4);
502 rate_limiter = rocksdb_ratelimiter_create(1000 * 1024 * 1024, 100 * 1000, 10);
503 rocksdb_options_set_ratelimiter(options, rate_limiter);
504 rocksdb_ratelimiter_destroy(rate_limiter);
505
506 roptions = rocksdb_readoptions_create();
507 rocksdb_readoptions_set_verify_checksums(roptions, 1);
508 rocksdb_readoptions_set_fill_cache(roptions, 1);
509
510 woptions = rocksdb_writeoptions_create();
511 rocksdb_writeoptions_set_sync(woptions, 1);
512
513 coptions = rocksdb_compactoptions_create();
514 rocksdb_compactoptions_set_exclusive_manual_compaction(coptions, 1);
515
516 StartPhase("destroy");
517 rocksdb_destroy_db(options, dbname, &err);
518 Free(&err);
519
520 StartPhase("open_error");
521 rocksdb_open(options, dbname, &err);
522 CheckCondition(err != NULL);
523 Free(&err);
524
525 StartPhase("open");
526 rocksdb_options_set_create_if_missing(options, 1);
527 db = rocksdb_open(options, dbname, &err);
528 CheckNoError(err);
529 CheckGet(db, roptions, "foo", NULL);
530
531 StartPhase("put");
532 rocksdb_put(db, woptions, "foo", 3, "hello", 5, &err);
533 CheckNoError(err);
534 CheckGet(db, roptions, "foo", "hello");
535
536 StartPhase("backup_and_restore");
537 {
538 rocksdb_destroy_db(options, dbbackupname, &err);
539 CheckNoError(err);
540
541 rocksdb_backup_engine_t *be = rocksdb_backup_engine_open(options, dbbackupname, &err);
542 CheckNoError(err);
543
544 rocksdb_backup_engine_create_new_backup(be, db, &err);
545 CheckNoError(err);
546
547 // need a change to trigger a new backup
548 rocksdb_delete(db, woptions, "does-not-exist", 14, &err);
549 CheckNoError(err);
550
551 rocksdb_backup_engine_create_new_backup(be, db, &err);
552 CheckNoError(err);
553
554 const rocksdb_backup_engine_info_t* bei = rocksdb_backup_engine_get_backup_info(be);
555 CheckCondition(rocksdb_backup_engine_info_count(bei) > 1);
556 rocksdb_backup_engine_info_destroy(bei);
557
558 rocksdb_backup_engine_purge_old_backups(be, 1, &err);
559 CheckNoError(err);
560
561 bei = rocksdb_backup_engine_get_backup_info(be);
562 CheckCondition(rocksdb_backup_engine_info_count(bei) == 1);
563 rocksdb_backup_engine_info_destroy(bei);
564
565 rocksdb_delete(db, woptions, "foo", 3, &err);
566 CheckNoError(err);
567
568 rocksdb_close(db);
569
570 rocksdb_destroy_db(options, dbname, &err);
571 CheckNoError(err);
572
573 rocksdb_restore_options_t *restore_options = rocksdb_restore_options_create();
574 rocksdb_restore_options_set_keep_log_files(restore_options, 0);
575 rocksdb_backup_engine_restore_db_from_latest_backup(be, dbname, dbname, restore_options, &err);
576 CheckNoError(err);
577 rocksdb_restore_options_destroy(restore_options);
578
579 rocksdb_options_set_error_if_exists(options, 0);
580 db = rocksdb_open(options, dbname, &err);
581 CheckNoError(err);
582 rocksdb_options_set_error_if_exists(options, 1);
583
584 CheckGet(db, roptions, "foo", "hello");
585
586 rocksdb_backup_engine_close(be);
587 }
588
589 StartPhase("checkpoint");
590 {
591 rocksdb_destroy_db(options, dbcheckpointname, &err);
592 CheckNoError(err);
593
594 rocksdb_checkpoint_t* checkpoint = rocksdb_checkpoint_object_create(db, &err);
595 CheckNoError(err);
596
597 rocksdb_checkpoint_create(checkpoint, dbcheckpointname, 0, &err);
598 CheckNoError(err);
599
600 // start a new database from the checkpoint
601 rocksdb_close(db);
602 rocksdb_options_set_error_if_exists(options, 0);
603 db = rocksdb_open(options, dbcheckpointname, &err);
604 CheckNoError(err);
605
606 CheckGet(db, roptions, "foo", "hello");
607
608 rocksdb_checkpoint_object_destroy(checkpoint);
609
610 rocksdb_close(db);
611 rocksdb_destroy_db(options, dbcheckpointname, &err);
612 CheckNoError(err);
613
614 db = rocksdb_open(options, dbname, &err);
615 CheckNoError(err);
616 rocksdb_options_set_error_if_exists(options, 1);
617 }
618
619 StartPhase("compactall");
620 rocksdb_compact_range(db, NULL, 0, NULL, 0);
621 CheckGet(db, roptions, "foo", "hello");
622
623 StartPhase("compactrange");
624 rocksdb_compact_range(db, "a", 1, "z", 1);
625 CheckGet(db, roptions, "foo", "hello");
626
627 StartPhase("compactallopt");
628 rocksdb_compact_range_opt(db, coptions, NULL, 0, NULL, 0);
629 CheckGet(db, roptions, "foo", "hello");
630
631 StartPhase("compactrangeopt");
632 rocksdb_compact_range_opt(db, coptions, "a", 1, "z", 1);
633 CheckGet(db, roptions, "foo", "hello");
634
635 // Simple check cache usage
636 StartPhase("cache_usage");
637 {
638 rocksdb_readoptions_set_pin_data(roptions, 1);
639 rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);
640 rocksdb_iter_seek(iter, "foo", 3);
641
642 size_t usage = rocksdb_cache_get_usage(cache);
643 CheckCondition(usage > 0);
644
645 size_t pin_usage = rocksdb_cache_get_pinned_usage(cache);
646 CheckCondition(pin_usage > 0);
647
648 rocksdb_iter_next(iter);
649 rocksdb_iter_destroy(iter);
650 rocksdb_readoptions_set_pin_data(roptions, 0);
651 }
652
653 StartPhase("addfile");
654 {
655 rocksdb_envoptions_t* env_opt = rocksdb_envoptions_create();
656 rocksdb_options_t* io_options = rocksdb_options_create();
657 rocksdb_sstfilewriter_t* writer =
658 rocksdb_sstfilewriter_create(env_opt, io_options);
659
660 remove(sstfilename);
661 rocksdb_sstfilewriter_open(writer, sstfilename, &err);
662 CheckNoError(err);
663 rocksdb_sstfilewriter_put(writer, "sstk1", 5, "v1", 2, &err);
664 CheckNoError(err);
665 rocksdb_sstfilewriter_put(writer, "sstk2", 5, "v2", 2, &err);
666 CheckNoError(err);
667 rocksdb_sstfilewriter_put(writer, "sstk3", 5, "v3", 2, &err);
668 CheckNoError(err);
669 rocksdb_sstfilewriter_finish(writer, &err);
670 CheckNoError(err);
671
672 rocksdb_ingestexternalfileoptions_t* ing_opt =
673 rocksdb_ingestexternalfileoptions_create();
674 const char* file_list[1] = {sstfilename};
675 rocksdb_ingest_external_file(db, file_list, 1, ing_opt, &err);
676 CheckNoError(err);
677 CheckGet(db, roptions, "sstk1", "v1");
678 CheckGet(db, roptions, "sstk2", "v2");
679 CheckGet(db, roptions, "sstk3", "v3");
680
681 remove(sstfilename);
682 rocksdb_sstfilewriter_open(writer, sstfilename, &err);
683 CheckNoError(err);
684 rocksdb_sstfilewriter_put(writer, "sstk2", 5, "v4", 2, &err);
685 CheckNoError(err);
686 rocksdb_sstfilewriter_put(writer, "sstk22", 6, "v5", 2, &err);
687 CheckNoError(err);
688 rocksdb_sstfilewriter_put(writer, "sstk3", 5, "v6", 2, &err);
689 CheckNoError(err);
690 rocksdb_sstfilewriter_finish(writer, &err);
691 CheckNoError(err);
692
693 rocksdb_ingest_external_file(db, file_list, 1, ing_opt, &err);
694 CheckNoError(err);
695 CheckGet(db, roptions, "sstk1", "v1");
696 CheckGet(db, roptions, "sstk2", "v4");
697 CheckGet(db, roptions, "sstk22", "v5");
698 CheckGet(db, roptions, "sstk3", "v6");
699
700 rocksdb_ingestexternalfileoptions_destroy(ing_opt);
701 rocksdb_sstfilewriter_destroy(writer);
702 rocksdb_options_destroy(io_options);
703 rocksdb_envoptions_destroy(env_opt);
704
705 // Delete all keys we just ingested
706 rocksdb_delete(db, woptions, "sstk1", 5, &err);
707 CheckNoError(err);
708 rocksdb_delete(db, woptions, "sstk2", 5, &err);
709 CheckNoError(err);
710 rocksdb_delete(db, woptions, "sstk22", 6, &err);
711 CheckNoError(err);
712 rocksdb_delete(db, woptions, "sstk3", 5, &err);
713 CheckNoError(err);
714 }
715
716 StartPhase("writebatch");
717 {
718 rocksdb_writebatch_t* wb = rocksdb_writebatch_create();
719 rocksdb_writebatch_put(wb, "foo", 3, "a", 1);
720 rocksdb_writebatch_clear(wb);
721 rocksdb_writebatch_put(wb, "bar", 3, "b", 1);
722 rocksdb_writebatch_put(wb, "box", 3, "c", 1);
723 rocksdb_writebatch_delete(wb, "bar", 3);
724 rocksdb_write(db, woptions, wb, &err);
725 CheckNoError(err);
726 CheckGet(db, roptions, "foo", "hello");
727 CheckGet(db, roptions, "bar", NULL);
728 CheckGet(db, roptions, "box", "c");
729 int pos = 0;
730 rocksdb_writebatch_iterate(wb, &pos, CheckPut, CheckDel);
731 CheckCondition(pos == 3);
732 rocksdb_writebatch_clear(wb);
733 rocksdb_writebatch_put(wb, "bar", 3, "b", 1);
734 rocksdb_writebatch_put(wb, "bay", 3, "d", 1);
735 rocksdb_writebatch_delete_range(wb, "bar", 3, "bay", 3);
736 rocksdb_write(db, woptions, wb, &err);
737 CheckNoError(err);
738 CheckGet(db, roptions, "bar", NULL);
739 CheckGet(db, roptions, "bay", "d");
740 rocksdb_writebatch_clear(wb);
741 const char* start_list[1] = {"bay"};
742 const size_t start_sizes[1] = {3};
743 const char* end_list[1] = {"baz"};
744 const size_t end_sizes[1] = {3};
745 rocksdb_writebatch_delete_rangev(wb, 1, start_list, start_sizes, end_list,
746 end_sizes);
747 rocksdb_write(db, woptions, wb, &err);
748 CheckNoError(err);
749 CheckGet(db, roptions, "bay", NULL);
750 rocksdb_writebatch_destroy(wb);
751 }
752
753 StartPhase("writebatch_vectors");
754 {
755 rocksdb_writebatch_t* wb = rocksdb_writebatch_create();
756 const char* k_list[2] = { "z", "ap" };
757 const size_t k_sizes[2] = { 1, 2 };
758 const char* v_list[3] = { "x", "y", "z" };
759 const size_t v_sizes[3] = { 1, 1, 1 };
760 rocksdb_writebatch_putv(wb, 2, k_list, k_sizes, 3, v_list, v_sizes);
761 rocksdb_write(db, woptions, wb, &err);
762 CheckNoError(err);
763 CheckGet(db, roptions, "zap", "xyz");
764 rocksdb_writebatch_delete(wb, "zap", 3);
765 rocksdb_write(db, woptions, wb, &err);
766 CheckNoError(err);
767 CheckGet(db, roptions, "zap", NULL);
768 rocksdb_writebatch_destroy(wb);
769 }
770
771 StartPhase("writebatch_savepoint");
772 {
773 rocksdb_writebatch_t* wb = rocksdb_writebatch_create();
774 rocksdb_writebatch_set_save_point(wb);
775 rocksdb_writebatch_set_save_point(wb);
776 const char* k_list[2] = {"z", "ap"};
777 const size_t k_sizes[2] = {1, 2};
778 const char* v_list[3] = {"x", "y", "z"};
779 const size_t v_sizes[3] = {1, 1, 1};
780 rocksdb_writebatch_pop_save_point(wb, &err);
781 CheckNoError(err);
782 rocksdb_writebatch_putv(wb, 2, k_list, k_sizes, 3, v_list, v_sizes);
783 rocksdb_writebatch_rollback_to_save_point(wb, &err);
784 CheckNoError(err);
785 rocksdb_write(db, woptions, wb, &err);
786 CheckNoError(err);
787 CheckGet(db, roptions, "zap", NULL);
788 rocksdb_writebatch_destroy(wb);
789 }
790
791 StartPhase("writebatch_rep");
792 {
793 rocksdb_writebatch_t* wb1 = rocksdb_writebatch_create();
794 rocksdb_writebatch_put(wb1, "baz", 3, "d", 1);
795 rocksdb_writebatch_put(wb1, "quux", 4, "e", 1);
796 rocksdb_writebatch_delete(wb1, "quux", 4);
797 size_t repsize1 = 0;
798 const char* rep = rocksdb_writebatch_data(wb1, &repsize1);
799 rocksdb_writebatch_t* wb2 = rocksdb_writebatch_create_from(rep, repsize1);
800 CheckCondition(rocksdb_writebatch_count(wb1) ==
801 rocksdb_writebatch_count(wb2));
802 size_t repsize2 = 0;
803 CheckCondition(
804 memcmp(rep, rocksdb_writebatch_data(wb2, &repsize2), repsize1) == 0);
805 rocksdb_writebatch_destroy(wb1);
806 rocksdb_writebatch_destroy(wb2);
807 }
808
809 StartPhase("writebatch_wi");
810 {
811 rocksdb_writebatch_wi_t* wbi = rocksdb_writebatch_wi_create(0, 1);
812 rocksdb_writebatch_wi_put(wbi, "foo", 3, "a", 1);
813 rocksdb_writebatch_wi_clear(wbi);
814 rocksdb_writebatch_wi_put(wbi, "bar", 3, "b", 1);
815 rocksdb_writebatch_wi_put(wbi, "box", 3, "c", 1);
816 rocksdb_writebatch_wi_delete(wbi, "bar", 3);
817 int count = rocksdb_writebatch_wi_count(wbi);
818 CheckCondition(count == 3);
819 size_t size;
820 char* value;
821 value = rocksdb_writebatch_wi_get_from_batch(wbi, options, "box", 3, &size, &err);
822 CheckValue(err, "c", &value, size);
823 value = rocksdb_writebatch_wi_get_from_batch(wbi, options, "bar", 3, &size, &err);
824 CheckValue(err, NULL, &value, size);
825 value = rocksdb_writebatch_wi_get_from_batch_and_db(wbi, db, roptions, "foo", 3, &size, &err);
826 CheckValue(err, "hello", &value, size);
827 value = rocksdb_writebatch_wi_get_from_batch_and_db(wbi, db, roptions, "box", 3, &size, &err);
828 CheckValue(err, "c", &value, size);
829 rocksdb_write_writebatch_wi(db, woptions, wbi, &err);
830 CheckNoError(err);
831 CheckGet(db, roptions, "foo", "hello");
832 CheckGet(db, roptions, "bar", NULL);
833 CheckGet(db, roptions, "box", "c");
834 int pos = 0;
835 rocksdb_writebatch_wi_iterate(wbi, &pos, CheckPut, CheckDel);
836 CheckCondition(pos == 3);
837 rocksdb_writebatch_wi_clear(wbi);
838 rocksdb_writebatch_wi_destroy(wbi);
839 }
840
841 StartPhase("writebatch_wi_vectors");
842 {
843 rocksdb_writebatch_wi_t* wb = rocksdb_writebatch_wi_create(0, 1);
844 const char* k_list[2] = { "z", "ap" };
845 const size_t k_sizes[2] = { 1, 2 };
846 const char* v_list[3] = { "x", "y", "z" };
847 const size_t v_sizes[3] = { 1, 1, 1 };
848 rocksdb_writebatch_wi_putv(wb, 2, k_list, k_sizes, 3, v_list, v_sizes);
849 rocksdb_write_writebatch_wi(db, woptions, wb, &err);
850 CheckNoError(err);
851 CheckGet(db, roptions, "zap", "xyz");
852 rocksdb_writebatch_wi_delete(wb, "zap", 3);
853 rocksdb_write_writebatch_wi(db, woptions, wb, &err);
854 CheckNoError(err);
855 CheckGet(db, roptions, "zap", NULL);
856 rocksdb_writebatch_wi_destroy(wb);
857 }
858
859 StartPhase("writebatch_wi_savepoint");
860 {
861 rocksdb_writebatch_wi_t* wb = rocksdb_writebatch_wi_create(0, 1);
862 rocksdb_writebatch_wi_set_save_point(wb);
863 const char* k_list[2] = {"z", "ap"};
864 const size_t k_sizes[2] = {1, 2};
865 const char* v_list[3] = {"x", "y", "z"};
866 const size_t v_sizes[3] = {1, 1, 1};
867 rocksdb_writebatch_wi_putv(wb, 2, k_list, k_sizes, 3, v_list, v_sizes);
868 rocksdb_writebatch_wi_rollback_to_save_point(wb, &err);
869 CheckNoError(err);
870 rocksdb_write_writebatch_wi(db, woptions, wb, &err);
871 CheckNoError(err);
872 CheckGet(db, roptions, "zap", NULL);
873 rocksdb_writebatch_wi_destroy(wb);
874 }
875
876 StartPhase("iter");
877 {
878 rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);
879 CheckCondition(!rocksdb_iter_valid(iter));
880 rocksdb_iter_seek_to_first(iter);
881 CheckCondition(rocksdb_iter_valid(iter));
882 CheckIter(iter, "box", "c");
883 rocksdb_iter_next(iter);
884 CheckIter(iter, "foo", "hello");
885 rocksdb_iter_prev(iter);
886 CheckIter(iter, "box", "c");
887 rocksdb_iter_prev(iter);
888 CheckCondition(!rocksdb_iter_valid(iter));
889 rocksdb_iter_seek_to_last(iter);
890 CheckIter(iter, "foo", "hello");
891 rocksdb_iter_seek(iter, "b", 1);
892 CheckIter(iter, "box", "c");
893 rocksdb_iter_seek_for_prev(iter, "g", 1);
894 CheckIter(iter, "foo", "hello");
895 rocksdb_iter_seek_for_prev(iter, "box", 3);
896 CheckIter(iter, "box", "c");
897 rocksdb_iter_get_error(iter, &err);
898 CheckNoError(err);
899 rocksdb_iter_destroy(iter);
900 }
901
902 StartPhase("wbwi_iter");
903 {
904 rocksdb_iterator_t* base_iter = rocksdb_create_iterator(db, roptions);
905 rocksdb_writebatch_wi_t* wbi = rocksdb_writebatch_wi_create(0, 1);
906 rocksdb_writebatch_wi_put(wbi, "bar", 3, "b", 1);
907 rocksdb_writebatch_wi_delete(wbi, "foo", 3);
908 rocksdb_iterator_t* iter =
909 rocksdb_writebatch_wi_create_iterator_with_base(wbi, base_iter);
910 CheckCondition(!rocksdb_iter_valid(iter));
911 rocksdb_iter_seek_to_first(iter);
912 CheckCondition(rocksdb_iter_valid(iter));
913 CheckIter(iter, "bar", "b");
914 rocksdb_iter_next(iter);
915 CheckIter(iter, "box", "c");
916 rocksdb_iter_prev(iter);
917 CheckIter(iter, "bar", "b");
918 rocksdb_iter_prev(iter);
919 CheckCondition(!rocksdb_iter_valid(iter));
920 rocksdb_iter_seek_to_last(iter);
921 CheckIter(iter, "box", "c");
922 rocksdb_iter_seek(iter, "b", 1);
923 CheckIter(iter, "bar", "b");
924 rocksdb_iter_seek_for_prev(iter, "c", 1);
925 CheckIter(iter, "box", "c");
926 rocksdb_iter_seek_for_prev(iter, "box", 3);
927 CheckIter(iter, "box", "c");
928 rocksdb_iter_get_error(iter, &err);
929 CheckNoError(err);
930 rocksdb_iter_destroy(iter);
931 rocksdb_writebatch_wi_destroy(wbi);
932 }
933
934 StartPhase("multiget");
935 {
936 const char* keys[3] = { "box", "foo", "notfound" };
937 const size_t keys_sizes[3] = { 3, 3, 8 };
938 char* vals[3];
939 size_t vals_sizes[3];
940 char* errs[3];
941 rocksdb_multi_get(db, roptions, 3, keys, keys_sizes, vals, vals_sizes, errs);
942
943 int i;
944 for (i = 0; i < 3; i++) {
945 CheckEqual(NULL, errs[i], 0);
946 switch (i) {
947 case 0:
948 CheckEqual("c", vals[i], vals_sizes[i]);
949 break;
950 case 1:
951 CheckEqual("hello", vals[i], vals_sizes[i]);
952 break;
953 case 2:
954 CheckEqual(NULL, vals[i], vals_sizes[i]);
955 break;
956 }
957 Free(&vals[i]);
958 }
959 }
960
961 StartPhase("pin_get");
962 {
963 CheckPinGet(db, roptions, "box", "c");
964 CheckPinGet(db, roptions, "foo", "hello");
965 CheckPinGet(db, roptions, "notfound", NULL);
966 }
967
968 StartPhase("approximate_sizes");
969 {
970 int i;
971 int n = 20000;
972 char keybuf[100];
973 char valbuf[100];
974 uint64_t sizes[2];
975 const char* start[2] = { "a", "k00000000000000010000" };
976 size_t start_len[2] = { 1, 21 };
977 const char* limit[2] = { "k00000000000000010000", "z" };
978 size_t limit_len[2] = { 21, 1 };
979 rocksdb_writeoptions_set_sync(woptions, 0);
980 for (i = 0; i < n; i++) {
981 snprintf(keybuf, sizeof(keybuf), "k%020d", i);
982 snprintf(valbuf, sizeof(valbuf), "v%020d", i);
983 rocksdb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf),
984 &err);
985 CheckNoError(err);
986 }
987 rocksdb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes);
988 CheckCondition(sizes[0] > 0);
989 CheckCondition(sizes[1] > 0);
990 }
991
992 StartPhase("property");
993 {
994 char* prop = rocksdb_property_value(db, "nosuchprop");
995 CheckCondition(prop == NULL);
996 prop = rocksdb_property_value(db, "rocksdb.stats");
997 CheckCondition(prop != NULL);
998 Free(&prop);
999 }
1000
1001 StartPhase("snapshot");
1002 {
1003 const rocksdb_snapshot_t* snap;
1004 snap = rocksdb_create_snapshot(db);
1005 rocksdb_delete(db, woptions, "foo", 3, &err);
1006 CheckNoError(err);
1007 rocksdb_readoptions_set_snapshot(roptions, snap);
1008 CheckGet(db, roptions, "foo", "hello");
1009 rocksdb_readoptions_set_snapshot(roptions, NULL);
1010 CheckGet(db, roptions, "foo", NULL);
1011 rocksdb_release_snapshot(db, snap);
1012 }
1013
1014 StartPhase("repair");
1015 {
1016 // If we do not compact here, then the lazy deletion of
1017 // files (https://reviews.facebook.net/D6123) would leave
1018 // around deleted files and the repair process will find
1019 // those files and put them back into the database.
1020 rocksdb_compact_range(db, NULL, 0, NULL, 0);
1021 rocksdb_close(db);
1022 rocksdb_options_set_create_if_missing(options, 0);
1023 rocksdb_options_set_error_if_exists(options, 0);
1024 rocksdb_options_set_wal_recovery_mode(options, 2);
1025 rocksdb_repair_db(options, dbname, &err);
1026 CheckNoError(err);
1027 db = rocksdb_open(options, dbname, &err);
1028 CheckNoError(err);
1029 CheckGet(db, roptions, "foo", NULL);
1030 CheckGet(db, roptions, "bar", NULL);
1031 CheckGet(db, roptions, "box", "c");
1032 rocksdb_options_set_create_if_missing(options, 1);
1033 rocksdb_options_set_error_if_exists(options, 1);
1034 }
1035
1036 StartPhase("filter");
1037 for (run = 0; run <= 2; run++) {
1038 // First run uses custom filter
1039 // Second run uses old block-based bloom filter
1040 // Third run uses full bloom filter
1041 CheckNoError(err);
1042 rocksdb_filterpolicy_t* policy;
1043 if (run == 0) {
1044 policy = rocksdb_filterpolicy_create(NULL, FilterDestroy, FilterCreate,
1045 FilterKeyMatch, NULL, FilterName);
1046 } else if (run == 1) {
1047 policy = rocksdb_filterpolicy_create_bloom(8);
1048 } else {
1049 policy = rocksdb_filterpolicy_create_bloom_full(8);
1050 }
1051 rocksdb_block_based_options_set_filter_policy(table_options, policy);
1052
1053 // Create new database
1054 rocksdb_close(db);
1055 rocksdb_destroy_db(options, dbname, &err);
1056 rocksdb_options_set_block_based_table_factory(options, table_options);
1057 db = rocksdb_open(options, dbname, &err);
1058 CheckNoError(err);
1059 rocksdb_put(db, woptions, "foo", 3, "foovalue", 8, &err);
1060 CheckNoError(err);
1061 rocksdb_put(db, woptions, "bar", 3, "barvalue", 8, &err);
1062 CheckNoError(err);
1063
1064 {
1065 // Add enough keys to get just one reasonably populated Bloom filter
1066 const int keys_to_add = 1500;
1067 int i;
1068 char keybuf[100];
1069 for (i = 0; i < keys_to_add; i++) {
1070 snprintf(keybuf, sizeof(keybuf), "yes%020d", i);
1071 rocksdb_put(db, woptions, keybuf, strlen(keybuf), "val", 3, &err);
1072 CheckNoError(err);
1073 }
1074 }
1075 rocksdb_compact_range(db, NULL, 0, NULL, 0);
1076
1077 fake_filter_result = 1;
1078 CheckGet(db, roptions, "foo", "foovalue");
1079 CheckGet(db, roptions, "bar", "barvalue");
1080 if (run == 0) {
1081 // Must not find value when custom filter returns false
1082 fake_filter_result = 0;
1083 CheckGet(db, roptions, "foo", NULL);
1084 CheckGet(db, roptions, "bar", NULL);
1085 fake_filter_result = 1;
1086
1087 CheckGet(db, roptions, "foo", "foovalue");
1088 CheckGet(db, roptions, "bar", "barvalue");
1089 }
1090
1091 {
1092 // Query some keys not added to identify Bloom filter implementation
1093 // from false positive queries, using perfcontext to detect Bloom
1094 // filter behavior
1095 rocksdb_perfcontext_t* perf = rocksdb_perfcontext_create();
1096 rocksdb_perfcontext_reset(perf);
1097
1098 const int keys_to_query = 10000;
1099 int i;
1100 char keybuf[100];
1101 for (i = 0; i < keys_to_query; i++) {
1102 fake_filter_result = i % 2;
1103 snprintf(keybuf, sizeof(keybuf), "no%020d", i);
1104 CheckGet(db, roptions, keybuf, NULL);
1105 }
1106
1107 const int hits =
1108 (int)rocksdb_perfcontext_metric(perf, rocksdb_bloom_sst_hit_count);
1109 if (run == 0) {
1110 // Due to half true, half false with fake filter result
1111 CheckCondition(hits == keys_to_query / 2);
1112 } else if (run == 1) {
1113 // Essentially a fingerprint of the block-based Bloom schema
1114 CheckCondition(hits == 241);
1115 } else {
1116 // Essentially a fingerprint of the full Bloom schema(s),
1117 // format_version < 5, which vary for three different CACHE_LINE_SIZEs
1118 CheckCondition(hits == 224 || hits == 180 || hits == 125);
1119 }
1120 CheckCondition(
1121 (keys_to_query - hits) ==
1122 (int)rocksdb_perfcontext_metric(perf, rocksdb_bloom_sst_miss_count));
1123
1124 rocksdb_perfcontext_destroy(perf);
1125 }
1126
1127 // Reset the policy
1128 rocksdb_block_based_options_set_filter_policy(table_options, NULL);
1129 rocksdb_options_set_block_based_table_factory(options, table_options);
1130 }
1131
1132 StartPhase("compaction_filter");
1133 {
1134 rocksdb_options_t* options_with_filter = rocksdb_options_create();
1135 rocksdb_options_set_create_if_missing(options_with_filter, 1);
1136 rocksdb_compactionfilter_t* cfilter;
1137 cfilter = rocksdb_compactionfilter_create(NULL, CFilterDestroy,
1138 CFilterFilter, CFilterName);
1139 // Create new database
1140 rocksdb_close(db);
1141 rocksdb_destroy_db(options_with_filter, dbname, &err);
1142 rocksdb_options_set_compaction_filter(options_with_filter, cfilter);
1143 db = CheckCompaction(db, options_with_filter, roptions, woptions);
1144
1145 rocksdb_options_set_compaction_filter(options_with_filter, NULL);
1146 rocksdb_compactionfilter_destroy(cfilter);
1147 rocksdb_options_destroy(options_with_filter);
1148 }
1149
1150 StartPhase("compaction_filter_factory");
1151 {
1152 rocksdb_options_t* options_with_filter_factory = rocksdb_options_create();
1153 rocksdb_options_set_create_if_missing(options_with_filter_factory, 1);
1154 rocksdb_compactionfilterfactory_t* factory;
1155 factory = rocksdb_compactionfilterfactory_create(
1156 NULL, CFilterFactoryDestroy, CFilterCreate, CFilterFactoryName);
1157 // Create new database
1158 rocksdb_close(db);
1159 rocksdb_destroy_db(options_with_filter_factory, dbname, &err);
1160 rocksdb_options_set_compaction_filter_factory(options_with_filter_factory,
1161 factory);
1162 db = CheckCompaction(db, options_with_filter_factory, roptions, woptions);
1163
1164 rocksdb_options_set_compaction_filter_factory(
1165 options_with_filter_factory, NULL);
1166 rocksdb_options_destroy(options_with_filter_factory);
1167 }
1168
1169 StartPhase("merge_operator");
1170 {
1171 rocksdb_mergeoperator_t* merge_operator;
1172 merge_operator = rocksdb_mergeoperator_create(
1173 NULL, MergeOperatorDestroy, MergeOperatorFullMerge,
1174 MergeOperatorPartialMerge, NULL, MergeOperatorName);
1175 // Create new database
1176 rocksdb_close(db);
1177 rocksdb_destroy_db(options, dbname, &err);
1178 rocksdb_options_set_merge_operator(options, merge_operator);
1179 db = rocksdb_open(options, dbname, &err);
1180 CheckNoError(err);
1181 rocksdb_put(db, woptions, "foo", 3, "foovalue", 8, &err);
1182 CheckNoError(err);
1183 CheckGet(db, roptions, "foo", "foovalue");
1184 rocksdb_merge(db, woptions, "foo", 3, "barvalue", 8, &err);
1185 CheckNoError(err);
1186 CheckGet(db, roptions, "foo", "fake");
1187
1188 // Merge of a non-existing value
1189 rocksdb_merge(db, woptions, "bar", 3, "barvalue", 8, &err);
1190 CheckNoError(err);
1191 CheckGet(db, roptions, "bar", "fake");
1192
1193 }
1194
1195 StartPhase("columnfamilies");
1196 {
1197 rocksdb_close(db);
1198 rocksdb_destroy_db(options, dbname, &err);
1199 CheckNoError(err);
1200
1201 rocksdb_options_t* db_options = rocksdb_options_create();
1202 rocksdb_options_set_create_if_missing(db_options, 1);
1203 db = rocksdb_open(db_options, dbname, &err);
1204 CheckNoError(err)
1205 rocksdb_column_family_handle_t* cfh;
1206 cfh = rocksdb_create_column_family(db, db_options, "cf1", &err);
1207 rocksdb_column_family_handle_destroy(cfh);
1208 CheckNoError(err);
1209 rocksdb_close(db);
1210
1211 size_t cflen;
1212 char** column_fams = rocksdb_list_column_families(db_options, dbname, &cflen, &err);
1213 CheckNoError(err);
1214 CheckEqual("default", column_fams[0], 7);
1215 CheckEqual("cf1", column_fams[1], 3);
1216 CheckCondition(cflen == 2);
1217 rocksdb_list_column_families_destroy(column_fams, cflen);
1218
1219 rocksdb_options_t* cf_options = rocksdb_options_create();
1220
1221 const char* cf_names[2] = {"default", "cf1"};
1222 const rocksdb_options_t* cf_opts[2] = {cf_options, cf_options};
1223 rocksdb_column_family_handle_t* handles[2];
1224 db = rocksdb_open_column_families(db_options, dbname, 2, cf_names, cf_opts, handles, &err);
1225 CheckNoError(err);
1226
1227 rocksdb_put_cf(db, woptions, handles[1], "foo", 3, "hello", 5, &err);
1228 CheckNoError(err);
1229
1230 rocksdb_put_cf(db, woptions, handles[1], "foobar1", 7, "hello1", 6, &err);
1231 CheckNoError(err);
1232 rocksdb_put_cf(db, woptions, handles[1], "foobar2", 7, "hello2", 6, &err);
1233 CheckNoError(err);
1234 rocksdb_put_cf(db, woptions, handles[1], "foobar3", 7, "hello3", 6, &err);
1235 CheckNoError(err);
1236 rocksdb_put_cf(db, woptions, handles[1], "foobar4", 7, "hello4", 6, &err);
1237 CheckNoError(err);
1238
1239 rocksdb_flushoptions_t *flush_options = rocksdb_flushoptions_create();
1240 rocksdb_flushoptions_set_wait(flush_options, 1);
1241 rocksdb_flush_cf(db, flush_options, handles[1], &err);
1242 CheckNoError(err)
1243 rocksdb_flushoptions_destroy(flush_options);
1244
1245 CheckGetCF(db, roptions, handles[1], "foo", "hello");
1246 CheckPinGetCF(db, roptions, handles[1], "foo", "hello");
1247
1248 rocksdb_delete_cf(db, woptions, handles[1], "foo", 3, &err);
1249 CheckNoError(err);
1250
1251 rocksdb_delete_range_cf(db, woptions, handles[1], "foobar2", 7, "foobar4",
1252 7, &err);
1253 CheckNoError(err);
1254
1255 CheckGetCF(db, roptions, handles[1], "foo", NULL);
1256 CheckPinGetCF(db, roptions, handles[1], "foo", NULL);
1257
1258 rocksdb_writebatch_t* wb = rocksdb_writebatch_create();
1259 rocksdb_writebatch_put_cf(wb, handles[1], "baz", 3, "a", 1);
1260 rocksdb_writebatch_clear(wb);
1261 rocksdb_writebatch_put_cf(wb, handles[1], "bar", 3, "b", 1);
1262 rocksdb_writebatch_put_cf(wb, handles[1], "box", 3, "c", 1);
1263 rocksdb_writebatch_delete_cf(wb, handles[1], "bar", 3);
1264 rocksdb_write(db, woptions, wb, &err);
1265 CheckNoError(err);
1266 CheckGetCF(db, roptions, handles[1], "baz", NULL);
1267 CheckGetCF(db, roptions, handles[1], "bar", NULL);
1268 CheckGetCF(db, roptions, handles[1], "box", "c");
1269 CheckPinGetCF(db, roptions, handles[1], "baz", NULL);
1270 CheckPinGetCF(db, roptions, handles[1], "bar", NULL);
1271 CheckPinGetCF(db, roptions, handles[1], "box", "c");
1272 rocksdb_writebatch_destroy(wb);
1273
1274 const char* keys[3] = { "box", "box", "barfooxx" };
1275 const rocksdb_column_family_handle_t* get_handles[3] = { handles[0], handles[1], handles[1] };
1276 const size_t keys_sizes[3] = { 3, 3, 8 };
1277 char* vals[3];
1278 size_t vals_sizes[3];
1279 char* errs[3];
1280 rocksdb_multi_get_cf(db, roptions, get_handles, 3, keys, keys_sizes, vals, vals_sizes, errs);
1281
1282 int i;
1283 for (i = 0; i < 3; i++) {
1284 CheckEqual(NULL, errs[i], 0);
1285 switch (i) {
1286 case 0:
1287 CheckEqual(NULL, vals[i], vals_sizes[i]); // wrong cf
1288 break;
1289 case 1:
1290 CheckEqual("c", vals[i], vals_sizes[i]); // bingo
1291 break;
1292 case 2:
1293 CheckEqual(NULL, vals[i], vals_sizes[i]); // normal not found
1294 break;
1295 }
1296 Free(&vals[i]);
1297 }
1298
1299 rocksdb_iterator_t* iter = rocksdb_create_iterator_cf(db, roptions, handles[1]);
1300 CheckCondition(!rocksdb_iter_valid(iter));
1301 rocksdb_iter_seek_to_first(iter);
1302 CheckCondition(rocksdb_iter_valid(iter));
1303
1304 for (i = 0; rocksdb_iter_valid(iter) != 0; rocksdb_iter_next(iter)) {
1305 i++;
1306 }
1307 CheckCondition(i == 3);
1308 rocksdb_iter_get_error(iter, &err);
1309 CheckNoError(err);
1310 rocksdb_iter_destroy(iter);
1311
1312 rocksdb_column_family_handle_t* iters_cf_handles[2] = { handles[0], handles[1] };
1313 rocksdb_iterator_t* iters_handles[2];
1314 rocksdb_create_iterators(db, roptions, iters_cf_handles, iters_handles, 2, &err);
1315 CheckNoError(err);
1316
1317 iter = iters_handles[0];
1318 CheckCondition(!rocksdb_iter_valid(iter));
1319 rocksdb_iter_seek_to_first(iter);
1320 CheckCondition(!rocksdb_iter_valid(iter));
1321 rocksdb_iter_destroy(iter);
1322
1323 iter = iters_handles[1];
1324 CheckCondition(!rocksdb_iter_valid(iter));
1325 rocksdb_iter_seek_to_first(iter);
1326 CheckCondition(rocksdb_iter_valid(iter));
1327
1328 for (i = 0; rocksdb_iter_valid(iter) != 0; rocksdb_iter_next(iter)) {
1329 i++;
1330 }
1331 CheckCondition(i == 3);
1332 rocksdb_iter_get_error(iter, &err);
1333 CheckNoError(err);
1334 rocksdb_iter_destroy(iter);
1335
1336 rocksdb_drop_column_family(db, handles[1], &err);
1337 CheckNoError(err);
1338 for (i = 0; i < 2; i++) {
1339 rocksdb_column_family_handle_destroy(handles[i]);
1340 }
1341 rocksdb_close(db);
1342 rocksdb_destroy_db(options, dbname, &err);
1343 rocksdb_options_destroy(db_options);
1344 rocksdb_options_destroy(cf_options);
1345 }
1346
1347 StartPhase("prefix");
1348 {
1349 // Create new database
1350 rocksdb_options_set_allow_mmap_reads(options, 1);
1351 rocksdb_options_set_prefix_extractor(options, rocksdb_slicetransform_create_fixed_prefix(3));
1352 rocksdb_options_set_hash_skip_list_rep(options, 5000, 4, 4);
1353 rocksdb_options_set_plain_table_factory(options, 4, 10, 0.75, 16);
1354 rocksdb_options_set_allow_concurrent_memtable_write(options, 0);
1355
1356 db = rocksdb_open(options, dbname, &err);
1357 CheckNoError(err);
1358
1359 rocksdb_put(db, woptions, "foo1", 4, "foo", 3, &err);
1360 CheckNoError(err);
1361 rocksdb_put(db, woptions, "foo2", 4, "foo", 3, &err);
1362 CheckNoError(err);
1363 rocksdb_put(db, woptions, "foo3", 4, "foo", 3, &err);
1364 CheckNoError(err);
1365 rocksdb_put(db, woptions, "bar1", 4, "bar", 3, &err);
1366 CheckNoError(err);
1367 rocksdb_put(db, woptions, "bar2", 4, "bar", 3, &err);
1368 CheckNoError(err);
1369 rocksdb_put(db, woptions, "bar3", 4, "bar", 3, &err);
1370 CheckNoError(err);
1371
1372 rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);
1373 CheckCondition(!rocksdb_iter_valid(iter));
1374
1375 rocksdb_iter_seek(iter, "bar", 3);
1376 rocksdb_iter_get_error(iter, &err);
1377 CheckNoError(err);
1378 CheckCondition(rocksdb_iter_valid(iter));
1379
1380 CheckIter(iter, "bar1", "bar");
1381 rocksdb_iter_next(iter);
1382 CheckIter(iter, "bar2", "bar");
1383 rocksdb_iter_next(iter);
1384 CheckIter(iter, "bar3", "bar");
1385 rocksdb_iter_get_error(iter, &err);
1386 CheckNoError(err);
1387 rocksdb_iter_destroy(iter);
1388
1389 rocksdb_readoptions_set_total_order_seek(roptions, 1);
1390 iter = rocksdb_create_iterator(db, roptions);
1391 CheckCondition(!rocksdb_iter_valid(iter));
1392
1393 rocksdb_iter_seek(iter, "ba", 2);
1394 rocksdb_iter_get_error(iter, &err);
1395 CheckNoError(err);
1396 CheckCondition(rocksdb_iter_valid(iter));
1397 CheckIter(iter, "bar1", "bar");
1398
1399 rocksdb_iter_destroy(iter);
1400 rocksdb_readoptions_set_total_order_seek(roptions, 0);
1401
1402 rocksdb_close(db);
1403 rocksdb_destroy_db(options, dbname, &err);
1404 }
1405
1406 // Check memory usage stats
1407 StartPhase("approximate_memory_usage");
1408 {
1409 // Create database
1410 db = rocksdb_open(options, dbname, &err);
1411 CheckNoError(err);
1412
1413 rocksdb_memory_consumers_t* consumers;
1414 consumers = rocksdb_memory_consumers_create();
1415 rocksdb_memory_consumers_add_db(consumers, db);
1416 rocksdb_memory_consumers_add_cache(consumers, cache);
1417
1418 // take memory usage report before write-read operation
1419 rocksdb_memory_usage_t* mu1;
1420 mu1 = rocksdb_approximate_memory_usage_create(consumers, &err);
1421 CheckNoError(err);
1422
1423 // Put data (this should affect memtables)
1424 rocksdb_put(db, woptions, "memory", 6, "test", 4, &err);
1425 CheckNoError(err);
1426 CheckGet(db, roptions, "memory", "test");
1427
1428 // take memory usage report after write-read operation
1429 rocksdb_memory_usage_t* mu2;
1430 mu2 = rocksdb_approximate_memory_usage_create(consumers, &err);
1431 CheckNoError(err);
1432
1433 // amount of memory used within memtables should grow
1434 CheckCondition(rocksdb_approximate_memory_usage_get_mem_table_total(mu2) >=
1435 rocksdb_approximate_memory_usage_get_mem_table_total(mu1));
1436 CheckCondition(rocksdb_approximate_memory_usage_get_mem_table_unflushed(mu2) >=
1437 rocksdb_approximate_memory_usage_get_mem_table_unflushed(mu1));
1438
1439 rocksdb_memory_consumers_destroy(consumers);
1440 rocksdb_approximate_memory_usage_destroy(mu1);
1441 rocksdb_approximate_memory_usage_destroy(mu2);
1442 rocksdb_close(db);
1443 rocksdb_destroy_db(options, dbname, &err);
1444 CheckNoError(err);
1445 }
1446
1447 StartPhase("cuckoo_options");
1448 {
1449 rocksdb_cuckoo_table_options_t* cuckoo_options;
1450 cuckoo_options = rocksdb_cuckoo_options_create();
1451 rocksdb_cuckoo_options_set_hash_ratio(cuckoo_options, 0.5);
1452 rocksdb_cuckoo_options_set_max_search_depth(cuckoo_options, 200);
1453 rocksdb_cuckoo_options_set_cuckoo_block_size(cuckoo_options, 10);
1454 rocksdb_cuckoo_options_set_identity_as_first_hash(cuckoo_options, 1);
1455 rocksdb_cuckoo_options_set_use_module_hash(cuckoo_options, 0);
1456 rocksdb_options_set_cuckoo_table_factory(options, cuckoo_options);
1457
1458 db = rocksdb_open(options, dbname, &err);
1459 CheckNoError(err);
1460
1461 rocksdb_cuckoo_options_destroy(cuckoo_options);
1462 }
1463
1464 StartPhase("iterate_upper_bound");
1465 {
1466 // Create new empty database
1467 rocksdb_close(db);
1468 rocksdb_destroy_db(options, dbname, &err);
1469 CheckNoError(err);
1470
1471 rocksdb_options_set_prefix_extractor(options, NULL);
1472 db = rocksdb_open(options, dbname, &err);
1473 CheckNoError(err);
1474
1475 rocksdb_put(db, woptions, "a", 1, "0", 1, &err); CheckNoError(err);
1476 rocksdb_put(db, woptions, "foo", 3, "bar", 3, &err); CheckNoError(err);
1477 rocksdb_put(db, woptions, "foo1", 4, "bar1", 4, &err); CheckNoError(err);
1478 rocksdb_put(db, woptions, "g1", 2, "0", 1, &err); CheckNoError(err);
1479
1480 // testing basic case with no iterate_upper_bound and no prefix_extractor
1481 {
1482 rocksdb_readoptions_set_iterate_upper_bound(roptions, NULL, 0);
1483 rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);
1484
1485 rocksdb_iter_seek(iter, "foo", 3);
1486 CheckCondition(rocksdb_iter_valid(iter));
1487 CheckIter(iter, "foo", "bar");
1488
1489 rocksdb_iter_next(iter);
1490 CheckCondition(rocksdb_iter_valid(iter));
1491 CheckIter(iter, "foo1", "bar1");
1492
1493 rocksdb_iter_next(iter);
1494 CheckCondition(rocksdb_iter_valid(iter));
1495 CheckIter(iter, "g1", "0");
1496
1497 rocksdb_iter_destroy(iter);
1498 }
1499
1500 // testing iterate_upper_bound and forward iterator
1501 // to make sure it stops at bound
1502 {
1503 // iterate_upper_bound points beyond the last expected entry
1504 rocksdb_readoptions_set_iterate_upper_bound(roptions, "foo2", 4);
1505
1506 rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);
1507
1508 rocksdb_iter_seek(iter, "foo", 3);
1509 CheckCondition(rocksdb_iter_valid(iter));
1510 CheckIter(iter, "foo", "bar");
1511
1512 rocksdb_iter_next(iter);
1513 CheckCondition(rocksdb_iter_valid(iter));
1514 CheckIter(iter, "foo1", "bar1");
1515
1516 rocksdb_iter_next(iter);
1517 // should stop here...
1518 CheckCondition(!rocksdb_iter_valid(iter));
1519
1520 rocksdb_iter_destroy(iter);
1521 rocksdb_readoptions_set_iterate_upper_bound(roptions, NULL, 0);
1522 }
1523 }
1524
1525 StartPhase("transactions");
1526 {
1527 rocksdb_close(db);
1528 rocksdb_destroy_db(options, dbname, &err);
1529 CheckNoError(err);
1530
1531 // open a TransactionDB
1532 txn_db_options = rocksdb_transactiondb_options_create();
1533 txn_options = rocksdb_transaction_options_create();
1534 rocksdb_options_set_create_if_missing(options, 1);
1535 txn_db = rocksdb_transactiondb_open(options, txn_db_options, dbname, &err);
1536 CheckNoError(err);
1537
1538 // put outside a transaction
1539 rocksdb_transactiondb_put(txn_db, woptions, "foo", 3, "hello", 5, &err);
1540 CheckNoError(err);
1541 CheckTxnDBGet(txn_db, roptions, "foo", "hello");
1542
1543 // delete from outside transaction
1544 rocksdb_transactiondb_delete(txn_db, woptions, "foo", 3, &err);
1545 CheckNoError(err);
1546 CheckTxnDBGet(txn_db, roptions, "foo", NULL);
1547
1548 // write batch into TransactionDB
1549 rocksdb_writebatch_t* wb = rocksdb_writebatch_create();
1550 rocksdb_writebatch_put(wb, "foo", 3, "a", 1);
1551 rocksdb_writebatch_clear(wb);
1552 rocksdb_writebatch_put(wb, "bar", 3, "b", 1);
1553 rocksdb_writebatch_put(wb, "box", 3, "c", 1);
1554 rocksdb_writebatch_delete(wb, "bar", 3);
1555 rocksdb_transactiondb_write(txn_db, woptions, wb, &err);
1556 rocksdb_writebatch_destroy(wb);
1557 CheckTxnDBGet(txn_db, roptions, "box", "c");
1558 CheckNoError(err);
1559
1560 // begin a transaction
1561 txn = rocksdb_transaction_begin(txn_db, woptions, txn_options, NULL);
1562 // put
1563 rocksdb_transaction_put(txn, "foo", 3, "hello", 5, &err);
1564 CheckNoError(err);
1565 CheckTxnGet(txn, roptions, "foo", "hello");
1566 // delete
1567 rocksdb_transaction_delete(txn, "foo", 3, &err);
1568 CheckNoError(err);
1569 CheckTxnGet(txn, roptions, "foo", NULL);
1570
1571 rocksdb_transaction_put(txn, "foo", 3, "hello", 5, &err);
1572 CheckNoError(err);
1573
1574 // read from outside transaction, before commit
1575 CheckTxnDBGet(txn_db, roptions, "foo", NULL);
1576
1577 // commit
1578 rocksdb_transaction_commit(txn, &err);
1579 CheckNoError(err);
1580
1581 // read from outside transaction, after commit
1582 CheckTxnDBGet(txn_db, roptions, "foo", "hello");
1583
1584 // reuse old transaction
1585 txn = rocksdb_transaction_begin(txn_db, woptions, txn_options, txn);
1586
1587 // snapshot
1588 const rocksdb_snapshot_t* snapshot;
1589 snapshot = rocksdb_transactiondb_create_snapshot(txn_db);
1590 rocksdb_readoptions_set_snapshot(roptions, snapshot);
1591
1592 rocksdb_transactiondb_put(txn_db, woptions, "foo", 3, "hey", 3, &err);
1593 CheckNoError(err);
1594
1595 CheckTxnDBGet(txn_db, roptions, "foo", "hello");
1596 rocksdb_readoptions_set_snapshot(roptions, NULL);
1597 rocksdb_transactiondb_release_snapshot(txn_db, snapshot);
1598 CheckTxnDBGet(txn_db, roptions, "foo", "hey");
1599
1600 // iterate
1601 rocksdb_transaction_put(txn, "bar", 3, "hi", 2, &err);
1602 rocksdb_iterator_t* iter = rocksdb_transaction_create_iterator(txn, roptions);
1603 CheckCondition(!rocksdb_iter_valid(iter));
1604 rocksdb_iter_seek_to_first(iter);
1605 CheckCondition(rocksdb_iter_valid(iter));
1606 CheckIter(iter, "bar", "hi");
1607 rocksdb_iter_get_error(iter, &err);
1608 CheckNoError(err);
1609 rocksdb_iter_destroy(iter);
1610
1611 // rollback
1612 rocksdb_transaction_rollback(txn, &err);
1613 CheckNoError(err);
1614 CheckTxnDBGet(txn_db, roptions, "bar", NULL);
1615
1616 // save point
1617 rocksdb_transaction_put(txn, "foo1", 4, "hi1", 3, &err);
1618 rocksdb_transaction_set_savepoint(txn);
1619 CheckTxnGet(txn, roptions, "foo1", "hi1");
1620 rocksdb_transaction_put(txn, "foo2", 4, "hi2", 3, &err);
1621 CheckTxnGet(txn, roptions, "foo2", "hi2");
1622
1623 // rollback to savepoint
1624 rocksdb_transaction_rollback_to_savepoint(txn, &err);
1625 CheckNoError(err);
1626 CheckTxnGet(txn, roptions, "foo2", NULL);
1627 CheckTxnGet(txn, roptions, "foo1", "hi1");
1628 CheckTxnDBGet(txn_db, roptions, "foo1", NULL);
1629 CheckTxnDBGet(txn_db, roptions, "foo2", NULL);
1630 rocksdb_transaction_commit(txn, &err);
1631 CheckNoError(err);
1632 CheckTxnDBGet(txn_db, roptions, "foo1", "hi1");
1633 CheckTxnDBGet(txn_db, roptions, "foo2", NULL);
1634
1635 // Column families.
1636 rocksdb_column_family_handle_t* cfh;
1637 cfh = rocksdb_transactiondb_create_column_family(txn_db, options,
1638 "txn_db_cf", &err);
1639 CheckNoError(err);
1640
1641 rocksdb_transactiondb_put_cf(txn_db, woptions, cfh, "cf_foo", 6, "cf_hello",
1642 8, &err);
1643 CheckNoError(err);
1644 CheckTxnDBGetCF(txn_db, roptions, cfh, "cf_foo", "cf_hello");
1645
1646 rocksdb_transactiondb_delete_cf(txn_db, woptions, cfh, "cf_foo", 6, &err);
1647 CheckNoError(err);
1648 CheckTxnDBGetCF(txn_db, roptions, cfh, "cf_foo", NULL);
1649
1650 rocksdb_column_family_handle_destroy(cfh);
1651
1652 // close and destroy
1653 rocksdb_transaction_destroy(txn);
1654 rocksdb_transactiondb_close(txn_db);
1655 rocksdb_destroy_db(options, dbname, &err);
1656 CheckNoError(err);
1657 rocksdb_transaction_options_destroy(txn_options);
1658 rocksdb_transactiondb_options_destroy(txn_db_options);
1659 }
1660
1661 StartPhase("optimistic_transactions");
1662 {
1663 rocksdb_options_t* db_options = rocksdb_options_create();
1664 rocksdb_options_set_create_if_missing(db_options, 1);
1665 rocksdb_options_set_allow_concurrent_memtable_write(db_options, 1);
1666 otxn_db = rocksdb_optimistictransactiondb_open(db_options, dbname, &err);
1667 otxn_options = rocksdb_optimistictransaction_options_create();
1668 rocksdb_transaction_t* txn1 = rocksdb_optimistictransaction_begin(
1669 otxn_db, woptions, otxn_options, NULL);
1670 rocksdb_transaction_t* txn2 = rocksdb_optimistictransaction_begin(
1671 otxn_db, woptions, otxn_options, NULL);
1672 rocksdb_transaction_put(txn1, "key", 3, "value", 5, &err);
1673 CheckNoError(err);
1674 rocksdb_transaction_put(txn2, "key1", 4, "value1", 6, &err);
1675 CheckNoError(err);
1676 CheckTxnGet(txn1, roptions, "key", "value");
1677 rocksdb_transaction_commit(txn1, &err);
1678 CheckNoError(err);
1679 rocksdb_transaction_commit(txn2, &err);
1680 CheckNoError(err);
1681 rocksdb_transaction_destroy(txn1);
1682 rocksdb_transaction_destroy(txn2);
1683
1684 // Check column family
1685 db = rocksdb_optimistictransactiondb_get_base_db(otxn_db);
1686 rocksdb_put(db, woptions, "key", 3, "value", 5, &err);
1687 CheckNoError(err);
1688 rocksdb_column_family_handle_t *cfh1, *cfh2;
1689 cfh1 = rocksdb_create_column_family(db, db_options, "txn_db_cf1", &err);
1690 cfh2 = rocksdb_create_column_family(db, db_options, "txn_db_cf2", &err);
1691 txn = rocksdb_optimistictransaction_begin(otxn_db, woptions, otxn_options,
1692 NULL);
1693 rocksdb_transaction_put_cf(txn, cfh1, "key_cf1", 7, "val_cf1", 7, &err);
1694 CheckNoError(err);
1695 rocksdb_transaction_put_cf(txn, cfh2, "key_cf2", 7, "val_cf2", 7, &err);
1696 CheckNoError(err);
1697 rocksdb_transaction_commit(txn, &err);
1698 CheckNoError(err);
1699 txn = rocksdb_optimistictransaction_begin(otxn_db, woptions, otxn_options,
1700 txn);
1701 CheckGetCF(db, roptions, cfh1, "key_cf1", "val_cf1");
1702 CheckTxnGetCF(txn, roptions, cfh1, "key_cf1", "val_cf1");
1703
1704 // Check iterator with column family
1705 rocksdb_transaction_put_cf(txn, cfh1, "key1_cf", 7, "val1_cf", 7, &err);
1706 CheckNoError(err);
1707 rocksdb_iterator_t* iter =
1708 rocksdb_transaction_create_iterator_cf(txn, roptions, cfh1);
1709 CheckCondition(!rocksdb_iter_valid(iter));
1710 rocksdb_iter_seek_to_first(iter);
1711 CheckCondition(rocksdb_iter_valid(iter));
1712 CheckIter(iter, "key1_cf", "val1_cf");
1713 rocksdb_iter_get_error(iter, &err);
1714 CheckNoError(err);
1715 rocksdb_iter_destroy(iter);
1716
1717 rocksdb_transaction_destroy(txn);
1718 rocksdb_column_family_handle_destroy(cfh1);
1719 rocksdb_column_family_handle_destroy(cfh2);
1720 rocksdb_optimistictransactiondb_close_base_db(db);
1721 rocksdb_optimistictransactiondb_close(otxn_db);
1722
1723 // Check open optimistic transaction db with column families
1724 size_t cf_len;
1725 char** column_fams =
1726 rocksdb_list_column_families(db_options, dbname, &cf_len, &err);
1727 CheckNoError(err);
1728 CheckEqual("default", column_fams[0], 7);
1729 CheckEqual("txn_db_cf1", column_fams[1], 10);
1730 CheckEqual("txn_db_cf2", column_fams[2], 10);
1731 CheckCondition(cf_len == 3);
1732 rocksdb_list_column_families_destroy(column_fams, cf_len);
1733
1734 const char* cf_names[3] = {"default", "txn_db_cf1", "txn_db_cf2"};
1735 rocksdb_options_t* cf_options = rocksdb_options_create();
1736 const rocksdb_options_t* cf_opts[3] = {cf_options, cf_options, cf_options};
1737
1738 rocksdb_options_set_error_if_exists(cf_options, 0);
1739 rocksdb_column_family_handle_t* cf_handles[3];
1740 otxn_db = rocksdb_optimistictransactiondb_open_column_families(
1741 db_options, dbname, 3, cf_names, cf_opts, cf_handles, &err);
1742 CheckNoError(err);
1743 rocksdb_transaction_t* txn_cf = rocksdb_optimistictransaction_begin(
1744 otxn_db, woptions, otxn_options, NULL);
1745 CheckTxnGetCF(txn_cf, roptions, cf_handles[0], "key", "value");
1746 CheckTxnGetCF(txn_cf, roptions, cf_handles[1], "key_cf1", "val_cf1");
1747 CheckTxnGetCF(txn_cf, roptions, cf_handles[2], "key_cf2", "val_cf2");
1748 rocksdb_transaction_destroy(txn_cf);
1749 rocksdb_options_destroy(cf_options);
1750 rocksdb_column_family_handle_destroy(cf_handles[0]);
1751 rocksdb_column_family_handle_destroy(cf_handles[1]);
1752 rocksdb_column_family_handle_destroy(cf_handles[2]);
1753 rocksdb_optimistictransactiondb_close(otxn_db);
1754 rocksdb_destroy_db(db_options, dbname, &err);
1755 rocksdb_options_destroy(db_options);
1756 rocksdb_optimistictransaction_options_destroy(otxn_options);
1757 CheckNoError(err);
1758 }
1759
1760 // Simple sanity check that setting memtable rep works.
1761 StartPhase("memtable_reps");
1762 {
1763 // Create database with vector memtable.
1764 rocksdb_options_set_memtable_vector_rep(options);
1765 db = rocksdb_open(options, dbname, &err);
1766 CheckNoError(err);
1767
1768 // Create database with hash skiplist memtable.
1769 rocksdb_close(db);
1770 rocksdb_destroy_db(options, dbname, &err);
1771 CheckNoError(err);
1772
1773 rocksdb_options_set_hash_skip_list_rep(options, 5000, 4, 4);
1774 db = rocksdb_open(options, dbname, &err);
1775 CheckNoError(err);
1776 }
1777
1778 // Check that secondary instance works.
1779 StartPhase("open_as_secondary");
1780 {
1781 rocksdb_close(db);
1782 rocksdb_destroy_db(options, dbname, &err);
1783
1784 rocksdb_options_t* db_options = rocksdb_options_create();
1785 rocksdb_options_set_create_if_missing(db_options, 1);
1786 db = rocksdb_open(db_options, dbname, &err);
1787 CheckNoError(err);
1788 rocksdb_t* db1;
1789 rocksdb_options_t* opts = rocksdb_options_create();
1790 rocksdb_options_set_max_open_files(opts, -1);
1791 rocksdb_options_set_create_if_missing(opts, 1);
1792 snprintf(secondary_path, sizeof(secondary_path),
1793 "%s/rocksdb_c_test_secondary-%d", GetTempDir(), ((int)geteuid()));
1794 db1 = rocksdb_open_as_secondary(opts, dbname, secondary_path, &err);
1795 CheckNoError(err);
1796
1797 rocksdb_writeoptions_set_sync(woptions, 0);
1798 rocksdb_writeoptions_disable_WAL(woptions, 1);
1799 rocksdb_put(db, woptions, "key0", 4, "value0", 6, &err);
1800 CheckNoError(err);
1801 rocksdb_flushoptions_t* flush_opts = rocksdb_flushoptions_create();
1802 rocksdb_flushoptions_set_wait(flush_opts, 1);
1803 rocksdb_flush(db, flush_opts, &err);
1804 CheckNoError(err);
1805 rocksdb_try_catch_up_with_primary(db1, &err);
1806 CheckNoError(err);
1807 rocksdb_readoptions_t* ropts = rocksdb_readoptions_create();
1808 rocksdb_readoptions_set_verify_checksums(ropts, 1);
1809 rocksdb_readoptions_set_snapshot(ropts, NULL);
1810 CheckGet(db, ropts, "key0", "value0");
1811 CheckGet(db1, ropts, "key0", "value0");
1812
1813 rocksdb_writeoptions_disable_WAL(woptions, 0);
1814 rocksdb_put(db, woptions, "key1", 4, "value1", 6, &err);
1815 CheckNoError(err);
1816 rocksdb_try_catch_up_with_primary(db1, &err);
1817 CheckNoError(err);
1818 CheckGet(db1, ropts, "key0", "value0");
1819 CheckGet(db1, ropts, "key1", "value1");
1820
1821 rocksdb_close(db1);
1822 rocksdb_destroy_db(opts, secondary_path, &err);
1823 CheckNoError(err);
1824
1825 rocksdb_options_destroy(db_options);
1826 rocksdb_options_destroy(opts);
1827 rocksdb_readoptions_destroy(ropts);
1828 rocksdb_flushoptions_destroy(flush_opts);
1829 }
1830
1831 // Simple sanity check that options setting db_paths work.
1832 StartPhase("open_db_paths");
1833 {
1834 rocksdb_close(db);
1835 rocksdb_destroy_db(options, dbname, &err);
1836
1837 const rocksdb_dbpath_t* paths[1] = {dbpath};
1838 rocksdb_options_set_db_paths(options, paths, 1);
1839 db = rocksdb_open(options, dbname, &err);
1840 CheckNoError(err);
1841 }
1842
1843 StartPhase("cleanup");
1844 rocksdb_close(db);
1845 rocksdb_options_destroy(options);
1846 rocksdb_block_based_options_destroy(table_options);
1847 rocksdb_readoptions_destroy(roptions);
1848 rocksdb_writeoptions_destroy(woptions);
1849 rocksdb_compactoptions_destroy(coptions);
1850 rocksdb_cache_destroy(cache);
1851 rocksdb_comparator_destroy(cmp);
1852 rocksdb_dbpath_destroy(dbpath);
1853 rocksdb_env_destroy(env);
1854
1855 fprintf(stderr, "PASS\n");
1856 return 0;
1857 }
1858
1859 #else
1860
main()1861 int main() {
1862 fprintf(stderr, "SKIPPED\n");
1863 return 0;
1864 }
1865
1866 #endif // !ROCKSDB_LITE
1867