21 #include <ripple/unity/rocksdb.h>
23 #if RIPPLE_ROCKSDB_AVAILABLE
25 #include <ripple/basics/contract.h>
26 #include <ripple/basics/ByteUtilities.h>
27 #include <ripple/core/Config.h>
28 #include <ripple/nodestore/Factory.h>
29 #include <ripple/nodestore/Manager.h>
30 #include <ripple/nodestore/impl/BatchWriter.h>
31 #include <ripple/nodestore/impl/DecodedBlob.h>
32 #include <ripple/nodestore/impl/EncodedBlob.h>
33 #include <ripple/beast/core/CurrentThreadName.h>
40 class RocksDBEnv :
public rocksdb::EnvWrapper
44 : EnvWrapper (rocksdb::Env::Default())
50 ThreadParams (
void (*f_)(
void*),
void* a_)
62 thread_entry (
void* ptr)
64 ThreadParams*
const p (
reinterpret_cast <ThreadParams*
> (ptr));
65 void (*f)(
void*) = p->f;
72 ss <<
"rocksdb #" << id;
79 StartThread (
void (*f)(
void*),
void* a)
override
81 ThreadParams*
const p (
new ThreadParams (f, a));
82 EnvWrapper::StartThread (&RocksDBEnv::thread_entry, p);
90 ,
public BatchWriter::Callback
97 size_t const m_keyBytes;
98 Scheduler& m_scheduler;
102 int fdRequired_ = 2048;
103 rocksdb::Options m_options;
105 RocksDBBackend (
int keyBytes, Section
const& keyValues,
107 : m_deletePath (false)
108 , m_journal (journal)
109 , m_keyBytes (keyBytes)
110 , m_scheduler (scheduler)
111 , m_batch (*this, scheduler)
114 Throw<std::runtime_error> (
"Missing path in RocksDBFactory backend");
116 rocksdb::BlockBasedTableOptions table_options;
119 if (keyValues.exists (
"cache_mb"))
120 table_options.block_cache = rocksdb::NewLRUCache (
121 get<int>(keyValues,
"cache_mb") *
megabytes(1));
123 if (
auto const v = get<int>(keyValues,
"filter_bits"))
125 bool const filter_blocks = !keyValues.exists (
"filter_full") ||
126 (get<int>(keyValues,
"filter_full") == 0);
127 table_options.filter_policy.reset (rocksdb::NewBloomFilterPolicy (v, filter_blocks));
130 if (
get_if_exists (keyValues,
"open_files", m_options.max_open_files))
131 fdRequired_ = m_options.max_open_files;
133 if (keyValues.exists (
"file_size_mb"))
135 m_options.target_file_size_base =
megabytes(1) * get<int>(keyValues,
"file_size_mb");
136 m_options.max_bytes_for_level_base = 5 * m_options.target_file_size_base;
137 m_options.write_buffer_size = 2 * m_options.target_file_size_base;
140 get_if_exists (keyValues,
"file_size_mult", m_options.target_file_size_multiplier);
142 if (keyValues.exists (
"bg_threads"))
144 m_options.env->SetBackgroundThreads
145 (get<int>(keyValues,
"bg_threads"), rocksdb::Env::LOW);
148 if (keyValues.exists (
"high_threads"))
150 auto const highThreads = get<int>(keyValues,
"high_threads");
151 m_options.env->SetBackgroundThreads (highThreads, rocksdb::Env::HIGH);
156 m_options.max_background_flushes = highThreads;
159 m_options.compression = rocksdb::kSnappyCompression;
161 get_if_exists (keyValues,
"block_size", table_options.block_size);
163 if (keyValues.exists (
"universal_compaction") &&
164 (get<int>(keyValues,
"universal_compaction") != 0))
166 m_options.compaction_style = rocksdb::kCompactionStyleUniversal;
167 m_options.min_write_buffer_number_to_merge = 2;
168 m_options.max_write_buffer_number = 6;
169 m_options.write_buffer_size = 6 * m_options.target_file_size_base;
172 if (keyValues.exists(
"bbt_options"))
174 auto const s = rocksdb::GetBlockBasedTableOptionsFromString(
176 get<std::string>(keyValues,
"bbt_options"),
179 Throw<std::runtime_error> (
180 std::string(
"Unable to set RocksDB bbt_options: ") + s.ToString());
183 m_options.table_factory.reset(NewBlockBasedTableFactory(table_options));
185 if (keyValues.exists(
"options"))
187 auto const s = rocksdb::GetOptionsFromString(
188 m_options, get<std::string>(keyValues,
"options"), &m_options);
190 Throw<std::runtime_error> (
191 std::string(
"Unable to set RocksDB options: ") + s.ToString());
195 rocksdb::GetStringFromDBOptions(&s1, m_options,
"; ");
196 rocksdb::GetStringFromColumnFamilyOptions(&s2, m_options,
"; ");
197 JLOG(m_journal.
debug()) <<
"RocksDB DBOptions: " << s1;
198 JLOG(m_journal.
debug()) <<
"RocksDB CFOptions: " << s2;
201 ~RocksDBBackend ()
override
207 open(
bool createIfMissing)
override
212 JLOG(m_journal.
error()) <<
213 "database is already open";
216 rocksdb::DB* db =
nullptr;
217 m_options.create_if_missing = createIfMissing;
218 rocksdb::Status
status = rocksdb::DB::Open(m_options, m_name, &db);
220 Throw<std::runtime_error>(
234 boost::filesystem::path dir = m_name;
235 boost::filesystem::remove_all (dir);
256 rocksdb::ReadOptions
const options;
257 rocksdb::Slice
const slice (
static_cast <char const*
> (key), m_keyBytes);
261 rocksdb::Status getStatus = m_db->Get (options, slice, &
string);
265 DecodedBlob decoded (key,
string.data (),
string.size ());
267 if (decoded.wasOk ())
269 *pObject = decoded.createObject ();
280 if (getStatus.IsCorruption ())
284 else if (getStatus.IsNotFound ())
292 JLOG(m_journal.
error()) << getStatus.ToString ();
300 canFetchBatch()
override
306 fetchBatch (
std::size_t n,
void const*
const* keys)
override
308 Throw<std::runtime_error> (
"pure virtual called");
315 m_batch.store (
object);
319 storeBatch (
Batch const& batch)
override
322 rocksdb::WriteBatch wb;
326 for (
auto const& e : batch)
331 rocksdb::Slice (
reinterpret_cast <char const*
> (
332 encoded.getKey ()), m_keyBytes),
333 rocksdb::Slice (
reinterpret_cast <char const*
> (
334 encoded.getData ()), encoded.getSize ()));
337 rocksdb::WriteOptions
const options;
339 auto ret = m_db->Write (options, &wb);
342 Throw<std::runtime_error> (
"storeBatch failed: " + ret.ToString());
349 rocksdb::ReadOptions
const options;
353 for (it->SeekToFirst (); it->Valid (); it->Next ())
355 if (it->key ().size () == m_keyBytes)
357 DecodedBlob decoded (it->key ().data (),
358 it->value ().data (),
359 it->value ().size ());
361 if (decoded.wasOk ())
363 f (decoded.createObject ());
368 JLOG(m_journal.
fatal()) <<
369 "Corrupt NodeObject #" <<
370 from_hex_text<uint256>(it->key ().data ());
377 JLOG(m_journal.
fatal()) <<
378 "Bad key size = " << it->key ().size ();
384 getWriteLoad ()
override
386 return m_batch.getWriteLoad ();
390 setDeletePath()
override
398 writeBatch (
Batch const& batch)
override
410 fdRequired()
const override
418 class RocksDBFactory :
public Factory
428 ~RocksDBFactory ()
override
434 getName ()
const override
442 Section
const& keyValues,
443 Scheduler& scheduler,
446 return std::make_unique <RocksDBBackend> (
447 keyBytes, keyValues, scheduler, journal, &m_env);
451 static RocksDBFactory rocksDBFactory;