rocks 0.1.10

RocksDB bindings for Rust.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
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
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
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
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
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
//! Table options.
//!
//! Currently we support two types of tables: plain table and block-based table.
//!
//! 1. Block-based table: this is the default table type that we inherited from
//!    LevelDB, which was designed for storing data in hard disk or flash
//!    device.
//! 2. Plain table: it is one of RocksDB's SST file format optimized
//!    for low query latency on pure-memory or really low-latency media.
//!
//! A tutorial of rocksdb table formats is available here:
//! >  https://github.com/facebook/rocksdb/wiki/A-Tutorial-of-RocksDB-SST-formats
//!
//! Example code is also available
//! > https://github.com/facebook/rocksdb/wiki/A-Tutorial-of-RocksDB-SST-formats#wiki-examples

use std::mem;
use std::os::raw::c_int;
use std::ptr;

use rocks_sys as ll;

use crate::cache::Cache;
use crate::filter_policy::FilterPolicy;
use crate::persistent_cache::PersistentCache;
use crate::to_raw::ToRaw;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(C)]
pub enum IndexType {
    /// A space efficient index block that is optimized for
    /// binary-search-based index.
    BinarySearch,

    /// The hash index, if enabled, will do the hash lookup when
    /// `Options.prefix_extractor` is provided.
    HashSearch,

    /// TODO(myabandeh): this feature is in experimental phase and shall not be
    /// used in production; either remove the feature or remove this comment if
    /// it is ready to be used in production.
    ///
    /// A two-level index implementation. Both levels are binary search indexes.
    TwoLevelIndexSearch,
}

// not yet supported. Will fail
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(C)]
pub enum ChecksumType {
    NoChecksum = 0,
    CRC32c = 1,
}

/// For advanced user only
pub struct BlockBasedTableOptions {
    raw: *mut ll::rocks_block_based_table_options_t,
}

impl Default for BlockBasedTableOptions {
    fn default() -> Self {
        BlockBasedTableOptions {
            raw: unsafe { ll::rocks_block_based_table_options_create() },
        }
    }
}

impl ToRaw<ll::rocks_block_based_table_options_t> for BlockBasedTableOptions {
    fn raw(&self) -> *mut ll::rocks_block_based_table_options_t {
        self.raw
    }
}

impl Drop for BlockBasedTableOptions {
    /// since underlying C++ use shared_ptr, ok to have rust free one.
    fn drop(&mut self) {
        unsafe {
            ll::rocks_block_based_table_options_destroy(self.raw);
        }
    }
}

impl BlockBasedTableOptions {
    // `flush_block_policy_factory` creates the instances of flush block policy.
    // which provides a configurable way to determine when to flush a block in
    // the block based tables.  If not set, table builder will use the default
    // block flush policy, which cut blocks by block size (please refer to
    // `FlushBlockBySizePolicy`).
    //
    // std::shared_ptr<FlushBlockPolicyFactory> ;
    // pub fn flush_block_policy_factory(self, v: ()) -> Self {
    //     unimplemented!()
    // }

