c_test.c 31.4 KB
Newer Older
1 2 3 4
/* Copyright (c) 2011 The LevelDB Authors. All rights reserved.
   Use of this source code is governed by a BSD-style license that can be
   found in the LICENSE file. See the AUTHORS file for names of contributors. */

5
#include "rocksdb/c.h"
6 7 8 9 10 11 12

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
13
#include <inttypes.h>
14 15 16

const char* phase = "";
static char dbname[200];
17
static char dbbackupname[200];
18 19 20 21 22 23

static void StartPhase(const char* name) {
  fprintf(stderr, "=== Test %s\n", name);
  phase = name;
}

H
heyongqiang 已提交
24 25 26 27 28 29 30
static const char* GetTempDir(void) {
    const char* ret = getenv("TEST_TMPDIR");
    if (ret == NULL || ret[0] == '\0')
        ret = "/tmp";
    return ret;
}

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
#define CheckNoError(err)                                               \
  if ((err) != NULL) {                                                  \
    fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \
    abort();                                                            \
  }

#define CheckCondition(cond)                                            \
  if (!(cond)) {                                                        \
    fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \
    abort();                                                            \
  }

static void CheckEqual(const char* expected, const char* v, size_t n) {
  if (expected == NULL && v == NULL) {
    // ok
  } else if (expected != NULL && v != NULL && n == strlen(expected) &&
             memcmp(expected, v, n) == 0) {
    // ok
    return;
  } else {
    fprintf(stderr, "%s: expected '%s', got '%s'\n",
            phase,
            (expected ? expected : "(null)"),
            (v ? v : "(null"));
    abort();
  }
}

static void Free(char** ptr) {
  if (*ptr) {
    free(*ptr);
    *ptr = NULL;
  }
}

static void CheckGet(
67 68
    rocksdb_t* db,
    const rocksdb_readoptions_t* options,
69 70 71 72 73
    const char* key,
    const char* expected) {
  char* err = NULL;
  size_t val_len;
  char* val;
74
  val = rocksdb_get(db, options, key, strlen(key), &val_len, &err);
75 76 77 78 79
  CheckNoError(err);
  CheckEqual(expected, val, val_len);
  Free(&val);
}

R
Reed Allman 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
static void CheckGetCF(
    rocksdb_t* db,
    const rocksdb_readoptions_t* options,
    rocksdb_column_family_handle_t* handle,
    const char* key,
    const char* expected) {
  char* err = NULL;
  size_t val_len;
  char* val;
  val = rocksdb_get_cf(db, options, handle, key, strlen(key), &val_len, &err);
  CheckNoError(err);
  CheckEqual(expected, val, val_len);
  Free(&val);
}


96
static void CheckIter(rocksdb_iterator_t* iter,
97 98 99
                      const char* key, const char* val) {
  size_t len;
  const char* str;
100
  str = rocksdb_iter_key(iter, &len);
101
  CheckEqual(key, str, len);
102
  str = rocksdb_iter_value(iter, &len);
103 104 105
  CheckEqual(val, str, len);
}

106
// Callback from rocksdb_writebatch_iterate()
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
static void CheckPut(void* ptr,
                     const char* k, size_t klen,
                     const char* v, size_t vlen) {
  int* state = (int*) ptr;
  CheckCondition(*state < 2);
  switch (*state) {
    case 0:
      CheckEqual("bar", k, klen);
      CheckEqual("b", v, vlen);
      break;
    case 1:
      CheckEqual("box", k, klen);
      CheckEqual("c", v, vlen);
      break;
  }
  (*state)++;
}

125
// Callback from rocksdb_writebatch_iterate()
126 127 128 129 130 131 132 133 134 135 136
static void CheckDel(void* ptr, const char* k, size_t klen) {
  int* state = (int*) ptr;
  CheckCondition(*state == 2);
  CheckEqual("bar", k, klen);
  (*state)++;
}

static void CmpDestroy(void* arg) { }

static int CmpCompare(void* arg, const char* a, size_t alen,
                      const char* b, size_t blen) {
137
  size_t n = (alen < blen) ? alen : blen;
138 139 140 141 142 143 144 145 146 147 148 149
  int r = memcmp(a, b, n);
  if (r == 0) {
    if (alen < blen) r = -1;
    else if (alen > blen) r = +1;
  }
  return r;
}

static const char* CmpName(void* arg) {
  return "foo";
}

