Skip to main content

rust_rocksdb/
sst_file_writer.rs

1// Copyright 2020 Lucjan Suski
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
16use crate::{Error, Options, ffi, ffi_util::to_cpath};
17
18use libc::{self, c_char, size_t};
19use std::{ffi::CString, marker::PhantomData, path::Path};
20
21/// SstFileWriter is used to create sst files that can be added to database later
22/// All keys in files generated by SstFileWriter will have sequence number = 0.
23pub struct SstFileWriter<'a> {
24    pub(crate) inner: *mut ffi::rocksdb_sstfilewriter_t,
25    // Options are needed to be alive when calling open(),
26    // so let's make sure it doesn't get, dropped for the lifetime of SstFileWriter
27    phantom: PhantomData<&'a Options>,
28}
29
30unsafe impl Send for SstFileWriter<'_> {}
31unsafe impl Sync for SstFileWriter<'_> {}
32
33struct EnvOptions {
34    inner: *mut ffi::rocksdb_envoptions_t,
35}
36
37impl Drop for EnvOptions {
38    fn drop(&mut self) {
39        unsafe {
40            ffi::rocksdb_envoptions_destroy(self.inner);
41        }
42    }
43}
44
45impl Default for EnvOptions {
46    fn default() -> Self {
47        let opts = unsafe { ffi::rocksdb_envoptions_create() };
48        Self { inner: opts }
49    }
50}
51
52impl<'a> SstFileWriter<'a> {
53    /// Initializes SstFileWriter with given DB options.
54    pub fn create(opts: &'a Options) -> Self {
55        let env_options = EnvOptions::default();
56
57        let writer = Self::create_raw(opts, &env_options);
58
59        Self {
60            inner: writer,
61            phantom: PhantomData,
62        }
63    }
64
65    fn create_raw(opts: &Options, env_opts: &EnvOptions) -> *mut ffi::rocksdb_sstfilewriter_t {
66        unsafe { ffi::rocksdb_sstfilewriter_create(env_opts.inner, opts.inner) }
67    }
68
69    /// Prepare SstFileWriter to write into file located at "file_path".
70    ///
71    /// Takes `&mut self` because the underlying `rocksdb::SstFileWriter::Open`
72    /// mutates the writer (it installs a new `WritableFileWriter` and table
73    /// builder) and is not thread safe. With `&self` and the `Sync` impl above,
74    /// two threads could call this concurrently on the same writer from safe
75    /// code and race on those fields.
76    pub fn open<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
77        let cpath = to_cpath(&path)?;
78        self.open_raw(&cpath)
79    }
80
81    fn open_raw(&mut self, cpath: &CString) -> Result<(), Error> {
82        unsafe {
83            ffi_try!(ffi::rocksdb_sstfilewriter_open(
84                self.inner,
85                cpath.as_ptr() as *const _
86            ));
87
88            Ok(())
89        }
90    }
91
92    /// Finalize writing to sst file and close file.
93    pub fn finish(&mut self) -> Result<(), Error> {
94        unsafe {
95            ffi_try!(ffi::rocksdb_sstfilewriter_finish(self.inner,));
96            Ok(())
97        }
98    }
99
100    /// returns the current file size
101    pub fn file_size(&self) -> u64 {
102        let mut file_size: u64 = 0;
103        unsafe {
104            ffi::rocksdb_sstfilewriter_file_size(self.inner, &raw mut file_size);
105        }
106        file_size
107    }
108
109    /// Adds a Put key with value to currently opened file
110    /// REQUIRES: key is after any previously added key according to comparator.
111    pub fn put<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
112    where
113        K: AsRef<[u8]>,
114        V: AsRef<[u8]>,
115    {
116        let key = key.as_ref();
117        let value = value.as_ref();
118        unsafe {
119            ffi_try!(ffi::rocksdb_sstfilewriter_put(
120                self.inner,
121                key.as_ptr() as *const c_char,
122                key.len() as size_t,
123                value.as_ptr() as *const c_char,
124                value.len() as size_t,
125            ));
126            Ok(())
127        }
128    }
129
130    /// Adds a Put key with value to currently opened file
131    /// REQUIRES: key is after any previously added key according to comparator.
132    pub fn put_with_ts<K, V, S>(&mut self, key: K, ts: S, value: V) -> Result<(), Error>
133    where
134        K: AsRef<[u8]>,
135        V: AsRef<[u8]>,
136        S: AsRef<[u8]>,
137    {
138        let key = key.as_ref();
139        let value = value.as_ref();
140        let ts = ts.as_ref();
141        unsafe {
142            ffi_try!(ffi::rocksdb_sstfilewriter_put_with_ts(
143                self.inner,
144                key.as_ptr() as *const c_char,
145                key.len() as size_t,
146                ts.as_ptr() as *const c_char,
147                ts.len() as size_t,
148                value.as_ptr() as *const c_char,
149                value.len() as size_t,
150            ));
151            Ok(())
152        }
153    }
154
155    /// Adds a Merge key with value to currently opened file
156    /// REQUIRES: key is after any previously added key according to comparator.
157    pub fn merge<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
158    where
159        K: AsRef<[u8]>,
160        V: AsRef<[u8]>,
161    {
162        let key = key.as_ref();
163        let value = value.as_ref();
164
165        unsafe {
166            ffi_try!(ffi::rocksdb_sstfilewriter_merge(
167                self.inner,
168                key.as_ptr() as *const c_char,
169                key.len() as size_t,
170                value.as_ptr() as *const c_char,
171                value.len() as size_t,
172            ));
173            Ok(())
174        }
175    }
176
177    /// Adds a deletion key to currently opened file
178    /// REQUIRES: key is after any previously added key according to comparator.
179    pub fn delete<K: AsRef<[u8]>>(&mut self, key: K) -> Result<(), Error> {
180        let key = key.as_ref();
181
182        unsafe {
183            ffi_try!(ffi::rocksdb_sstfilewriter_delete(
184                self.inner,
185                key.as_ptr() as *const c_char,
186                key.len() as size_t,
187            ));
188            Ok(())
189        }
190    }
191
192    /// Adds a range deletion tombstone to the currently opened file.
193    /// Unlike point entries, range tombstones may be added out of order.
194    /// REQUIRES: `begin_key` <= `end_key` according to the comparator.
195    /// REQUIRES: comparator is not timestamp-aware.
196    pub fn delete_range<K: AsRef<[u8]>>(&mut self, begin_key: K, end_key: K) -> Result<(), Error> {
197        let begin_key = begin_key.as_ref();
198        let end_key = end_key.as_ref();
199
200        unsafe {
201            ffi_try!(ffi::rocksdb_sstfilewriter_delete_range(
202                self.inner,
203                begin_key.as_ptr() as *const c_char,
204                begin_key.len() as size_t,
205                end_key.as_ptr() as *const c_char,
206                end_key.len() as size_t,
207            ));
208            Ok(())
209        }
210    }
211
212    /// Adds a deletion key to currently opened file
213    /// REQUIRES: key is after any previously added key according to comparator.
214    pub fn delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
215        &mut self,
216        key: K,
217        ts: S,
218    ) -> Result<(), Error> {
219        let key = key.as_ref();
220        let ts = ts.as_ref();
221        unsafe {
222            ffi_try!(ffi::rocksdb_sstfilewriter_delete_with_ts(
223                self.inner,
224                key.as_ptr() as *const c_char,
225                key.len() as size_t,
226                ts.as_ptr() as *const c_char,
227                ts.len() as size_t,
228            ));
229            Ok(())
230        }
231    }
232}
233
234impl Drop for SstFileWriter<'_> {
235    fn drop(&mut self) {
236        unsafe {
237            ffi::rocksdb_sstfilewriter_destroy(self.inner);
238        }
239    }
240}