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 <string> 41 42 #include <db.h> 43 44 #include "db_env.hpp" 45 #include "db_txn.hpp" 46 #include "exceptions.hpp" 47 #include "slice.hpp" 48 #include "stats.hpp" 49 50 namespace ftcxx { 51 52 template<class Comparator, class Handler> 53 class CallbackCursor; 54 template<class Comparator, class Predicate> 55 class BufferedCursor; 56 template<class Comparator> 57 class SimpleCursor; 58 59 class DB { 60 public: DB()61 DB() 62 : _db(nullptr), 63 _close_on_destroy(false) 64 {} 65 DB(::DB * d,bool close_on_destroy=false)66 explicit DB(::DB *d, bool close_on_destroy=false) 67 : _db(d), 68 _close_on_destroy(close_on_destroy) 69 {} 70 ~DB()71 ~DB() { 72 if (_db && _close_on_destroy) { 73 close(); 74 } 75 } 76 77 DB(const DB &) = delete; 78 DB& operator=(const DB &) = delete; 79 DB(DB && o)80 DB(DB &&o) 81 : _db(nullptr), 82 _close_on_destroy(false) 83 { 84 std::swap(_db, o._db); 85 std::swap(_close_on_destroy, o._close_on_destroy); 86 } 87 operator =(DB && o)88 DB& operator=(DB &&o) { 89 std::swap(_db, o._db); 90 std::swap(_close_on_destroy, o._close_on_destroy); 91 return *this; 92 } 93 db() const94 ::DB *db() const { return _db; } 95 descriptor() const96 Slice descriptor() const { 97 return Slice(_db->cmp_descriptor->dbt); 98 } 99 100 template<typename Callback> getf_set(const DBTxn & txn,const Slice & key,int flags,Callback cb) const101 int getf_set(const DBTxn &txn, const Slice &key, int flags, Callback cb) const { 102 class WrappedCallback { 103 Callback &_cb; 104 public: 105 WrappedCallback(Callback &cb_) 106 : _cb(cb_) 107 {} 108 109 static int call(const DBT *key_, const DBT *val_, void *extra) { 110 WrappedCallback *wc = static_cast<WrappedCallback *>(extra); 111 return wc->call(key_, val_); 112 } 113 114 int call(const DBT *key_, const DBT *val_) { 115 return _cb(Slice(*key_), Slice(*val_)); 116 } 117 } wc(cb); 118 119 DBT kdbt = key.dbt(); 120 return _db->getf_set(_db, txn.txn(), flags, &kdbt, &WrappedCallback::call, &wc); 121 } 122 put(const DBTxn & txn,DBT * key,DBT * val,int flags=0) const123 int put(const DBTxn &txn, DBT *key, DBT *val, int flags=0) const { 124 return _db->put(_db, txn.txn(), key, val, flags); 125 } 126 put(const DBTxn & txn,const Slice & key,const Slice & val,int flags=0) const127 int put(const DBTxn &txn, const Slice &key, const Slice &val, int flags=0) const { 128 DBT kdbt = key.dbt(); 129 DBT vdbt = val.dbt(); 130 return put(txn, &kdbt, &vdbt, flags); 131 } 132 update(const DBTxn & txn,DBT * key,DBT * val,int flags=0) const133 int update(const DBTxn &txn, DBT *key, DBT *val, int flags=0) const { 134 return _db->update(_db, txn.txn(), key, val, flags); 135 } 136 update(const DBTxn & txn,const Slice & key,const Slice & extra,int flags=0) const137 int update(const DBTxn &txn, const Slice &key, const Slice &extra, int flags=0) const { 138 DBT kdbt = key.dbt(); 139 DBT edbt = extra.dbt(); 140 return update(txn, &kdbt, &edbt, flags); 141 } 142 del(const DBTxn & txn,DBT * key,int flags=0) const143 int del(const DBTxn &txn, DBT *key, int flags=0) const { 144 return _db->del(_db, txn.txn(), key, flags); 145 } 146 del(const DBTxn & txn,const Slice & key,int flags=0) const147 int del(const DBTxn &txn, const Slice &key, int flags=0) const { 148 DBT kdbt = key.dbt(); 149 return _db->del(_db, txn.txn(), &kdbt, flags); 150 } 151 152 template<class OptimizeCallback> hot_optimize(const Slice & left,const Slice & right,OptimizeCallback callback,uint64_t * loops_run=NULL) const153 int hot_optimize(const Slice &left, const Slice &right, OptimizeCallback callback, uint64_t *loops_run = NULL) const { 154 DBT ldbt = left.dbt(); 155 DBT rdbt = right.dbt(); 156 157 class WrappedOptimizeCallback { 158 OptimizeCallback &_oc; 159 size_t _loops; 160 161 public: 162 WrappedOptimizeCallback(OptimizeCallback &oc) 163 : _oc(oc), 164 _loops(0) 165 {} 166 167 static int call(void *extra, float progress) { 168 WrappedOptimizeCallback *e = static_cast<WrappedOptimizeCallback *>(extra); 169 return e->_oc(progress, ++e->_loops); 170 } 171 } woc(callback); 172 173 uint64_t dummy; 174 return _db->hot_optimize(_db, &ldbt, &rdbt, 175 &WrappedOptimizeCallback::call, &woc, 176 loops_run == NULL ? &dummy : loops_run); 177 } 178 get_stats() const179 Stats get_stats() const { 180 Stats stats; 181 DB_BTREE_STAT64 s = {0, 0, 0, 0, 0, 0, 0}; 182 int r = _db->stat64(_db, NULL, &s); 183 handle_ft_retval(r); 184 stats.data_size = s.bt_dsize; 185 stats.file_size = s.bt_fsize; 186 stats.num_keys = s.bt_nkeys; 187 return stats; 188 } 189 190 struct NullFilter { operator ()ftcxx::DB::NullFilter191 bool operator()(const Slice &, const Slice &) { 192 return true; 193 } 194 }; 195 196 /** 197 * Constructs a Cursor over this DB, over the range from left to 198 * right (or right to left if !forward). 199 */ 200 template<class Comparator, class Handler> 201 CallbackCursor<Comparator, Handler> cursor(const DBTxn &txn, DBT *left, DBT *right, 202 Comparator &&cmp, Handler &&handler, int flags=0, 203 bool forward=true, bool end_exclusive=false, bool prelock=false) const; 204 205 template<class Comparator, class Handler> 206 CallbackCursor<Comparator, Handler> cursor(const DBTxn &txn, const Slice &start_key, 207 Comparator &&cmp, Handler &&handler, int flags=0, 208 bool forward=true, bool end_exclusive=false, bool prelock=false) const; 209 210 template<class Comparator, class Handler> 211 CallbackCursor<Comparator, Handler> cursor(const DBTxn &txn, const Slice &left, const Slice &right, 212 Comparator &&cmp, Handler &&handler, int flags=0, 213 bool forward=true, bool end_exclusive=false, bool prelock=false) const; 214 215 template<class Comparator, class Handler> 216 CallbackCursor<Comparator, Handler> cursor(const DBTxn &txn, Comparator &&cmp, Handler &&handler, 217 int flags=0, bool forward=true, bool prelock=false) const; 218 219 template<class Comparator, class Predicate> 220 BufferedCursor<Comparator, Predicate> buffered_cursor(const DBTxn &txn, DBT *left, DBT *right, 221 Comparator &&cmp, Predicate &&filter, int flags=0, 222 bool forward=true, bool end_exclusive=false, bool prelock=false) const; 223 224 template<class Comparator, class Predicate> 225 BufferedCursor<Comparator, Predicate> buffered_cursor(const DBTxn &txn, const Slice &start_key, 226 Comparator &&cmp, Predicate &&filter, int flags=0, 227 bool forward=true, bool end_exclusive=false, bool prelock=false) const; 228 229 template<class Comparator, class Predicate> 230 BufferedCursor<Comparator, Predicate> buffered_cursor(const DBTxn &txn, const Slice &left, const Slice &right, 231 Comparator &&cmp, Predicate &&filter, int flags=0, 232 bool forward=true, bool end_exclusive=false, bool prelock=false) const; 233 234 template<class Comparator, class Predicate> 235 BufferedCursor<Comparator, Predicate> buffered_cursor(const DBTxn &txn, Comparator &&cmp, Predicate &&filter, 236 int flags=0, bool forward=true, bool prelock=false) const; 237 238 template<class Comparator> 239 SimpleCursor<Comparator> simple_cursor(const DBTxn &txn, DBT *left, DBT *right, 240 Comparator &&cmp, Slice &key, Slice &val, int flags=0, 241 bool forward=true, bool end_exclusive=false, bool prelock=false) const; 242 243 template<class Comparator> 244 SimpleCursor<Comparator> simple_cursor(const DBTxn &txn, const Slice &start_key, 245 Comparator &&cmp, Slice &key, Slice &val, int flags=0, 246 bool forward=true, bool end_exclusive=false, bool prelock=false) const; 247 248 template<class Comparator> 249 SimpleCursor<Comparator> simple_cursor(const DBTxn &txn, const Slice &left, const Slice &right, 250 Comparator &&cmp, Slice &key, Slice &val, int flags=0, 251 bool forward=true, bool end_exclusive=false, bool prelock=false) const; 252 253 template<class Comparator> 254 SimpleCursor<Comparator> simple_cursor(const DBTxn &txn, Comparator &&cmp, Slice &key, Slice &val, 255 int flags=0, bool forward=true, bool prelock=false) const; 256 close()257 void close() { 258 int r = _db->close(_db, 0); 259 handle_ft_retval(r); 260 _db = nullptr; 261 } 262 263 private: 264 ::DB *_db; 265 bool _close_on_destroy; 266 }; 267 268 class DBBuilder { 269 uint32_t _readpagesize; 270 int _compression_method; 271 uint32_t _fanout; 272 uint8_t _memcmp_magic; 273 uint32_t _pagesize; 274 Slice _descriptor; 275 276 public: DBBuilder()277 DBBuilder() 278 : _readpagesize(0), 279 _compression_method(-1), 280 _fanout(0), 281 _memcmp_magic(0), 282 _pagesize(0), 283 _descriptor() 284 {} 285 open(const DBEnv & env,const DBTxn & txn,const char * fname,const char * dbname,DBTYPE dbtype,uint32_t flags,int mode) const286 DB open(const DBEnv &env, const DBTxn &txn, const char *fname, const char *dbname, DBTYPE dbtype, uint32_t flags, int mode) const { 287 ::DB *db; 288 int r = db_create(&db, env.env(), 0); 289 handle_ft_retval(r); 290 291 if (_readpagesize) { 292 r = db->set_readpagesize(db, _readpagesize); 293 handle_ft_retval(r); 294 } 295 296 if (_compression_method >= 0) { 297 r = db->set_compression_method(db, TOKU_COMPRESSION_METHOD(_compression_method)); 298 handle_ft_retval(r); 299 } 300 301 if (_fanout) { 302 r = db->set_fanout(db, _fanout); 303 handle_ft_retval(r); 304 } 305 306 if (_memcmp_magic) { 307 r = db->set_memcmp_magic(db, _memcmp_magic); 308 handle_ft_retval(r); 309 } 310 311 if (_pagesize) { 312 r = db->set_pagesize(db, _pagesize); 313 handle_ft_retval(r); 314 } 315 316 const DBTxn *txnp = &txn; 317 DBTxn writeTxn; 318 if (txn.is_read_only()) { 319 writeTxn = DBTxn(env, DB_SERIALIZABLE); 320 txnp = &writeTxn; 321 } 322 323 r = db->open(db, txnp->txn(), fname, dbname, dbtype, flags, mode); 324 handle_ft_retval(r); 325 326 if (!_descriptor.empty()) { 327 DBT desc = _descriptor.dbt(); 328 r = db->change_descriptor(db, txnp->txn(), &desc, DB_UPDATE_CMP_DESCRIPTOR); 329 handle_ft_retval(r); 330 } 331 332 if (txn.is_read_only()) { 333 writeTxn.commit(); 334 } 335 336 return DB(db, true); 337 } 338 set_readpagesize(uint32_t readpagesize)339 DBBuilder& set_readpagesize(uint32_t readpagesize) { 340 _readpagesize = readpagesize; 341 return *this; 342 } 343 set_compression_method(TOKU_COMPRESSION_METHOD _compressionmethod)344 DBBuilder& set_compression_method(TOKU_COMPRESSION_METHOD _compressionmethod) { 345 _compression_method = int(_compressionmethod); 346 return *this; 347 } 348 set_fanout(uint32_t fanout)349 DBBuilder& set_fanout(uint32_t fanout) { 350 _fanout = fanout; 351 return *this; 352 } 353 set_memcmp_magic(uint8_t _memcmpmagic)354 DBBuilder& set_memcmp_magic(uint8_t _memcmpmagic) { 355 _memcmp_magic = _memcmpmagic; 356 return *this; 357 } 358 set_pagesize(uint32_t pagesize)359 DBBuilder& set_pagesize(uint32_t pagesize) { 360 _pagesize = pagesize; 361 return *this; 362 } 363 set_descriptor(const Slice & desc)364 DBBuilder& set_descriptor(const Slice &desc) { 365 _descriptor = desc.owned(); 366 return *this; 367 } 368 }; 369 370 } // namespace ftcxx 371