S
Sanjay Ghemawat 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
// Custom filter policy
static unsigned char fake_filter_result = 1;
static void FilterDestroy(void* arg) { }
static const char* FilterName(void* arg) {
  return "TestFilter";
}
static char* FilterCreate(
    void* arg,
    const char* const* key_array, const size_t* key_length_array,
    int num_keys,
    size_t* filter_length) {
  *filter_length = 4;
  char* result = malloc(4);
  memcpy(result, "fake", 4);
  return result;
}
I
Igor Canadi 已提交
166
static unsigned char FilterKeyMatch(
S
Sanjay Ghemawat 已提交
167 168 169 170 171 172 173 174
    void* arg,
    const char* key, size_t length,
    const char* filter, size_t filter_length) {
  CheckCondition(filter_length == 4);
  CheckCondition(memcmp(filter, "fake", 4) == 0);
  return fake_filter_result;
}

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
// Custom compaction filter
static void CFilterDestroy(void* arg) {}
static const char* CFilterName(void* arg) { return "foo"; }
static unsigned char 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) {
  if (key_length == 3) {
    if (memcmp(key, "bar", key_length) == 0) {
      return 1;
    } else if (memcmp(key, "baz", key_length) == 0) {
      *value_changed = 1;
      *new_value = "newbazvalue";
      *new_value_length = 11;
      return 0;
    }
  }
  return 0;
}

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
static void CFilterFactoryDestroy(void* arg) {}
static const char* CFilterFactoryName(void* arg) { return "foo"; }
static rocksdb_compactionfilter_t* CFilterCreate(
    void* arg, rocksdb_compactionfiltercontext_t* context) {
  return rocksdb_compactionfilter_create(NULL, CFilterDestroy, CFilterFilter,
                                         CFilterName);
}

static rocksdb_t* CheckCompaction(rocksdb_t* db, rocksdb_options_t* options,
                                  rocksdb_readoptions_t* roptions,
                                  rocksdb_writeoptions_t* woptions) {
  char* err = NULL;
  db = rocksdb_open(options, dbname, &err);
  CheckNoError(err);
  rocksdb_put(db, woptions, "foo", 3, "foovalue", 8, &err);
  CheckNoError(err);
  CheckGet(db, roptions, "foo", "foovalue");
  rocksdb_put(db, woptions, "bar", 3, "barvalue", 8, &err);
  CheckNoError(err);
  CheckGet(db, roptions, "bar", "barvalue");
  rocksdb_put(db, woptions, "baz", 3, "bazvalue", 8, &err);
  CheckNoError(err);
  CheckGet(db, roptions, "baz", "bazvalue");

  // Force compaction
  rocksdb_compact_range(db, NULL, 0, NULL, 0);
  // should have filtered bar, but not foo
  CheckGet(db, roptions, "foo", "foovalue");
  CheckGet(db, roptions, "bar", NULL);
  CheckGet(db, roptions, "baz", "newbazvalue");
  return db;
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
// Custom compaction filter V2.
static void CompactionFilterV2Destroy(void* arg) { }
static const char* CompactionFilterV2Name(void* arg) {
  return "TestCompactionFilterV2";
}
static void CompactionFilterV2Filter(
    void* arg, int level, size_t num_keys,
    const char* const* keys_list, const size_t* keys_list_sizes,
    const char* const* existing_values_list, const size_t* existing_values_list_sizes,
    char** new_values_list, size_t* new_values_list_sizes,
    unsigned char* to_delete_list) {
  size_t i;
  for (i = 0; i < num_keys; i++) {
    // If any value is "gc", it's removed.
    if (existing_values_list_sizes[i] == 2 && memcmp(existing_values_list[i], "gc", 2) == 0) {
      to_delete_list[i] = 1;
    } else if (existing_values_list_sizes[i] == 6 && memcmp(existing_values_list[i], "gc all", 6) == 0) {
      // If any value is "gc all", all keys are removed.
      size_t j;
      for (j = 0; j < num_keys; j++) {
        to_delete_list[j] = 1;
      }
      return;
    } else if (existing_values_list_sizes[i] == 6 && memcmp(existing_values_list[i], "change", 6) == 0) {
      // If value is "change", set changed value to "changed".
      size_t len;
      len = strlen("changed");
      new_values_list[i] = malloc(len);
      memcpy(new_values_list[i], "changed", len);
      new_values_list_sizes[i] = len;
    } else {
      // Otherwise, no keys are removed.
    }
  }
}

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
// Custom prefix extractor for compaction filter V2 which extracts first 3 characters.
static void CFV2PrefixExtractorDestroy(void* arg) { }
static char* CFV2PrefixExtractorTransform(void* arg, const char* key, size_t length, size_t* dst_length) {
  // Verify keys are maximum length 4; this verifies fix for a
  // prior bug which was passing the RocksDB-encoded key with
  // logical timestamp suffix instead of parsed user key.
  if (length > 4) {
    fprintf(stderr, "%s:%d: %s: key %s is not user key\n", __FILE__, __LINE__, phase, key);
    abort();
  }
  *dst_length = length < 3 ? length : 3;
  return (char*)key;
}
static unsigned char CFV2PrefixExtractorInDomain(void* state, const char* key, size_t length) {
  return 1;
}
static unsigned char CFV2PrefixExtractorInRange(void* state, const char* key, size_t length) {
  return 1;
}
static const char* CFV2PrefixExtractorName(void* state) {
  return "TestCFV2PrefixExtractor";
}

289
// Custom compaction filter factory V2.
I
Igor Canadi 已提交
290 291 292
static void CompactionFilterFactoryV2Destroy(void* arg) {
  rocksdb_slicetransform_destroy((rocksdb_slicetransform_t*)arg);
}
293 294 295 296
static const char* CompactionFilterFactoryV2Name(void* arg) {
  return "TestCompactionFilterFactoryV2";
}
static rocksdb_compactionfilterv2_t* CompactionFilterFactoryV2Create(
I
Igor Canadi 已提交
297 298 299 300
    void* state, const rocksdb_compactionfiltercontext_t* context) {
  return rocksdb_compactionfilterv2_create(state, CompactionFilterV2Destroy,
                                           CompactionFilterV2Filter,
                                           CompactionFilterV2Name);
301 302
}

303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
// Custom merge operator
static void MergeOperatorDestroy(void* arg) { }
static const char* MergeOperatorName(void* arg) {
  return "TestMergeOperator";
}
static char* 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) {
  *new_value_length = 4;
  *success = 1;
  char* result = malloc(4);
  memcpy(result, "fake", 4);
  return result;
}
static char* MergeOperatorPartialMerge(
    void* arg,
    const char* key, size_t key_length,
324 325
    const char* const* operands_list, const size_t* operands_list_length,
    int num_operands,
326 327 328 329 330 331 332 333
    unsigned char* success, size_t* new_value_length) {
  *new_value_length = 4;
  *success = 1;
  char* result = malloc(4);
  memcpy(result, "fake", 4);
  return result;
}

