1use std::{ffi::CStr, path};
16
17use crate::{
18 db_options::{Cache, OptionsMustOutliveDB},
19 ffi, ffi_util, ColumnFamilyDescriptor, Error, Options,
20};
21
22#[derive(Clone)]
23pub struct FullOptions {
24 pub db_opts: Options,
25 pub cf_descriptors: Vec<ColumnFamilyDescriptor>,
26}
27
28impl FullOptions {
29 pub fn load_from_file<P>(
30 file: P,
31 cache_size: Option<usize>,
32 ignore_unknown_options: bool,
33 ) -> Result<Self, Error>
34 where
35 P: AsRef<path::Path>,
36 {
37 Self::load_from_file_with_cache(
38 file,
39 cache_size.map(Cache::new_lru_cache),
40 ignore_unknown_options,
41 )
42 }
43
44 pub fn load_from_file_with_cache<P>(
45 file: P,
46 cache: Option<Cache>,
47 ignore_unknown_options: bool,
48 ) -> Result<Self, Error>
49 where
50 P: AsRef<path::Path>,
51 {
52 let cpath = ffi_util::to_cpath(
53 file,
54 "Failed to convert path to CString when load config file.",
55 )?;
56
57 unsafe {
58 let env = ffi::rocksdb_create_default_env();
59 let result = ffi_try!(ffi::rocksdb_options_load_from_file(
60 cpath.as_ptr(),
61 env,
62 ignore_unknown_options,
63 cache
64 .as_ref()
65 .map(|c| c.0.inner.as_ptr())
66 .unwrap_or_else(|| ffi::rocksdb_null_cache()),
67 ));
68 ffi::rocksdb_env_destroy(env);
69 let db_opts = result.db_opts;
70 let cf_descs = result.cf_descs;
71 let cf_descs_size = ffi::rocksdb_column_family_descriptors_count(cf_descs);
72 let mut cf_descriptors = Vec::new();
73 for index in 0..cf_descs_size {
74 let name_raw = ffi::rocksdb_column_family_descriptors_name(cf_descs, index);
75 let name_cstr = CStr::from_ptr(name_raw as *const _);
76 let name = String::from_utf8_lossy(name_cstr.to_bytes());
77 let cf_opts_inner = ffi::rocksdb_column_family_descriptors_options(cf_descs, index);
78 let outlive = OptionsMustOutliveDB {
79 row_cache: cache.clone(),
80 ..Default::default()
81 };
82 let cf_opts = Options {
83 inner: cf_opts_inner,
84 outlive,
85 };
86 cf_descriptors.push(ColumnFamilyDescriptor::new(name, cf_opts));
87 }
88 ffi::rocksdb_column_family_descriptors_destroy(cf_descs);
89
90 let outlive = OptionsMustOutliveDB {
91 row_cache: cache,
92 ..Default::default()
93 };
94
95 Ok(Self {
96 db_opts: Options {
97 inner: db_opts,
98 outlive,
99 },
100 cf_descriptors,
101 })
102 }
103 }
104
105 pub fn complete_column_families(
123 &mut self,
124 cf_names: &[&str],
125 ignore_unknown_column_families: bool,
126 ) -> Result<(), Error> {
127 let cf_name_default = "default";
128 let mut options_default = None;
129 for cfd in &self.cf_descriptors {
130 if cfd.name == cf_name_default {
131 options_default = Some(cfd.options.clone());
132 continue;
133 }
134 if cf_names.iter().any(|cf_name| &cfd.name == cf_name) {
135 continue;
136 }
137 if !ignore_unknown_column_families {
138 return Err(Error::new(format!(
139 "an unknown column family named \"{}\"",
140 cfd.name
141 )));
142 }
143 }
144 if options_default.is_none() {
145 let cf = ColumnFamilyDescriptor::new(cf_name_default, Options::default());
146 options_default = Some(cf.options.clone());
147 self.cf_descriptors.insert(0, cf);
148 }
149 let options_default = options_default.unwrap();
150 for cf_name in cf_names {
151 if cf_name == &cf_name_default {
152 return Err(Error::new(format!(
153 "don't name a user-defined column family as \"{}\"",
154 cf_name
155 )));
156 }
157 if self.cf_descriptors.iter().all(|cfd| &cfd.name != cf_name) {
158 let cf = ColumnFamilyDescriptor::new(cf_name.to_owned(), options_default.clone());
159 self.cf_descriptors.push(cf);
160 }
161 }
162 Ok(())
163 }
164}