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::{ffi, ffi_util::to_cpath, Error, Options};
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    pub fn open<P: AsRef<Path>>(&'a self, path: P) -> Result<(), Error> {
71        let cpath = to_cpath(&path)?;
72        self.open_raw(&cpath)
73    }
74
75    fn open_raw(&'a self, cpath: &CString) -> Result<(), Error> {
76        unsafe {
77            ffi_try!(ffi::rocksdb_sstfilewriter_open(
78                self.inner,
79                cpath.as_ptr() as *const _
80            ));
81
82            Ok(())
83        }
84    }
85
86    /// Finalize writing to sst file and close file.
87    pub fn finish(&mut self) -> Result<(), Error> {
88        unsafe {
89            ffi_try!(ffi::rocksdb_sstfilewriter_finish(self.inner,));
90            Ok(())
91        }
92    }
93
94    /// returns the current file size
95    pub fn file_size(&self) -> u64 {
96        let mut file_size: u64 = 0;
97        unsafe {
98            ffi::rocksdb_sstfilewriter_file_size(self.inner, &mut file_size);
99        }
100        file_size
101    }
102
103    /// Adds a Put key with value to currently opened file
104    /// REQUIRES: key is after any previously added key according to comparator.
105    pub fn put<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
106    where
107        K: AsRef<[u8]>,
108        V: AsRef<[u8]>,
109    {
110        let key = key.as_ref();
111        let value = value.as_ref();
112        unsafe {
113            ffi_try!(ffi::rocksdb_sstfilewriter_put(
114                self.inner,
115                key.as_ptr() as *const c_char,
116                key.len() as size_t,
117                value.as_ptr() as *const c_char,
118                value.len() as size_t,
119            ));
120            Ok(())
121        }
122    }
123
124    /// Adds a Put key with value to currently opened file
125    /// REQUIRES: key is after any previously added key according to comparator.
126    pub fn put_with_ts<K, V, S>(&mut self, key: K, ts: S, value: V) -> Result<(), Error>
127    where
128        K: AsRef<[u8]>,
129        V: AsRef<[u8]>,
130        S: AsRef<[u8]>,
131    {
132        let key = key.as_ref();
133        let value = value.as_ref();
134        let ts = ts.as_ref();
135        unsafe {
136            ffi_try!(ffi::rocksdb_sstfilewriter_put_with_ts(
137                self.inner,
138                key.as_ptr() as *const c_char,
139                key.len() as size_t,
140                ts.as_ptr() as *const c_char,
141                ts.len() as size_t,
142                value.as_ptr() as *const c_char,
143                value.len() as size_t,
144            ));
145            Ok(())
146        }
147    }
148
149    /// Adds a Merge key with value to currently opened file
150    /// REQUIRES: key is after any previously added key according to comparator.
151    pub fn merge<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
152    where
153        K: AsRef<[u8]>,
154        V: AsRef<[u8]>,
155    {
156        let key = key.as_ref();
157        let value = value.as_ref();
158
159        unsafe {
160            ffi_try!(ffi::rocksdb_sstfilewriter_merge(
161                self.inner,
162                key.as_ptr() as *const c_char,
163                key.len() as size_t,
164                value.as_ptr() as *const c_char,
165                value.len() as size_t,
166            ));
167            Ok(())
168        }
169    }
170
171    /// Adds a deletion key to currently opened file
172    /// REQUIRES: key is after any previously added key according to comparator.
173    pub fn delete<K: AsRef<[u8]>>(&mut self, key: K) -> Result<(), Error> {
174        let key = key.as_ref();
175
176        unsafe {
177            ffi_try!(ffi::rocksdb_sstfilewriter_delete(
178                self.inner,
179                key.as_ptr() as *const c_char,
180                key.len() as size_t,
181            ));
182            Ok(())
183        }
184    }
185
186    /// Adds a deletion key to currently opened file
187    /// REQUIRES: key is after any previously added key according to comparator.
188    pub fn delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
189        &mut self,
190        key: K,
191        ts: S,
192    ) -> Result<(), Error> {
193        let key = key.as_ref();
194        let ts = ts.as_ref();
195        unsafe {
196            ffi_try!(ffi::rocksdb_sstfilewriter_delete_with_ts(
197                self.inner,
198                key.as_ptr() as *const c_char,
199                key.len() as size_t,
200                ts.as_ptr() as *const c_char,
201                ts.len() as size_t,
202            ));
203            Ok(())
204        }
205    }
206}
207
208impl Drop for SstFileWriter<'_> {
209    fn drop(&mut self) {
210        unsafe {
211            ffi::rocksdb_sstfilewriter_destroy(self.inner);
212        }
213    }
214}