334
int main(int argc, char** argv) {
335 336 337 338 339
  rocksdb_t* db;
  rocksdb_comparator_t* cmp;
  rocksdb_cache_t* cache;
  rocksdb_env_t* env;
  rocksdb_options_t* options;
340
  rocksdb_block_based_table_options_t* table_options;
341 342
  rocksdb_readoptions_t* roptions;
  rocksdb_writeoptions_t* woptions;
343
  char* err = NULL;
S
Sanjay Ghemawat 已提交
344
  int run = -1;
345

H
heyongqiang 已提交
346
  snprintf(dbname, sizeof(dbname),
347
           "%s/rocksdb_c_test-%d",
H
heyongqiang 已提交
348
           GetTempDir(),
349 350
           ((int) geteuid()));

351 352 353 354 355
  snprintf(dbbackupname, sizeof(dbbackupname),
           "%s/rocksdb_c_test-%d-backup",
           GetTempDir(),
           ((int) geteuid()));

356
  StartPhase("create_objects");
357 358 359 360 361 362 363 364 365 366 367 368
  cmp = rocksdb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName);
  env = rocksdb_create_default_env();
  cache = rocksdb_cache_create_lru(100000);

  options = rocksdb_options_create();
  rocksdb_options_set_comparator(options, cmp);
  rocksdb_options_set_error_if_exists(options, 1);
  rocksdb_options_set_env(options, env);
  rocksdb_options_set_info_log(options, NULL);
  rocksdb_options_set_write_buffer_size(options, 100000);
  rocksdb_options_set_paranoid_checks(options, 1);
  rocksdb_options_set_max_open_files(options, 10);
369 370 371 372
  table_options = rocksdb_block_based_options_create();
  rocksdb_block_based_options_set_block_cache(table_options, cache);
  rocksdb_options_set_block_based_table_factory(options, table_options);

373 374 375 376 377 378 379 380 381 382 383 384
  rocksdb_options_set_compression(options, rocksdb_no_compression);
  rocksdb_options_set_compression_options(options, -14, -1, 0);
  int compression_levels[] = {rocksdb_no_compression, rocksdb_no_compression,
                              rocksdb_no_compression, rocksdb_no_compression};
  rocksdb_options_set_compression_per_level(options, compression_levels, 4);

  roptions = rocksdb_readoptions_create();
  rocksdb_readoptions_set_verify_checksums(roptions, 1);
  rocksdb_readoptions_set_fill_cache(roptions, 0);

  woptions = rocksdb_writeoptions_create();
  rocksdb_writeoptions_set_sync(woptions, 1);
385 386

  StartPhase("destroy");
387
  rocksdb_destroy_db(options, dbname, &err);
388 389 390
  Free(&err);

  StartPhase("open_error");
391
  db = rocksdb_open(options, dbname, &err);
392 393 394 395
  CheckCondition(err != NULL);
  Free(&err);

  StartPhase("open");
396 397
  rocksdb_options_set_create_if_missing(options, 1);
  db = rocksdb_open(options, dbname, &err);
398 399 400 401
  CheckNoError(err);
  CheckGet(db, roptions, "foo", NULL);

  StartPhase("put");
402
  rocksdb_put(db, woptions, "foo", 3, "hello", 5, &err);
403 404 405
  CheckNoError(err);
  CheckGet(db, roptions, "foo", "hello");

