ckb_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<'a> Send for SstFileWriter<'a> {}
31unsafe impl<'a> Sync for SstFileWriter<'a> {}
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(
72            &path,
73            "Failed to convert path to CString when create SstFileWriter.",
74        )?;
75        self.open_raw(&cpath)
76    }
77
78    fn open_raw(&'a self, cpath: &CString) -> Result<(), Error> {
79        unsafe {
80            ffi_try!(ffi::rocksdb_sstfilewriter_open(
81                self.inner,
82                cpath.as_ptr() as *const _
83            ));
84
85            Ok(())
86        }
87    }
88
89    /// Finalize writing to sst file and close file.
90    pub fn finish(&mut self) -> Result<(), Error> {
91        unsafe {
92            ffi_try!(ffi::rocksdb_sstfilewriter_finish(self.inner,));
93            Ok(())
94        }
95    }
96
97    /// returns the current file size
98    pub fn file_size(&self) -> u64 {
99        let mut file_size: u64 = 0;
100        unsafe {
101            ffi::rocksdb_sstfilewriter_file_size(self.inner, &mut file_size);
102        }
103        file_size
104    }
105
106    /// Adds a Put key with value to currently opened file
107    /// REQUIRES: key is after any previously added key according to comparator.
108    pub fn put<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
109    where
110        K: AsRef<[u8]>,
111        V: AsRef<[u8]>,
112    {
113        let key = key.as_ref();
114        let value = value.as_ref();
115
116        unsafe {
117            ffi_try!(ffi::rocksdb_sstfilewriter_put(
118                self.inner,
119                key.as_ptr() as *const c_char,
120                key.len() as size_t,
121                value.as_ptr() as *const c_char,
122                value.len() as size_t,
123            ));
124            Ok(())
125        }
126    }
127
128    /// Adds a Merge key with value to currently opened file
129    /// REQUIRES: key is after any previously added key according to comparator.
130    pub fn merge<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
131    where
132        K: AsRef<[u8]>,
133        V: AsRef<[u8]>,
134    {
135        let key = key.as_ref();
136        let value = value.as_ref();
137
138        unsafe {
139            ffi_try!(ffi::rocksdb_sstfilewriter_merge(
140                self.inner,
141                key.as_ptr() as *const c_char,
142                key.len() as size_t,
143                value.as_ptr() as *const c_char,
144                value.len() as size_t,
145            ));
146            Ok(())
147        }
148    }
149
150    /// Adds a deletion key to currently opened file
151    /// REQUIRES: key is after any previously added key according to comparator.
152    pub fn delete<K: AsRef<[u8]>>(&mut self, key: K) -> Result<(), Error> {
153        let key = key.as_ref();
154
155        unsafe {
156            ffi_try!(ffi::rocksdb_sstfilewriter_delete(
157                self.inner,
158                key.as_ptr() as *const c_char,
159                key.len() as size_t,
160            ));
161            Ok(())
162        }
163    }
164}
165
166impl<'a> Drop for SstFileWriter<'a> {
167    fn drop(&mut self) {
168        unsafe {
169            ffi::rocksdb_sstfilewriter_destroy(self.inner);
170        }
171    }
172}