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