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 <algorithm>
41#include <cstdint>
42#include <utility>
43
44#include <db.h>
45
46#include "buffer.hpp"
47#include "db_txn.hpp"
48#include "exceptions.hpp"
49#include "slice.hpp"
50
51namespace ftcxx {
52
53 class DB;
54
55 template<class Comparator>
56 bool Bounds::check(Comparator &cmp, const IterationStrategy &strategy, const Slice &key) const {
57 int c;
58 if (strategy.forward) {
59 if (_right_infinite) {
60 return true;
61 }
62 c = cmp(key, _right);
63 } else {
64 if (_left_infinite) {
65 return true;
66 }
67 c = cmp(_left, key);
68 }
69 if (c > 0 || (c == 0 && _end_exclusive)) {
70 return false;
71 }
72 return true;
73 }
74
75 template<class Comparator, class Handler>
76 CallbackCursor<Comparator, Handler>::CallbackCursor(const DBEnv &env, const DBTxn &txn,
77 Comparator &&cmp, Handler &&handler)
78 : _dbc(env, txn),
79 _iteration_strategy(IterationStrategy(true, true)),
80 _bounds(DB(env.env()->get_db_for_directory(env.env())), Bounds::Infinite(), Bounds::Infinite(), false),
81 _cmp(std::forward<Comparator>(cmp)),
82 _handler(std::forward<Handler>(handler)),
83 _finished(false)
84 {
85 init();
86 }
87
88 template<class Comparator, class Handler>
89 CallbackCursor<Comparator, Handler>::CallbackCursor(const DB &db, const DBTxn &txn, int flags,
90 IterationStrategy iteration_strategy,
91 Bounds bounds,
92 Comparator &&cmp, Handler &&handler)
93 : _dbc(db, txn, flags),
94 _iteration_strategy(iteration_strategy),
95 _bounds(std::move(bounds)),
96 _cmp(std::forward<Comparator>(cmp)),
97 _handler(std::forward<Handler>(handler)),
98 _finished(false)
99 {
100 init();
101 }
102
103 template<class Comparator, class Handler>
104 void CallbackCursor<Comparator, Handler>::init() {
105 if (!_dbc.set_range(_iteration_strategy, _bounds, getf_callback, this)) {
106 _finished = true;
107 }
108 }
109
110 template<class Comparator, class Handler>
111 int CallbackCursor<Comparator, Handler>::getf(const DBT *key, const DBT *val) {
112 if (!_bounds.check(_cmp, _iteration_strategy, Slice(*key))) {
113 _finished = true;
114 return -1;
115 }
116
117 if (!_handler(key, val)) {
118 return 0;
119 }
120
121 return TOKUDB_CURSOR_CONTINUE;
122 }
123
124 template<class Comparator, class Handler>
125 bool CallbackCursor<Comparator, Handler>::consume_batch() {
126 if (!_dbc.advance(_iteration_strategy, getf_callback, this)) {
127 _finished = true;
128 }
129 return !_finished;
130 }
131
132 template<class Comparator, class Handler>
133 void CallbackCursor<Comparator, Handler>::seek(const Slice &key) {
134 if (_iteration_strategy.forward) {
135 _bounds.set_left(key);
136 } else {
137 _bounds.set_right(key);
138 }
139 if (!_dbc.set_range(_iteration_strategy, _bounds, getf_callback, this)) {
140 _finished = true;
141 }
142 }
143
144 template<class Predicate>
145 inline void BufferAppender<Predicate>::marshall(char *dest, const DBT *key, const DBT *val) {
146 uint32_t *keylen = reinterpret_cast<uint32_t *>(&dest[0]);
147 uint32_t *vallen = reinterpret_cast<uint32_t *>(&dest[sizeof *keylen]);
148 *keylen = key->size;
149 *vallen = val->size;
150
151 char *p = &dest[(sizeof *keylen) + (sizeof *vallen)];
152
153 const char *kp = static_cast<char *>(key->data);
154 std::copy(kp, kp + key->size, p);
155
156 p += key->size;
157
158 const char *vp = static_cast<char *>(val->data);
159 std::copy(vp, vp + val->size, p);
160 }
161
162 template<class Predicate>
163 inline void BufferAppender<Predicate>::unmarshall(char *src, DBT *key, DBT *val) {
164 const uint32_t *keylen = reinterpret_cast<uint32_t *>(&src[0]);
165 const uint32_t *vallen = reinterpret_cast<uint32_t *>(&src[sizeof *keylen]);
166 key->size = *keylen;
167 val->size = *vallen;
168 char *p = &src[(sizeof *keylen) + (sizeof *vallen)];
169 key->data = p;
170 val->data = p + key->size;
171 }
172
173 template<class Predicate>
174 inline void BufferAppender<Predicate>::unmarshall(char *src, Slice &key, Slice &val) {
175 const uint32_t *keylen = reinterpret_cast<uint32_t *>(&src[0]);
176 const uint32_t *vallen = reinterpret_cast<uint32_t *>(&src[sizeof *keylen]);
177 char *p = &src[(sizeof *keylen) + (sizeof *vallen)];
178 key = Slice(p, *keylen);
179 val = Slice(p + *keylen, *vallen);
180 }
181
182 template<class Predicate>
183 inline bool BufferAppender<Predicate>::operator()(const DBT *key, const DBT *val) {
184 if (_filter(Slice(*key), Slice(*val))) {
185 size_t needed = marshalled_size(key->size, val->size);
186 char *dest = _buf.alloc(needed);
187 marshall(dest, key, val);
188 }
189 return !_buf.full();
190 }
191
192 template<class Comparator, class Predicate>
193 BufferedCursor<Comparator, Predicate>::BufferedCursor(const DBEnv &env, const DBTxn &txn,
194 Comparator &&cmp, Predicate &&filter)
195 : _buf(),
196 _cur(env, txn, std::forward<Comparator>(cmp), Appender(_buf, std::forward<Predicate>(filter)))
197 {}
198
199 template<class Comparator, class Predicate>
200 BufferedCursor<Comparator, Predicate>::BufferedCursor(const DB &db, const DBTxn &txn, int flags,
201 IterationStrategy iteration_strategy,
202 Bounds bounds,
203 Comparator &&cmp, Predicate &&filter)
204 : _buf(),
205 _cur(db, txn, flags,
206 iteration_strategy,
207 std::move(bounds),
208 std::forward<Comparator>(cmp), Appender(_buf, std::forward<Predicate>(filter)))
209 {}
210
211 template<class Comparator, class Predicate>
212 bool BufferedCursor<Comparator, Predicate>::next(DBT *key, DBT *val) {
213 if (!_buf.more() && !_cur.finished()) {
214 _buf.clear();
215 _cur.consume_batch();
216 }
217
218 if (!_buf.more()) {
219 return false;
220 }
221
222 char *src = _buf.current();
223 Appender::unmarshall(src, key, val);
224 _buf.advance(Appender::marshalled_size(key->size, val->size));
225 return true;
226 }
227
228 template<class Comparator, class Predicate>
229 bool BufferedCursor<Comparator, Predicate>::next(Slice &key, Slice &val) {
230 if (!_buf.more() && !_cur.finished()) {
231 _buf.clear();
232 _cur.consume_batch();
233 }
234
235 if (!_buf.more()) {
236 return false;
237 }
238
239 char *src = _buf.current();
240 Appender::unmarshall(src, key, val);
241 _buf.advance(Appender::marshalled_size(key.size(), val.size()));
242 return true;
243 }
244
245 template<class Comparator, class Predicate>
246 void BufferedCursor<Comparator, Predicate>::seek(const Slice &key) {
247 _buf.clear();
248 _cur.seek(key);
249 }
250
251 template<class Comparator>
252 SimpleCursor<Comparator>::SimpleCursor(const DBEnv &env, const DBTxn &txn, Comparator &&cmp,
253 Slice &key, Slice &val)
254 : _copier(key, val),
255 _cur(env, txn, std::forward<Comparator>(cmp), _copier)
256 {}
257
258 template<class Comparator>
259 SimpleCursor<Comparator>::SimpleCursor(const DB &db, const DBTxn &txn, int flags,
260 IterationStrategy iteration_strategy,
261 Bounds bounds, Comparator &&cmp,
262 Slice &key, Slice &val)
263 : _copier(key, val),
264 _cur(db, txn, flags,
265 iteration_strategy,
266 std::move(bounds),
267 std::forward<Comparator>(cmp), _copier)
268 {}
269
270 template<class Comparator>
271 bool SimpleCursor<Comparator>::next() {
272 return _cur.consume_batch();
273 }
274
275 template<class Comparator>
276 void SimpleCursor<Comparator>::seek(const Slice &key) {
277 _cur.seek(key);
278 }
279
280 template<class Comparator, class Handler>
281 CallbackCursor<Comparator, Handler> DB::cursor(const DBTxn &txn, DBT *left, DBT *right,
282 Comparator &&cmp, Handler &&handler, int flags,
283 bool forward, bool end_exclusive, bool prelock) const {
284 IterationStrategy strategy(forward, prelock);
285 return CallbackCursor<Comparator, Handler>(*this, txn, flags, strategy,
286 Bounds(*this, Slice(*left), Slice(*right), end_exclusive),
287 std::forward<Comparator>(cmp), std::forward<Handler>(handler));
288 }
289
290 template<class Comparator, class Handler>
291 CallbackCursor<Comparator, Handler> DB::cursor(const DBTxn &txn, const Slice &start_key,
292 Comparator &&cmp, Handler &&handler, int flags,
293 bool forward, bool end_exclusive, bool prelock) const {
294 IterationStrategy strategy(forward, prelock);
295 Bounds bounds = forward
296 ? Bounds(*this, start_key, Bounds::Infinite(), end_exclusive)
297 : Bounds(*this, Bounds::Infinite(), start_key, end_exclusive);
298 return CallbackCursor<Comparator, Handler>(*this, txn, flags, strategy, std::move(bounds),
299 std::forward<Comparator>(cmp), std::forward<Handler>(handler));
300 }
301
302 template<class Comparator, class Handler>
303 CallbackCursor<Comparator, Handler> DB::cursor(const DBTxn &txn, const Slice &left, const Slice &right,
304 Comparator &&cmp, Handler &&handler, int flags,
305 bool forward, bool end_exclusive, bool prelock) const {
306 IterationStrategy strategy(forward, prelock);
307 return CallbackCursor<Comparator, Handler>(*this, txn, flags, strategy,
308 Bounds(*this, left, right, end_exclusive),
309 std::forward<Comparator>(cmp), std::forward<Handler>(handler));
310 }
311
312 template<class Comparator, class Handler>
313 CallbackCursor<Comparator, Handler> DB::cursor(const DBTxn &txn, Comparator &&cmp, Handler &&handler,
314 int flags, bool forward, bool prelock) const {
315 IterationStrategy strategy(forward, prelock);
316 return CallbackCursor<Comparator, Handler>(*this, txn, flags, strategy,
317 Bounds(*this, Bounds::Infinite(), Bounds::Infinite(), false),
318 std::forward<Comparator>(cmp), std::forward<Handler>(handler));
319 }
320
321 template<class Comparator, class Predicate>
322 BufferedCursor<Comparator, Predicate> DB::buffered_cursor(const DBTxn &txn, DBT *left, DBT *right,
323 Comparator &&cmp, Predicate &&filter, int flags,
324 bool forward, bool end_exclusive, bool prelock) const {
325 IterationStrategy strategy(forward, prelock);
326 return BufferedCursor<Comparator, Predicate>(*this, txn, flags, strategy,
327 Bounds(*this, Slice(*left), Slice(*right), end_exclusive),
328 std::forward<Comparator>(cmp), std::forward<Predicate>(filter));
329 }
330
331 template<class Comparator, class Predicate>
332 BufferedCursor<Comparator, Predicate> DB::buffered_cursor(const DBTxn &txn, const Slice &start_key,
333 Comparator &&cmp, Predicate &&filter, int flags,
334 bool forward, bool end_exclusive, bool prelock) const {
335 IterationStrategy strategy(forward, prelock);
336 Bounds bounds = forward
337 ? Bounds(*this, start_key, Bounds::Infinite(), end_exclusive)
338 : Bounds(*this, Bounds::Infinite(), start_key, end_exclusive);
339 return BufferedCursor<Comparator, Predicate>(*this, txn, flags, strategy, std::move(bounds),
340 std::forward<Comparator>(cmp), std::forward<Predicate>(filter));
341 }
342
343 template<class Comparator, class Predicate>
344 BufferedCursor<Comparator, Predicate> DB::buffered_cursor(const DBTxn &txn, const Slice &left, const Slice &right,
345 Comparator &&cmp, Predicate &&filter, int flags,
346 bool forward, bool end_exclusive, bool prelock) const {
347 IterationStrategy strategy(forward, prelock);
348 return BufferedCursor<Comparator, Predicate>(*this, txn, flags, strategy,
349 Bounds(*this, left, right, end_exclusive),
350 std::forward<Comparator>(cmp), std::forward<Predicate>(filter));
351 }
352
353 template<class Comparator, class Predicate>
354 BufferedCursor<Comparator, Predicate> DB::buffered_cursor(const DBTxn &txn, Comparator &&cmp, Predicate &&filter,
355 int flags, bool forward, bool prelock) const {
356 IterationStrategy strategy(forward, prelock);
357 return BufferedCursor<Comparator, Predicate>(*this, txn, flags, strategy,
358 Bounds(*this, Bounds::Infinite(), Bounds::Infinite(), false),
359 std::forward<Comparator>(cmp), std::forward<Predicate>(filter));
360 }
361
362 template<class Comparator>
363 SimpleCursor<Comparator> DB::simple_cursor(const DBTxn &txn, DBT *left, DBT *right,
364 Comparator &&cmp, Slice &key, Slice &val, int flags,
365 bool forward, bool end_exclusive, bool prelock) const {
366 IterationStrategy strategy(forward, prelock);
367 return SimpleCursor<Comparator>(*this, txn, flags, strategy,
368 Bounds(*this, Slice(*left), Slice(*right), end_exclusive),
369 std::forward<Comparator>(cmp), key, val);
370 }
371
372 template<class Comparator>
373 SimpleCursor<Comparator> DB::simple_cursor(const DBTxn &txn, const Slice &start_key,
374 Comparator &&cmp, Slice &key, Slice &val, int flags,
375 bool forward, bool end_exclusive, bool prelock) const {
376 IterationStrategy strategy(forward, prelock);
377 Bounds bounds = forward
378 ? Bounds(*this, start_key, Bounds::Infinite(), end_exclusive)
379 : Bounds(*this, Bounds::Infinite(), start_key, end_exclusive);
380 return SimpleCursor<Comparator>(*this, txn, flags, strategy, std::move(bounds),
381 std::forward<Comparator>(cmp), key, val);
382 }
383
384 template<class Comparator>
385 SimpleCursor<Comparator> DB::simple_cursor(const DBTxn &txn, const Slice &left, const Slice &right,
386 Comparator &&cmp, Slice &key, Slice &val, int flags,
387 bool forward, bool end_exclusive, bool prelock) const {
388 IterationStrategy strategy(forward, prelock);
389 return SimpleCursor<Comparator>(*this, txn, flags, strategy,
390 Bounds(*this, left, right, end_exclusive),
391 std::forward<Comparator>(cmp), key, val);
392 }
393
394 template<class Comparator>
395 SimpleCursor<Comparator> DB::simple_cursor(const DBTxn &txn, Comparator &&cmp, Slice &key, Slice &val,
396 int flags, bool forward, bool prelock) const {
397 IterationStrategy strategy(forward, prelock);
398 return SimpleCursor<Comparator>(*this, txn, flags, strategy,
399 Bounds(*this, Bounds::Infinite(), Bounds::Infinite(), false),
400 std::forward<Comparator>(cmp), key, val);
401 }
402
403 template<class Comparator, class Handler>
404 CallbackCursor<Comparator, Handler> DBEnv::cursor(const DBTxn &txn, Comparator &&cmp, Handler &&handler) const {
405 return CallbackCursor<Comparator, Handler>(*this, txn, std::forward<Comparator>(cmp), std::forward<Handler>(handler));
406 }
407
408 template<class Comparator, class Predicate>
409 BufferedCursor<Comparator, Predicate> DBEnv::buffered_cursor(const DBTxn &txn, Comparator &&cmp, Predicate &&filter) const {
410 return BufferedCursor<Comparator, Predicate>(*this, txn, std::forward<Comparator>(cmp), std::forward<Predicate>(filter));
411 }
412
413 template<class Comparator>
414 SimpleCursor<Comparator> DBEnv::simple_cursor(const DBTxn &txn, Comparator &&cmp, Slice &key, Slice &val) const {
415 return SimpleCursor<Comparator>(*this, txn, std::forward<Comparator>(cmp), key, val);
416 }
417
418} // namespace ftcxx
419