406
  StartPhase("backup_and_restore");
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
  {
    rocksdb_destroy_db(options, dbbackupname, &err);
    CheckNoError(err);

    rocksdb_backup_engine_t *be = rocksdb_backup_engine_open(options, dbbackupname, &err);
    CheckNoError(err);

    rocksdb_backup_engine_create_new_backup(be, db, &err);
    CheckNoError(err);

    rocksdb_delete(db, woptions, "foo", 3, &err);
    CheckNoError(err);

    rocksdb_close(db);

    rocksdb_destroy_db(options, dbname, &err);
    CheckNoError(err);

    rocksdb_restore_options_t *restore_options = rocksdb_restore_options_create();
    rocksdb_restore_options_set_keep_log_files(restore_options, 0);
    rocksdb_backup_engine_restore_db_from_latest_backup(be, dbname, dbname, restore_options, &err);
    CheckNoError(err);
    rocksdb_restore_options_destroy(restore_options);

    rocksdb_options_set_error_if_exists(options, 0);
    db = rocksdb_open(options, dbname, &err);
    CheckNoError(err);
    rocksdb_options_set_error_if_exists(options, 1);

    CheckGet(db, roptions, "foo", "hello");

    rocksdb_backup_engine_close(be);
  }

S
Sanjay Ghemawat 已提交
441
  StartPhase("compactall");
442
  rocksdb_compact_range(db, NULL, 0, NULL, 0);
S
Sanjay Ghemawat 已提交
443 444 445
  CheckGet(db, roptions, "foo", "hello");

  StartPhase("compactrange");
446
  rocksdb_compact_range(db, "a", 1, "z", 1);
S
Sanjay Ghemawat 已提交
447 448
  CheckGet(db, roptions, "foo", "hello");

449 450
  StartPhase("writebatch");
  {
451 452 453 454 455 456 457
    rocksdb_writebatch_t* wb = rocksdb_writebatch_create();
    rocksdb_writebatch_put(wb, "foo", 3, "a", 1);
    rocksdb_writebatch_clear(wb);
    rocksdb_writebatch_put(wb, "bar", 3, "b", 1);
    rocksdb_writebatch_put(wb, "box", 3, "c", 1);
    rocksdb_writebatch_delete(wb, "bar", 3);
    rocksdb_write(db, woptions, wb, &err);
458 459 460 461 462
    CheckNoError(err);
    CheckGet(db, roptions, "foo", "hello");
    CheckGet(db, roptions, "bar", NULL);
    CheckGet(db, roptions, "box", "c");
    int pos = 0;
463
    rocksdb_writebatch_iterate(wb, &pos, CheckPut, CheckDel);
464
    CheckCondition(pos == 3);
465
    rocksdb_writebatch_destroy(wb);
466 467
  }

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
  StartPhase("writebatch_rep");
  {
    rocksdb_writebatch_t* wb1 = rocksdb_writebatch_create();
    rocksdb_writebatch_put(wb1, "baz", 3, "d", 1);
    rocksdb_writebatch_put(wb1, "quux", 4, "e", 1);
    rocksdb_writebatch_delete(wb1, "quux", 4);
    size_t repsize1 = 0;
    const char* rep = rocksdb_writebatch_data(wb1, &repsize1);
    rocksdb_writebatch_t* wb2 = rocksdb_writebatch_create_from(rep, repsize1);
    CheckCondition(rocksdb_writebatch_count(wb1) ==
                   rocksdb_writebatch_count(wb2));
    size_t repsize2 = 0;
    CheckCondition(
        memcmp(rep, rocksdb_writebatch_data(wb2, &repsize2), repsize1) == 0);
    rocksdb_writebatch_destroy(wb1);
    rocksdb_writebatch_destroy(wb2);
  }

486 487
  StartPhase("iter");
  {
488 489 490 491
    rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);
    CheckCondition(!rocksdb_iter_valid(iter));
    rocksdb_iter_seek_to_first(iter);
    CheckCondition(rocksdb_iter_valid(iter));
492
    CheckIter(iter, "box", "c");
493
    rocksdb_iter_next(iter);
494
    CheckIter(iter, "foo", "hello");
495
    rocksdb_iter_prev(iter);
496
    CheckIter(iter, "box", "c");
497 498 499
    rocksdb_iter_prev(iter);
    CheckCondition(!rocksdb_iter_valid(iter));
    rocksdb_iter_seek_to_last(iter);
500
    CheckIter(iter, "foo", "hello");
501
    rocksdb_iter_seek(iter, "b", 1);
502
    CheckIter(iter, "box", "c");
503
    rocksdb_iter_get_error(iter, &err);
504
    CheckNoError(err);
505
    rocksdb_iter_destroy(iter);
506 507 508 509 510 511 512 513 514 515 516 517 518
  }

  StartPhase("approximate_sizes");
  {
    int i;
    int n = 20000;
    char keybuf[100];
    char valbuf[100];
    uint64_t sizes[2];
    const char* start[2] = { "a", "k00000000000000010000" };
    size_t start_len[2] = { 1, 21 };
    const char* limit[2] = { "k00000000000000010000", "z" };
    size_t limit_len[2] = { 21, 1 };
519
    rocksdb_writeoptions_set_sync(woptions, 0);
520 521 522
    for (i = 0; i < n; i++) {
      snprintf(keybuf, sizeof(keybuf), "k%020d", i);
      snprintf(valbuf, sizeof(valbuf), "v%020d", i);
523
      rocksdb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf),
524 525 526
                  &err);
      CheckNoError(err);
    }