    /// TODO(kailiu) Temporarily disable this feature by making the default value
    /// to be false.
    ///
    /// Indicating if we'd put index/filter blocks to the block cache.
    ///
    /// If not specified, each "table reader" object will pre-load index/filter
    /// block during table initialization.
    pub fn cache_index_and_filter_blocks(self, val: bool) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_cache_index_and_filter_blocks(self.raw, val as u8);
        }
        self
    }

    /// If `cache_index_and_filter_blocks` is enabled, cache index and filter
    /// blocks with high priority. If set to true, depending on implementation of
    /// block cache, index and filter blocks may be less likely to be evicted
    /// than data blocks.
    pub fn cache_index_and_filter_blocks_with_high_priority(self, val: bool) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_cache_index_and_filter_blocks_with_high_priority(
                self.raw, val as u8,
            );
        }
        self
    }

    /// if `cache_index_and_filter_blocks` is true and the below is true, then
    /// filter and index blocks are stored in the cache, but a reference is
    /// held in the "table reader" object so the blocks are pinned and only
    /// evicted from cache when the table reader is freed.
    pub fn pin_l0_filter_and_index_blocks_in_cache(self, val: bool) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_pin_l0_filter_and_index_blocks_in_cache(self.raw, val as u8);
        }
        self
    }

    /// The index type that will be used for this table.
    ///
    /// Default: BinarySearch
    pub fn index_type(self, val: IndexType) -> Self {
        unsafe { ll::rocks_block_based_table_options_set_index_type(self.raw, mem::transmute(val)) }
        self
    }

    /// This option is now deprecated. No matter what value it is set to,
    /// it will behave as if `hash_index_allow_collision=true`.
    pub fn hash_index_allow_collision(self, val: bool) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_hash_index_allow_collision(self.raw, val as u8);
        }
        self
    }

    // Use the specified checksum type. Newly created table files will be
    // protected with this checksum type. Old table files will still be readable,
    // even though they have different checksum type.
    //
    // ChecksumType checksum = kCRC32c;

    /// Disable block cache. If this is set to true,
    /// then no block cache should be used, and the block_cache should
    /// point to a nullptr object.
    pub fn no_block_cache(self, val: bool) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_no_block_cache(self.raw, val as u8);
        }
        self
    }

    /// If non-NULL use the specified cache for blocks.
    ///
    /// If NULL, rocksdb will automatically create and use an 8MB internal cache.
    pub fn block_cache(self, val: Option<Cache>) -> Self {
        unsafe {
            let ptr = val.map(|c| c.raw()).unwrap_or_else(ptr::null_mut);
            ll::rocks_block_based_table_options_set_block_cache(self.raw, ptr);
        }
        self
    }

    /// If non-NULL use the specified cache for pages read from device
    /// IF NULL, no page cache is used
    pub fn persistent_cache(self, val: Option<PersistentCache>) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_persistent_cache(
                self.raw,
                val.map(|cache| cache.raw()).unwrap_or(ptr::null_mut()),
            )
        }
        self
    }

    /// If non-NULL use the specified cache for compressed blocks.
    ///
    /// If NULL, rocksdb will not use a compressed block cache.
    pub fn block_cache_compressed(self, val: Option<Cache>) -> Self {
        unsafe {
            let ptr = val.map(|c| c.raw()).unwrap_or_else(ptr::null_mut);
            ll::rocks_block_based_table_options_set_block_cache_compressed(self.raw, ptr);
        }
        self
    }

    /// Approximate size of user data packed per block.  Note that the
    /// block size specified here corresponds to uncompressed data.  The
    /// actual size of the unit read from disk may be smaller if
    /// compression is enabled.  This parameter can be changed dynamically.
    pub fn block_size(self, val: usize) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_block_size(self.raw, val);
        }
        self
    }

    /// This is used to close a block before it reaches the configured
    /// 'block_size'. If the percentage of free space in the current block is less
    /// than this specified number and adding a new record to the block will
    /// exceed the configured block size, then this block will be closed and the
    /// new record will be written to the next block.
    pub fn block_size_deviation(self, val: i32) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_block_size_deviation(self.raw, val as c_int);
        }
        self
    }

    /// Number of keys between restart points for delta encoding of keys.
    /// This parameter can be changed dynamically.  Most clients should
    /// leave this parameter alone.  The minimum value allowed is 1.  Any smaller
    /// value will be silently overwritten with 1.
    pub fn block_restart_interval(self, val: i32) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_block_restart_interval(self.raw, val);
        }
        self
    }

    /// Same as `block_restart_interval` but used for the index block.
    pub fn index_block_restart_interval(self, val: i32) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_index_block_restart_interval(self.raw, val);
        }
        self
    }

    /// Block size for partitioned metadata. Currently applied to indexes when
    /// `kTwoLevelIndexSearch` is used and to filters when partition_filters is used.
    ///
    /// Note: Since in the current implementation the filters and index partitions
    /// are aligned, an index/filter block is created when either index or filter
    /// block size reaches the specified limit.
    ///
    /// Note: this limit is currently applied to only index blocks; a filter
    /// partition is cut right after an index block is cut
    ///
    /// TODO(myabandeh): remove the note above when filter partitions are cut
    /// separately
    pub fn metadata_block_size(self, val: u64) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_metadata_block_size(self.raw, val);
        }
        self
    }

    /// Note: currently this option requires kTwoLevelIndexSearch to be set as
    /// well.
    ///
    /// TODO(myabandeh): remove the note above once the limitation is lifted
    ///
    /// TODO(myabandeh): this feature is in experimental phase and shall not be
    /// used in production; either remove the feature or remove this comment if
    /// it is ready to be used in production.
    ///
    /// Use partitioned full filters for each SST file
    pub fn partition_filters(self, val: bool) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_partition_filters(self.raw, val as u8);
        }
        self
    }

    /// Use delta encoding to compress keys in blocks.
    /// `ReadOptions::pin_data` requires this option to be disabled.
    ///
    /// Default: true
    pub fn use_delta_encoding(self, val: bool) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_use_delta_encoding(self.raw, val as u8);
        }
        self
    }

    /// If non-nullptr, use the specified filter policy to reduce disk reads.
    ///
    /// Many applications will benefit from passing the result of
    /// `NewBloomFilterPolicy()` here.
    pub fn filter_policy(self, val: Option<FilterPolicy>) -> Self {
        if let Some(policy) = val {
            unsafe {
                ll::rocks_block_based_table_options_set_filter_policy(self.raw, policy.raw());
            }
        } else {
            unsafe {
                ll::rocks_block_based_table_options_set_filter_policy(self.raw, ptr::null_mut());
            }
        }
        self
    }

    /// If true, place whole keys in the filter (not just prefixes).
    /// This must generally be true for gets to be efficient.
    pub fn whole_key_filtering(self, val: bool) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_whole_key_filtering(self.raw, val as u8);
        }
        self
    }

    /// Verify that decompressing the compressed block gives back the input. This
    /// is a verification mode that we use to detect bugs in compression
    /// algorithms.
    pub fn verify_compression(self, val: bool) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_verify_compression(self.raw, val as u8);
        }
        self
    }

    /// If used, For every data block we load into memory, we will create a bitmap
    /// of size ((block_size / `read_amp_bytes_per_bit`) / 8) bytes. This bitmap
    /// will be used to figure out the percentage we actually read of the blocks.
    ///
    /// When this feature is used Tickers::READ_AMP_ESTIMATE_USEFUL_BYTES and
    /// Tickers::READ_AMP_TOTAL_READ_BYTES can be used to calculate the
    /// read amplification using this formula
    /// (READ_AMP_TOTAL_READ_BYTES / READ_AMP_ESTIMATE_USEFUL_BYTES)
    ///
    /// value  =>  memory usage (percentage of loaded blocks memory)
    /// 1      =>  12.50 %
    /// 2      =>  06.25 %
    /// 4      =>  03.12 %
    /// 8      =>  01.56 %
    /// 16     =>  00.78 %
    ///
    /// Note: This number must be a power of 2, if not it will be sanitized
    /// to be the next lowest power of 2, for example a value of 7 will be
    /// treated as 4, a value of 19 will be treated as 16.
    ///
    /// Default: 0 (disabled)
    pub fn read_amp_bytes_per_bit(self, val: u32) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_read_amp_bytes_per_bit(self.raw, val);
        }
        self
    }

    /// We currently have three versions:
    ///
    /// 0 -- This version is currently written out by all RocksDB's versions by
    /// default.  Can be read by really old RocksDB's. Doesn't support changing
    /// checksum (default is CRC32).
    ///
    /// 1 -- Can be read by RocksDB's versions since 3.0. Supports non-default
    /// checksum, like xxHash. It is written by RocksDB when
    /// BlockBasedTableOptions::checksum is something other than kCRC32c. (version
    /// 0 is silently upconverted)
    ///
    /// 2 -- Can be read by RocksDB's versions since 3.10. Changes the way we
    /// encode compressed blocks with LZ4, BZip2 and Zlib compression. If you
    /// don't plan to run RocksDB before version 3.10, you should probably use
    /// this.
    ///
    /// This option only affects newly written tables. When reading exising tables,
    /// the information about version is read from the footer.
    pub fn format_version(self, val: u32) -> Self {
        unsafe {
            ll::rocks_block_based_table_options_set_format_version(self.raw, val);
        }
        self
    }
}

