2019-12-09 20:45:58 -05:00
|
|
|
#include "rocksdb.h"
|
2020-03-17 17:11:41 -04:00
|
|
|
#include "../version.h"
|
2019-12-24 02:22:47 -05:00
|
|
|
#include <rocksdb/filter_policy.h>
|
|
|
|
#include <rocksdb/table.h>
|
|
|
|
#include <rocksdb/utilities/options_util.h>
|
2020-06-07 16:40:03 -04:00
|
|
|
#include <rocksdb/sst_file_manager.h>
|
2020-07-14 04:24:46 +00:00
|
|
|
#include <rocksdb/utilities/convenience.h>
|
2021-04-21 01:19:44 +00:00
|
|
|
#include <rocksdb/slice_transform.h>
|
2019-12-09 20:45:58 -05:00
|
|
|
|
|
|
|
class RocksDBStorageFactory : public IStorageFactory
|
|
|
|
{
|
|
|
|
std::shared_ptr<rocksdb::DB> m_spdb; // Note: This must be first so it is deleted last
|
|
|
|
std::vector<std::unique_ptr<rocksdb::ColumnFamilyHandle>> m_vecspcols;
|
2020-06-07 16:40:03 -04:00
|
|
|
std::shared_ptr<rocksdb::SstFileManager> m_pfilemanager;
|
2019-12-09 20:45:58 -05:00
|
|
|
|
|
|
|
public:
|
2020-07-14 04:24:46 +00:00
|
|
|
RocksDBStorageFactory(const char *dbfile, int dbnum, const char *rgchConfig, size_t cchConfig);
|
2019-12-09 20:45:58 -05:00
|
|
|
~RocksDBStorageFactory();
|
|
|
|
|
2020-07-11 21:23:48 +00:00
|
|
|
virtual IStorage *create(int db, key_load_iterator iter, void *privdata) override;
|
2019-12-09 21:07:37 -05:00
|
|
|
virtual const char *name() const override;
|
2020-03-17 17:11:41 -04:00
|
|
|
|
2020-06-07 16:40:03 -04:00
|
|
|
virtual size_t totalDiskspaceUsed() const override;
|
|
|
|
|
2020-07-11 21:23:48 +00:00
|
|
|
virtual bool FSlow() const override { return true; }
|
|
|
|
|
2020-03-17 17:11:41 -04:00
|
|
|
private:
|
|
|
|
void setVersion(rocksdb::ColumnFamilyHandle*);
|
2019-12-09 20:45:58 -05:00
|
|
|
};
|
|
|
|
|
2020-07-14 04:24:46 +00:00
|
|
|
IStorageFactory *CreateRocksDBStorageFactory(const char *path, int dbnum, const char *rgchConfig, size_t cchConfig)
|
2019-12-09 20:45:58 -05:00
|
|
|
{
|
2020-07-14 04:24:46 +00:00
|
|
|
return new RocksDBStorageFactory(path, dbnum, rgchConfig, cchConfig);
|
2019-12-09 20:45:58 -05:00
|
|
|
}
|
|
|
|
|
2020-07-14 04:24:46 +00:00
|
|
|
RocksDBStorageFactory::RocksDBStorageFactory(const char *dbfile, int dbnum, const char *rgchConfig, size_t cchConfig)
|
2019-12-09 20:45:58 -05:00
|
|
|
{
|
|
|
|
// Get the count of column families in the actual database
|
|
|
|
std::vector<std::string> vecT;
|
|
|
|
auto status = rocksdb::DB::ListColumnFamilies(rocksdb::Options(), dbfile, &vecT);
|
|
|
|
// RocksDB requires we know the count of col families before opening, if the user only wants to see less
|
|
|
|
// we still have to make room for all column family handles regardless
|
|
|
|
if (status.ok() && (int)vecT.size() > dbnum)
|
|
|
|
dbnum = (int)vecT.size();
|
|
|
|
|
|
|
|
std::vector<rocksdb::ColumnFamilyDescriptor> veccoldesc;
|
|
|
|
veccoldesc.push_back(rocksdb::ColumnFamilyDescriptor(rocksdb::kDefaultColumnFamilyName, rocksdb::ColumnFamilyOptions())); // ignore default col family
|
|
|
|
|
2020-06-07 16:40:03 -04:00
|
|
|
m_pfilemanager = std::shared_ptr<rocksdb::SstFileManager>(rocksdb::NewSstFileManager(rocksdb::Env::Default()));
|
|
|
|
|
2019-12-09 20:45:58 -05:00
|
|
|
rocksdb::Options options;
|
|
|
|
options.create_if_missing = true;
|
|
|
|
options.create_missing_column_families = true;
|
|
|
|
rocksdb::DB *db = nullptr;
|
2019-12-24 02:22:47 -05:00
|
|
|
|
2020-07-14 04:24:46 +00:00
|
|
|
if (rgchConfig != nullptr)
|
|
|
|
{
|
|
|
|
std::string options_string(rgchConfig, cchConfig);
|
|
|
|
rocksdb::Status status;
|
|
|
|
if (!(status = rocksdb::GetDBOptionsFromString(options, options_string, &options)).ok())
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Failed to parse FLASH options: %s\r\n", status.ToString().c_str());
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-24 02:22:47 -05:00
|
|
|
options.max_background_compactions = 4;
|
|
|
|
options.max_background_flushes = 2;
|
|
|
|
options.bytes_per_sync = 1048576;
|
|
|
|
options.compaction_pri = rocksdb::kMinOverlappingRatio;
|
2020-08-06 22:30:56 +00:00
|
|
|
options.compression = rocksdb::kNoCompression;
|
2020-07-11 21:23:48 +00:00
|
|
|
options.enable_pipelined_write = true;
|
2020-06-07 16:40:03 -04:00
|
|
|
options.sst_file_manager = m_pfilemanager;
|
2021-04-21 01:19:44 +00:00
|
|
|
options.allow_mmap_reads = true;
|
|
|
|
options.prefix_extractor.reset(rocksdb::NewFixedPrefixTransform(0));
|
2019-12-24 02:22:47 -05:00
|
|
|
rocksdb::BlockBasedTableOptions table_options;
|
|
|
|
table_options.block_size = 16 * 1024;
|
|
|
|
table_options.cache_index_and_filter_blocks = true;
|
|
|
|
table_options.pin_l0_filter_and_index_blocks_in_cache = true;
|
2020-08-09 23:36:20 +00:00
|
|
|
table_options.data_block_index_type = rocksdb::BlockBasedTableOptions::kDataBlockBinaryAndHash;
|
|
|
|
table_options.checksum = rocksdb::kNoChecksum;
|
2021-03-24 20:12:43 +00:00
|
|
|
table_options.format_version = 4;
|
2019-12-24 02:22:47 -05:00
|
|
|
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
|
|
options.table_factory.reset(
|
|
|
|
rocksdb::NewBlockBasedTableFactory(table_options));
|
|
|
|
|
|
|
|
for (int idb = 0; idb < dbnum; ++idb)
|
|
|
|
{
|
|
|
|
rocksdb::ColumnFamilyOptions cf_options(options);
|
|
|
|
cf_options.level_compaction_dynamic_level_bytes = true;
|
|
|
|
veccoldesc.push_back(rocksdb::ColumnFamilyDescriptor(std::to_string(idb), cf_options));
|
|
|
|
}
|
2019-12-09 20:45:58 -05:00
|
|
|
|
|
|
|
std::vector<rocksdb::ColumnFamilyHandle*> handles;
|
|
|
|
status = rocksdb::DB::Open(options, dbfile, veccoldesc, &handles, &db);
|
|
|
|
if (!status.ok())
|
|
|
|
throw status.ToString();
|
|
|
|
|
2020-03-17 17:11:41 -04:00
|
|
|
m_spdb = std::shared_ptr<rocksdb::DB>(db);
|
2019-12-09 20:45:58 -05:00
|
|
|
for (auto handle : handles)
|
2020-03-17 17:11:41 -04:00
|
|
|
{
|
|
|
|
std::string strVersion;
|
|
|
|
auto status = m_spdb->Get(rocksdb::ReadOptions(), handle, rocksdb::Slice(version_key, sizeof(version_key)), &strVersion);
|
|
|
|
if (!status.ok())
|
|
|
|
{
|
|
|
|
setVersion(handle);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SymVer ver = parseVersion(strVersion.c_str());
|
|
|
|
auto cmp = compareVersion(&ver);
|
|
|
|
if (cmp == NewerVersion)
|
|
|
|
throw "Cannot load FLASH database created by newer version of KeyDB";
|
|
|
|
if (cmp == OlderVersion)
|
|
|
|
setVersion(handle);
|
|
|
|
}
|
2019-12-09 20:45:58 -05:00
|
|
|
m_vecspcols.emplace_back(handle);
|
2020-03-17 17:11:41 -04:00
|
|
|
}
|
2019-12-09 20:45:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
RocksDBStorageFactory::~RocksDBStorageFactory()
|
|
|
|
{
|
|
|
|
m_spdb->SyncWAL();
|
|
|
|
}
|
|
|
|
|
2020-03-17 17:11:41 -04:00
|
|
|
void RocksDBStorageFactory::setVersion(rocksdb::ColumnFamilyHandle *handle)
|
|
|
|
{
|
|
|
|
auto status = m_spdb->Put(rocksdb::WriteOptions(), handle, rocksdb::Slice(version_key, sizeof(version_key)), rocksdb::Slice(KEYDB_REAL_VERSION, strlen(KEYDB_REAL_VERSION)+1));
|
|
|
|
if (!status.ok())
|
|
|
|
throw status.ToString();
|
|
|
|
}
|
|
|
|
|
2020-07-11 21:23:48 +00:00
|
|
|
IStorage *RocksDBStorageFactory::create(int db, key_load_iterator iter, void *privdata)
|
2019-12-09 20:45:58 -05:00
|
|
|
{
|
|
|
|
++db; // skip default col family
|
|
|
|
std::shared_ptr<rocksdb::ColumnFamilyHandle> spcolfamily(m_vecspcols[db].release());
|
2019-12-22 18:38:10 -05:00
|
|
|
size_t count = 0;
|
2020-04-28 20:48:46 -04:00
|
|
|
bool fUnclean = false;
|
2020-03-17 17:11:41 -04:00
|
|
|
|
|
|
|
std::string value;
|
|
|
|
auto status = m_spdb->Get(rocksdb::ReadOptions(), spcolfamily.get(), rocksdb::Slice(count_key, sizeof(count_key)), &value);
|
|
|
|
if (status.ok() && value.size() == sizeof(size_t))
|
|
|
|
{
|
|
|
|
count = *reinterpret_cast<const size_t*>(value.data());
|
|
|
|
m_spdb->Delete(rocksdb::WriteOptions(), spcolfamily.get(), rocksdb::Slice(count_key, sizeof(count_key)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-28 20:48:46 -04:00
|
|
|
fUnclean = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fUnclean || iter != nullptr)
|
|
|
|
{
|
|
|
|
count = 0;
|
|
|
|
auto opts = rocksdb::ReadOptions();
|
|
|
|
opts.tailing = true;
|
|
|
|
std::unique_ptr<rocksdb::Iterator> it = std::unique_ptr<rocksdb::Iterator>(m_spdb->NewIterator(opts, spcolfamily.get()));
|
2021-02-26 06:06:58 +00:00
|
|
|
|
|
|
|
it->SeekToFirst();
|
|
|
|
if (fUnclean && it->Valid())
|
|
|
|
printf("\tDatabase was not shutdown cleanly, recomputing metrics\n");
|
|
|
|
|
|
|
|
for (;it->Valid(); it->Next()) {
|
2020-03-23 19:47:48 -04:00
|
|
|
if (FInternalKey(it->key().data(), it->key().size()))
|
|
|
|
continue;
|
2020-04-28 20:48:46 -04:00
|
|
|
if (iter != nullptr)
|
2020-07-11 21:23:48 +00:00
|
|
|
iter(it->key().data(), it->key().size(), privdata);
|
2020-03-17 17:11:41 -04:00
|
|
|
++count;
|
|
|
|
}
|
2019-12-22 18:38:10 -05:00
|
|
|
}
|
|
|
|
return new RocksDBStorageProvider(m_spdb, spcolfamily, nullptr, count);
|
2019-12-09 21:07:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *RocksDBStorageFactory::name() const
|
|
|
|
{
|
|
|
|
return "flash";
|
2020-06-07 16:40:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t RocksDBStorageFactory::totalDiskspaceUsed() const
|
|
|
|
{
|
|
|
|
return m_pfilemanager->GetTotalSize();
|
2020-08-06 22:30:56 +00:00
|
|
|
}
|