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: |
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 *) { |
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 &, 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 *, 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 | |