LevelDBDatabase.cpp [plain text]
#include "config.h"
#include "LevelDBDatabase.h"
#if USE(LEVELDB)
#include "LevelDBComparator.h"
#include "LevelDBIterator.h"
#include "LevelDBSlice.h"
#include "LevelDBWriteBatch.h"
#include "Logging.h"
#include "NotImplemented.h"
#include <helpers/memenv/memenv.h>
#include <leveldb/comparator.h>
#include <leveldb/db.h>
#include <leveldb/env.h>
#include <leveldb/slice.h>
#include <string>
#include <wtf/text/CString.h>
#include <wtf/text/WTFString.h>
namespace leveldb {
static Env* IDBEnv()
{
return leveldb::Env::Default();
}
}
namespace WebCore {
static leveldb::Slice makeSlice(const Vector<char>& value)
{
return leveldb::Slice(value.data(), value.size());
}
static leveldb::Slice makeSlice(const LevelDBSlice& s)
{
return leveldb::Slice(s.begin(), s.end() - s.begin());
}
static LevelDBSlice makeLevelDBSlice(const leveldb::Slice& s)
{
return LevelDBSlice(s.data(), s.data() + s.size());
}
class ComparatorAdapter : public leveldb::Comparator {
public:
ComparatorAdapter(const LevelDBComparator* comparator)
: m_comparator(comparator)
{
}
virtual int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const
{
return m_comparator->compare(makeLevelDBSlice(a), makeLevelDBSlice(b));
}
virtual const char* Name() const { return m_comparator->name(); }
virtual void FindShortestSeparator(std::string* , const leveldb::Slice& ) const { }
virtual void FindShortSuccessor(std::string* ) const { }
private:
const LevelDBComparator* m_comparator;
};
LevelDBSnapshot::LevelDBSnapshot(LevelDBDatabase* db)
: m_db(db->m_db.get())
, m_snapshot(m_db->GetSnapshot())
{
}
LevelDBSnapshot::~LevelDBSnapshot()
{
m_db->ReleaseSnapshot(m_snapshot);
}
LevelDBDatabase::LevelDBDatabase()
{
}
LevelDBDatabase::~LevelDBDatabase()
{
m_db = nullptr;
m_comparatorAdapter = nullptr;
m_env = nullptr;
}
static leveldb::Status openDB(leveldb::Comparator* comparator, leveldb::Env* env, const String& path, leveldb::DB** db)
{
leveldb::Options options;
options.comparator = comparator;
options.create_if_missing = true;
options.paranoid_checks = true;
options.max_open_files = 20;
options.env = env;
return leveldb::DB::Open(options, path.utf8().data(), db);
}
bool LevelDBDatabase::destroy(const String& fileName)
{
leveldb::Options options;
options.env = leveldb::IDBEnv();
const leveldb::Status s = leveldb::DestroyDB(fileName.utf8().data(), options);
return s.ok();
}
std::unique_ptr<LevelDBDatabase> LevelDBDatabase::open(const String& fileName, const LevelDBComparator* comparator)
{
auto comparatorAdapter = std::make_unique<ComparatorAdapter>(comparator);
leveldb::DB* db;
const leveldb::Status s = openDB(comparatorAdapter.get(), leveldb::IDBEnv(), fileName, &db);
if (!s.ok()) {
LOG_ERROR("Failed to open LevelDB database from %s: %s", fileName.ascii().data(), s.ToString().c_str());
return nullptr;
}
auto result = std::make_unique<LevelDBDatabase>();
result->m_db = std::unique_ptr<leveldb::DB>(db);
result->m_comparatorAdapter = WTF::move(comparatorAdapter);
result->m_comparator = comparator;
return result;
}
std::unique_ptr<LevelDBDatabase> LevelDBDatabase::openInMemory(const LevelDBComparator* comparator)
{
auto comparatorAdapter = std::make_unique<ComparatorAdapter>(comparator);
std::unique_ptr<leveldb::Env> inMemoryEnv(leveldb::NewMemEnv(leveldb::IDBEnv()));
leveldb::DB* db;
const leveldb::Status s = openDB(comparatorAdapter.get(), inMemoryEnv.get(), String(), &db);
if (!s.ok()) {
LOG_ERROR("Failed to open in-memory LevelDB database: %s", s.ToString().c_str());
return nullptr;
}
auto result = std::make_unique<LevelDBDatabase>();
result->m_env = WTF::move(inMemoryEnv);
result->m_db = std::unique_ptr<leveldb::DB>(db);
result->m_comparatorAdapter = WTF::move(comparatorAdapter);
result->m_comparator = comparator;
return result;
}
bool LevelDBDatabase::put(const LevelDBSlice& key, const Vector<char>& value)
{
leveldb::WriteOptions writeOptions;
writeOptions.sync = true;
const leveldb::Status s = m_db->Put(writeOptions, makeSlice(key), makeSlice(value));
if (s.ok())
return true;
LOG_ERROR("LevelDB put failed: %s", s.ToString().c_str());
return false;
}
bool LevelDBDatabase::remove(const LevelDBSlice& key)
{
leveldb::WriteOptions writeOptions;
writeOptions.sync = true;
const leveldb::Status s = m_db->Delete(writeOptions, makeSlice(key));
if (s.ok())
return true;
if (s.IsNotFound())
return false;
LOG_ERROR("LevelDB remove failed: %s", s.ToString().c_str());
return false;
}
bool LevelDBDatabase::safeGet(const LevelDBSlice& key, Vector<char>& value, bool& found, const LevelDBSnapshot* snapshot)
{
found = false;
std::string result;
leveldb::ReadOptions readOptions;
readOptions.verify_checksums = true; readOptions.snapshot = snapshot ? snapshot->m_snapshot : 0;
const leveldb::Status s = m_db->Get(readOptions, makeSlice(key), &result);
if (s.ok()) {
found = true;
value.clear();
value.append(result.c_str(), result.length());
return true;
}
if (s.IsNotFound())
return true;
LOG_ERROR("LevelDB get failed: %s", s.ToString().c_str());
return false;
}
bool LevelDBDatabase::write(LevelDBWriteBatch& writeBatch)
{
leveldb::WriteOptions writeOptions;
writeOptions.sync = true;
const leveldb::Status s = m_db->Write(writeOptions, writeBatch.m_writeBatch.get());
if (s.ok())
return true;
LOG_ERROR("LevelDB write failed: %s", s.ToString().c_str());
return false;
}
namespace {
class IteratorImpl : public LevelDBIterator {
public:
explicit IteratorImpl(std::unique_ptr<leveldb::Iterator>);
~IteratorImpl() { };
virtual bool isValid() const;
virtual void seekToLast();
virtual void seek(const LevelDBSlice& target);
virtual void next();
virtual void prev();
virtual LevelDBSlice key() const;
virtual LevelDBSlice value() const;
private:
void checkStatus();
std::unique_ptr<leveldb::Iterator> m_iterator;
};
}
IteratorImpl::IteratorImpl(std::unique_ptr<leveldb::Iterator> it)
: m_iterator(WTF::move(it))
{
}
void IteratorImpl::checkStatus()
{
const leveldb::Status s = m_iterator->status();
if (!s.ok())
LOG_ERROR("LevelDB iterator error: %s", s.ToString().c_str());
}
bool IteratorImpl::isValid() const
{
return m_iterator->Valid();
}
void IteratorImpl::seekToLast()
{
m_iterator->SeekToLast();
checkStatus();
}
void IteratorImpl::seek(const LevelDBSlice& target)
{
m_iterator->Seek(makeSlice(target));
checkStatus();
}
void IteratorImpl::next()
{
ASSERT(isValid());
m_iterator->Next();
checkStatus();
}
void IteratorImpl::prev()
{
ASSERT(isValid());
m_iterator->Prev();
checkStatus();
}
LevelDBSlice IteratorImpl::key() const
{
ASSERT(isValid());
return makeLevelDBSlice(m_iterator->key());
}
LevelDBSlice IteratorImpl::value() const
{
ASSERT(isValid());
return makeLevelDBSlice(m_iterator->value());
}
std::unique_ptr<LevelDBIterator> LevelDBDatabase::createIterator(const LevelDBSnapshot* snapshot)
{
leveldb::ReadOptions readOptions;
readOptions.verify_checksums = true; readOptions.snapshot = snapshot ? snapshot->m_snapshot : 0;
std::unique_ptr<leveldb::Iterator> i(m_db->NewIterator(readOptions));
if (!i) return nullptr;
return std::make_unique<IteratorImpl>(WTF::move(i));
}
const LevelDBComparator* LevelDBDatabase::comparator() const
{
return m_comparator;
}
}
#endif