527
    rocksdb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes);
528 529 530 531 532 533
    CheckCondition(sizes[0] > 0);
    CheckCondition(sizes[1] > 0);
  }

  StartPhase("property");
  {
534
    char* prop = rocksdb_property_value(db, "nosuchprop");
535
    CheckCondition(prop == NULL);
536
    prop = rocksdb_property_value(db, "rocksdb.stats");
537 538 539 540 541 542
    CheckCondition(prop != NULL);
    Free(&prop);
  }

  StartPhase("snapshot");
  {
543 544 545
    const rocksdb_snapshot_t* snap;
    snap = rocksdb_create_snapshot(db);
    rocksdb_delete(db, woptions, "foo", 3, &err);
546
    CheckNoError(err);
547
    rocksdb_readoptions_set_snapshot(roptions, snap);
548
    CheckGet(db, roptions, "foo", "hello");
549
    rocksdb_readoptions_set_snapshot(roptions, NULL);
550
    CheckGet(db, roptions, "foo", NULL);
551
    rocksdb_release_snapshot(db, snap);
552 553 554 555
  }

  StartPhase("repair");
  {
556 557 558 559
    // If we do not compact here, then the lazy deletion of
    // files (https://reviews.facebook.net/D6123) would leave
    // around deleted files and the repair process will find
    // those files and put them back into the database.
560 561 562 563 564
    rocksdb_compact_range(db, NULL, 0, NULL, 0);
    rocksdb_close(db);
    rocksdb_options_set_create_if_missing(options, 0);
    rocksdb_options_set_error_if_exists(options, 0);
    rocksdb_repair_db(options, dbname, &err);
565
    CheckNoError(err);
566
    db = rocksdb_open(options, dbname, &err);
567 568 569 570
    CheckNoError(err);
    CheckGet(db, roptions, "foo", NULL);
    CheckGet(db, roptions, "bar", NULL);
    CheckGet(db, roptions, "box", "c");
571 572
    rocksdb_options_set_create_if_missing(options, 1);
    rocksdb_options_set_error_if_exists(options, 1);
S
Sanjay Ghemawat 已提交
573 574 575 576 577 578
  }

  StartPhase("filter");
  for (run = 0; run < 2; run++) {
    // First run uses custom filter, second run uses bloom filter
    CheckNoError(err);
579
    rocksdb_filterpolicy_t* policy;
S
Sanjay Ghemawat 已提交
580
    if (run == 0) {
581
      policy = rocksdb_filterpolicy_create(
582
          NULL, FilterDestroy, FilterCreate, FilterKeyMatch, NULL, FilterName);
S
Sanjay Ghemawat 已提交
583
    } else {
584
      policy = rocksdb_filterpolicy_create_bloom(10);
S
Sanjay Ghemawat 已提交
585 586
    }

587 588
    rocksdb_block_based_options_set_filter_policy(table_options, policy);

S
Sanjay Ghemawat 已提交
589
    // Create new database
590 591
    rocksdb_close(db);
    rocksdb_destroy_db(options, dbname, &err);
592
    rocksdb_options_set_block_based_table_factory(options, table_options);
593
    db = rocksdb_open(options, dbname, &err);
S
Sanjay Ghemawat 已提交
594
    CheckNoError(err);
595
    rocksdb_put(db, woptions, "foo", 3, "foovalue", 8, &err);
S
Sanjay Ghemawat 已提交
596
    CheckNoError(err);
597
    rocksdb_put(db, woptions, "bar", 3, "barvalue", 8, &err);
S
Sanjay Ghemawat 已提交
598
    CheckNoError(err);
599
    rocksdb_compact_range(db, NULL, 0, NULL, 0);
S
Sanjay Ghemawat 已提交
600 601 602 603 604 605 606 607 608 609 610 611 612 613

    fake_filter_result = 1;
    CheckGet(db, roptions, "foo", "foovalue");
    CheckGet(db, roptions, "bar", "barvalue");
    if (phase == 0) {
      // Must not find value when custom filter returns false
      fake_filter_result = 0;
      CheckGet(db, roptions, "foo", NULL);
      CheckGet(db, roptions, "bar", NULL);
      fake_filter_result = 1;

      CheckGet(db, roptions, "foo", "foovalue");
      CheckGet(db, roptions, "bar", "barvalue");
    }
614 615 616
    // Reset the policy
    rocksdb_block_based_options_set_filter_policy(table_options, NULL);
    rocksdb_options_set_block_based_table_factory(options, table_options);
617 618
  }

