1 From: Steve Vinoski <vinoski@ieee.org>
2 Date: Thu, 20 Dec 2012 16:14:11 -0500
3 Subject: [PATCH] allow Get() calls to avoid copies into std::string
4
5 Add a new abstract base class leveldb::Value that applications can easily
6 derive from to supply their own memory management for values retrieved via
7 Get(). Add an internal class derived from Value that provides std::string
8 management to preserve backward compatibility. Overload DBImpl::Get() to
9 accept a Value*, and to preserve backward compatibility also keep the
10 original version taking a std::string*.
11
12 diff --git a/db/db_impl.cc b/db/db_impl.cc
13 index ae7b96d..5c3a05c 100644
14 --- a/db/db_impl.cc
15 +++ b/db/db_impl.cc
16 @@ -85,6 +85,22 @@ struct DBImpl::CompactionState {
17 uint64_t total_bytes;
18 };
19
20 +Value::~Value() {}
21 +
22 +class StringValue : public Value {
23 + public:
24 + explicit StringValue(std::string& val) : value_(val) {}
25 + ~StringValue() {}
26 +
27 + StringValue& assign(const char* data, size_t size) {
28 + value_.assign(data, size);
29 + return *this;
30 + }
31 +
32 + private:
33 + std::string& value_;
34 +};
35 +
36 // Fix user-supplied options to be reasonable
37 template <class T, class V>
38 static void ClipToRange(T* ptr, V minvalue, V maxvalue) {
39 @@ -1117,6 +1133,13 @@ int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() {
40
41 Status DBImpl::Get(const ReadOptions& options, const Slice& key,
42 std::string* value) {
43 + StringValue stringvalue(*value);
44 + return DBImpl::Get(options, key, &stringvalue);
45 +}
46 +
47 +Status DBImpl::Get(const ReadOptions& options,
48 + const Slice& key,
49 + Value* value) {
50 Status s;
51 MutexLock l(&mutex_);
52 SequenceNumber snapshot;
53 diff --git a/db/db_impl.h b/db/db_impl.h
54 index d955c2a..3127110 100644
55 --- a/db/db_impl.h
56 +++ b/db/db_impl.h
57 @@ -42,6 +42,9 @@ class DBImpl : public DB {
58 Status Write(const WriteOptions& options, WriteBatch* updates) override;
59 Status Get(const ReadOptions& options, const Slice& key,
60 std::string* value) override;
61 + virtual Status Get(const ReadOptions& options,
62 + const Slice& key,
63 + Value* value);
64 Iterator* NewIterator(const ReadOptions&) override;
65 const Snapshot* GetSnapshot() override;
66 void ReleaseSnapshot(const Snapshot* snapshot) override;
67 diff --git a/db/db_test.cc b/db/db_test.cc
68 index 2e65370..db778d9 100644
69 --- a/db/db_test.cc
70 +++ b/db/db_test.cc
71 @@ -2065,6 +2065,11 @@ class ModelDB : public DB {
72 assert(false); // Not implemented
73 return Status::NotFound(key);
74 }
75 + Status Get(const ReadOptions& options,
76 + const Slice& key, Value* value) override {
77 + assert(false); // Not implemented
78 + return Status::NotFound(key);
79 + }
80 Iterator* NewIterator(const ReadOptions& options) override {
81 if (options.snapshot == nullptr) {
82 KVMap* saved = new KVMap;
83 diff --git a/db/memtable.cc b/db/memtable.cc
84 index f42774d..4689e2d 100644
85 --- a/db/memtable.cc
86 +++ b/db/memtable.cc
87 @@ -98,7 +98,7 @@ void MemTable::Add(SequenceNumber s, ValueType type, const Slice& key,
88 table_.Insert(buf);
89 }
90
91 -bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) {
92 +bool MemTable::Get(const LookupKey& key, Value* value, Status* s) {
93 Slice memkey = key.memtable_key();
94 Table::Iterator iter(&table_);
95 iter.Seek(memkey.data());
96 diff --git a/db/memtable.h b/db/memtable.h
97 index 9d986b1..85c4cce 100644
98 --- a/db/memtable.h
99 +++ b/db/memtable.h
100 @@ -60,7 +60,7 @@ class MemTable {
101 // If memtable contains a deletion for key, store a NotFound() error
102 // in *status and return true.
103 // Else, return false.
104 - bool Get(const LookupKey& key, std::string* value, Status* s);
105 + bool Get(const LookupKey& key, Value* value, Status* s);
106
107 private:
108 friend class MemTableIterator;
109 diff --git a/db/version_set.cc b/db/version_set.cc
110 index 1963353..c83a4d2 100644
111 --- a/db/version_set.cc
112 +++ b/db/version_set.cc
113 @@ -256,7 +256,7 @@ struct Saver {
114 SaverState state;
115 const Comparator* ucmp;
116 Slice user_key;
117 - std::string* value;
118 + Value* value;
119 };
120 } // namespace
121 static void SaveValue(void* arg, const Slice& ikey, const Slice& v) {
122 @@ -322,7 +322,7 @@ void Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg,
123 }
124
125 Status Version::Get(const ReadOptions& options, const LookupKey& k,
126 - std::string* value, GetStats* stats) {
127 + Value* value, GetStats* stats) {
128 stats->seek_file = nullptr;
129 stats->seek_file_level = -1;
130
131 diff --git a/db/version_set.h b/db/version_set.h
132 index 69f3d70..0f0a463 100644
133 --- a/db/version_set.h
134 +++ b/db/version_set.h
135 @@ -72,7 +72,7 @@ class Version {
136 // REQUIRES: This version has been saved (see VersionSet::SaveTo)
137 void AddIterators(const ReadOptions&, std::vector<Iterator*>* iters);
138
139 - Status Get(const ReadOptions&, const LookupKey& key, std::string* val,
140 + Status Get(const ReadOptions&, const LookupKey& key, Value* val,
141 GetStats* stats);
142
143 // Adds "stats" into the current state. Returns true if a new
144 diff --git a/include/leveldb/db.h b/include/leveldb/db.h
145 index 61c29c0..1a93feb 100644
146 --- a/include/leveldb/db.h
147 +++ b/include/leveldb/db.h
148 @@ -40,6 +40,17 @@ struct LEVELDB_EXPORT Range {
149 Slice limit; // Not included in the range
150 };
151
152 +// Abstract holder for a DB value.
153 +// This allows callers to manage their own value buffers and have
154 +// DB values copied directly into those buffers.
155 +class Value {
156 + public:
157 + virtual Value& assign(const char* data, size_t size) = 0;
158 +
159 + protected:
160 + virtual ~Value();
161 +};
162 +
163 // A DB is a persistent ordered map from keys to values.
164 // A DB is safe for concurrent access from multiple threads without
165 // any external synchronization.
|