// Copyright 2020 Lucjan Suski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //` use crate::{ffi, ffi_util::to_cpath, Error, Options}; use libc::{self, c_char, size_t}; use std::{ffi::CString, marker::PhantomData, path::Path}; /// SstFileWriter is used to create sst files that can be added to database later /// All keys in files generated by SstFileWriter will have sequence number = 0. pub struct SstFileWriter<'a> { pub(crate) inner: *mut ffi::rocksdb_sstfilewriter_t, // Options are needed to be alive when calling open(), // so let's make sure it doesn't get, dropped for the lifetime of SstFileWriter phantom: PhantomData<&'a Options>, } unsafe impl<'a> Send for SstFileWriter<'a> {} unsafe impl<'a> Sync for SstFileWriter<'a> {} struct EnvOptions { inner: *mut ffi::rocksdb_envoptions_t, } impl Drop for EnvOptions { fn drop(&mut self) { unsafe { ffi::rocksdb_envoptions_destroy(self.inner); } } } impl Default for EnvOptions { fn default() -> Self { let opts = unsafe { ffi::rocksdb_envoptions_create() }; Self { inner: opts } } } impl<'a> SstFileWriter<'a> { /// Initializes SstFileWriter with given DB options. pub fn create(opts: &'a Options) -> Self { let env_options = EnvOptions::default(); let writer = Self::create_raw(opts, &env_options); Self { inner: writer, phantom: PhantomData, } } fn create_raw(opts: &Options, env_opts: &EnvOptions) -> *mut ffi::rocksdb_sstfilewriter_t { unsafe { ffi::rocksdb_sstfilewriter_create(env_opts.inner, opts.inner) } } /// Prepare SstFileWriter to write into file located at "file_path". pub fn open>(&'a self, path: P) -> Result<(), Error> { let cpath = to_cpath(&path)?; self.open_raw(&cpath) } fn open_raw(&'a self, cpath: &CString) -> Result<(), Error> { unsafe { ffi_try!(ffi::rocksdb_sstfilewriter_open( self.inner, cpath.as_ptr() as *const _ )); Ok(()) } } /// Finalize writing to sst file and close file. pub fn finish(&mut self) -> Result<(), Error> { unsafe { ffi_try!(ffi::rocksdb_sstfilewriter_finish(self.inner,)); Ok(()) } } /// returns the current file size pub fn file_size(&self) -> u64 { let mut file_size: u64 = 0; unsafe { ffi::rocksdb_sstfilewriter_file_size(self.inner, &mut file_size); } file_size } /// Adds a Put key with value to currently opened file /// REQUIRES: key is after any previously added key according to comparator. pub fn put(&mut self, key: K, value: V) -> Result<(), Error> where K: AsRef<[u8]>, V: AsRef<[u8]>, { let key = key.as_ref(); let value = value.as_ref(); unsafe { ffi_try!(ffi::rocksdb_sstfilewriter_put( self.inner, key.as_ptr() as *const c_char, key.len() as size_t, value.as_ptr() as *const c_char, value.len() as size_t, )); Ok(()) } } /// Adds a Merge key with value to currently opened file /// REQUIRES: key is after any previously added key according to comparator. pub fn merge(&mut self, key: K, value: V) -> Result<(), Error> where K: AsRef<[u8]>, V: AsRef<[u8]>, { let key = key.as_ref(); let value = value.as_ref(); unsafe { ffi_try!(ffi::rocksdb_sstfilewriter_merge( self.inner, key.as_ptr() as *const c_char, key.len() as size_t, value.as_ptr() as *const c_char, value.len() as size_t, )); Ok(()) } } /// Adds a deletion key to currently opened file /// REQUIRES: key is after any previously added key according to comparator. pub fn delete>(&mut self, key: K) -> Result<(), Error> { let key = key.as_ref(); unsafe { ffi_try!(ffi::rocksdb_sstfilewriter_delete( self.inner, key.as_ptr() as *const c_char, key.len() as size_t, )); Ok(()) } } } impl<'a> Drop for SstFileWriter<'a> { fn drop(&mut self) { unsafe { ffi::rocksdb_sstfilewriter_destroy(self.inner); } } }