1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #ident "$Id$"
3 /*======
4 This file is part of PerconaFT.
5 
6 
7 Copyright (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 
50 namespace 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:
DB()61         DB()
62             : _db(nullptr),
63               _close_on_destroy(false)
64         {}
65 
DB(::DB * d,bool close_on_destroy=false)66         explicit DB(::DB *d, bool close_on_destroy=false)
67             : _db(d),
68               _close_on_destroy(close_on_destroy)
69         {}
70 
~DB()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 
DB(DB && o)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 
operator =(DB && o)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 
db() const94         ::DB *db() const { return _db; }
95 
descriptor() const96         Slice descriptor() const {
97             return Slice(_db->cmp_descriptor->dbt);
98         }
99 
100         template<typename Callback>
getf_set(const DBTxn & txn,const Slice & key,int flags,Callback cb) const101         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 
put(const DBTxn & txn,DBT * key,DBT * val,int flags=0) const123         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 
put(const DBTxn & txn,const Slice & key,const Slice & val,int flags=0) const127         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 
update(const DBTxn & txn,DBT * key,DBT * val,int flags=0) const133         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 
update(const DBTxn & txn,const Slice & key,const Slice & extra,int flags=0) const137         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 
del(const DBTxn & txn,DBT * key,int flags=0) const143         int del(const DBTxn &txn, DBT *key, int flags=0) const {
144             return _db->del(_db, txn.txn(), key, flags);
145         }
146 
del(const DBTxn & txn,const Slice & key,int flags=0) const147         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>
hot_optimize(const Slice & left,const Slice & right,OptimizeCallback callback,uint64_t * loops_run=NULL) const153         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 
get_stats() const179         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 {
operator ()ftcxx::DB::NullFilter191             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 
close()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:
DBBuilder()277         DBBuilder()
278             : _readpagesize(0),
279               _compression_method(-1),
280               _fanout(0),
281               _memcmp_magic(0),
282               _pagesize(0),
283               _descriptor()
284         {}
285 
open(const DBEnv & env,const DBTxn & txn,const char * fname,const char * dbname,DBTYPE dbtype,uint32_t flags,int mode) const286         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 
set_readpagesize(uint32_t readpagesize)339         DBBuilder& set_readpagesize(uint32_t readpagesize) {
340             _readpagesize = readpagesize;
341             return *this;
342         }
343 
set_compression_method(TOKU_COMPRESSION_METHOD _compressionmethod)344         DBBuilder& set_compression_method(TOKU_COMPRESSION_METHOD _compressionmethod) {
345             _compression_method = int(_compressionmethod);
346             return *this;
347         }
348 
set_fanout(uint32_t fanout)349         DBBuilder& set_fanout(uint32_t fanout) {
350             _fanout = fanout;
351             return *this;
352         }
353 
set_memcmp_magic(uint8_t _memcmpmagic)354         DBBuilder& set_memcmp_magic(uint8_t _memcmpmagic) {
355             _memcmp_magic = _memcmpmagic;
356             return *this;
357         }
358 
set_pagesize(uint32_t pagesize)359         DBBuilder& set_pagesize(uint32_t pagesize) {
360             _pagesize = pagesize;
361             return *this;
362         }
363 
set_descriptor(const Slice & desc)364         DBBuilder& set_descriptor(const Slice &desc) {
365             _descriptor = desc.owned();
366             return *this;
367         }
368     };
369 
370 } // namespace ftcxx
371