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
use crate::{LruCacheOptions, ffi};
use libc::size_t;
use std::ptr::NonNull;
use std::sync::Arc;
pub(crate) struct CacheWrapper {
pub(crate) inner: NonNull<ffi::rocksdb_cache_t>,
}
unsafe impl Send for CacheWrapper {}
unsafe impl Sync for CacheWrapper {}
impl Drop for CacheWrapper {
fn drop(&mut self) {
unsafe {
ffi::rocksdb_cache_destroy(self.inner.as_ptr());
}
}
}
#[derive(Clone)]
pub struct Cache(pub(crate) Arc<CacheWrapper>);
impl Cache {
/// Creates an LRU cache with capacity in bytes.
pub fn new_lru_cache(capacity: size_t) -> Cache {
let inner = NonNull::new(unsafe { ffi::rocksdb_cache_create_lru(capacity) }).unwrap();
Cache(Arc::new(CacheWrapper { inner }))
}
/// Creates an LRU cache with custom options.
pub fn new_lru_cache_opts(opts: &LruCacheOptions) -> Cache {
let inner =
NonNull::new(unsafe { ffi::rocksdb_cache_create_lru_opts(opts.inner) }).unwrap();
Cache(Arc::new(CacheWrapper { inner }))
}
/// Creates a HyperClockCache with `capacity` in bytes.
///
/// HyperClockCache is now generally recommended over LRUCache. See RocksDB's
/// [HyperClockCacheOptions in cache.h](https://github.com/facebook/rocksdb/blob/main/include/rocksdb/cache.h)
/// for details.
///
/// `estimated_entry_charge` is an optional parameter. When not provided
/// (== 0, recommended and default), an HCC variant with a
/// dynamically-growing table and generally good performance is used. This
/// variant depends on anonymous mmaps so might not be available on all
/// platforms.
///
/// If the average "charge" (uncompressed block size) of block cache entries
/// is reasonably predicted and provided here, the most efficient variant of
/// HCC is used. Performance is degraded if the prediction is inaccurate.
/// Prediction could be difficult or impossible with cache-charging features
/// such as WriteBufferManager. The best parameter choice based on a cache
/// in use is roughly given by `cache.get_usage() / cache.get_occupancy_count()`,
/// though it is better to estimate toward the lower side than the higher
/// side when the ratio might vary.
pub fn new_hyper_clock_cache(capacity: size_t, estimated_entry_charge: size_t) -> Cache {
Cache(Arc::new(CacheWrapper {
inner: NonNull::new(unsafe {
ffi::rocksdb_cache_create_hyper_clock(capacity, estimated_entry_charge)
})
.unwrap(),
}))
}
/// Returns the cache memory usage in bytes.
pub fn get_usage(&self) -> usize {
unsafe { ffi::rocksdb_cache_get_usage(self.0.inner.as_ptr()) }
}
/// Returns the pinned memory usage in bytes.
pub fn get_pinned_usage(&self) -> usize {
unsafe { ffi::rocksdb_cache_get_pinned_usage(self.0.inner.as_ptr()) }
}
/// Sets cache capacity in bytes.
pub fn set_capacity(&mut self, capacity: size_t) {
unsafe {
ffi::rocksdb_cache_set_capacity(self.0.inner.as_ptr(), capacity);
}
}
}