-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Samuel Just <[email protected]>
- Loading branch information
Samuel Just
committed
Mar 1, 2012
1 parent
58a3b7f
commit d9b130f
Showing
5 changed files
with
267 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ AC_PREREQ(2.59) | |
AC_INIT([ceph], [0.42.2], [[email protected]]) | ||
|
||
AC_CONFIG_SUBDIRS([src/gtest]) | ||
AC_CONFIG_SUBDIRS([src/leveldb]) | ||
|
||
# Environment | ||
AC_CANONICAL_HOST | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- | ||
|
||
#include "LevelDBStore.h" | ||
#include <set> | ||
#include <map> | ||
#include <string> | ||
#include <tr1/memory> | ||
#include "leveldb/include/leveldb/db.h" | ||
#include "leveldb/include/leveldb/write_batch.h" | ||
#include "leveldb/include/leveldb/slice.h" | ||
#include <errno.h> | ||
using std::string; | ||
|
||
int LevelDBStore::init(ostream &out) | ||
{ | ||
leveldb::Options options; | ||
options.create_if_missing = true; | ||
leveldb::DB *_db; | ||
leveldb::Status status = leveldb::DB::Open(options, path, &_db); | ||
db.reset(_db); | ||
if (!status.ok()) { | ||
out << status.ToString() << std::endl; | ||
return -EINVAL; | ||
} else | ||
return 0; | ||
} | ||
|
||
void LevelDBStore::LevelDBTransactionImpl::set( | ||
const string &prefix, | ||
const std::map<string, bufferlist> &to_set) | ||
{ | ||
for (std::map<string, bufferlist>::const_iterator i = to_set.begin(); | ||
i != to_set.end(); | ||
++i) { | ||
buffers.push_back(i->second); | ||
buffers.rbegin()->rebuild(); | ||
bufferlist &bl = *(buffers.rbegin()); | ||
string key = combine_strings(prefix, i->first); | ||
keys.push_back(key); | ||
bat.Delete(leveldb::Slice(*(keys.rbegin()))); | ||
bat.Put(leveldb::Slice(*(keys.rbegin())), | ||
leveldb::Slice(bl.c_str(), bl.length())); | ||
} | ||
} | ||
void LevelDBStore::LevelDBTransactionImpl::rmkeys(const string &prefix, | ||
const std::set<string> &to_rm) | ||
{ | ||
for (std::set<string>::const_iterator i = to_rm.begin(); | ||
i != to_rm.end(); | ||
++i) { | ||
string key = combine_strings(prefix, *i); | ||
keys.push_back(key); | ||
bat.Delete(leveldb::Slice(*(keys.rbegin()))); | ||
} | ||
} | ||
|
||
void LevelDBStore::LevelDBTransactionImpl::rmkeys_by_prefix(const string &prefix) | ||
{ | ||
KeyValueDB::Iterator it = db->get_iterator(prefix); | ||
for (it->seek_to_first(); | ||
it->valid(); | ||
it->next()) { | ||
string key = combine_strings(prefix, it->key()); | ||
keys.push_back(key); | ||
bat.Delete(*(keys.rbegin())); | ||
} | ||
} | ||
|
||
int LevelDBStore::get( | ||
const string &prefix, | ||
const std::set<string> &keys, | ||
std::map<string, bufferlist> *out) | ||
{ | ||
KeyValueDB::Iterator it = get_iterator(prefix); | ||
for (std::set<string>::const_iterator i = keys.begin(); | ||
i != keys.end(); | ||
++i) { | ||
it->lower_bound(*i); | ||
if (it->valid() && it->key() == *i) { | ||
out->insert(make_pair(*i, it->value())); | ||
} else if (!it->valid()) | ||
break; | ||
} | ||
return 0; | ||
} | ||
|
||
string LevelDBStore::combine_strings(const string &prefix, const string &value) | ||
{ | ||
string out = prefix; | ||
out.push_back(0); | ||
out.append(value); | ||
return out; | ||
} | ||
|
||
bufferlist LevelDBStore::to_bufferlist(leveldb::Slice in) | ||
{ | ||
bufferlist bl; | ||
bl.append(bufferptr(in.data(), in.size())); | ||
return bl; | ||
} | ||
|
||
int LevelDBStore::split_key(leveldb::Slice in, string *prefix, string *key) | ||
{ | ||
string in_prefix = in.ToString(); | ||
size_t prefix_len = in_prefix.find('\0'); | ||
if (prefix_len >= in_prefix.size()) | ||
return -EINVAL; | ||
|
||
if (prefix) | ||
*prefix = string(in_prefix, 0, prefix_len); | ||
if (key) | ||
*key= string(in_prefix, prefix_len + 1); | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- | ||
#ifndef LEVEL_DB_STORE_H | ||
#define LEVEL_DB_STORE_H | ||
|
||
#include "include/buffer.h" | ||
#include "KeyValueDB.h" | ||
#include <set> | ||
#include <map> | ||
#include <string> | ||
#include <tr1/memory> | ||
#include <boost/scoped_ptr.hpp> | ||
#include "leveldb/include/leveldb/db.h" | ||
#include "leveldb/include/leveldb/write_batch.h" | ||
#include "leveldb/include/leveldb/slice.h" | ||
|
||
/** | ||
* Uses LevelDB to implement the KeyValueDB interface | ||
*/ | ||
class LevelDBStore : public KeyValueDB { | ||
string path; | ||
boost::scoped_ptr<leveldb::DB> db; | ||
public: | ||
LevelDBStore(const string &path) : path(path) {} | ||
|
||
/// Opens underlying db | ||
int init(ostream &out); | ||
|
||
class LevelDBTransactionImpl : public KeyValueDB::TransactionImpl { | ||
public: | ||
leveldb::WriteBatch bat; | ||
list<bufferlist> buffers; | ||
list<string> keys; | ||
LevelDBStore *db; | ||
|
||
LevelDBTransactionImpl(LevelDBStore *db) : db(db) {} | ||
void set( | ||
const string &prefix, | ||
const std::map<string, bufferlist> &to_set | ||
); | ||
void rmkeys( | ||
const string &prefix, | ||
const std::set<string> &keys | ||
); | ||
void rmkeys_by_prefix( | ||
const string &prefix | ||
); | ||
}; | ||
|
||
KeyValueDB::Transaction get_transaction() { | ||
return std::tr1::shared_ptr< LevelDBTransactionImpl >( | ||
new LevelDBTransactionImpl(this)); | ||
} | ||
|
||
int submit_transaction(KeyValueDB::Transaction t) { | ||
LevelDBTransactionImpl * _t = | ||
static_cast<LevelDBTransactionImpl *>(t.get()); | ||
leveldb::Status s = db->Write(leveldb::WriteOptions(), &(_t->bat)); | ||
return s.ok() ? 0 : -1; | ||
} | ||
|
||
int get( | ||
const string &prefix, | ||
const std::set<string> &key, | ||
std::map<string, bufferlist> *out | ||
); | ||
|
||
class LevelDBIteratorImpl : public KeyValueDB::IteratorImpl { | ||
boost::scoped_ptr<leveldb::Iterator> dbiter; | ||
const string prefix; | ||
public: | ||
LevelDBIteratorImpl(leveldb::Iterator *iter, const string &prefix) : | ||
dbiter(iter), prefix(prefix) {} | ||
int seek_to_first() { | ||
leveldb::Slice slice_prefix(prefix); | ||
dbiter->Seek(slice_prefix); | ||
return dbiter->status().ok() ? 0 : -1; | ||
} | ||
int seek_to_last() { | ||
string limit = past_prefix(prefix); | ||
leveldb::Slice slice_limit(limit); | ||
dbiter->Seek(slice_limit); | ||
if (!dbiter->Valid()) { | ||
dbiter->SeekToLast(); | ||
} else { | ||
dbiter->Prev(); | ||
} | ||
return dbiter->status().ok() ? 0 : -1; | ||
} | ||
int upper_bound(const string &after) { | ||
lower_bound(after); | ||
if (valid() && key() == after) | ||
next(); | ||
return dbiter->status().ok() ? 0 : -1; | ||
} | ||
int lower_bound(const string &to) { | ||
string bound = combine_strings(prefix, to); | ||
leveldb::Slice slice_bound(bound); | ||
dbiter->Seek(slice_bound); | ||
return dbiter->status().ok() ? 0 : -1; | ||
} | ||
bool valid() { | ||
return dbiter->Valid() && in_prefix(prefix, dbiter->key()); | ||
} | ||
int next() { | ||
if (valid()) | ||
dbiter->Next(); | ||
return dbiter->status().ok() ? 0 : -1; | ||
} | ||
int prev() { | ||
if (valid()) | ||
dbiter->Prev(); | ||
return dbiter->status().ok() ? 0 : -1; | ||
} | ||
string key() { | ||
string out_key; | ||
split_key(dbiter->key(), 0, &out_key); | ||
return out_key; | ||
} | ||
bufferlist value() { | ||
return to_bufferlist(dbiter->value()); | ||
} | ||
int status() { | ||
return dbiter->status().ok() ? 0 : -1; | ||
} | ||
}; | ||
Iterator get_iterator(const string &prefix) { | ||
return std::tr1::shared_ptr<LevelDBIteratorImpl>( | ||
new LevelDBIteratorImpl( | ||
db->NewIterator(leveldb::ReadOptions()), | ||
prefix)); | ||
} | ||
|
||
|
||
/// Utility | ||
static string combine_strings(const string &prefix, const string &value); | ||
static int split_key(leveldb::Slice in, string *prefix, string *key); | ||
static bufferlist to_bufferlist(leveldb::Slice in); | ||
static bool in_prefix(const string &prefix, leveldb::Slice key) { | ||
return (key.compare(leveldb::Slice(past_prefix(prefix))) < 0) && | ||
(key.compare(leveldb::Slice(prefix)) > 0); | ||
} | ||
static string past_prefix(const string prefix) { | ||
string limit = prefix; | ||
limit.push_back(1); | ||
return limit; | ||
} | ||
}; | ||
|
||
#endif |