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 <utility>
41
42#include <db.h>
43
44#include "buffer.hpp"
45#include "db.hpp"
46#include "db_env.hpp"
47#include "db_txn.hpp"
48#include "slice.hpp"
49
50namespace ftcxx {
51
52 class DB;
53
54 struct IterationStrategy {
55 bool forward;
56 bool prelock;
57
58 IterationStrategy(bool forward_, bool prelock_)
59 : forward(forward_),
60 prelock(prelock_)
61 {}
62
63 int getf_flags() const {
64 if (prelock) {
65 return DB_PRELOCKED | DB_PRELOCKED_WRITE;
66 } else {
67 return DBC_DISABLE_PREFETCHING;
68 }
69 }
70 };
71
72 class Bounds {
73 const ::DB *_db;
74 Slice _left;
75 Slice _right;
76 DBT _left_dbt;
77 DBT _right_dbt;
78 bool _left_infinite;
79 bool _right_infinite;
80 bool _end_exclusive;
81
82 public:
83 Bounds(const DB &db, const Slice &left, const Slice &right, bool end_exclusive)
84 : _db(db.db()),
85 _left(left.owned()),
86 _right(right.owned()),
87 _left_dbt(_left.dbt()),
88 _right_dbt(_right.dbt()),
89 _left_infinite(false),
90 _right_infinite(false),
91 _end_exclusive(end_exclusive)
92 {}
93
94 struct Infinite {};
95
96 Bounds(const DB &db, Infinite, const Slice &right, bool end_exclusive)
97 : _db(db.db()),
98 _left(),
99 _right(right.owned()),
100 _left_dbt(_left.dbt()),
101 _right_dbt(_right.dbt()),
102 _left_infinite(true),
103 _right_infinite(false),
104 _end_exclusive(end_exclusive)
105 {}
106
107 Bounds(const DB &db, const Slice &left, Infinite, bool end_exclusive)
108 : _db(db.db()),
109 _left(left.owned()),
110 _right(),
111 _left_dbt(_left.dbt()),
112 _right_dbt(_right.dbt()),
113 _left_infinite(false),
114 _right_infinite(true),
115 _end_exclusive(end_exclusive)
116 {}
117
118 Bounds(const DB &db, Infinite, Infinite, bool end_exclusive)
119 : _db(db.db()),
120 _left(),
121 _right(),
122 _left_dbt(_left.dbt()),
123 _right_dbt(_right.dbt()),
124 _left_infinite(true),
125 _right_infinite(true),
126 _end_exclusive(end_exclusive)
127 {}
128
129 Bounds(const Bounds &other) = delete;
130 Bounds& operator=(const Bounds &) = delete;
131
132 Bounds(Bounds &&o)
133 : _db(nullptr),
134 _left(),
135 _right(),
136 _left_infinite(o._left_infinite),
137 _right_infinite(o._right_infinite),
138 _end_exclusive(o._end_exclusive)
139 {
140 std::swap(_db, o._db);
141 std::swap(_left, o._left);
142 std::swap(_right, o._right);
143 _left_dbt = _left.dbt();
144 _right_dbt = _right.dbt();
145 }
146
147 Bounds& operator=(Bounds&& other) {
148 std::swap(_db, other._db);
149 std::swap(_left, other._left);
150 std::swap(_right, other._right);
151 _left_dbt = _left.dbt();
152 _right_dbt = _right.dbt();
153 _left_infinite = other._left_infinite;
154 _right_infinite = other._right_infinite;
155 _end_exclusive = other._end_exclusive;
156 return *this;
157 }
158
159 const DBT *left_dbt() const {
160 if (_left_infinite) {
161 return _db->dbt_neg_infty();
162 } else {
163 return &_left_dbt;
164 }
165 }
166
167 const DBT *right_dbt() const {
168 if (_right_infinite) {
169 return _db->dbt_pos_infty();
170 } else {
171 return &_right_dbt;
172 }
173 }
174
175 void set_left(const Slice &left) {
176 _left = left.owned();
177 _left_dbt = _left.dbt();
178 _left_infinite = false;
179 }
180
181 void set_right(const Slice &right) {
182 _right = right.owned();
183 _right_dbt = _right.dbt();
184 _right_infinite = false;
185 }
186
187 bool left_infinite() const { return _left_infinite; }
188 bool right_infinite() const { return _right_infinite; }
189
190 template<class Comparator>
191 bool check(Comparator &cmp, const IterationStrategy &strategy, const Slice &key) const;
192 };
193
194 /**
195 * DBC is a simple RAII wrapper around a DBC object.
196 */
197 class DBC {
198 public:
199 DBC(const DB &db, const DBTxn &txn=DBTxn(), int flags=0);
200 ~DBC();
201
202 // Directory cursor.
203 DBC(const DBEnv &env, const DBTxn &txn=DBTxn());
204
205 DBC(const DBC &) = delete;
206 DBC& operator=(const DBC &) = delete;
207
208 DBC(DBC &&o)
209 : _txn(),
210 _dbc(nullptr)
211 {
212 std::swap(_txn, o._txn);
213 std::swap(_dbc, o._dbc);
214 }
215
216 DBC& operator=(DBC &&o) {
217 std::swap(_txn, o._txn);
218 std::swap(_dbc, o._dbc);
219 return *this;
220 }
221
222 ::DBC *dbc() const { return _dbc; }
223
224 void set_txn(const DBTxn &txn) const {
225 _dbc->c_set_txn(_dbc, txn.txn());
226 }
227
228 void close();
229
230 bool set_range(const IterationStrategy &strategy, const Bounds &bounds, YDB_CALLBACK_FUNCTION callback, void *extra) const;
231
232 bool advance(const IterationStrategy &strategy, YDB_CALLBACK_FUNCTION callback, void *extra) const;
233
234 protected:
235
236 // the ordering here matters, for destructors
237 DBTxn _txn;
238 ::DBC *_dbc;
239 };
240
241 /**
242 * Cursor supports iterating a cursor over a key range,
243 * with bulk fetch buffering, and optional filtering.
244 */
245 template<class Comparator, class Handler>
246 class CallbackCursor {
247 public:
248
249 /**
250 * Directory cursor.
251 */
252 CallbackCursor(const DBEnv &env, const DBTxn &txn,
253 Comparator &&cmp, Handler &&handler);
254
255 /**
256 * Constructs an cursor. Better to use DB::cursor instead to
257 * avoid template parameters.
258 */
259 CallbackCursor(const DB &db, const DBTxn &txn, int flags,
260 IterationStrategy iteration_strategy,
261 Bounds bounds,
262 Comparator &&cmp, Handler &&handler);
263
264 /**
265 * Gets the next key/val pair in the iteration. Returns true
266 * if there is more data, and fills in key and val. If the
267 * range is exhausted, returns false.
268 */
269 bool consume_batch();
270
271 void seek(const Slice &key);
272
273 bool finished() const { return _finished; }
274
275 bool ok() const { return !finished(); }
276
277 void set_txn(const DBTxn &txn) const { _dbc.set_txn(txn); }
278
279 private:
280
281 DBC _dbc;
282 IterationStrategy _iteration_strategy;
283 Bounds _bounds;
284 Comparator _cmp;
285 Handler _handler;
286
287 bool _finished;
288
289 void init();
290
291 static int getf_callback(const DBT *key, const DBT *val, void *extra) {
292 CallbackCursor *i = static_cast<CallbackCursor *>(extra);
293 return i->getf(key, val);
294 }
295
296 int getf(const DBT *key, const DBT *val);
297 };
298
299 template<class Predicate>
300 class BufferAppender {
301 Buffer &_buf;
302 Predicate _filter;
303
304 public:
305 BufferAppender(Buffer &buf, Predicate &&filter)
306 : _buf(buf),
307 _filter(std::forward<Predicate>(filter))
308 {}
309
310 bool operator()(const DBT *key, const DBT *val);
311
312 static size_t marshalled_size(size_t keylen, size_t vallen) {
313 return (sizeof(((DBT *)0)->size)) + (sizeof(((DBT *)0)->size)) + keylen + vallen;
314 }
315
316 static void marshall(char *dest, const DBT *key, const DBT *val);
317
318 static void unmarshall(char *src, DBT *key, DBT *val);
319 static void unmarshall(char *src, Slice &key, Slice &val);
320 };
321
322 template<class Comparator, class Predicate>
323 class BufferedCursor {
324 public:
325
326 /**
327 * Directory cursor.
328 */
329 BufferedCursor(const DBEnv &env, const DBTxn &txn,
330 Comparator &&cmp, Predicate &&filter);
331
332 /**
333 * Constructs an buffered cursor. Better to use
334 * DB::buffered_cursor instead to avoid template parameters.
335 */
336 BufferedCursor(const DB &db, const DBTxn &txn, int flags,
337 IterationStrategy iteration_strategy,
338 Bounds bounds,
339 Comparator &&cmp, Predicate &&filter);
340
341 /**
342 * Gets the next key/val pair in the iteration. Returns true
343 * if there is more data, and fills in key and val. If the
344 * range is exhausted, returns false.
345 */
346 bool next(DBT *key, DBT *val);
347 bool next(Slice &key, Slice &val);
348
349 void seek(const Slice &key);
350
351 bool ok() const {
352 return _cur.ok() || _buf.more();
353 }
354
355 void set_txn(const DBTxn &txn) const { _cur.set_txn(txn); }
356
357 private:
358
359 typedef BufferAppender<Predicate> Appender;
360
361 Buffer _buf;
362 CallbackCursor<Comparator, Appender> _cur;
363 };
364
365 template<class Comparator>
366 class SimpleCursor {
367 public:
368 SimpleCursor(const DBEnv &env, const DBTxn &txn,
369 Comparator &&cmp, Slice &key, Slice &val);
370
371 SimpleCursor(const DB &db, const DBTxn &txn, int flags,
372 IterationStrategy iteration_strategy,
373 Bounds bounds, Comparator &&cmp,
374 Slice &key, Slice &val);
375
376 /**
377 * Gets the next key/val pair in the iteration. Copies data
378 * directly into key and val, which will own their buffers.
379 */
380 bool next();
381
382 void seek(const Slice &key);
383
384 bool ok() const {
385 return _cur.ok();
386 }
387
388 void set_txn(const DBTxn &txn) const { _cur.set_txn(txn); }
389
390 class SliceCopier {
391 Slice &_key;
392 Slice &_val;
393
394 public:
395 SliceCopier(Slice &key, Slice &val)
396 : _key(key),
397 _val(val)
398 {}
399
400 bool operator()(const DBT *key, const DBT *val) {
401 _key = std::move(Slice(*key).owned());
402 _val = std::move(Slice(*val).owned());
403
404 // Don't bulk fetch.
405 return false;
406 }
407 };
408
409 private:
410
411 SliceCopier _copier;
412 CallbackCursor<Comparator, SliceCopier&> _cur;
413 };
414
415} // namespace ftcxx
416
417#include "cursor-inl.hpp"
418