|
|
2d5d9c |
From: Steve Vinoski <vinoski@ieee.org>
|
|
|
2d5d9c |
Date: Thu, 20 Dec 2012 16:14:11 -0500
|
|
|
2d5d9c |
Subject: [PATCH] allow Get() calls to avoid copies into std::string
|
|
|
2d5d9c |
|
|
|
2d5d9c |
Add a new abstract base class leveldb::Value that applications can easily
|
|
|
2d5d9c |
derive from to supply their own memory management for values retrieved via
|
|
|
2d5d9c |
Get(). Add an internal class derived from Value that provides std::string
|
|
|
2d5d9c |
management to preserve backward compatibility. Overload DBImpl::Get() to
|
|
|
2d5d9c |
accept a Value*, and to preserve backward compatibility also keep the
|
|
|
2d5d9c |
original version taking a std::string*.
|
|
|
2d5d9c |
|
|
|
2d5d9c |
diff --git a/db/db_impl.cc b/db/db_impl.cc
|
|
|
2d5d9c |
index ae7b96d..5c3a05c 100644
|
|
|
2d5d9c |
--- a/db/db_impl.cc
|
|
|
2d5d9c |
+++ b/db/db_impl.cc
|
|
|
2d5d9c |
@@ -85,6 +85,22 @@ struct DBImpl::CompactionState {
|
|
|
2d5d9c |
uint64_t total_bytes;
|
|
|
2d5d9c |
};
|
|
|
2d5d9c |
|
|
|
2d5d9c |
+Value::~Value() {}
|
|
|
2d5d9c |
+
|
|
|
2d5d9c |
+class StringValue : public Value {
|
|
|
2d5d9c |
+ public:
|
|
|
2d5d9c |
+ explicit StringValue(std::string& val) : value_(val) {}
|
|
|
2d5d9c |
+ ~StringValue() {}
|
|
|
2d5d9c |
+
|
|
|
2d5d9c |
+ StringValue& assign(const char* data, size_t size) {
|
|
|
2d5d9c |
+ value_.assign(data, size);
|
|
|
2d5d9c |
+ return *this;
|
|
|
2d5d9c |
+ }
|
|
|
2d5d9c |
+
|
|
|
2d5d9c |
+ private:
|
|
|
2d5d9c |
+ std::string& value_;
|
|
|
2d5d9c |
+};
|
|
|
2d5d9c |
+
|
|
|
2d5d9c |
// Fix user-supplied options to be reasonable
|
|
|
2d5d9c |
template <class T, class V>
|
|
|
2d5d9c |
static void ClipToRange(T* ptr, V minvalue, V maxvalue) {
|
|
|
2d5d9c |
@@ -1117,6 +1133,13 @@ int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() {
|
|
|
2d5d9c |
|
|
|
2d5d9c |
Status DBImpl::Get(const ReadOptions& options, const Slice& key,
|
|
|
2d5d9c |
std::string* value) {
|
|
|
2d5d9c |
+ StringValue stringvalue(*value);
|
|
|
2d5d9c |
+ return DBImpl::Get(options, key, &stringvalue);
|
|
|
2d5d9c |
+}
|
|
|
2d5d9c |
+
|
|
|
2d5d9c |
+Status DBImpl::Get(const ReadOptions& options,
|
|
|
2d5d9c |
+ const Slice& key,
|
|
|
2d5d9c |
+ Value* value) {
|
|
|
2d5d9c |
Status s;
|
|
|
2d5d9c |
MutexLock l(&mutex_);
|
|
|
2d5d9c |
SequenceNumber snapshot;
|
|
|
2d5d9c |
diff --git a/db/db_impl.h b/db/db_impl.h
|
|
|
2d5d9c |
index d955c2a..3127110 100644
|
|
|
2d5d9c |
--- a/db/db_impl.h
|
|
|
2d5d9c |
+++ b/db/db_impl.h
|
|
|
2d5d9c |
@@ -42,6 +42,9 @@ class DBImpl : public DB {
|
|
|
2d5d9c |
Status Write(const WriteOptions& options, WriteBatch* updates) override;
|
|
|
2d5d9c |
Status Get(const ReadOptions& options, const Slice& key,
|
|
|
2d5d9c |
std::string* value) override;
|
|
|
2d5d9c |
+ virtual Status Get(const ReadOptions& options,
|
|
|
2d5d9c |
+ const Slice& key,
|
|
|
2d5d9c |
+ Value* value);
|
|
|
2d5d9c |
Iterator* NewIterator(const ReadOptions&) override;
|
|
|
2d5d9c |
const Snapshot* GetSnapshot() override;
|
|
|
2d5d9c |
void ReleaseSnapshot(const Snapshot* snapshot) override;
|
|
|
2d5d9c |
diff --git a/db/db_test.cc b/db/db_test.cc
|
|
|
2d5d9c |
index 2e65370..db778d9 100644
|
|
|
2d5d9c |
--- a/db/db_test.cc
|
|
|
2d5d9c |
+++ b/db/db_test.cc
|
|
|
2d5d9c |
@@ -2065,6 +2065,11 @@ class ModelDB : public DB {
|
|
|
2d5d9c |
assert(false); // Not implemented
|
|
|
2d5d9c |
return Status::NotFound(key);
|
|
|
2d5d9c |
}
|
|
|
2d5d9c |
+ Status Get(const ReadOptions& options,
|
|
|
2d5d9c |
+ const Slice& key, Value* value) override {
|
|
|
2d5d9c |
+ assert(false); // Not implemented
|
|
|
2d5d9c |
+ return Status::NotFound(key);
|
|
|
2d5d9c |
+ }
|
|
|
2d5d9c |
Iterator* NewIterator(const ReadOptions& options) override {
|
|
|
2d5d9c |
if (options.snapshot == nullptr) {
|
|
|
2d5d9c |
KVMap* saved = new KVMap;
|
|
|
2d5d9c |
diff --git a/db/memtable.cc b/db/memtable.cc
|
|
|
2d5d9c |
index f42774d..4689e2d 100644
|
|
|
2d5d9c |
--- a/db/memtable.cc
|
|
|
2d5d9c |
+++ b/db/memtable.cc
|
|
|
2d5d9c |
@@ -98,7 +98,7 @@ void MemTable::Add(SequenceNumber s, ValueType type, const Slice& key,
|
|
|
2d5d9c |
table_.Insert(buf);
|
|
|
2d5d9c |
}
|
|
|
2d5d9c |
|
|
|
2d5d9c |
-bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) {
|
|
|
2d5d9c |
+bool MemTable::Get(const LookupKey& key, Value* value, Status* s) {
|
|
|
2d5d9c |
Slice memkey = key.memtable_key();
|
|
|
2d5d9c |
Table::Iterator iter(&table_);
|
|
|
2d5d9c |
iter.Seek(memkey.data());
|
|
|
2d5d9c |
diff --git a/db/memtable.h b/db/memtable.h
|
|
|
2d5d9c |
index 9d986b1..85c4cce 100644
|
|
|
2d5d9c |
--- a/db/memtable.h
|
|
|
2d5d9c |
+++ b/db/memtable.h
|
|
|
2d5d9c |
@@ -60,7 +60,7 @@ class MemTable {
|
|
|
2d5d9c |
// If memtable contains a deletion for key, store a NotFound() error
|
|
|
2d5d9c |
// in *status and return true.
|
|
|
2d5d9c |
// Else, return false.
|
|
|
2d5d9c |
- bool Get(const LookupKey& key, std::string* value, Status* s);
|
|
|
2d5d9c |
+ bool Get(const LookupKey& key, Value* value, Status* s);
|
|
|
2d5d9c |
|
|
|
2d5d9c |
private:
|
|
|
2d5d9c |
friend class MemTableIterator;
|
|
|
2d5d9c |
diff --git a/db/version_set.cc b/db/version_set.cc
|
|
|
2d5d9c |
index 1963353..c83a4d2 100644
|
|
|
2d5d9c |
--- a/db/version_set.cc
|
|
|
2d5d9c |
+++ b/db/version_set.cc
|
|
|
2d5d9c |
@@ -256,7 +256,7 @@ struct Saver {
|
|
|
2d5d9c |
SaverState state;
|
|
|
2d5d9c |
const Comparator* ucmp;
|
|
|
2d5d9c |
Slice user_key;
|
|
|
2d5d9c |
- std::string* value;
|
|
|
2d5d9c |
+ Value* value;
|
|
|
2d5d9c |
};
|
|
|
2d5d9c |
} // namespace
|
|
|
2d5d9c |
static void SaveValue(void* arg, const Slice& ikey, const Slice& v) {
|
|
|
2d5d9c |
@@ -322,7 +322,7 @@ void Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg,
|
|
|
2d5d9c |
}
|
|
|
2d5d9c |
|
|
|
2d5d9c |
Status Version::Get(const ReadOptions& options, const LookupKey& k,
|
|
|
2d5d9c |
- std::string* value, GetStats* stats) {
|
|
|
2d5d9c |
+ Value* value, GetStats* stats) {
|
|
|
2d5d9c |
stats->seek_file = nullptr;
|
|
|
2d5d9c |
stats->seek_file_level = -1;
|
|
|
2d5d9c |
|
|
|
2d5d9c |
diff --git a/db/version_set.h b/db/version_set.h
|
|
|
2d5d9c |
index 69f3d70..0f0a463 100644
|
|
|
2d5d9c |
--- a/db/version_set.h
|
|
|
2d5d9c |
+++ b/db/version_set.h
|
|
|
2d5d9c |
@@ -72,7 +72,7 @@ class Version {
|
|
|
2d5d9c |
// REQUIRES: This version has been saved (see VersionSet::SaveTo)
|
|
|
2d5d9c |
void AddIterators(const ReadOptions&, std::vector<Iterator*>* iters);
|
|
|
2d5d9c |
|
|
|
2d5d9c |
- Status Get(const ReadOptions&, const LookupKey& key, std::string* val,
|
|
|
2d5d9c |
+ Status Get(const ReadOptions&, const LookupKey& key, Value* val,
|
|
|
2d5d9c |
GetStats* stats);
|
|
|
2d5d9c |
|
|
|
2d5d9c |
// Adds "stats" into the current state. Returns true if a new
|
|
|
2d5d9c |
diff --git a/include/leveldb/db.h b/include/leveldb/db.h
|
|
|
2d5d9c |
index 61c29c0..1a93feb 100644
|
|
|
2d5d9c |
--- a/include/leveldb/db.h
|
|
|
2d5d9c |
+++ b/include/leveldb/db.h
|
|
|
2d5d9c |
@@ -40,6 +40,17 @@ struct LEVELDB_EXPORT Range {
|
|
|
2d5d9c |
Slice limit; // Not included in the range
|
|
|
2d5d9c |
};
|
|
|
2d5d9c |
|
|
|
2d5d9c |
+// Abstract holder for a DB value.
|
|
|
2d5d9c |
+// This allows callers to manage their own value buffers and have
|
|
|
2d5d9c |
+// DB values copied directly into those buffers.
|
|
|
2d5d9c |
+class Value {
|
|
|
2d5d9c |
+ public:
|
|
|
2d5d9c |
+ virtual Value& assign(const char* data, size_t size) = 0;
|
|
|
2d5d9c |
+
|
|
|
2d5d9c |
+ protected:
|
|
|
2d5d9c |
+ virtual ~Value();
|
|
|
2d5d9c |
+};
|
|
|
2d5d9c |
+
|
|
|
2d5d9c |
// A DB is a persistent ordered map from keys to values.
|
|
|
2d5d9c |
// A DB is safe for concurrent access from multiple threads without
|
|
|
2d5d9c |
// any external synchronization.
|