619 620
  StartPhase("compaction_filter");
  {
L
Lei Jin 已提交
621 622
    rocksdb_options_t* options_with_filter = rocksdb_options_create();
    rocksdb_options_set_create_if_missing(options_with_filter, 1);
623 624 625 626 627
    rocksdb_compactionfilter_t* cfilter;
    cfilter = rocksdb_compactionfilter_create(NULL, CFilterDestroy,
                                              CFilterFilter, CFilterName);
    // Create new database
    rocksdb_close(db);
L
Lei Jin 已提交
628 629 630
    rocksdb_destroy_db(options_with_filter, dbname, &err);
    rocksdb_options_set_compaction_filter(options_with_filter, cfilter);
    db = CheckCompaction(db, options_with_filter, roptions, woptions);
631

L
Lei Jin 已提交
632
    rocksdb_options_set_compaction_filter(options_with_filter, NULL);
633
    rocksdb_compactionfilter_destroy(cfilter);
L
Lei Jin 已提交
634
    rocksdb_options_destroy(options_with_filter);
635 636 637 638
  }

  StartPhase("compaction_filter_factory");
  {
L
Lei Jin 已提交
639 640
    rocksdb_options_t* options_with_filter_factory = rocksdb_options_create();
    rocksdb_options_set_create_if_missing(options_with_filter_factory, 1);
641 642 643 644 645
    rocksdb_compactionfilterfactory_t* factory;
    factory = rocksdb_compactionfilterfactory_create(
        NULL, CFilterFactoryDestroy, CFilterCreate, CFilterFactoryName);
    // Create new database
    rocksdb_close(db);
L
Lei Jin 已提交
646 647 648 649 650 651 652 653
    rocksdb_destroy_db(options_with_filter_factory, dbname, &err);
    rocksdb_options_set_compaction_filter_factory(options_with_filter_factory,
                                                  factory);
    db = CheckCompaction(db, options_with_filter_factory, roptions, woptions);

    rocksdb_options_set_compaction_filter_factory(
        options_with_filter_factory, NULL);
    rocksdb_options_destroy(options_with_filter_factory);
654 655
  }

656 657 658 659
  StartPhase("compaction_filter_v2");
  {
    rocksdb_compactionfilterfactoryv2_t* factory;
    rocksdb_slicetransform_t* prefix_extractor;
660 661 662 663
    prefix_extractor = rocksdb_slicetransform_create(
        NULL, CFV2PrefixExtractorDestroy, CFV2PrefixExtractorTransform,
        CFV2PrefixExtractorInDomain, CFV2PrefixExtractorInRange,
        CFV2PrefixExtractorName);
664
    factory = rocksdb_compactionfilterfactoryv2_create(
I
Igor Canadi 已提交
665
        prefix_extractor, prefix_extractor, CompactionFilterFactoryV2Destroy,
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
        CompactionFilterFactoryV2Create, CompactionFilterFactoryV2Name);
    // Create new database
    rocksdb_close(db);
    rocksdb_destroy_db(options, dbname, &err);
    rocksdb_options_set_compaction_filter_factory_v2(options, factory);
    db = rocksdb_open(options, dbname, &err);
    CheckNoError(err);
    // Only foo2 is GC'd, foo3 is changed.
    rocksdb_put(db, woptions, "foo1", 4, "no gc", 5, &err);
    CheckNoError(err);
    rocksdb_put(db, woptions, "foo2", 4, "gc", 2, &err);
    CheckNoError(err);
    rocksdb_put(db, woptions, "foo3", 4, "change", 6, &err);
    CheckNoError(err);
    // All bars are GC'd.
    rocksdb_put(db, woptions, "bar1", 4, "no gc", 5, &err);
    CheckNoError(err);
    rocksdb_put(db, woptions, "bar2", 4, "gc all", 6, &err);
    CheckNoError(err);
    rocksdb_put(db, woptions, "bar3", 4, "no gc", 5, &err);
    CheckNoError(err);
    // Compact the DB to garbage collect.
    rocksdb_compact_range(db, NULL, 0, NULL, 0);

    // Verify foo entries.
    CheckGet(db, roptions, "foo1", "no gc");
    CheckGet(db, roptions, "foo2", NULL);
    CheckGet(db, roptions, "foo3", "changed");
    // Verify bar entries were all deleted.
    CheckGet(db, roptions, "bar1", NULL);
    CheckGet(db, roptions, "bar2", NULL);
    CheckGet(db, roptions, "bar3", NULL);
  }

700 701 702 703 704 705 706 707 708
  StartPhase("merge_operator");
  {
    rocksdb_mergeoperator_t* merge_operator;
    merge_operator = rocksdb_mergeoperator_create(
        NULL, MergeOperatorDestroy, MergeOperatorFullMerge,
        MergeOperatorPartialMerge, NULL, MergeOperatorName);
    // Create new database
    rocksdb_close(db);
    rocksdb_destroy_db(options, dbname, &err);
I
Igor Canadi 已提交
709
    rocksdb_options_set_merge_operator(options, merge_operator);
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
    db = rocksdb_open(options, dbname, &err);
    CheckNoError(err);
    rocksdb_put(db, woptions, "foo", 3, "foovalue", 8, &err);
    CheckNoError(err);
    CheckGet(db, roptions, "foo", "foovalue");
    rocksdb_merge(db, woptions, "foo", 3, "barvalue", 8, &err);
    CheckNoError(err);
    CheckGet(db, roptions, "foo", "fake");

    // Merge of a non-existing value
    rocksdb_merge(db, woptions, "bar", 3, "barvalue", 8, &err);
    CheckNoError(err);
    CheckGet(db, roptions, "bar", "fake");

  }

