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: |
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 | |