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         lock_wait_callback _lock_wait_needed_callback;
206         uint64_t (*_loader_memory_size_callback)(void);
207 
208         uint32_t _cachesize_gbytes;
209         uint32_t _cachesize_bytes;
210         uint32_t _cachetable_bucket_mutexes;
211 
212         std::string _product_name;
213 
214         std::string _lg_dir;
215         std::string _tmp_dir;
216 
217         bool _direct_io;
218         bool _compress_buffers;
219 
220     public:
DBEnvBuilder()221         DBEnvBuilder()
222             : _bt_compare(nullptr),
223               _update_function(nullptr),
224               _generate_row_for_put(nullptr),
225               _generate_row_for_del(nullptr),
226               _cleaner_period(0),
227               _cleaner_iterations(0),
228               _checkpointing_period(0),
229               _fsync_log_period_msec(0),
230               _fs_redzone(0),
231               _lk_max_memory(0),
232               _lock_wait_time_msec(0),
233               _get_lock_wait_time_cb(nullptr),
234               _lock_timeout_callback(nullptr),
235               _lock_wait_needed_callback(nullptr),
236               _loader_memory_size_callback(nullptr),
237               _cachesize_gbytes(0),
238               _cachesize_bytes(0),
239               _cachetable_bucket_mutexes(0),
240               _product_name(""),
241               _lg_dir(""),
242               _tmp_dir(""),
243               _direct_io(false),
244               _compress_buffers(true)
245         {}
246 
open(const char * env_dir,uint32_t flags,int mode) const247         DBEnv open(const char *env_dir, uint32_t flags, int mode) const {
248             db_env_set_direct_io(_direct_io);
249             db_env_set_compress_buffers_before_eviction(_compress_buffers);
250             if (_cachetable_bucket_mutexes) {
251                 db_env_set_num_bucket_mutexes(_cachetable_bucket_mutexes);
252             }
253 
254             if (!_product_name.empty()) {
255                 db_env_set_toku_product_name(_product_name.c_str());
256             }
257 
258             DB_ENV *env;
259             int r = db_env_create(&env, 0);
260             handle_ft_retval(r);
261 
262             if (_bt_compare) {
263                 r = env->set_default_bt_compare(env, _bt_compare);
264                 handle_ft_retval(r);
265             }
266 
267             if (_update_function) {
268                 env->set_update(env, _update_function);
269             }
270 
271             if (_generate_row_for_put) {
272                 r = env->set_generate_row_callback_for_put(env, _generate_row_for_put);
273                 handle_ft_retval(r);
274             }
275 
276             if (_generate_row_for_del) {
277                 r = env->set_generate_row_callback_for_del(env, _generate_row_for_del);
278                 handle_ft_retval(r);
279             }
280 
281             if (_lk_max_memory) {
282                 r = env->set_lk_max_memory(env, _lk_max_memory);
283                 handle_ft_retval(r);
284             }
285 
286             if (_lock_wait_time_msec || _get_lock_wait_time_cb) {
287                 uint64_t wait_time = _lock_wait_time_msec;
288                 if (!wait_time) {
289                     r = env->get_lock_timeout(env, &wait_time);
290                     handle_ft_retval(r);
291                 }
292                 r = env->set_lock_timeout(env, wait_time, _get_lock_wait_time_cb);
293                 handle_ft_retval(r);
294             }
295 
296             if (_lock_timeout_callback) {
297                 r = env->set_lock_timeout_callback(env, _lock_timeout_callback);
298                 handle_ft_retval(r);
299             }
300 
301             if (_lock_wait_needed_callback) {
302                 r = env->set_lock_wait_callback(env, _lock_wait_needed_callback);
303                 handle_ft_retval(r);
304             }
305 
306             if (_loader_memory_size_callback) {
307                 env->set_loader_memory_size(env, _loader_memory_size_callback);
308             }
309 
310             if (_cachesize_gbytes || _cachesize_bytes) {
311                 r = env->set_cachesize(env, _cachesize_gbytes, _cachesize_bytes, 1);
312                 handle_ft_retval(r);
313             }
314 
315             if (_fs_redzone) {
316                 env->set_redzone(env, _fs_redzone);
317             }
318 
319             if (!_lg_dir.empty()) {
320                 r = env->set_lg_dir(env, _lg_dir.c_str());
321                 handle_ft_retval(r);
322             }
323 
324             if (!_tmp_dir.empty()) {
325                 r = env->set_tmp_dir(env, _tmp_dir.c_str());
326                 handle_ft_retval(r);
327             }
328 
329             r = env->open(env, env_dir, flags, mode);
330             handle_ft_retval(r);
331 
332             if (_cleaner_period) {
333                 r = env->cleaner_set_period(env, _cleaner_period);
334                 handle_ft_retval(r);
335             }
336 
337             if (_cleaner_iterations) {
338                 r = env->cleaner_set_iterations(env, _cleaner_iterations);
339                 handle_ft_retval(r);
340             }
341 
342             if (_checkpointing_period) {
343                 r = env->checkpointing_set_period(env, _checkpointing_period);
344                 handle_ft_retval(r);
345             }
346 
347             if (_fsync_log_period_msec) {
348                 env->change_fsync_log_period(env, _fsync_log_period_msec);
349             }
350 
351             return DBEnv(env, true);
352         }
353 
set_direct_io(bool direct_io)354         DBEnvBuilder& set_direct_io(bool direct_io) {
355             _direct_io = direct_io;
356             return *this;
357         }
358 
set_compress_buffers_before_eviction(bool compress_buffers)359         DBEnvBuilder& set_compress_buffers_before_eviction(bool compress_buffers) {
360             _compress_buffers = compress_buffers;
361             return *this;
362         }
363 
set_default_bt_compare(bt_compare_func bt_compare)364         DBEnvBuilder& set_default_bt_compare(bt_compare_func bt_compare) {
365             _bt_compare = bt_compare;
366             return *this;
367         }
368 
set_update(update_func update_function)369         DBEnvBuilder& set_update(update_func update_function) {
370             _update_function = update_function;
371             return *this;
372         }
373 
set_generate_row_callback_for_put(generate_row_for_put_func generate_row_for_put)374         DBEnvBuilder& set_generate_row_callback_for_put(generate_row_for_put_func generate_row_for_put) {
375             _generate_row_for_put = generate_row_for_put;
376             return *this;
377         }
378 
set_generate_row_callback_for_del(generate_row_for_del_func generate_row_for_del)379         DBEnvBuilder& set_generate_row_callback_for_del(generate_row_for_del_func generate_row_for_del) {
380             _generate_row_for_del = generate_row_for_del;
381             return *this;
382         }
383 
cleaner_set_period(uint32_t period)384         DBEnvBuilder& cleaner_set_period(uint32_t period) {
385             _cleaner_period = period;
386             return *this;
387         }
388 
cleaner_set_iterations(uint32_t iterations)389         DBEnvBuilder& cleaner_set_iterations(uint32_t iterations) {
390             _cleaner_iterations = iterations;
391             return *this;
392         }
393 
checkpointing_set_period(uint32_t period)394         DBEnvBuilder& checkpointing_set_period(uint32_t period) {
395             _checkpointing_period = period;
396             return *this;
397         }
398 
change_fsync_log_period(uint32_t period)399         DBEnvBuilder& change_fsync_log_period(uint32_t period) {
400             _fsync_log_period_msec = period;
401             return *this;
402         }
403 
set_fs_redzone(int fs_redzone)404         DBEnvBuilder& set_fs_redzone(int fs_redzone) {
405             _fs_redzone = fs_redzone;
406             return *this;
407         }
408 
set_lk_max_memory(uint64_t sz)409         DBEnvBuilder& set_lk_max_memory(uint64_t sz) {
410             _lk_max_memory = sz;
411             return *this;
412         }
413 
set_lock_wait_time_msec(uint64_t lock_wait_time_msec)414         DBEnvBuilder& set_lock_wait_time_msec(uint64_t lock_wait_time_msec) {
415             _lock_wait_time_msec = lock_wait_time_msec;
416             return *this;
417         }
418 
set_lock_wait_time_cb(get_lock_wait_time_cb_func get_lock_wait_time_cb)419         DBEnvBuilder& set_lock_wait_time_cb(get_lock_wait_time_cb_func get_lock_wait_time_cb) {
420             _get_lock_wait_time_cb = get_lock_wait_time_cb;
421             return *this;
422         }
423 
set_lock_timeout_callback(lock_timeout_callback callback)424         DBEnvBuilder& set_lock_timeout_callback(lock_timeout_callback callback) {
425             _lock_timeout_callback = callback;
426             return *this;
427         }
428 
set_lock_wait_callback(lock_wait_callback callback)429         DBEnvBuilder& set_lock_wait_callback(lock_wait_callback callback) {
430             _lock_wait_needed_callback = callback;
431             return *this;
432         }
433 
set_loader_memory_size(uint64_t (* callback)(void))434         DBEnvBuilder& set_loader_memory_size(uint64_t (*callback)(void)) {
435             _loader_memory_size_callback = callback;
436             return *this;
437         }
438 
set_cachesize(uint32_t gbytes,uint32_t bytes)439         DBEnvBuilder& set_cachesize(uint32_t gbytes, uint32_t bytes) {
440             _cachesize_gbytes = gbytes;
441             _cachesize_bytes = bytes;
442             return *this;
443         }
444 
set_cachetable_bucket_mutexes(uint32_t mutexes)445         DBEnvBuilder& set_cachetable_bucket_mutexes(uint32_t mutexes) {
446             _cachetable_bucket_mutexes = mutexes;
447             return *this;
448         }
449 
set_product_name(const char * product_name)450         DBEnvBuilder& set_product_name(const char *product_name) {
451             _product_name = std::string(product_name);
452             return *this;
453         }
454 
set_lg_dir(const char * lg_dir)455         DBEnvBuilder& set_lg_dir(const char *lg_dir) {
456             _lg_dir = std::string(lg_dir);
457             return *this;
458         }
459 
set_tmp_dir(const char * tmp_dir)460         DBEnvBuilder& set_tmp_dir(const char *tmp_dir) {
461             _tmp_dir = std::string(tmp_dir);
462             return *this;
463         }
464     };
465 
466 } // namespace ftcxx
467