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 <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 | |
51 | namespace 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 | |