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 <errno.h>
41
42#include <map>
43#include <string>
44
45#include <db.h>
46
47#include "exceptions.hpp"
48#include "slice.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 DBTxn;
60
61 class DBEnv {
62 public:
63 explicit DBEnv(DB_ENV *e, bool close_on_destroy=false)
64 : _env(e),
65 _close_on_destroy(close_on_destroy)
66 {}
67
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
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
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
91 DB_ENV *env() const { return _env; }
92
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
102 void log_flush() {
103 int r = _env->log_flush(_env, NULL);
104 handle_ft_retval(r);
105 }
106
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
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
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
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
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
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:
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
247 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
354 DBEnvBuilder& set_direct_io(bool direct_io) {
355 _direct_io = direct_io;
356 return *this;
357 }
358
359 DBEnvBuilder& set_compress_buffers_before_eviction(bool compress_buffers) {
360 _compress_buffers = compress_buffers;
361 return *this;
362 }
363
364 DBEnvBuilder& set_default_bt_compare(bt_compare_func bt_compare) {
365 _bt_compare = bt_compare;
366 return *this;
367 }
368
369 DBEnvBuilder& set_update(update_func update_function) {
370 _update_function = update_function;
371 return *this;
372 }
373
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
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
384 DBEnvBuilder& cleaner_set_period(uint32_t period) {
385 _cleaner_period = period;
386 return *this;
387 }
388
389 DBEnvBuilder& cleaner_set_iterations(uint32_t iterations) {
390 _cleaner_iterations = iterations;
391 return *this;
392 }
393
394 DBEnvBuilder& checkpointing_set_period(uint32_t period) {
395 _checkpointing_period = period;
396 return *this;
397 }
398
399 DBEnvBuilder& change_fsync_log_period(uint32_t period) {
400 _fsync_log_period_msec = period;
401 return *this;
402 }
403
404 DBEnvBuilder& set_fs_redzone(int fs_redzone) {
405 _fs_redzone = fs_redzone;
406 return *this;
407 }
408
409 DBEnvBuilder& set_lk_max_memory(uint64_t sz) {
410 _lk_max_memory = sz;
411 return *this;
412 }
413
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
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
424 DBEnvBuilder& set_lock_timeout_callback(lock_timeout_callback callback) {
425 _lock_timeout_callback = callback;
426 return *this;
427 }
428
429 DBEnvBuilder& set_lock_wait_callback(lock_wait_callback callback) {
430 _lock_wait_needed_callback = callback;
431 return *this;
432 }
433
434 DBEnvBuilder& set_loader_memory_size(uint64_t (*callback)(void)) {
435 _loader_memory_size_callback = callback;
436 return *this;
437 }
438
439 DBEnvBuilder& set_cachesize(uint32_t gbytes, uint32_t bytes) {
440 _cachesize_gbytes = gbytes;
441 _cachesize_bytes = bytes;
442 return *this;
443 }
444
445 DBEnvBuilder& set_cachetable_bucket_mutexes(uint32_t mutexes) {
446 _cachetable_bucket_mutexes = mutexes;
447 return *this;
448 }
449
450 DBEnvBuilder& set_product_name(const char *product_name) {
451 _product_name = std::string(product_name);
452 return *this;
453 }
454
455 DBEnvBuilder& set_lg_dir(const char *lg_dir) {
456 _lg_dir = std::string(lg_dir);
457 return *this;
458 }
459
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