#[repr(u8)]
pub enum EncodingType {
    /// Always write full keys without any special encoding.
    Plain,
    /// Find opportunity to write the same prefix once for multiple rows.
    /// In some cases, when a key follows a previous key with the same prefix,
    /// instead of writing out the full key, it just writes out the size of the
    /// shared prefix, as well as other bytes, to save some bytes.
    ///
    /// When using this option, the user is required to use the same prefix
    /// extractor to make sure the same prefix will be extracted from the same key.
    /// The Name() value of the prefix extractor will be stored in the file. When
    /// reopening the file, the name of the options.prefix_extractor given will be
    /// bitwise compared to the prefix extractors stored in the file. An error
    /// will be returned if the two don't match.
    Prefix,
}

pub struct PlainTableOptions {
    raw: *mut ll::rocks_plain_table_options_t,
}

impl Default for PlainTableOptions {
    fn default() -> Self {
        PlainTableOptions {
            raw: unsafe { ll::rocks_plain_table_options_create() },
        }
    }
}

impl ToRaw<ll::rocks_plain_table_options_t> for PlainTableOptions {
    fn raw(&self) -> *mut ll::rocks_plain_table_options_t {
        self.raw
    }
}

impl PlainTableOptions {
    /// @user_key_len: plain table has optimization for fix-sized keys, which can
    ///                be specified via user_key_len.  Alternatively, you can pass
    ///                `kPlainTableVariableLength` if your keys have variable
    ///                lengths.
    pub fn user_key_len(self, val: u32) -> Self {
        unsafe {
            ll::rocks_plain_table_options_set_user_key_len(self.raw, val);
        }
        self
    }

