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<'_> {}