1/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2#ident "$Id$"
3/*======
4This file is part of PerconaFT.
5
6
7Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
8
9 PerconaFT is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License, version 2,
11 as published by the Free Software Foundation.
12
13 PerconaFT is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
20
21----------------------------------------
22
23 PerconaFT is free software: you can redistribute it and/or modify
24 it under the terms of the GNU Affero General Public License, version 3,
25 as published by the Free Software Foundation.
26
27 PerconaFT is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU Affero General Public License for more details.
31
32 You should have received a copy of the GNU Affero General Public License
33 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
34======= */
35
36#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
37
38#pragma once
39
40#include <string>
41
42#include <db.h>
43
44#include "db_env.hpp"
45#include "db_txn.hpp"
46#include "exceptions.hpp"
47#include "slice.hpp"
48#include "stats.hpp"
49
50namespace ftcxx {
51
52 template<class Comparator, class Handler>
53 class CallbackCursor;
54 template<class Comparator, class Predicate>
55 class BufferedCursor;
56 template<class Comparator>
57 class SimpleCursor;
58
59 class DB {
60 public:
61 DB()
62 : _db(nullptr),
63 _close_on_destroy(false)
64 {}
65
66 explicit DB(::DB *d, bool close_on_destroy=false)
67 : _db(d),
68 _close_on_destroy(close_on_destroy)
69 {}
70
71 ~DB() {
72 if (_db && _close_on_destroy) {
73 close();
74 }
75 }
76
77 DB(const DB &) = delete;
78 DB& operator=(const DB &) = delete;
79
80 DB(DB &&o)
81 : _db(nullptr),
82 _close_on_destroy(false)
83 {
84 std::swap(_db, o._db);
85 std::swap(_close_on_destroy, o._close_on_destroy);
86 }
87
88 DB& operator=(DB &&o) {
89 std::swap(_db, o._db);
90 std::swap(_close_on_destroy, o._close_on_destroy);
91 return *this;
92 }
93
94 ::DB *db() const { return _db; }
95
96 Slice descriptor() const {
97 return Slice(_db->cmp_descriptor->dbt);
98 }
99
100 template<typename Callback>
101 int getf_set(const DBTxn &txn, const Slice &key, int flags, Callback cb) const {
102 class WrappedCallback {
103 Callback &_cb;
104 public:
105 WrappedCallback(Callback &cb_)
106 : _cb(cb_)
107 {}
108
109 static int call(const DBT *key_, const DBT *val_, void *extra) {
110 WrappedCallback *wc = static_cast<WrappedCallback *>(extra);
111 return wc->call(key_, val_);
112 }
113
114 int call(const DBT *key_, const DBT *val_) {
115 return _cb(Slice(*key_), Slice(*val_));
116 }
117 } wc(cb);
118
119 DBT kdbt = key.dbt();
120 return _db->getf_set(_db, txn.txn(), flags, &kdbt, &WrappedCallback::call, &wc);
121 }
122
123 int put(const DBTxn &txn, DBT *key, DBT *val, int flags=0) const {
124 return _db->put(_db, txn.txn(), key, val, flags);
125 }
126
127 int put(const DBTxn &txn, const Slice &key, const Slice &val, int flags=0) const {
128 DBT kdbt = key.dbt();
129 DBT vdbt = val.dbt();
130 return put(txn, &kdbt, &vdbt, flags);
131 }
132
133 int update(const DBTxn &txn, DBT *key, DBT *val, int flags=0) const {
134 return _db->update(_db, txn.txn(), key, val, flags);
135 }
136
137 int update(const DBTxn &txn, const Slice &key, const Slice &extra, int flags=0) const {
138 DBT kdbt = key.dbt();
139 DBT edbt = extra.dbt();
140 return update(txn, &kdbt, &edbt, flags);
141 }
142
143 int del(const DBTxn &txn, DBT *key, int flags=0) const {
144 return _db->del(_db, txn.txn(), key, flags);
145 }
146
147 int del(const DBTxn &txn, const Slice &key, int flags=0) const {
148 DBT kdbt = key.dbt();
149 return _db->del(_db, txn.txn(), &kdbt, flags);
150 }
151
152 template<class OptimizeCallback>
153 int hot_optimize(const Slice &left, const Slice &right, OptimizeCallback callback, uint64_t *loops_run = NULL) const {
154 DBT ldbt = left.dbt();
155 DBT rdbt = right.dbt();
156
157 class WrappedOptimizeCallback {
158 OptimizeCallback &_oc;
159 size_t _loops;
160
161 public:
162 WrappedOptimizeCallback(OptimizeCallback &oc)
163 : _oc(oc),
164 _loops(0)
165 {}
166
167 static int call(void *extra, float progress) {
168 WrappedOptimizeCallback *e = static_cast<WrappedOptimizeCallback *>(extra);
169 return e->_oc(progress, ++e->_loops);
170 }
171 } woc(callback);
172
173 uint64_t dummy;
174 return _db->hot_optimize(_db, &ldbt, &rdbt,
175 &WrappedOptimizeCallback::call, &woc,
176 loops_run == NULL ? &dummy : loops_run);
177 }
178
179 Stats get_stats() const {
180 Stats stats;
181 DB_BTREE_STAT64 s = {0, 0, 0, 0, 0, 0, 0};
182 int r = _db->stat64(_db, NULL, &s);
183 handle_ft_retval(r);
184 stats.data_size = s.bt_dsize;
185 stats.file_size = s.bt_fsize;
186 stats.num_keys = s.bt_nkeys;
187 return stats;
188 }
189
190 struct NullFilter {
191 bool operator()(const Slice &, const Slice &) {
192 return true;
193 }
194 };
195
196 /**
197 * Constructs a Cursor over this DB, over the range from left to
198 * right (or right to left if !forward).
199 */
200 template<class Comparator, class Handler>
201 CallbackCursor<Comparator, Handler> cursor(const DBTxn &txn, DBT *left, DBT *right,
202 Comparator &&cmp, Handler &&handler, int flags=0,
203 bool forward=true, bool end_exclusive=false, bool prelock=false) const;
204
205 template<class Comparator, class Handler>
206 CallbackCursor<Comparator, Handler> cursor(const DBTxn &txn, const Slice &start_key,
207 Comparator &&cmp, Handler &&handler, int flags=0,
208 bool forward=true, bool end_exclusive=false, bool prelock=false) const;
209
210 template<class Comparator, class Handler>
211 CallbackCursor<Comparator, Handler> cursor(const DBTxn &txn, const Slice &left, const Slice &right,
212 Comparator &&cmp, Handler &&handler, int flags=0,
213 bool forward=true, bool end_exclusive=false, bool prelock=false) const;
214
215 template<class Comparator, class Handler>
216 CallbackCursor<Comparator, Handler> cursor(const DBTxn &txn, Comparator &&cmp, Handler &&handler,
217 int flags=0, bool forward=true, bool prelock=false) const;
218
219 template<class Comparator, class Predicate>
220 BufferedCursor<Comparator, Predicate> buffered_cursor(const DBTxn &txn, DBT *left, DBT *right,
221 Comparator &&cmp, Predicate &&filter, int flags=0,
222 bool forward=true, bool end_exclusive=false, bool prelock=false) const;
223
224 template<class Comparator, class Predicate>
225 BufferedCursor<Comparator, Predicate> buffered_cursor(const DBTxn &txn, const Slice &start_key,
226 Comparator &&cmp, Predicate &&filter, int flags=0,
227 bool forward=true, bool end_exclusive=false, bool prelock=false) const;
228
229 template<class Comparator, class Predicate>
230 BufferedCursor<Comparator, Predicate> buffered_cursor(const DBTxn &txn, const Slice &left, const Slice &right,
231 Comparator &&cmp, Predicate &&filter, int flags=0,
232 bool forward=true, bool end_exclusive=false, bool prelock=false) const;
233
234 template<class Comparator, class Predicate>
235 BufferedCursor<Comparator, Predicate> buffered_cursor(const DBTxn &txn, Comparator &&cmp, Predicate &&filter,
236 int flags=0, bool forward=true, bool prelock=false) const;
237
238 template<class Comparator>
239 SimpleCursor<Comparator> simple_cursor(const DBTxn &txn, DBT *left, DBT *right,
240 Comparator &&cmp, Slice &key, Slice &val, int flags=0,
241 bool forward=true, bool end_exclusive=false, bool prelock=false) const;
242
243 template<class Comparator>
244 SimpleCursor<Comparator> simple_cursor(const DBTxn &txn, const Slice &start_key,
245 Comparator &&cmp, Slice &key, Slice &val, int flags=0,
246 bool forward=true, bool end_exclusive=false, bool prelock=false) const;
247
248 template<class Comparator>
249 SimpleCursor<Comparator> simple_cursor(const DBTxn &txn, const Slice &left, const Slice &right,
250 Comparator &&cmp, Slice &key, Slice &val, int flags=0,
251 bool forward=true, bool end_exclusive=false, bool prelock=false) const;
252
253 template<class Comparator>
254 SimpleCursor<Comparator> simple_cursor(const DBTxn &txn, Comparator &&cmp, Slice &key, Slice &val,
255 int flags=0, bool forward=true, bool prelock=false) const;
256
257 void close() {
258 int r = _db->close(_db, 0);
259 handle_ft_retval(r);
260 _db = nullptr;
261 }
262
263 private:
264 ::DB *_db;
265 bool _close_on_destroy;
266 };
267
268 class DBBuilder {
269 uint32_t _readpagesize;
270 int _compression_method;
271 uint32_t _fanout;
272 uint8_t _memcmp_magic;
273 uint32_t _pagesize;
274 Slice _descriptor;
275
276 public:
277 DBBuilder()
278 : _readpagesize(0),
279 _compression_method(-1),
280 _fanout(0),
281 _memcmp_magic(0),
282 _pagesize(0),
283 _descriptor()
284 {}
285
286 DB open(const DBEnv &env, const DBTxn &txn, const char *fname, const char *dbname, DBTYPE dbtype, uint32_t flags, int mode) const {
287 ::DB *db;
288 int r = db_create(&db, env.env(), 0);
289 handle_ft_retval(r);
290
291 if (_readpagesize) {
292 r = db->set_readpagesize(db, _readpagesize);
293 handle_ft_retval(r);
294 }
295
296 if (_compression_method >= 0) {
297 r = db->set_compression_method(db, TOKU_COMPRESSION_METHOD(_compression_method));
298 handle_ft_retval(r);
299 }
300
301 if (_fanout) {
302 r = db->set_fanout(db, _fanout);
303 handle_ft_retval(r);
304 }
305
306 if (_memcmp_magic) {
307 r = db->set_memcmp_magic(db, _memcmp_magic);
308 handle_ft_retval(r);
309 }
310
311 if (_pagesize) {
312 r = db->set_pagesize(db, _pagesize);
313 handle_ft_retval(r);
314 }
315
316 const DBTxn *txnp = &txn;
317 DBTxn writeTxn;
318 if (txn.is_read_only()) {
319 writeTxn = DBTxn(env, DB_SERIALIZABLE);
320 txnp = &writeTxn;
321 }
322
323 r = db->open(db, txnp->txn(), fname, dbname, dbtype, flags, mode);
324 handle_ft_retval(r);
325
326 if (!_descriptor.empty()) {
327 DBT desc = _descriptor.dbt();
328 r = db->change_descriptor(db, txnp->txn(), &desc, DB_UPDATE_CMP_DESCRIPTOR);
329 handle_ft_retval(r);
330 }
331
332 if (txn.is_read_only()) {
333 writeTxn.commit();
334 }
335
336 return DB(db, true);
337 }
338
339 DBBuilder& set_readpagesize(uint32_t readpagesize) {
340 _readpagesize = readpagesize;
341 return *this;
342 }
343
344 DBBuilder& set_compression_method(TOKU_COMPRESSION_METHOD _compressionmethod) {
345 _compression_method = int(_compressionmethod);
346 return *this;
347 }
348
349 DBBuilder& set_fanout(uint32_t fanout) {
350 _fanout = fanout;
351 return *this;
352 }
353
354 DBBuilder& set_memcmp_magic(uint8_t _memcmpmagic) {
355 _memcmp_magic = _memcmpmagic;
356 return *this;
357 }
358
359 DBBuilder& set_pagesize(uint32_t pagesize) {
360 _pagesize = pagesize;
361 return *this;
362 }
363
364 DBBuilder& set_descriptor(const Slice &desc) {
365 _descriptor = desc.owned();
366 return *this;
367 }
368 };
369
370} // namespace ftcxx
371