R
Reed Allman 已提交
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
  StartPhase("columnfamilies");
  {
    rocksdb_close(db);
    rocksdb_destroy_db(options, dbname, &err);
    CheckNoError(err)

    rocksdb_options_t* db_options = rocksdb_options_create();
    rocksdb_options_set_create_if_missing(db_options, 1);
    db = rocksdb_open(db_options, dbname, &err);
    CheckNoError(err)
    rocksdb_column_family_handle_t* cfh;
    cfh = rocksdb_create_column_family(db, db_options, "cf1", &err);
    rocksdb_column_family_handle_destroy(cfh);
    CheckNoError(err);
    rocksdb_close(db);

    size_t cflen;
    char** column_fams = rocksdb_list_column_families(db_options, dbname, &cflen, &err);
    CheckNoError(err);
    CheckEqual("default", column_fams[0], 7);
    CheckEqual("cf1", column_fams[1], 3);
    CheckCondition(cflen == 2);
I
Igor Canadi 已提交
748
    rocksdb_list_column_families_destroy(column_fams, cflen);
R
Reed Allman 已提交
749 750

    rocksdb_options_t* cf_options = rocksdb_options_create();
I
Igor Canadi 已提交
751

R
Reed Allman 已提交
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
    const char* cf_names[2] = {"default", "cf1"};
    const rocksdb_options_t* cf_opts[2] = {cf_options, cf_options};
    rocksdb_column_family_handle_t* handles[2];
    db = rocksdb_open_column_families(db_options, dbname, 2, cf_names, cf_opts, handles, &err);
    CheckNoError(err);

    rocksdb_put_cf(db, woptions, handles[1], "foo", 3, "hello", 5, &err);
    CheckNoError(err);

    CheckGetCF(db, roptions, handles[1], "foo", "hello");

    rocksdb_delete_cf(db, woptions, handles[1], "foo", 3, &err);
    CheckNoError(err);

    CheckGetCF(db, roptions, handles[1], "foo", NULL);

    rocksdb_writebatch_t* wb = rocksdb_writebatch_create();
    rocksdb_writebatch_put_cf(wb, handles[1], "baz", 3, "a", 1);
    rocksdb_writebatch_clear(wb);
    rocksdb_writebatch_put_cf(wb, handles[1], "bar", 3, "b", 1);
    rocksdb_writebatch_put_cf(wb, handles[1], "box", 3, "c", 1);
    rocksdb_writebatch_delete_cf(wb, handles[1], "bar", 3);
    rocksdb_write(db, woptions, wb, &err);
    CheckNoError(err);
    CheckGetCF(db, roptions, handles[1], "baz", NULL);
    CheckGetCF(db, roptions, handles[1], "bar", NULL);
    CheckGetCF(db, roptions, handles[1], "box", "c");
    rocksdb_writebatch_destroy(wb);

    rocksdb_iterator_t* iter = rocksdb_create_iterator_cf(db, roptions, handles[1]);
    CheckCondition(!rocksdb_iter_valid(iter));
    rocksdb_iter_seek_to_first(iter);
    CheckCondition(rocksdb_iter_valid(iter));

    int i;
    for (i = 0; rocksdb_iter_valid(iter) != 0; rocksdb_iter_next(iter)) {
      i++;
    }
    CheckCondition(i == 1);
    rocksdb_iter_get_error(iter, &err);
    CheckNoError(err);
    rocksdb_iter_destroy(iter);

    rocksdb_drop_column_family(db, handles[1], &err);
    CheckNoError(err);
    for (i = 0; i < 2; i++) {
      rocksdb_column_family_handle_destroy(handles[i]);
    }
I
Igor Canadi 已提交
800 801 802 803
    rocksdb_close(db);
    rocksdb_destroy_db(options, dbname, &err);
    rocksdb_options_destroy(db_options);
    rocksdb_options_destroy(cf_options);
R
Reed Allman 已提交
804 805
  }

