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 <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 50 namespace ftcxx { 51 52 class DB; 53 54 struct IterationStrategy { 55 bool forward; 56 bool prelock; 57 IterationStrategyftcxx::IterationStrategy58 IterationStrategy(bool forward_, bool prelock_) 59 : forward(forward_), 60 prelock(prelock_) 61 {} 62 getf_flagsftcxx::IterationStrategy63 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: Bounds(const DB & db,const Slice & left,const Slice & right,bool end_exclusive)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 Bounds(const DB & db,Infinite,const Slice & right,bool end_exclusive)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 Bounds(const DB & db,const Slice & left,Infinite,bool end_exclusive)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 Bounds(const DB & db,Infinite,Infinite,bool end_exclusive)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 Bounds(Bounds && o)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 operator =(Bounds && other)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 left_dbt() const159 const DBT *left_dbt() const { 160 if (_left_infinite) { 161 return _db->dbt_neg_infty(); 162 } else { 163 return &_left_dbt; 164 } 165 } 166 right_dbt() const167 const DBT *right_dbt() const { 168 if (_right_infinite) { 169 return _db->dbt_pos_infty(); 170 } else { 171 return &_right_dbt; 172 } 173 } 174 set_left(const Slice & left)175 void set_left(const Slice &left) { 176 _left = left.owned(); 177 _left_dbt = _left.dbt(); 178 _left_infinite = false; 179 } 180 set_right(const Slice & right)181 void set_right(const Slice &right) { 182 _right = right.owned(); 183 _right_dbt = _right.dbt(); 184 _right_infinite = false; 185 } 186 left_infinite() const187 bool left_infinite() const { return _left_infinite; } right_infinite() const188 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 DBC(DBC && o)208 DBC(DBC &&o) 209 : _txn(), 210 _dbc(nullptr) 211 { 212 std::swap(_txn, o._txn); 213 std::swap(_dbc, o._dbc); 214 } 215 operator =(DBC && o)216 DBC& operator=(DBC &&o) { 217 std::swap(_txn, o._txn); 218 std::swap(_dbc, o._dbc); 219 return *this; 220 } 221 dbc() const222 ::DBC *dbc() const { return _dbc; } 223 set_txn(const DBTxn & txn) const224 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 finished() const273 bool finished() const { return _finished; } 274 ok() const275 bool ok() const { return !finished(); } 276 set_txn(const DBTxn & txn) const277 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 getf_callback(const DBT * key,const DBT * val,void * extra)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: BufferAppender(Buffer & buf,Predicate && filter)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 marshalled_size(size_t keylen,size_t vallen)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 ok() const351 bool ok() const { 352 return _cur.ok() || _buf.more(); 353 } 354 set_txn(const DBTxn & txn) const355 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 ok() const384 bool ok() const { 385 return _cur.ok(); 386 } 387 set_txn(const DBTxn & txn) const388 void set_txn(const DBTxn &txn) const { _cur.set_txn(txn); } 389 390 class SliceCopier { 391 Slice &_key; 392 Slice &_val; 393 394 public: SliceCopier(Slice & key,Slice & val)395 SliceCopier(Slice &key, Slice &val) 396 : _key(key), 397 _val(val) 398 {} 399 operator ()(const DBT * key,const DBT * val)400 bool operator()(const DBT *key, const DBT *val) { 401 _key = Slice(*key).owned(); 402 _val = 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