    /// @bloom_bits_per_key: the number of bits used for bloom filer per prefix.
    ///                      You may disable it by passing a zero.
    pub fn bloom_bits_per_key(self, val: i32) -> Self {
        unsafe {
            ll::rocks_plain_table_options_set_bloom_bits_per_key(self.raw, val);
        }
        self
    }

    /// @hash_table_ratio: the desired utilization of the hash table used for
    ///                    prefix hashing.
    ///                    hash_table_ratio = number of prefixes / #buckets in the
    ///                    hash table
    pub fn hash_table_ratio(self, val: f64) -> Self {
        unsafe {
            ll::rocks_plain_table_options_set_hash_table_ratio(self.raw, val);
        }
        self
    }

    /// @index_sparseness: inside each prefix, need to build one index record for
    ///                    how many keys for binary search inside each hash bucket.
    ///                    For encoding type kPrefix, the value will be used when
    ///                    writing to determine an interval to rewrite the full
    ///                    key. It will also be used as a suggestion and satisfied
    ///                    when possible.
    pub fn index_sparseness(self, val: usize) -> Self {
        unsafe {
            ll::rocks_plain_table_options_set_index_sparseness(self.raw, val);
        }
        self
    }

    /// @huge_page_tlb_size: if <=0, allocate hash indexes and blooms from malloc.
    ///                      Otherwise from huge page TLB. The user needs to
    ///                      reserve huge pages for it to be allocated, like:
    ///                          sysctl -w vm.nr_hugepages=20
    ///                      See linux doc Documentation/vm/hugetlbpage.txt
    pub fn huge_page_tlb_size(self, val: usize) -> Self {
        unsafe {
            ll::rocks_plain_table_options_set_huge_page_tlb_size(self.raw, val);
        }
        self
    }

