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 <errno.h>
41 
42 #include <map>
43 #include <string>
44 
45 #include <db.h>
46 
47 #include "exceptions.hpp"
48 #include "slice.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 DBTxn;
60 
61     class DBEnv {
62     public:
DBEnv(DB_ENV * e,bool close_on_destroy=false)63         explicit DBEnv(DB_ENV *e, bool close_on_destroy=false)
64             : _env(e),
65               _close_on_destroy(close_on_destroy)
66         {}
67 
~DBEnv()68         ~DBEnv() {
69             if (_env && _close_on_destroy) {
70                 close();
71             }
72         }
73 
74         DBEnv(const DBEnv &) = delete;
75         DBEnv& operator=(const DBEnv &) = delete;
76 
DBEnv(DBEnv && o)77         DBEnv(DBEnv &&o)
78             : _env(nullptr),
79               _close_on_destroy(false)
80         {
81             std::swap(_env, o._env);
82             std::swap(_close_on_destroy, o._close_on_destroy);
83         }
84 
operator =(DBEnv && o)85         DBEnv& operator=(DBEnv &&o) {
86             std::swap(_env, o._env);
87             std::swap(_close_on_destroy, o._close_on_destroy);
88             return *this;
89         }
90 
env() const91         DB_ENV *env() const { return _env; }
92 
close()93         void close() {
94             int r = _env->close(_env, 0);
95             handle_ft_retval(r);
96             _env = nullptr;
97         }
98 
99         typedef std::map<std::string, TOKU_ENGINE_STATUS_ROW_S> Status;
100         void get_status(Status &status, fs_redzone_state &redzone_state, uint64_t &env_panic, std::string &panic_string) const;
101 
log_flush()102         void log_flush() {
103             int r = _env->log_flush(_env, NULL);
104             handle_ft_retval(r);
105         }
106 
checkpointing_set_period(uint32_t period)107         int checkpointing_set_period(uint32_t period) {
108             if (!_env) {
109                 return EINVAL;
110             }
111             _env->checkpointing_set_period(_env, period);
112             return 0;
113         }
114 
cleaner_set_iterations(uint32_t iterations)115         int cleaner_set_iterations(uint32_t iterations) {
116             if (!_env) {
117                 return EINVAL;
118             }
119             _env->cleaner_set_iterations(_env, iterations);
120             return 0;
121         }
122 
cleaner_set_period(uint32_t period)123         int cleaner_set_period(uint32_t period) {
124             if (!_env) {
125                 return EINVAL;
126             }
127             _env->cleaner_set_period(_env, period);
128             return 0;
129         }
130 
change_fsync_log_period(uint32_t period)131         int change_fsync_log_period(uint32_t period) {
132             if (!_env) {
133                 return EINVAL;
134             }
135             _env->change_fsync_log_period(_env, period);
136             return 0;
137         }
138 
get_engine_status_num_rows()139         uint64_t get_engine_status_num_rows() {
140             if (!_env) {
141                 handle_ft_retval(EINVAL); // throws
142             }
143             uint64_t ret;
144             int r = _env->get_engine_status_num_rows(_env, &ret);
145             handle_ft_retval(r);
146             return ret;
147         }
148 
get_engine_status(TOKU_ENGINE_STATUS_ROW_S * rows,uint64_t max_rows,uint64_t & num_rows,uint64_t & panic,std::string & panic_string,toku_engine_status_include_type include_type)149         void get_engine_status(TOKU_ENGINE_STATUS_ROW_S *rows, uint64_t max_rows, uint64_t &num_rows,
150                                uint64_t &panic, std::string &panic_string,
151                                toku_engine_status_include_type include_type) {
152             if (!_env) {
153                 handle_ft_retval(EINVAL);
154             }
155             fs_redzone_state dummy;  // this is duplicated in the actual engine status output
156             const size_t panic_string_len = 1024;
157             char panic_string_buf[panic_string_len];
158             panic_string_buf[0] = '\0';
159             int r = _env->get_engine_status(_env, rows, max_rows, &num_rows,
160                                             &dummy, &panic, panic_string_buf, panic_string_len,
161                                             include_type);
162             handle_ft_retval(r);
163             panic_string = panic_string_buf;
164         }
165 
166         /**
167          * Constructs a Cursor over this DBEnv's directory.
168          */
169         template<class Comparator, class Handler>
170         CallbackCursor<Comparator, Handler> cursor(const DBTxn &txn, Comparator &&cmp, Handler &&handler) const;
171 
172         template<class Comparator, class Predicate>
173         BufferedCursor<Comparator, Predicate> buffered_cursor(const DBTxn &txn, Comparator &&cmp, Predicate &&filter) const;
174 
175         template<class Comparator>
176         SimpleCursor<Comparator> simple_cursor(const DBTxn &txn, Comparator &&cmp, Slice &key, Slice &val) const;
177 
178     private:
179         DB_ENV *_env;
180         bool _close_on_destroy;
181     };
182 
183     class DBEnvBuilder {
184         typedef int (*bt_compare_func)(DB *, const DBT *, const DBT *);
185         bt_compare_func _bt_compare;
186 
187         typedef int (*update_func)(DB *, const DBT *, const DBT *, const DBT *, void (*)(const DBT *, void *), void *);
188         update_func _update_function;
189 
190         generate_row_for_put_func _generate_row_for_put;
191         generate_row_for_del_func _generate_row_for_del;
192 
193         uint32_t _cleaner_period;
194         uint32_t _cleaner_iterations;
195         uint32_t _checkpointing_period;
196         uint32_t _fsync_log_period_msec;
197         int _fs_redzone;
198 
199         uint64_t _lk_max_memory;
200         uint64_t _lock_wait_time_msec;
201 
202         typedef uint64_t (*get_lock_wait_time_cb_func)(uint64_t);
203         get_lock_wait_time_cb_func _get_lock_wait_time_cb;
204         lock_timeout_callback _lock_timeout_callback;
205         uint64_t (*_loader_memory_size_callback)(void);
206 
207         uint32_t _cachesize_gbytes;
208         uint32_t _cachesize_bytes;
209         uint32_t _cachetable_bucket_mutexes;
210 
211         std::string _product_name;
212 
213         std::string _lg_dir;
214         std::string _tmp_dir;
215 
216         bool _direct_io;
217         bool _compress_buffers;
218 
219     public:
DBEnvBuilder()220         DBEnvBuilder()
221             : _bt_compare(nullptr),
222               _update_function(nullptr),
223               _generate_row_for_put(nullptr),
224               _generate_row_for_del(nullptr),
225               _cleaner_period(0),
226               _cleaner_iterations(0),
227               _checkpointing_period(0),
228               _fsync_log_period_msec(0),
229               _fs_redzone(0),
230               _lk_max_memory(0),
231               _lock_wait_time_msec(0),
232               _get_lock_wait_time_cb(nullptr),
233               _lock_timeout_callback(nullptr),
234               _loader_memory_size_callback(nullptr),
235               _cachesize_gbytes(0),
236               _cachesize_bytes(0),
237               _cachetable_bucket_mutexes(0),
238               _product_name(""),
239               _lg_dir(""),
240               _tmp_dir(""),
241               _direct_io(false),
242               _compress_buffers(true)
243         {}
244 
open(const char * env_dir,uint32_t flags,int mode) const245         DBEnv open(const char *env_dir, uint32_t flags, int mode) const {
246             db_env_set_direct_io(_direct_io);
247             db_env_set_compress_buffers_before_eviction(_compress_buffers);
248             if (_cachetable_bucket_mutexes) {
249                 db_env_set_num_bucket_mutexes(_cachetable_bucket_mutexes);
250             }
251 
252             if (!_product_name.empty()) {
253                 db_env_set_toku_product_name(_product_name.c_str());
254             }
255 
256             DB_ENV *env;
257             int r = db_env_create(&env, 0);
258             handle_ft_retval(r);
259 
260             if (_bt_compare) {
261                 r = env->set_default_bt_compare(env, _bt_compare);
262                 handle_ft_retval(r);
263             }
264 
265             if (_update_function) {
266                 env->set_update(env, _update_function);
267             }
268 
269             if (_generate_row_for_put) {
270                 r = env->set_generate_row_callback_for_put(env, _generate_row_for_put);
271                 handle_ft_retval(r);
272             }
273 
274             if (_generate_row_for_del) {
275                 r = env->set_generate_row_callback_for_del(env, _generate_row_for_del);
276                 handle_ft_retval(r);
277             }
278 
279             if (_lk_max_memory) {
280                 r = env->set_lk_max_memory(env, _lk_max_memory);
281                 handle_ft_retval(r);
282             }
283 
284             if (_lock_wait_time_msec || _get_lock_wait_time_cb) {
285                 uint64_t wait_time = _lock_wait_time_msec;
286                 if (!wait_time) {
287                     r = env->get_lock_timeout(env, &wait_time);
288                     handle_ft_retval(r);
289                 }
290                 r = env->set_lock_timeout(env, wait_time, _get_lock_wait_time_cb);
291                 handle_ft_retval(r);
292             }
293 
294             if (_lock_timeout_callback) {
295                 r = env->set_lock_timeout_callback(env, _lock_timeout_callback);
296                 handle_ft_retval(r);
297             }
298 
299             if (_loader_memory_size_callback) {
300                 env->set_loader_memory_size(env, _loader_memory_size_callback);
301             }
302 
303             if (_cachesize_gbytes || _cachesize_bytes) {
304                 r = env->set_cachesize(env, _cachesize_gbytes, _cachesize_bytes, 1);
305                 handle_ft_retval(r);
306             }
307 
308             if (_fs_redzone) {
309                 env->set_redzone(env, _fs_redzone);
310             }
311 
312             if (!_lg_dir.empty()) {
313                 r = env->set_lg_dir(env, _lg_dir.c_str());
314                 handle_ft_retval(r);
315             }
316 
317             if (!_tmp_dir.empty()) {
318                 r = env->set_tmp_dir(env, _tmp_dir.c_str());
319                 handle_ft_retval(r);
320             }
321 
322             r = env->open(env, env_dir, flags, mode);
323             handle_ft_retval(r);
324 
325             if (_cleaner_period) {
326                 r = env->cleaner_set_period(env, _cleaner_period);
327                 handle_ft_retval(r);
328             }
329 
330             if (_cleaner_iterations) {
331                 r = env->cleaner_set_iterations(env, _cleaner_iterations);
332                 handle_ft_retval(r);
333             }
334 
335             if (_checkpointing_period) {
336                 r = env->checkpointing_set_period(env, _checkpointing_period);
337                 handle_ft_retval(r);
338             }
339 
340             if (_fsync_log_period_msec) {
341                 env->change_fsync_log_period(env, _fsync_log_period_msec);
342             }
343 
344             return DBEnv(env, true);
345         }
346 
set_direct_io(bool direct_io)347         DBEnvBuilder& set_direct_io(bool direct_io) {
348             _direct_io = direct_io;
349             return *this;
350         }
351 
set_compress_buffers_before_eviction(bool compress_buffers)352         DBEnvBuilder& set_compress_buffers_before_eviction(bool compress_buffers) {
353             _compress_buffers = compress_buffers;
354             return *this;
355         }
356 
set_default_bt_compare(bt_compare_func bt_compare)357         DBEnvBuilder& set_default_bt_compare(bt_compare_func bt_compare) {
358             _bt_compare = bt_compare;
359             return *this;
360         }
361 
set_update(update_func update_function)362         DBEnvBuilder& set_update(update_func update_function) {
363             _update_function = update_function;
364             return *this;
365         }
366 
set_generate_row_callback_for_put(generate_row_for_put_func generate_row_for_put)367         DBEnvBuilder& set_generate_row_callback_for_put(generate_row_for_put_func generate_row_for_put) {
368             _generate_row_for_put = generate_row_for_put;
369             return *this;
370         }
371 
set_generate_row_callback_for_del(generate_row_for_del_func generate_row_for_del)372         DBEnvBuilder& set_generate_row_callback_for_del(generate_row_for_del_func generate_row_for_del) {
373             _generate_row_for_del = generate_row_for_del;
374             return *this;
375         }
376 
cleaner_set_period(uint32_t period)377         DBEnvBuilder& cleaner_set_period(uint32_t period) {
378             _cleaner_period = period;
379             return *this;
380         }
381 
cleaner_set_iterations(uint32_t iterations)382         DBEnvBuilder& cleaner_set_iterations(uint32_t iterations) {
383             _cleaner_iterations = iterations;
384             return *this;
385         }
386 
checkpointing_set_period(uint32_t period)387         DBEnvBuilder& checkpointing_set_period(uint32_t period) {
388             _checkpointing_period = period;
389             return *this;
390         }
391 
change_fsync_log_period(uint32_t period)392         DBEnvBuilder& change_fsync_log_period(uint32_t period) {
393             _fsync_log_period_msec = period;
394             return *this;
395         }
396 
set_fs_redzone(int fs_redzone)397         DBEnvBuilder& set_fs_redzone(int fs_redzone) {
398             _fs_redzone = fs_redzone;
399             return *this;
400         }
401 
set_lk_max_memory(uint64_t sz)402         DBEnvBuilder& set_lk_max_memory(uint64_t sz) {
403             _lk_max_memory = sz;
404             return *this;
405         }
406 
set_lock_wait_time_msec(uint64_t lock_wait_time_msec)407         DBEnvBuilder& set_lock_wait_time_msec(uint64_t lock_wait_time_msec) {
408             _lock_wait_time_msec = lock_wait_time_msec;
409             return *this;
410         }
411 
set_lock_wait_time_cb(get_lock_wait_time_cb_func get_lock_wait_time_cb)412         DBEnvBuilder& set_lock_wait_time_cb(get_lock_wait_time_cb_func get_lock_wait_time_cb) {
413             _get_lock_wait_time_cb = get_lock_wait_time_cb;
414             return *this;
415         }
416 
set_lock_timeout_callback(lock_timeout_callback callback)417         DBEnvBuilder& set_lock_timeout_callback(lock_timeout_callback callback) {
418             _lock_timeout_callback = callback;
419             return *this;
420         }
421 
set_loader_memory_size(uint64_t (* callback)(void))422         DBEnvBuilder& set_loader_memory_size(uint64_t (*callback)(void)) {
423             _loader_memory_size_callback = callback;
424             return *this;
425         }
426 
set_cachesize(uint32_t gbytes,uint32_t bytes)427         DBEnvBuilder& set_cachesize(uint32_t gbytes, uint32_t bytes) {
428             _cachesize_gbytes = gbytes;
429             _cachesize_bytes = bytes;
430             return *this;
431         }
432 
set_cachetable_bucket_mutexes(uint32_t mutexes)433         DBEnvBuilder& set_cachetable_bucket_mutexes(uint32_t mutexes) {
434             _cachetable_bucket_mutexes = mutexes;
435             return *this;
436         }
437 
set_product_name(const char * product_name)438         DBEnvBuilder& set_product_name(const char *product_name) {
439             _product_name = std::string(product_name);
440             return *this;
441         }
442 
set_lg_dir(const char * lg_dir)443         DBEnvBuilder& set_lg_dir(const char *lg_dir) {
444             _lg_dir = std::string(lg_dir);
445             return *this;
446         }
447 
set_tmp_dir(const char * tmp_dir)448         DBEnvBuilder& set_tmp_dir(const char *tmp_dir) {
449             _tmp_dir = std::string(tmp_dir);
450             return *this;
451         }
452     };
453 
454 } // namespace ftcxx
455