rocksdb/column_family.rs
1// Copyright 2020 Tyler Neely
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
15use crate::{db::MultiThreaded, ffi, Options};
16
17use std::sync::Arc;
18use std::time::Duration;
19
20/// The name of the default column family.
21///
22/// The column family with this name is created implicitly whenever column
23/// families are used.
24pub const DEFAULT_COLUMN_FAMILY_NAME: &str = "default";
25
26/// A descriptor for a RocksDB column family.
27///
28/// A description of the column family, containing the name and `Options`.
29pub struct ColumnFamilyDescriptor {
30 pub(crate) name: String,
31 pub(crate) options: Options,
32 pub(crate) ttl: ColumnFamilyTtl,
33}
34
35impl ColumnFamilyDescriptor {
36 /// Create a new column family descriptor with the specified name and options.
37 /// *WARNING*:
38 /// Will use [`ColumnFamilyTtl::SameAsDb`] as ttl.
39 pub fn new<S>(name: S, options: Options) -> Self
40 where
41 S: Into<String>,
42 {
43 Self {
44 name: name.into(),
45 options,
46 ttl: ColumnFamilyTtl::SameAsDb,
47 }
48 }
49
50 /// Create a new column family descriptor with the specified name, options, and ttl.
51 /// *WARNING*:
52 /// The ttl is applied only when DB is opened with [`crate::db::DB::open_with_ttl()`].
53 pub fn new_with_ttl<S>(name: S, options: Options, ttl: ColumnFamilyTtl) -> Self
54 where
55 S: Into<String>,
56 {
57 Self {
58 name: name.into(),
59 options,
60 ttl,
61 }
62 }
63
64 /// Sets ttl for the column family. It's applied only when DB is opened with
65 /// [`crate::db::DB::open_with_ttl()`]. Changing ttl after DB is opened has no effect.
66 pub fn set_ttl(&mut self, ttl: ColumnFamilyTtl) {
67 self.ttl = ttl;
68 }
69
70 /// Get the name of the ColumnFamilyDescriptor.
71 pub fn name(&self) -> &str {
72 &self.name
73 }
74
75 pub fn ttl(&self) -> ColumnFamilyTtl {
76 self.ttl
77 }
78}
79
80#[derive(Debug, Clone, Copy, Default)]
81/// Specifies the TTL behavior for a column family.
82/// <https://github.com/facebook/rocksdb/blob/18cecb9c46b4c2a8b148659dac2fcab5a843d32b/include/rocksdb/utilities/db_ttl.h#L16-L46>
83pub enum ColumnFamilyTtl {
84 /// Will internally set TTL to -1 (disabled)
85 #[default]
86 Disabled,
87 /// Will set ttl to the specified duration
88 Duration(Duration),
89 /// Will use ttl specified at db open time
90 SameAsDb,
91}
92
93/// An opaque type used to represent a column family. Returned from some functions, and used
94/// in others
95pub struct ColumnFamily {
96 pub(crate) inner: *mut ffi::rocksdb_column_family_handle_t,
97}
98
99/// A specialized opaque type used to represent a column family by the [`MultiThreaded`]
100/// mode. Clone (and Copy) is derived to behave like `&ColumnFamily` (this is used for
101/// single-threaded mode). `Clone`/`Copy` is safe because this lifetime is bound to DB like
102/// iterators/snapshots. On top of it, this is as cheap and small as `&ColumnFamily` because
103/// this only has a single pointer-wide field.
104pub struct BoundColumnFamily<'a> {
105 pub(crate) inner: *mut ffi::rocksdb_column_family_handle_t,
106 pub(crate) multi_threaded_cfs: std::marker::PhantomData<&'a MultiThreaded>,
107}
108
109// internal struct which isn't exposed to public api.
110// but its memory will be exposed after transmute()-ing to BoundColumnFamily.
111// ColumnFamily's lifetime should be bound to DB. But, db holds cfs and cfs can't easily
112// self-reference DB as its lifetime due to rust's type system
113pub(crate) struct UnboundColumnFamily {
114 pub(crate) inner: *mut ffi::rocksdb_column_family_handle_t,
115}
116
117impl UnboundColumnFamily {
118 pub(crate) fn bound_column_family<'a>(self: Arc<Self>) -> Arc<BoundColumnFamily<'a>> {
119 // SAFETY: the new BoundColumnFamily here just adding lifetime,
120 // so that column family handle won't outlive db.
121 unsafe { Arc::from_raw(Arc::into_raw(self).cast()) }
122 }
123}
124
125fn destroy_handle(handle: *mut ffi::rocksdb_column_family_handle_t) {
126 // SAFETY: This should be called only from various Drop::drop(), strictly keeping a 1-to-1
127 // ownership to avoid double invocation to the rocksdb function with same handle.
128 unsafe {
129 ffi::rocksdb_column_family_handle_destroy(handle);
130 }
131}
132
133impl Drop for ColumnFamily {
134 fn drop(&mut self) {
135 destroy_handle(self.inner);
136 }
137}
138
139// these behaviors must be identical between BoundColumnFamily and UnboundColumnFamily
140// due to the unsafe transmute() in bound_column_family()!
141impl Drop for BoundColumnFamily<'_> {
142 fn drop(&mut self) {
143 destroy_handle(self.inner);
144 }
145}
146
147impl Drop for UnboundColumnFamily {
148 fn drop(&mut self) {
149 destroy_handle(self.inner);
150 }
151}
152
153/// Handy type alias to hide actual type difference to reference [`ColumnFamily`]
154/// depending on the `multi-threaded-cf` crate feature.
155#[cfg(not(feature = "multi-threaded-cf"))]
156pub type ColumnFamilyRef<'a> = &'a ColumnFamily;
157
158#[cfg(feature = "multi-threaded-cf")]
159pub type ColumnFamilyRef<'a> = Arc<BoundColumnFamily<'a>>;
160
161/// Utility trait to accept both supported references to `ColumnFamily`
162/// (`&ColumnFamily` and `BoundColumnFamily`)
163pub trait AsColumnFamilyRef {
164 fn inner(&self) -> *mut ffi::rocksdb_column_family_handle_t;
165}
166
167impl AsColumnFamilyRef for ColumnFamily {
168 fn inner(&self) -> *mut ffi::rocksdb_column_family_handle_t {
169 self.inner
170 }
171}
172
173impl AsColumnFamilyRef for &'_ ColumnFamily {
174 fn inner(&self) -> *mut ffi::rocksdb_column_family_handle_t {
175 self.inner
176 }
177}
178
179// Only implement for Arc-ed BoundColumnFamily as this tightly coupled and
180// implementation detail, considering use of std::mem::transmute. BoundColumnFamily
181// isn't expected to be used as naked.
182// Also, ColumnFamilyRef might not be Arc<BoundColumnFamily<'a>> depending crate
183// feature flags so, we can't use the type alias here.
184impl AsColumnFamilyRef for Arc<BoundColumnFamily<'_>> {
185 fn inner(&self) -> *mut ffi::rocksdb_column_family_handle_t {
186 self.inner
187 }
188}
189
190unsafe impl Send for ColumnFamily {}
191unsafe impl Sync for ColumnFamily {}
192unsafe impl Send for UnboundColumnFamily {}
193unsafe impl Sync for UnboundColumnFamily {}
194unsafe impl Send for BoundColumnFamily<'_> {}
195unsafe impl Sync for BoundColumnFamily<'_> {}