1 // Copyright 2016 Alex Regueiro
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15
16 // This code is based on <https://github.com/facebook/rocksdb/blob/master/db/c_test.c>, revision a10e8a056d569acf6a52045124e6414ad33bdfcd.
17
18 #![allow(
19 non_snake_case,
20 non_upper_case_globals,
21 unused_mut,
22 unused_unsafe,
23 unused_variables
24 )]
25
26 use const_cstr::const_cstr;
27 use libc::*;
28 use librocksdb_sys::*;
29 use std::borrow::Cow;
30 use std::env;
31 use std::ffi::{CStr, CString};
32 use std::io::Write;
33 use std::mem;
34 use std::path::PathBuf;
35 use std::ptr;
36 use std::slice;
37 use std::str;
38 use uuid::Uuid;
39
40 macro_rules! err_println {
41 ($($arg:tt)*) => (writeln!(&mut ::std::io::stderr(), $($arg)*).expect("failed printing to stderr"));
42 }
43
44 macro_rules! cstrp {
45 ($($arg:tt)*) => (const_cstr!($($arg)*).as_ptr());
46 }
47
48 static mut phase: &'static str = "";
49 // static mut dbname: *mut c_uchar = ptr::null_mut();
50 // static mut dbbackupname: *mut c_uchar = ptr::null_mut();
51
strndup(s: *const c_char, n: size_t) -> *mut c_char52 unsafe fn strndup(s: *const c_char, n: size_t) -> *mut c_char {
53 let r: *mut c_char = malloc(n + 1) as *mut c_char;
54 if r.is_null() {
55 return r;
56 }
57 strncpy(r, s, n)
58 }
59
rstr<'a>(s: *const c_char) -> Cow<'a, str>60 unsafe fn rstr<'a>(s: *const c_char) -> Cow<'a, str> {
61 CStr::from_ptr(s).to_string_lossy()
62 }
63
GetTempDir() -> PathBuf64 fn GetTempDir() -> PathBuf {
65 return match option_env!("TEST_TMPDIR") {
66 Some("") | None => env::temp_dir(),
67 Some(s) => s.into(),
68 };
69 }
70
StartPhase(name: &'static str)71 unsafe fn StartPhase(name: &'static str) {
72 err_println!("=== Test {}\n", name);
73 phase = name;
74 }
75
76 macro_rules! CheckNoError {
77 ($err:ident) => {
78 unsafe {
79 assert!($err.is_null(), "{}: {}", phase, rstr($err));
80 }
81 };
82 }
83
84 macro_rules! CheckCondition {
85 ($cond:expr) => {
86 unsafe {
87 assert!($cond, "{}: {}", phase, stringify!($cond));
88 }
89 };
90 }
91
CheckEqual(expected: *const c_char, v: *const c_char, n: size_t)92 unsafe fn CheckEqual(expected: *const c_char, v: *const c_char, n: size_t) {
93 if expected.is_null() && v.is_null() {
94 // ok
95 } else if !expected.is_null()
96 && !v.is_null()
97 && n == strlen(expected)
98 && memcmp(expected as *const c_void, v as *const c_void, n) == 0
99 {
100 // ok
101 } else {
102 panic!(
103 "{}: expected '{}', got '{}'",
104 phase,
105 rstr(strndup(expected, n)),
106 rstr(strndup(v, 5))
107 );
108 }
109 }
110
Free<T>(ptr: *mut *mut T)111 unsafe fn Free<T>(ptr: *mut *mut T) {
112 if !(*ptr).is_null() {
113 free(*ptr as *mut c_void);
114 *ptr = ptr::null_mut();
115 }
116 }
117
CheckGet( mut db: *mut rocksdb_t, options: *mut rocksdb_readoptions_t, key: *const c_char, expected: *const c_char, )118 unsafe fn CheckGet(
119 mut db: *mut rocksdb_t,
120 options: *mut rocksdb_readoptions_t,
121 key: *const c_char,
122 expected: *const c_char,
123 ) {
124 let mut err: *mut c_char = ptr::null_mut();
125 let mut val_len: size_t = 0;
126 let mut val: *mut c_char = rocksdb_get(db, options, key, strlen(key), &mut val_len, &mut err);
127 CheckNoError!(err);
128 CheckEqual(expected, val, val_len);
129 Free(&mut val);
130 }
131
CheckGetCF( db: *mut rocksdb_t, options: *const rocksdb_readoptions_t, handle: *mut rocksdb_column_family_handle_t, key: *const c_char, expected: *const c_char, )132 unsafe fn CheckGetCF(
133 db: *mut rocksdb_t,
134 options: *const rocksdb_readoptions_t,
135 handle: *mut rocksdb_column_family_handle_t,
136 key: *const c_char,
137 expected: *const c_char,
138 ) {
139 let mut err: *mut c_char = ptr::null_mut();
140 let mut val_len: size_t = 0;
141 let mut val: *mut c_char = rocksdb_get_cf(
142 db,
143 options,
144 handle,
145 key,
146 strlen(key),
147 &mut val_len,
148 &mut err,
149 );
150 CheckNoError!(err);
151 CheckEqual(expected, val, val_len);
152 Free(&mut val);
153 }
154
CheckIter(iter: *mut rocksdb_iterator_t, key: *const c_char, val: *const c_char)155 unsafe fn CheckIter(iter: *mut rocksdb_iterator_t, key: *const c_char, val: *const c_char) {
156 let mut len: size_t = 0;
157 let mut str: *const c_char;
158 str = rocksdb_iter_key(iter, &mut len);
159 CheckEqual(key, str, len);
160 str = rocksdb_iter_value(iter, &mut len);
161 CheckEqual(val, str, len);
162 }
163
164 // Callback from rocksdb_writebatch_iterate()
CheckPut( ptr: *mut c_void, k: *const c_char, klen: size_t, v: *const c_char, vlen: size_t, )165 unsafe extern "C" fn CheckPut(
166 ptr: *mut c_void,
167 k: *const c_char,
168 klen: size_t,
169 v: *const c_char,
170 vlen: size_t,
171 ) {
172 let mut state: *mut c_int = ptr as *mut c_int;
173 CheckCondition!(*state < 2);
174 match *state {
175 0 => {
176 CheckEqual(cstrp!("bar"), k, klen);
177 CheckEqual(cstrp!("b"), v, vlen);
178 }
179 1 => {
180 CheckEqual(cstrp!("box"), k, klen);
181 CheckEqual(cstrp!("c"), v, vlen);
182 }
183 _ => {}
184 }
185 *state += 1;
186 }
187
188 // Callback from rocksdb_writebatch_iterate()
CheckDel(ptr: *mut c_void, k: *const c_char, klen: size_t)189 unsafe extern "C" fn CheckDel(ptr: *mut c_void, k: *const c_char, klen: size_t) {
190 let mut state: *mut c_int = ptr as *mut c_int;
191 CheckCondition!(*state == 2);
192 CheckEqual(cstrp!("bar"), k, klen);
193 *state += 1;
194 }
195
CmpDestroy(arg: *mut c_void)196 unsafe extern "C" fn CmpDestroy(arg: *mut c_void) {}
197
CmpCompare( arg: *mut c_void, a: *const c_char, alen: size_t, b: *const c_char, blen: size_t, ) -> c_int198 unsafe extern "C" fn CmpCompare(
199 arg: *mut c_void,
200 a: *const c_char,
201 alen: size_t,
202 b: *const c_char,
203 blen: size_t,
204 ) -> c_int {
205 let n = if alen < blen { alen } else { blen };
206 let mut r = memcmp(a as *const c_void, b as *const c_void, n);
207 if r == 0 {
208 if alen < blen {
209 r = -1;
210 } else if alen > blen {
211 r = 1;
212 }
213 }
214 r
215 }
216
CmpName(arg: *mut c_void) -> *const c_char217 unsafe extern "C" fn CmpName(arg: *mut c_void) -> *const c_char {
218 cstrp!("foo")
219 }
220
221 // Custom filter policy
222
223 static mut fake_filter_result: c_uchar = 1;
224
FilterDestroy(arg: *mut c_void)225 unsafe extern "C" fn FilterDestroy(arg: *mut c_void) {}
226
FilterName(arg: *mut c_void) -> *const c_char227 unsafe extern "C" fn FilterName(arg: *mut c_void) -> *const c_char {
228 cstrp!("TestFilter")
229 }
230
FilterCreate( arg: *mut c_void, key_array: *const *const c_char, key_length_array: *const size_t, num_keys: c_int, filter_length: *mut size_t, ) -> *mut c_char231 unsafe extern "C" fn FilterCreate(
232 arg: *mut c_void,
233 key_array: *const *const c_char,
234 key_length_array: *const size_t,
235 num_keys: c_int,
236 filter_length: *mut size_t,
237 ) -> *mut c_char {
238 *filter_length = 4;
239 let result = malloc(4);
240 memcpy(result, cstrp!("fake") as *const c_void, 4);
241 result as *mut c_char
242 }
243
FilterKeyMatch( arg: *mut c_void, key: *const c_char, length: size_t, filter: *const c_char, filter_length: size_t, ) -> c_uchar244 unsafe extern "C" fn FilterKeyMatch(
245 arg: *mut c_void,
246 key: *const c_char,
247 length: size_t,
248 filter: *const c_char,
249 filter_length: size_t,
250 ) -> c_uchar {
251 CheckCondition!(filter_length == 4);
252 CheckCondition!(
253 memcmp(
254 filter as *const c_void,
255 cstrp!("fake") as *const c_void,
256 filter_length
257 ) == 0
258 );
259 fake_filter_result
260 }
261
262 // Custom compaction filter
263
CFilterDestroy(arg: *mut c_void)264 unsafe extern "C" fn CFilterDestroy(arg: *mut c_void) {}
265
CFilterName(arg: *mut c_void) -> *const c_char266 unsafe extern "C" fn CFilterName(arg: *mut c_void) -> *const c_char {
267 cstrp!("foo")
268 }
269
CFilterFilter( arg: *mut c_void, level: c_int, key: *const c_char, key_length: size_t, existing_value: *const c_char, value_length: size_t, new_value: *mut *mut c_char, new_value_length: *mut size_t, value_changed: *mut u8, ) -> c_uchar270 unsafe extern "C" fn CFilterFilter(
271 arg: *mut c_void,
272 level: c_int,
273 key: *const c_char,
274 key_length: size_t,
275 existing_value: *const c_char,
276 value_length: size_t,
277 new_value: *mut *mut c_char,
278 new_value_length: *mut size_t,
279 value_changed: *mut u8,
280 ) -> c_uchar {
281 if key_length == 3 {
282 if memcmp(
283 mem::transmute(key),
284 mem::transmute(cstrp!("bar")),
285 key_length,
286 ) == 0
287 {
288 return 1;
289 } else if memcmp(
290 mem::transmute(key),
291 mem::transmute(cstrp!("baz")),
292 key_length,
293 ) == 0
294 {
295 *value_changed = 1;
296 *new_value = cstrp!("newbazvalue") as *mut c_char;
297 *new_value_length = 11;
298 return 0;
299 }
300 }
301 0
302 }
303
CFilterFactoryDestroy(arg: *mut c_void)304 unsafe extern "C" fn CFilterFactoryDestroy(arg: *mut c_void) {}
305
CFilterFactoryName(arg: *mut c_void) -> *const c_char306 unsafe extern "C" fn CFilterFactoryName(arg: *mut c_void) -> *const c_char {
307 cstrp!("foo")
308 }
309
CFilterCreate( arg: *mut c_void, context: *mut rocksdb_compactionfiltercontext_t, ) -> *mut rocksdb_compactionfilter_t310 unsafe extern "C" fn CFilterCreate(
311 arg: *mut c_void,
312 context: *mut rocksdb_compactionfiltercontext_t,
313 ) -> *mut rocksdb_compactionfilter_t {
314 rocksdb_compactionfilter_create(
315 ptr::null_mut(),
316 Some(CFilterDestroy),
317 Some(CFilterFilter),
318 Some(CFilterName),
319 )
320 }
321
CheckCompaction( dbname: *const c_char, db: *mut rocksdb_t, options: *const rocksdb_options_t, roptions: *mut rocksdb_readoptions_t, woptions: *mut rocksdb_writeoptions_t, ) -> *mut rocksdb_t322 unsafe fn CheckCompaction(
323 dbname: *const c_char,
324 db: *mut rocksdb_t,
325 options: *const rocksdb_options_t,
326 roptions: *mut rocksdb_readoptions_t,
327 woptions: *mut rocksdb_writeoptions_t,
328 ) -> *mut rocksdb_t {
329 let mut err: *mut c_char = ptr::null_mut();
330 let db = rocksdb_open(options, dbname, &mut err);
331 CheckNoError!(err);
332 rocksdb_put(
333 db,
334 woptions,
335 cstrp!("foo"),
336 3,
337 cstrp!("foovalue"),
338 8,
339 &mut err,
340 );
341 CheckNoError!(err);
342 CheckGet(db, roptions, cstrp!("foo"), cstrp!("foovalue"));
343 rocksdb_put(
344 db,
345 woptions,
346 cstrp!("bar"),
347 3,
348 cstrp!("barvalue"),
349 8,
350 &mut err,
351 );
352 CheckNoError!(err);
353 CheckGet(db, roptions, cstrp!("bar"), cstrp!("barvalue"));
354 rocksdb_put(
355 db,
356 woptions,
357 cstrp!("baz"),
358 3,
359 cstrp!("bazvalue"),
360 8,
361 &mut err,
362 );
363 CheckNoError!(err);
364 CheckGet(db, roptions, cstrp!("baz"), cstrp!("bazvalue"));
365
366 // Force compaction
367 rocksdb_compact_range(db, ptr::null(), 0, ptr::null(), 0);
368 // should have filtered bar, but not foo
369 CheckGet(db, roptions, cstrp!("foo"), cstrp!("foovalue"));
370 CheckGet(db, roptions, cstrp!("bar"), ptr::null());
371 CheckGet(db, roptions, cstrp!("baz"), cstrp!("newbazvalue"));
372 db
373 }
374
375 // Custom merge operator
376
MergeOperatorDestroy(arg: *mut c_void)377 unsafe extern "C" fn MergeOperatorDestroy(arg: *mut c_void) {}
378
MergeOperatorName(arg: *mut c_void) -> *const c_char379 unsafe extern "C" fn MergeOperatorName(arg: *mut c_void) -> *const c_char {
380 cstrp!("foo")
381 }
382
MergeOperatorFullMerge( arg: *mut c_void, key: *const c_char, key_length: size_t, existing_value: *const c_char, existing_value_length: size_t, operands_list: *const *const c_char, operands_list_length: *const size_t, num_operands: c_int, success: *mut u8, new_value_length: *mut size_t, ) -> *mut c_char383 unsafe extern "C" fn MergeOperatorFullMerge(
384 arg: *mut c_void,
385 key: *const c_char,
386 key_length: size_t,
387 existing_value: *const c_char,
388 existing_value_length: size_t,
389 operands_list: *const *const c_char,
390 operands_list_length: *const size_t,
391 num_operands: c_int,
392 success: *mut u8,
393 new_value_length: *mut size_t,
394 ) -> *mut c_char {
395 *new_value_length = 4;
396 *success = 1;
397 let result: *mut c_char = malloc(4) as *mut _;
398 memcpy(result as *mut _, cstrp!("fake") as *mut _, 4);
399 result
400 }
401
MergeOperatorPartialMerge( arg: *mut c_void, key: *const c_char, key_length: size_t, operands_list: *const *const c_char, operands_list_length: *const size_t, num_operands: c_int, success: *mut u8, new_value_length: *mut size_t, ) -> *mut c_char402 unsafe extern "C" fn MergeOperatorPartialMerge(
403 arg: *mut c_void,
404 key: *const c_char,
405 key_length: size_t,
406 operands_list: *const *const c_char,
407 operands_list_length: *const size_t,
408 num_operands: c_int,
409 success: *mut u8,
410 new_value_length: *mut size_t,
411 ) -> *mut c_char {
412 *new_value_length = 4;
413 *success = 1;
414 let result: *mut c_char = malloc(4) as *mut _;
415 memcpy(result as *mut _, cstrp!("fake") as *const _, 4);
416 result
417 }
418
419 #[test]
ffi()420 fn ffi() {
421 unsafe {
422 let mut db: *mut rocksdb_t;
423 let mut cmp: *mut rocksdb_comparator_t;
424 let mut cache: *mut rocksdb_cache_t;
425 let mut env: *mut rocksdb_env_t;
426 let mut options: *mut rocksdb_options_t;
427 let mut table_options: *mut rocksdb_block_based_table_options_t;
428 let mut roptions: *mut rocksdb_readoptions_t;
429 let mut woptions: *mut rocksdb_writeoptions_t;
430 let mut err: *mut c_char = ptr::null_mut();
431 let run: c_int = -1;
432
433 let test_uuid = Uuid::new_v4().to_simple();
434
435 let dbname = {
436 let mut dir = GetTempDir();
437 dir.push(format!("rocksdb_c_test-{}", test_uuid));
438 let path = dir.to_str().unwrap();
439 CString::new(path).unwrap()
440 };
441 let dbbackupname = {
442 let mut dir = GetTempDir();
443 dir.push(format!("rocksdb_c_test-{}-backup", test_uuid));
444 let path = dir.to_str().unwrap();
445 CString::new(path).unwrap()
446 };
447
448 let dbname = dbname.as_ptr();
449 let dbbackupname = dbbackupname.as_ptr();
450
451 StartPhase("create_objects");
452 cmp = rocksdb_comparator_create(
453 ptr::null_mut(),
454 Some(CmpDestroy),
455 Some(CmpCompare),
456 Some(CmpName),
457 );
458 env = rocksdb_create_default_env();
459 cache = rocksdb_cache_create_lru(100000);
460
461 options = rocksdb_options_create();
462 rocksdb_options_set_comparator(options, cmp);
463 rocksdb_options_set_error_if_exists(options, 1);
464 rocksdb_options_set_env(options, env);
465 rocksdb_options_set_info_log(options, ptr::null_mut());
466 rocksdb_options_set_write_buffer_size(options, 100000);
467 rocksdb_options_set_paranoid_checks(options, 1);
468 rocksdb_options_set_max_open_files(options, 10);
469 table_options = rocksdb_block_based_options_create();
470 rocksdb_block_based_options_set_block_cache(table_options, cache);
471 rocksdb_options_set_block_based_table_factory(options, table_options);
472
473 let no_compression = rocksdb_no_compression;
474 rocksdb_options_set_compression(options, no_compression as i32);
475 rocksdb_options_set_compression_options(options, -14, -1, 0, 0);
476 let compression_levels = vec![
477 no_compression,
478 no_compression,
479 no_compression,
480 no_compression,
481 ];
482 rocksdb_options_set_compression_per_level(
483 options,
484 mem::transmute(compression_levels.as_ptr()),
485 compression_levels.len() as size_t,
486 );
487
488 roptions = rocksdb_readoptions_create();
489 rocksdb_readoptions_set_verify_checksums(roptions, 1);
490 rocksdb_readoptions_set_fill_cache(roptions, 0);
491
492 woptions = rocksdb_writeoptions_create();
493 rocksdb_writeoptions_set_sync(woptions, 1);
494
495 StartPhase("destroy");
496 rocksdb_destroy_db(options, dbname, &mut err);
497 Free(&mut err);
498
499 StartPhase("open_error");
500 rocksdb_open(options, dbname, &mut err);
501 CheckCondition!(!err.is_null());
502 Free(&mut err);
503
504 StartPhase("open");
505 rocksdb_options_set_create_if_missing(options, 1);
506 db = rocksdb_open(options, dbname, &mut err);
507 CheckNoError!(err);
508 CheckGet(db, roptions, cstrp!("foo") as *const _, ptr::null());
509
510 StartPhase("put");
511 rocksdb_put(db, woptions, cstrp!("foo"), 3, cstrp!("hello"), 5, &mut err);
512 CheckNoError!(err);
513 CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
514
515 StartPhase("backup_and_restore");
516 {
517 rocksdb_destroy_db(options, dbbackupname, &mut err);
518 CheckNoError!(err);
519
520 let be = rocksdb_backup_engine_open(options, dbbackupname, &mut err);
521 CheckNoError!(err);
522
523 rocksdb_backup_engine_create_new_backup(be, db, &mut err);
524 CheckNoError!(err);
525
526 // need a change to trigger a new backup
527 rocksdb_delete(db, woptions, cstrp!("does-not-exist"), 14, &mut err);
528 CheckNoError!(err);
529
530 rocksdb_backup_engine_create_new_backup(be, db, &mut err);
531 CheckNoError!(err);
532
533 let bei: *const rocksdb_backup_engine_info_t =
534 rocksdb_backup_engine_get_backup_info(be);
535 CheckCondition!(rocksdb_backup_engine_info_count(bei) > 1);
536 rocksdb_backup_engine_info_destroy(bei);
537
538 rocksdb_backup_engine_purge_old_backups(be, 1, &mut err);
539 CheckNoError!(err);
540
541 let bei: *const rocksdb_backup_engine_info_t =
542 rocksdb_backup_engine_get_backup_info(be);
543 CheckCondition!(rocksdb_backup_engine_info_count(bei) == 1);
544 rocksdb_backup_engine_info_destroy(bei);
545
546 rocksdb_delete(db, woptions, cstrp!("foo"), 3, &mut err);
547 CheckNoError!(err);
548
549 rocksdb_close(db);
550
551 rocksdb_destroy_db(options, dbname, &mut err);
552 CheckNoError!(err);
553
554 let restore_options = rocksdb_restore_options_create();
555 rocksdb_restore_options_set_keep_log_files(restore_options, 0);
556 rocksdb_backup_engine_restore_db_from_latest_backup(
557 be,
558 dbname,
559 dbname,
560 restore_options,
561 &mut err,
562 );
563 CheckNoError!(err);
564 rocksdb_restore_options_destroy(restore_options);
565
566 rocksdb_options_set_error_if_exists(options, 0);
567 db = rocksdb_open(options, dbname, &mut err);
568 CheckNoError!(err);
569 rocksdb_options_set_error_if_exists(options, 1);
570
571 CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
572
573 rocksdb_backup_engine_close(be);
574 }
575
576 StartPhase("compactall");
577 rocksdb_compact_range(db, ptr::null(), 0, ptr::null(), 0);
578 CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
579
580 StartPhase("compactrange");
581 rocksdb_compact_range(db, cstrp!("a"), 1, cstrp!("z"), 1);
582 CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
583
584 StartPhase("writebatch");
585 {
586 let mut wb = rocksdb_writebatch_create();
587 rocksdb_writebatch_put(wb, cstrp!("foo"), 3, cstrp!("a"), 1);
588 rocksdb_writebatch_clear(wb);
589 rocksdb_writebatch_put(wb, cstrp!("bar"), 3, cstrp!("b"), 1);
590 rocksdb_writebatch_put(wb, cstrp!("box"), 3, cstrp!("c"), 1);
591 rocksdb_writebatch_delete(wb, cstrp!("bar"), 3);
592 rocksdb_write(db, woptions, wb, &mut err);
593 CheckNoError!(err);
594 CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
595 CheckGet(db, roptions, cstrp!("bar"), ptr::null());
596 CheckGet(db, roptions, cstrp!("box"), cstrp!("c"));
597 let mut pos: c_int = 0;
598 rocksdb_writebatch_iterate(
599 wb,
600 mem::transmute(&mut pos),
601 Some(CheckPut),
602 Some(CheckDel),
603 );
604 CheckCondition!(pos == 3);
605 rocksdb_writebatch_destroy(wb);
606 }
607
608 StartPhase("writebatch_vectors");
609 {
610 let wb = rocksdb_writebatch_create();
611 let k_list: [*const c_char; 2] = [cstrp!("z"), cstrp!("ap")];
612 let k_sizes: [size_t; 2] = [1, 2];
613 let v_list: [*const c_char; 3] = [cstrp!("x"), cstrp!("y"), cstrp!("z")];
614 let v_sizes: [size_t; 3] = [1, 1, 1];
615 rocksdb_writebatch_putv(
616 wb,
617 k_list.len() as c_int,
618 k_list.as_ptr(),
619 k_sizes.as_ptr(),
620 v_list.len() as c_int,
621 v_list.as_ptr(),
622 v_sizes.as_ptr(),
623 );
624 rocksdb_write(db, woptions, wb, &mut err);
625 CheckNoError!(err);
626 CheckGet(db, roptions, cstrp!("zap"), cstrp!("xyz"));
627 rocksdb_writebatch_delete(wb, cstrp!("zap"), 3);
628 rocksdb_write(db, woptions, wb, &mut err);
629 CheckNoError!(err);
630 CheckGet(db, roptions, cstrp!("zap"), ptr::null());
631 rocksdb_writebatch_destroy(wb);
632 }
633
634 StartPhase("writebatch_rep");
635 {
636 let wb1: *mut rocksdb_writebatch_t = rocksdb_writebatch_create();
637 rocksdb_writebatch_put(wb1, cstrp!("baz"), 3, cstrp!("d"), 1);
638 rocksdb_writebatch_put(wb1, cstrp!("quux"), 4, cstrp!("e"), 1);
639 rocksdb_writebatch_delete(wb1, cstrp!("quux"), 4);
640 let mut repsize1: size_t = 0;
641 let mut rep = rocksdb_writebatch_data(wb1, &mut repsize1) as *const c_void;
642 let mut wb2 = rocksdb_writebatch_create_from(rep as *const c_char, repsize1);
643 CheckCondition!(rocksdb_writebatch_count(wb1) == rocksdb_writebatch_count(wb2));
644 let mut repsize2: size_t = 0;
645 CheckCondition!(
646 memcmp(
647 rep,
648 rocksdb_writebatch_data(wb2, &mut repsize2) as *const c_void,
649 repsize1
650 ) == 0
651 );
652 rocksdb_writebatch_destroy(wb1);
653 rocksdb_writebatch_destroy(wb2);
654 }
655
656 StartPhase("iter");
657 {
658 let mut iter = rocksdb_create_iterator(db, roptions);
659 CheckCondition!(rocksdb_iter_valid(iter) == 0);
660 rocksdb_iter_seek_to_first(iter);
661 CheckCondition!(rocksdb_iter_valid(iter) != 0);
662 CheckIter(iter, cstrp!("box"), cstrp!("c"));
663 rocksdb_iter_next(iter);
664 CheckIter(iter, cstrp!("foo"), cstrp!("hello"));
665 rocksdb_iter_prev(iter);
666 CheckIter(iter, cstrp!("box"), cstrp!("c"));
667 rocksdb_iter_prev(iter);
668 CheckCondition!(rocksdb_iter_valid(iter) == 0);
669 rocksdb_iter_seek_to_last(iter);
670 CheckIter(iter, cstrp!("foo"), cstrp!("hello"));
671 rocksdb_iter_seek(iter, cstrp!("b"), 1);
672 CheckIter(iter, cstrp!("box"), cstrp!("c"));
673 rocksdb_iter_get_error(iter, &mut err);
674 CheckNoError!(err);
675 rocksdb_iter_destroy(iter);
676 }
677
678 StartPhase("multiget");
679 {
680 let keys: [*const c_char; 3] = [cstrp!("box"), cstrp!("foo"), cstrp!("notfound")];
681 let keys_sizes: [size_t; 3] = [3, 3, 8];
682 let mut vals: [*mut c_char; 3] = [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()];
683 let mut vals_sizes: [size_t; 3] = [0, 0, 0];
684 let mut errs: [*mut c_char; 3] = [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()];
685 rocksdb_multi_get(
686 db,
687 roptions,
688 3,
689 keys.as_ptr(),
690 keys_sizes.as_ptr(),
691 vals.as_mut_ptr(),
692 vals_sizes.as_mut_ptr(),
693 errs.as_mut_ptr(),
694 );
695
696 for i in 0..3 {
697 CheckEqual(ptr::null(), errs[i], 0);
698 match i {
699 0 => CheckEqual(cstrp!("c"), vals[i], vals_sizes[i]),
700 1 => CheckEqual(cstrp!("hello"), vals[i], vals_sizes[i]),
701 2 => CheckEqual(ptr::null(), vals[i], vals_sizes[i]),
702 _ => {}
703 }
704 Free(&mut vals[i]);
705 }
706 }
707
708 StartPhase("approximate_sizes");
709 {
710 let mut sizes: [u64; 2] = [0, 0];
711 let start: [*const c_char; 2] = [cstrp!("a"), cstrp!("k00000000000000010000")];
712 let start_len: [size_t; 2] = [1, 21];
713 let limit: [*const c_char; 2] = [cstrp!("k00000000000000010000"), cstrp!("z")];
714 let limit_len: [size_t; 2] = [21, 1];
715 rocksdb_writeoptions_set_sync(woptions, 0);
716 for i in 0..20000 {
717 let keybuf = CString::new(format!("k{:020}", i)).unwrap();
718 let key = keybuf.to_bytes_with_nul();
719 let valbuf = CString::new(format!("v{:020}", i)).unwrap();
720 let val = valbuf.to_bytes_with_nul();
721 rocksdb_put(
722 db,
723 woptions,
724 key.as_ptr() as *const c_char,
725 key.len() as size_t,
726 val.as_ptr() as *const c_char,
727 val.len() as size_t,
728 &mut err,
729 );
730 CheckNoError!(err);
731 }
732 rocksdb_approximate_sizes(
733 db,
734 2,
735 start.as_ptr(),
736 start_len.as_ptr(),
737 limit.as_ptr(),
738 limit_len.as_ptr(),
739 sizes.as_mut_ptr(),
740 );
741 CheckCondition!(sizes[0] > 0);
742 CheckCondition!(sizes[1] > 0);
743 }
744
745 StartPhase("property");
746 {
747 let mut prop: *mut c_char;
748 prop = rocksdb_property_value(db, cstrp!("nosuchprop"));
749 CheckCondition!(prop.is_null());
750 prop = rocksdb_property_value(db, cstrp!("rocksdb.stats"));
751 CheckCondition!(!prop.is_null());
752 Free(&mut prop);
753 }
754
755 StartPhase("snapshot");
756 {
757 let snap: *const rocksdb_snapshot_t = rocksdb_create_snapshot(db);
758 rocksdb_delete(db, woptions, cstrp!("foo"), 3, &mut err);
759 CheckNoError!(err);
760 rocksdb_readoptions_set_snapshot(roptions, snap);
761 CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
762 rocksdb_readoptions_set_snapshot(roptions, ptr::null());
763 CheckGet(db, roptions, cstrp!("foo"), ptr::null());
764 rocksdb_release_snapshot(db, snap);
765 }
766
767 StartPhase("repair");
768 {
769 // 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.
770 rocksdb_compact_range(db, ptr::null(), 0, ptr::null(), 0);
771 rocksdb_close(db);
772 rocksdb_options_set_create_if_missing(options, 0);
773 rocksdb_options_set_error_if_exists(options, 0);
774 // rocksdb_options_set_wal_recovery_mode(options, 2);
775 rocksdb_repair_db(options, dbname, &mut err);
776 CheckNoError!(err);
777 db = rocksdb_open(options, dbname, &mut err);
778 CheckNoError!(err);
779 CheckGet(db, roptions, cstrp!("foo"), ptr::null());
780 CheckGet(db, roptions, cstrp!("bar"), ptr::null());
781 CheckGet(db, roptions, cstrp!("box"), cstrp!("c"));
782 rocksdb_options_set_create_if_missing(options, 1);
783 rocksdb_options_set_error_if_exists(options, 1);
784 }
785
786 StartPhase("filter");
787 for run in 0..2 {
788 // First run uses custom filter, second run uses bloom filter
789 CheckNoError!(err);
790 let mut policy: *mut rocksdb_filterpolicy_t = if run == 0 {
791 rocksdb_filterpolicy_create(
792 ptr::null_mut(),
793 Some(FilterDestroy),
794 Some(FilterCreate),
795 Some(FilterKeyMatch),
796 None,
797 Some(FilterName),
798 )
799 } else {
800 rocksdb_filterpolicy_create_bloom(10)
801 };
802
803 rocksdb_block_based_options_set_filter_policy(table_options, policy);
804
805 // Create new database
806 rocksdb_close(db);
807 rocksdb_destroy_db(options, dbname, &mut err);
808 rocksdb_options_set_block_based_table_factory(options, table_options);
809 db = rocksdb_open(options, dbname, &mut err);
810 CheckNoError!(err);
811 rocksdb_put(
812 db,
813 woptions,
814 cstrp!("foo"),
815 3,
816 cstrp!("foovalue"),
817 8,
818 &mut err,
819 );
820 CheckNoError!(err);
821 rocksdb_put(
822 db,
823 woptions,
824 cstrp!("bar"),
825 3,
826 cstrp!("barvalue"),
827 8,
828 &mut err,
829 );
830 CheckNoError!(err);
831 rocksdb_compact_range(db, ptr::null(), 0, ptr::null(), 0);
832
833 fake_filter_result = 1;
834 CheckGet(db, roptions, cstrp!("foo"), cstrp!("foovalue"));
835 CheckGet(db, roptions, cstrp!("bar"), cstrp!("barvalue"));
836 if phase == "" {
837 // Must not find value when custom filter returns false
838 fake_filter_result = 0;
839 CheckGet(db, roptions, cstrp!("foo"), ptr::null());
840 CheckGet(db, roptions, cstrp!("bar"), ptr::null());
841 fake_filter_result = 1;
842
843 CheckGet(db, roptions, cstrp!("foo"), cstrp!("foovalue"));
844 CheckGet(db, roptions, cstrp!("bar"), cstrp!("barvalue"));
845 }
846 // Reset the policy
847 rocksdb_block_based_options_set_filter_policy(table_options, ptr::null_mut());
848 rocksdb_options_set_block_based_table_factory(options, table_options);
849 }
850
851 StartPhase("compaction_filter");
852 {
853 let options_with_filter = rocksdb_options_create();
854 rocksdb_options_set_create_if_missing(options_with_filter, 1);
855 let cfilter = rocksdb_compactionfilter_create(
856 ptr::null_mut(),
857 Some(CFilterDestroy),
858 Some(CFilterFilter),
859 Some(CFilterName),
860 );
861 // Create new database
862 rocksdb_close(db);
863 rocksdb_destroy_db(options_with_filter, dbname, &mut err);
864 rocksdb_options_set_compaction_filter(options_with_filter, cfilter);
865 db = CheckCompaction(dbname, db, options_with_filter, roptions, woptions);
866
867 rocksdb_options_set_compaction_filter(options_with_filter, ptr::null_mut());
868 rocksdb_compactionfilter_destroy(cfilter);
869 rocksdb_options_destroy(options_with_filter);
870 }
871
872 StartPhase("compaction_filter_factory");
873 {
874 let mut options_with_filter_factory = rocksdb_options_create();
875 rocksdb_options_set_create_if_missing(options_with_filter_factory, 1);
876 let mut factory = rocksdb_compactionfilterfactory_create(
877 ptr::null_mut(),
878 Some(CFilterFactoryDestroy),
879 Some(CFilterCreate),
880 Some(CFilterFactoryName),
881 );
882 // Create new database
883 rocksdb_close(db);
884 rocksdb_destroy_db(options_with_filter_factory, dbname, &mut err);
885 rocksdb_options_set_compaction_filter_factory(options_with_filter_factory, factory);
886 db = CheckCompaction(dbname, db, options_with_filter_factory, roptions, woptions);
887
888 rocksdb_options_set_compaction_filter_factory(
889 options_with_filter_factory,
890 ptr::null_mut(),
891 );
892 rocksdb_options_destroy(options_with_filter_factory);
893 }
894
895 StartPhase("merge_operator");
896 {
897 let mut merge_operator = rocksdb_mergeoperator_create(
898 ptr::null_mut(),
899 Some(MergeOperatorDestroy),
900 Some(MergeOperatorFullMerge),
901 Some(MergeOperatorPartialMerge),
902 None,
903 Some(MergeOperatorName),
904 );
905 // Create new database
906 rocksdb_close(db);
907 rocksdb_destroy_db(options, dbname, &mut err);
908 rocksdb_options_set_merge_operator(options, merge_operator);
909 db = rocksdb_open(options, dbname, &mut err);
910 CheckNoError!(err);
911 rocksdb_put(
912 db,
913 woptions,
914 cstrp!("foo"),
915 3,
916 cstrp!("foovalue"),
917 8,
918 &mut err,
919 );
920 CheckNoError!(err);
921 CheckGet(db, roptions, cstrp!("foo"), cstrp!("foovalue"));
922 rocksdb_merge(
923 db,
924 woptions,
925 cstrp!("foo"),
926 3,
927 cstrp!("barvalue"),
928 8,
929 &mut err,
930 );
931 CheckNoError!(err);
932 CheckGet(db, roptions, cstrp!("foo"), cstrp!("fake"));
933
934 // Merge of a non-existing value
935 rocksdb_merge(
936 db,
937 woptions,
938 cstrp!("bar"),
939 3,
940 cstrp!("barvalue"),
941 8,
942 &mut err,
943 );
944 CheckNoError!(err);
945 CheckGet(db, roptions, cstrp!("bar"), cstrp!("fake"));
946 }
947
948 StartPhase("columnfamilies");
949 {
950 rocksdb_close(db);
951 rocksdb_destroy_db(options, dbname, &mut err);
952 CheckNoError!(err);
953
954 let mut db_options = rocksdb_options_create();
955 rocksdb_options_set_create_if_missing(db_options, 1);
956 db = rocksdb_open(db_options, dbname, &mut err);
957 CheckNoError!(err);
958 let mut cfh = rocksdb_create_column_family(db, db_options, cstrp!("cf1"), &mut err);
959 rocksdb_column_family_handle_destroy(cfh);
960 CheckNoError!(err);
961 rocksdb_close(db);
962
963 let mut cflen: size_t = 0;
964 let column_fams_raw =
965 rocksdb_list_column_families(db_options, dbname, &mut cflen, &mut err);
966 let column_fams = slice::from_raw_parts(column_fams_raw, cflen as usize);
967 CheckEqual(cstrp!("default"), column_fams[0], 7);
968 CheckEqual(cstrp!("cf1"), column_fams[1], 3);
969 CheckCondition!(cflen == 2);
970 rocksdb_list_column_families_destroy(column_fams_raw, cflen);
971
972 let mut cf_options = rocksdb_options_create();
973
974 let mut cf_names: [*const c_char; 2] = [cstrp!("default"), cstrp!("cf1")];
975 let mut cf_opts: [*const rocksdb_options_t; 2] = [cf_options, cf_options];
976 let mut handles: [*mut rocksdb_column_family_handle_t; 2] =
977 [ptr::null_mut(), ptr::null_mut()];
978 db = rocksdb_open_column_families(
979 db_options,
980 dbname,
981 2,
982 cf_names.as_mut_ptr(),
983 cf_opts.as_mut_ptr(),
984 handles.as_mut_ptr(),
985 &mut err,
986 );
987 CheckNoError!(err);
988
989 rocksdb_put_cf(
990 db,
991 woptions,
992 handles[1],
993 cstrp!("foo"),
994 3,
995 cstrp!("hello"),
996 5,
997 &mut err,
998 );
999 CheckNoError!(err);
1000
1001 CheckGetCF(db, roptions, handles[1], cstrp!("foo"), cstrp!("hello"));
1002
1003 rocksdb_delete_cf(db, woptions, handles[1], cstrp!("foo"), 3, &mut err);
1004 CheckNoError!(err);
1005
1006 CheckGetCF(db, roptions, handles[1], cstrp!("foo"), ptr::null());
1007
1008 let mut wb = rocksdb_writebatch_create();
1009 rocksdb_writebatch_put_cf(wb, handles[1], cstrp!("baz"), 3, cstrp!("a"), 1);
1010 rocksdb_writebatch_clear(wb);
1011 rocksdb_writebatch_put_cf(wb, handles[1], cstrp!("bar"), 3, cstrp!("b"), 1);
1012 rocksdb_writebatch_put_cf(wb, handles[1], cstrp!("box"), 3, cstrp!("c"), 1);
1013 rocksdb_writebatch_delete_cf(wb, handles[1], cstrp!("bar"), 3);
1014 rocksdb_write(db, woptions, wb, &mut err);
1015 CheckNoError!(err);
1016 CheckGetCF(db, roptions, handles[1], cstrp!("baz"), ptr::null());
1017 CheckGetCF(db, roptions, handles[1], cstrp!("bar"), ptr::null());
1018 CheckGetCF(db, roptions, handles[1], cstrp!("box"), cstrp!("c"));
1019 rocksdb_writebatch_destroy(wb);
1020
1021 let keys: [*const c_char; 3] = [cstrp!("box"), cstrp!("box"), cstrp!("barfooxx")];
1022 let get_handles: [*const rocksdb_column_family_handle_t; 3] =
1023 [handles[0], handles[1], handles[1]];
1024 let keys_sizes: [size_t; 3] = [3, 3, 8];
1025 let mut vals: [*mut c_char; 3] = [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()];
1026 let mut vals_sizes: [size_t; 3] = [0, 0, 0];
1027 let mut errs: [*mut c_char; 3] = [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()];
1028 rocksdb_multi_get_cf(
1029 db,
1030 roptions,
1031 get_handles.as_ptr(),
1032 3,
1033 keys.as_ptr(),
1034 keys_sizes.as_ptr(),
1035 vals.as_mut_ptr(),
1036 vals_sizes.as_mut_ptr(),
1037 errs.as_mut_ptr(),
1038 );
1039
1040 for i in 0..3 {
1041 CheckEqual(ptr::null(), errs[i], 0);
1042 match i {
1043 0 => CheckEqual(ptr::null(), vals[i], vals_sizes[i]), // wrong cf
1044 1 => CheckEqual(cstrp!("c"), vals[i], vals_sizes[i]), // bingo
1045 2 => CheckEqual(ptr::null(), vals[i], vals_sizes[i]), // normal not found
1046 _ => {}
1047 }
1048 Free(&mut vals[i]);
1049 }
1050
1051 let mut iter = rocksdb_create_iterator_cf(db, roptions, handles[1]);
1052 CheckCondition!(rocksdb_iter_valid(iter) == 0);
1053 rocksdb_iter_seek_to_first(iter);
1054 CheckCondition!(rocksdb_iter_valid(iter) != 0);
1055
1056 let mut i: u32 = 0;
1057 while rocksdb_iter_valid(iter) != 0 {
1058 rocksdb_iter_next(iter);
1059 i += 1;
1060 }
1061 CheckCondition!(i == 1);
1062 rocksdb_iter_get_error(iter, &mut err);
1063 CheckNoError!(err);
1064 rocksdb_iter_destroy(iter);
1065
1066 let mut iters_cf_handles: [*mut rocksdb_column_family_handle_t; 2] =
1067 [handles[0], handles[1]];
1068 let mut iters_handles: [*mut rocksdb_iterator_t; 2] =
1069 [ptr::null_mut(), ptr::null_mut()];
1070 rocksdb_create_iterators(
1071 db,
1072 roptions,
1073 iters_cf_handles.as_mut_ptr(),
1074 iters_handles.as_mut_ptr(),
1075 2,
1076 &mut err,
1077 );
1078 CheckNoError!(err);
1079
1080 iter = iters_handles[0];
1081 CheckCondition!(rocksdb_iter_valid(iter) == 0);
1082 rocksdb_iter_seek_to_first(iter);
1083 CheckCondition!(rocksdb_iter_valid(iter) == 0);
1084 rocksdb_iter_destroy(iter);
1085
1086 iter = iters_handles[1];
1087 CheckCondition!(rocksdb_iter_valid(iter) == 0);
1088 rocksdb_iter_seek_to_first(iter);
1089 CheckCondition!(rocksdb_iter_valid(iter) != 0);
1090
1091 let mut i: u32 = 0;
1092 while rocksdb_iter_valid(iter) != 0 {
1093 rocksdb_iter_next(iter);
1094 i += 1;
1095 }
1096 CheckCondition!(i == 1);
1097 rocksdb_iter_get_error(iter, &mut err);
1098 CheckNoError!(err);
1099 rocksdb_iter_destroy(iter);
1100
1101 rocksdb_drop_column_family(db, handles[1], &mut err);
1102 CheckNoError!(err);
1103 for i in 0..2 {
1104 rocksdb_column_family_handle_destroy(handles[i]);
1105 }
1106 rocksdb_close(db);
1107 rocksdb_destroy_db(options, dbname, &mut err);
1108 rocksdb_options_destroy(db_options);
1109 rocksdb_options_destroy(cf_options);
1110 }
1111
1112 StartPhase("prefix");
1113 {
1114 // Create new database
1115 rocksdb_options_set_allow_mmap_reads(options, 1);
1116 rocksdb_options_set_prefix_extractor(
1117 options,
1118 rocksdb_slicetransform_create_fixed_prefix(3),
1119 );
1120 rocksdb_options_set_hash_skip_list_rep(options, 5000, 4, 4);
1121 rocksdb_options_set_plain_table_factory(options, 4, 10, 0.75, 16);
1122 rocksdb_options_set_allow_concurrent_memtable_write(options, 0);
1123
1124 db = rocksdb_open(options, dbname, &mut err);
1125 CheckNoError!(err);
1126
1127 rocksdb_put(db, woptions, cstrp!("foo1"), 4, cstrp!("foo"), 3, &mut err);
1128 CheckNoError!(err);
1129 rocksdb_put(db, woptions, cstrp!("foo2"), 4, cstrp!("foo"), 3, &mut err);
1130 CheckNoError!(err);
1131 rocksdb_put(db, woptions, cstrp!("foo3"), 4, cstrp!("foo"), 3, &mut err);
1132 CheckNoError!(err);
1133 rocksdb_put(db, woptions, cstrp!("bar1"), 4, cstrp!("bar"), 3, &mut err);
1134 CheckNoError!(err);
1135 rocksdb_put(db, woptions, cstrp!("bar2"), 4, cstrp!("bar"), 3, &mut err);
1136 CheckNoError!(err);
1137 rocksdb_put(db, woptions, cstrp!("bar3"), 4, cstrp!("bar"), 3, &mut err);
1138 CheckNoError!(err);
1139
1140 let mut iter = rocksdb_create_iterator(db, roptions);
1141 CheckCondition!(rocksdb_iter_valid(iter) == 0);
1142
1143 rocksdb_iter_seek(iter, cstrp!("bar"), 3);
1144 rocksdb_iter_get_error(iter, &mut err);
1145 CheckNoError!(err);
1146 CheckCondition!(rocksdb_iter_valid(iter) != 0);
1147
1148 CheckIter(iter, cstrp!("bar1"), cstrp!("bar"));
1149 rocksdb_iter_next(iter);
1150 CheckIter(iter, cstrp!("bar2"), cstrp!("bar"));
1151 rocksdb_iter_next(iter);
1152 CheckIter(iter, cstrp!("bar3"), cstrp!("bar"));
1153 rocksdb_iter_get_error(iter, &mut err);
1154 CheckNoError!(err);
1155 rocksdb_iter_destroy(iter);
1156
1157 rocksdb_close(db);
1158 rocksdb_destroy_db(options, dbname, &mut err);
1159 }
1160
1161 StartPhase("cuckoo_options");
1162 {
1163 let mut cuckoo_options = rocksdb_cuckoo_options_create();
1164 rocksdb_cuckoo_options_set_hash_ratio(cuckoo_options, 0.5);
1165 rocksdb_cuckoo_options_set_max_search_depth(cuckoo_options, 200);
1166 rocksdb_cuckoo_options_set_cuckoo_block_size(cuckoo_options, 10);
1167 rocksdb_cuckoo_options_set_identity_as_first_hash(cuckoo_options, 1);
1168 rocksdb_cuckoo_options_set_use_module_hash(cuckoo_options, 0);
1169 rocksdb_options_set_cuckoo_table_factory(options, cuckoo_options);
1170
1171 db = rocksdb_open(options, dbname, &mut err);
1172 CheckNoError!(err);
1173
1174 rocksdb_cuckoo_options_destroy(cuckoo_options);
1175 }
1176
1177 StartPhase("iterate_upper_bound");
1178 {
1179 // Create new empty database
1180 rocksdb_close(db);
1181 rocksdb_destroy_db(options, dbname, &mut err);
1182 CheckNoError!(err);
1183
1184 rocksdb_options_set_prefix_extractor(options, ptr::null_mut());
1185 db = rocksdb_open(options, dbname, &mut err);
1186 CheckNoError!(err);
1187
1188 rocksdb_put(db, woptions, cstrp!("a"), 1, cstrp!("0"), 1, &mut err);
1189 CheckNoError!(err);
1190 rocksdb_put(db, woptions, cstrp!("foo"), 3, cstrp!("bar"), 3, &mut err);
1191 CheckNoError!(err);
1192 rocksdb_put(db, woptions, cstrp!("foo1"), 4, cstrp!("bar1"), 4, &mut err);
1193 CheckNoError!(err);
1194 rocksdb_put(db, woptions, cstrp!("g1"), 2, cstrp!("0"), 1, &mut err);
1195 CheckNoError!(err);
1196
1197 // testing basic case with no iterate_upper_bound and no prefix_extractor
1198 {
1199 rocksdb_readoptions_set_iterate_upper_bound(roptions, ptr::null(), 0);
1200 let mut iter = rocksdb_create_iterator(db, roptions);
1201
1202 rocksdb_iter_seek(iter, cstrp!("foo"), 3);
1203 CheckCondition!(rocksdb_iter_valid(iter) != 0);
1204 CheckIter(iter, cstrp!("foo"), cstrp!("bar"));
1205
1206 rocksdb_iter_next(iter);
1207 CheckCondition!(rocksdb_iter_valid(iter) != 0);
1208 CheckIter(iter, cstrp!("foo1"), cstrp!("bar1"));
1209
1210 rocksdb_iter_next(iter);
1211 CheckCondition!(rocksdb_iter_valid(iter) != 0);
1212 CheckIter(iter, cstrp!("g1"), cstrp!("0"));
1213
1214 rocksdb_iter_destroy(iter);
1215 }
1216
1217 // testing iterate_upper_bound and forward iterator
1218 // to make sure it stops at bound
1219 {
1220 // iterate_upper_bound points beyond the last expected entry
1221 rocksdb_readoptions_set_iterate_upper_bound(roptions, cstrp!("foo2"), 4);
1222
1223 let mut iter = rocksdb_create_iterator(db, roptions);
1224
1225 rocksdb_iter_seek(iter, cstrp!("foo"), 3);
1226 CheckCondition!(rocksdb_iter_valid(iter) != 0);
1227 CheckIter(iter, cstrp!("foo"), cstrp!("bar"));
1228
1229 rocksdb_iter_next(iter);
1230 CheckCondition!(rocksdb_iter_valid(iter) != 0);
1231 CheckIter(iter, cstrp!("foo1"), cstrp!("bar1"));
1232
1233 rocksdb_iter_next(iter);
1234 // should stop here...
1235 CheckCondition!(rocksdb_iter_valid(iter) == 0);
1236
1237 rocksdb_iter_destroy(iter);
1238 }
1239 }
1240
1241 // Simple sanity check that setting memtable rep works.
1242 StartPhase("memtable_reps");
1243 {
1244 // Create database with vector memtable.
1245 rocksdb_close(db);
1246 rocksdb_destroy_db(options, dbname, &mut err);
1247 CheckNoError!(err);
1248
1249 rocksdb_options_set_memtable_vector_rep(options);
1250 db = rocksdb_open(options, dbname, &mut err);
1251 CheckNoError!(err);
1252
1253 // // Create database with hash skiplist memtable.
1254 // rocksdb_close(db);
1255 // rocksdb_destroy_db(options, dbname, &mut err);
1256 // CheckNoError!(err);
1257 //
1258 // rocksdb_options_set_hash_skip_list_rep(options, 5000, 4, 4);
1259 // db = rocksdb_open(options, dbname, &mut err);
1260 // CheckNoError!(err);
1261 }
1262
1263 StartPhase("cleanup");
1264 rocksdb_close(db);
1265 rocksdb_options_destroy(options);
1266 rocksdb_block_based_options_destroy(table_options);
1267 rocksdb_readoptions_destroy(roptions);
1268 rocksdb_writeoptions_destroy(woptions);
1269 rocksdb_cache_destroy(cache);
1270 rocksdb_comparator_destroy(cmp);
1271 rocksdb_env_destroy(env);
1272
1273 err_println!("PASS");
1274 }
1275 }
1276