    /// @encoding_type: how to encode the keys. See enum EncodingType above for
    ///                 the choices. The value will determine how to encode keys
    ///                 when writing to a new SST file. This value will be stored
    ///                 inside the SST file which will be used when reading from
    ///                 the file, which makes it possible for users to choose
    ///                 different encoding type when reopening a DB. Files with
    ///                 different encoding types can co-exist in the same DB and
    ///                 can be read.
    pub fn encoding_type(self, val: EncodingType) -> Self {
        unsafe {
            ll::rocks_plain_table_options_set_encoding_type(self.raw, mem::transmute(val));
        }
        self
    }

    /// @full_scan_mode: mode for reading the whole file one record by one without
    ///                  using the index.
    pub fn full_scan_mode(self, val: bool) -> Self {
        unsafe {
            ll::rocks_plain_table_options_set_full_scan_mode(self.raw, val as u8);
        }
        self
    }

    /// @store_index_in_file: compute plain table index and bloom filter during
    ///                       file building and store it in file. When reading
    ///                       file, index will be mmaped instead of recomputation.
    pub fn store_index_in_file(self, val: bool) -> Self {
        unsafe {
            ll::rocks_plain_table_options_set_store_index_in_file(self.raw, val as u8);
        }
        self
    }
}

pub struct CuckooTableOptions {
    raw: *mut ll::rocks_cuckoo_table_options_t,
}

impl Default for CuckooTableOptions {
    fn default() -> Self {
        CuckooTableOptions {
            raw: unsafe { ll::rocks_cuckoo_table_options_create() },
        }
    }
}

impl ToRaw<ll::rocks_cuckoo_table_options_t> for CuckooTableOptions {
    fn raw(&self) -> *mut ll::rocks_cuckoo_table_options_t {
        self.raw
    }
}

impl CuckooTableOptions {
    /// Determines the utilization of hash tables. Smaller values
    /// result in larger hash tables with fewer collisions.
    pub fn hash_table_ratio(self, val: f64) -> Self {
        unsafe {
            ll::rocks_cuckoo_table_options_set_hash_table_ratio(self.raw, val);
        }
        self
    }
    /// A property used by builder to determine the depth to go to
    /// to search for a path to displace elements in case of
    /// collision. See Builder.MakeSpaceForKey method. Higher
    /// values result in more efficient hash tables with fewer
    /// lookups but take more time to build.
    pub fn max_search_depth(self, val: u32) -> Self {
        unsafe {
            ll::rocks_cuckoo_table_options_set_max_search_depth(self.raw, val);
        }
        self
    }
    /// In case of collision while inserting, the builder
    /// attempts to insert in the next cuckoo_block_size
    /// locations before skipping over to the next Cuckoo hash
    /// function. This makes lookups more cache friendly in case
    /// of collisions.
    pub fn cuckoo_block_size(self, val: u32) -> Self {
        unsafe {
            ll::rocks_cuckoo_table_options_set_cuckoo_block_size(self.raw, val);
        }
        self
    }
    /// If this option is enabled, user key is treated as uint64_t and its value
    /// is used as hash value directly. This option changes builder's behavior.
    /// Reader ignore this option and behave according to what specified in table
    /// property.
    pub fn identity_as_first_hash(self, val: bool) -> Self {
        unsafe {
            ll::rocks_cuckoo_table_options_set_identity_as_first_hash(self.raw, val as u8);
        }
        self
    }
    /// If this option is set to true, module is used during hash calculation.
    /// This often yields better space efficiency at the cost of performance.
    /// If this optino is set to false, # of entries in table is constrained to be
    /// power of two, and bit and is used to calculate hash, which is faster in
    /// general.
    pub fn use_module_hash(self, val: bool) -> Self {
        unsafe {
            ll::rocks_cuckoo_table_options_set_use_module_hash(self.raw, val as u8);
        }
        self
    }
}