806 807 808
  StartPhase("prefix");
  {
    // Create new database
Y
Yueh-Hsuan Chiang 已提交
809
    rocksdb_options_set_allow_mmap_reads(options, 1);
810
    rocksdb_options_set_prefix_extractor(options, rocksdb_slicetransform_create_fixed_prefix(3));
811
    rocksdb_options_set_hash_skip_list_rep(options, 5000, 4, 4);
812
    rocksdb_options_set_plain_table_factory(options, 4, 10, 0.75, 16);
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845

    db = rocksdb_open(options, dbname, &err);
    CheckNoError(err);

    rocksdb_put(db, woptions, "foo1", 4, "foo", 3, &err);
    CheckNoError(err);
    rocksdb_put(db, woptions, "foo2", 4, "foo", 3, &err);
    CheckNoError(err);
    rocksdb_put(db, woptions, "foo3", 4, "foo", 3, &err);
    CheckNoError(err);
    rocksdb_put(db, woptions, "bar1", 4, "bar", 3, &err);
    CheckNoError(err);
    rocksdb_put(db, woptions, "bar2", 4, "bar", 3, &err);
    CheckNoError(err);
    rocksdb_put(db, woptions, "bar3", 4, "bar", 3, &err);
    CheckNoError(err);

    rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);
    CheckCondition(!rocksdb_iter_valid(iter));

    rocksdb_iter_seek(iter, "bar", 3);
    rocksdb_iter_get_error(iter, &err);
    CheckNoError(err);
    CheckCondition(rocksdb_iter_valid(iter));

    CheckIter(iter, "bar1", "bar");
    rocksdb_iter_next(iter);
    CheckIter(iter, "bar2", "bar");
    rocksdb_iter_next(iter);
    CheckIter(iter, "bar3", "bar");
    rocksdb_iter_get_error(iter, &err);
    CheckNoError(err);
    rocksdb_iter_destroy(iter);
846 847 848

    rocksdb_close(db);
    rocksdb_destroy_db(options, dbname, &err);
849 850
  }

851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
  StartPhase("cuckoo_options");
  {
    rocksdb_cuckoo_table_options_t* cuckoo_options;
    cuckoo_options = rocksdb_cuckoo_options_create();
    rocksdb_cuckoo_options_set_hash_ratio(cuckoo_options, 0.5);
    rocksdb_cuckoo_options_set_max_search_depth(cuckoo_options, 200);
    rocksdb_cuckoo_options_set_cuckoo_block_size(cuckoo_options, 10);
    rocksdb_cuckoo_options_set_identity_as_first_hash(cuckoo_options, 1);
    rocksdb_cuckoo_options_set_use_module_hash(cuckoo_options, 0);
    rocksdb_options_set_cuckoo_table_factory(options, cuckoo_options);

    db = rocksdb_open(options, dbname, &err);
    CheckNoError(err);

    rocksdb_cuckoo_options_destroy(cuckoo_options);
  }
R
Reed Allman 已提交
867

868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
  StartPhase("iterate_upper_bound");
  {
    // Create new empty database
    rocksdb_close(db);
    rocksdb_destroy_db(options, dbname, &err);
    CheckNoError(err);

    rocksdb_options_set_prefix_extractor(options, NULL);
    db = rocksdb_open(options, dbname, &err);
    CheckNoError(err);

    rocksdb_put(db, woptions, "a",    1, "0",    1, &err); CheckNoError(err);
    rocksdb_put(db, woptions, "foo",  3, "bar",  3, &err); CheckNoError(err);
    rocksdb_put(db, woptions, "foo1", 4, "bar1", 4, &err); CheckNoError(err);
    rocksdb_put(db, woptions, "g1",   2, "0",    1, &err); CheckNoError(err);

    // testing basic case with no iterate_upper_bound and no prefix_extractor
    {
       rocksdb_readoptions_set_iterate_upper_bound(roptions, NULL, 0);
       rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);

       rocksdb_iter_seek(iter, "foo", 3);
       CheckCondition(rocksdb_iter_valid(iter));
       CheckIter(iter, "foo", "bar");

       rocksdb_iter_next(iter);
       CheckCondition(rocksdb_iter_valid(iter));
       CheckIter(iter, "foo1", "bar1");

       rocksdb_iter_next(iter);
       CheckCondition(rocksdb_iter_valid(iter));
       CheckIter(iter, "g1", "0");

       rocksdb_iter_destroy(iter);
    }

    // testing iterate_upper_bound and forward iterator
    // to make sure it stops at bound
    {
       // iterate_upper_bound points beyond the last expected entry
       rocksdb_readoptions_set_iterate_upper_bound(roptions, "foo2", 4);

       rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);

       rocksdb_iter_seek(iter, "foo", 3);
       CheckCondition(rocksdb_iter_valid(iter));
       CheckIter(iter, "foo", "bar");

       rocksdb_iter_next(iter);
       CheckCondition(rocksdb_iter_valid(iter));
       CheckIter(iter, "foo1", "bar1");

       rocksdb_iter_next(iter);
       // should stop here...
       CheckCondition(!rocksdb_iter_valid(iter));

       rocksdb_iter_destroy(iter);
    }
  }

928
  StartPhase("cleanup");
929 930
  rocksdb_close(db);
  rocksdb_options_destroy(options);
931
  rocksdb_block_based_options_destroy(table_options);
932 933 934 935 936
  rocksdb_readoptions_destroy(roptions);
  rocksdb_writeoptions_destroy(woptions);
  rocksdb_cache_destroy(cache);
  rocksdb_comparator_destroy(cmp);
  rocksdb_env_destroy(env);
937 938 939 940

  fprintf(stderr, "PASS\n");
  return 0;
}