diff --git a/lmdb-safe.hh b/lmdb-safe.hh index 5d27c0a..3db532f 100644 --- a/lmdb-safe.hh +++ b/lmdb-safe.hh @@ -294,35 +294,12 @@ public: "If the parent transaction commits, the cursor must not be used again." */ -class MDBROCursor +template +class MDBGenCursor { public: - MDBROCursor(MDBROTransaction* parent, const MDB_dbi& dbi) : d_parent(parent) - { - int rc= mdb_cursor_open(d_parent->d_txn, dbi, &d_cursor); - if(rc) { - throw std::runtime_error("Error creating RO cursor: "+std::string(mdb_strerror(rc))); - } - } - MDBROCursor(MDBROCursor&& rhs) - { - d_cursor = rhs.d_cursor; - rhs.d_cursor=0; - } - - void close() - { - mdb_cursor_close(d_cursor); - d_cursor=0; - } - - ~MDBROCursor() - { - if(d_cursor) - mdb_cursor_close(d_cursor); - } - - + MDBGenCursor(Transaction *t) : d_parent(t) + {} int get(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op) { int rc = mdb_cursor_get(d_cursor, &key.d_mdbval, &data.d_mdbval, op); @@ -339,7 +316,7 @@ public: throw std::runtime_error("Unable to find from cursor: " + std::string(mdb_strerror(rc))); return rc; } - + int lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data) { key.d_mdbval = in.d_mdbval; @@ -350,16 +327,78 @@ public: return rc; } + + int nextprev(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op) + { + int rc = mdb_cursor_get(d_cursor, const_cast(&key.d_mdbval), &data.d_mdbval, op); + if(rc && rc != MDB_NOTFOUND) + throw std::runtime_error("Unable to prevnext from cursor: " + std::string(mdb_strerror(rc))); + return rc; + } + int next(MDBOutVal& key, MDBOutVal& data) { - int rc = mdb_cursor_get(d_cursor, const_cast(&key.d_mdbval), &data.d_mdbval, MDB_NEXT); + return nextprev(key, data, MDB_NEXT); + } + + int prev(MDBOutVal& key, MDBOutVal& data) + { + return nextprev(key, data, MDB_PREV); + } + + int currentlast(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op) + { + int rc = mdb_cursor_get(d_cursor, const_cast(&key.d_mdbval), &data.d_mdbval, op); if(rc && rc != MDB_NOTFOUND) throw std::runtime_error("Unable to next from cursor: " + std::string(mdb_strerror(rc))); return rc; } - + + int current(MDBOutVal& key, MDBOutVal& data) + { + return currentlast(key, data, MDB_GET_CURRENT); + } + int last(MDBOutVal& key, MDBOutVal& data) + { + return currentlast(key, data, MDB_LAST); + } + + operator MDB_cursor*&() + { + return d_cursor; + } + MDB_cursor* d_cursor; - MDBROTransaction* d_parent; + Transaction* d_parent; +}; + +class MDBROCursor : public MDBGenCursor +{ +public: + MDBROCursor(MDBROTransaction* parent, const MDB_dbi& dbi) : MDBGenCursor(parent) + { + int rc= mdb_cursor_open(d_parent->d_txn, dbi, &d_cursor); + if(rc) { + throw std::runtime_error("Error creating RO cursor: "+std::string(mdb_strerror(rc))); + } + } + MDBROCursor(MDBROCursor&& rhs) : MDBGenCursor(rhs.d_parent) + { + rhs.d_cursor=0; + } + + void close() + { + mdb_cursor_close(d_cursor); + d_cursor=0; + } + + ~MDBROCursor() + { + if(d_cursor) + mdb_cursor_close(d_cursor); + } + }; class MDBRWCursor; @@ -510,10 +549,10 @@ public: /* "A cursor in a write-transaction can be closed before its transaction ends, and will otherwise be closed when its transaction ends" This is a problem for us since it may means we are closing the cursor twice, which is bad */ -class MDBRWCursor +class MDBRWCursor : public MDBGenCursor { public: - MDBRWCursor(MDBRWTransaction* parent, const MDB_dbi& dbi) : d_parent(parent) + MDBRWCursor(MDBRWTransaction* parent, const MDB_dbi& dbi) : MDBGenCursor(parent) { int rc= mdb_cursor_open(d_parent->d_txn, dbi, &d_cursor); if(rc) { @@ -521,9 +560,8 @@ public: } d_parent->reportCursor(this); } - MDBRWCursor(MDBRWCursor&& rhs) + MDBRWCursor(MDBRWCursor&& rhs) : MDBGenCursor(rhs.d_parent) { - d_parent = rhs.d_parent; d_cursor = rhs.d_cursor; rhs.d_cursor=0; d_parent->reportCursorMove(&rhs, this); @@ -543,12 +581,14 @@ public: d_parent->unreportCursor(this); } - int get(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op) + + void put(const MDBOutVal& key, const MDBInVal& data) { - int rc = mdb_cursor_get(d_cursor, &key.d_mdbval, &data.d_mdbval, op); - if(rc && rc != MDB_NOTFOUND) - throw std::runtime_error("mdb_cursor_get: " + std::string(mdb_strerror(rc))); - return rc; + int rc = mdb_cursor_put(d_cursor, + const_cast(&key.d_mdbval), + const_cast(&data.d_mdbval), MDB_CURRENT); + if(rc) + throw std::runtime_error("mdb_cursor_put: " + std::string(mdb_strerror(rc))); } @@ -560,45 +600,9 @@ public: const_cast(&data.d_mdbval), flags); } - int find(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data) - { - key.d_mdbval = in.d_mdbval; - int rc=mdb_cursor_get(d_cursor, const_cast(&key.d_mdbval), &data.d_mdbval, MDB_SET); - if(rc && rc != MDB_NOTFOUND) - throw std::runtime_error("Unable to find from cursor: " + std::string(mdb_strerror(rc))); - return rc; - } - - int lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data) - { - key.d_mdbval = in.d_mdbval; - - int rc = mdb_cursor_get(d_cursor, const_cast(&key.d_mdbval), &data.d_mdbval, MDB_SET_RANGE); - if(rc && rc != MDB_NOTFOUND) - throw std::runtime_error("Unable to lower_bound from cursor: " + std::string(mdb_strerror(rc))); - return rc; - } - - int next(MDBOutVal& key, MDBOutVal& data) - { - int rc = mdb_cursor_get(d_cursor, const_cast(&key.d_mdbval), &data.d_mdbval, MDB_NEXT); - if(rc && rc != MDB_NOTFOUND) - throw std::runtime_error("Unable to next from cursor: " + std::string(mdb_strerror(rc))); - return rc; - } - - int del(int flags=0) { return mdb_cursor_del(d_cursor, flags); } - - operator MDB_cursor*&() - { - return d_cursor; - } - - MDB_cursor* d_cursor; - MDBRWTransaction* d_parent; }; diff --git a/lmdb-typed.hh b/lmdb-typed.hh index 63e9faa..912b37e 100644 --- a/lmdb-typed.hh +++ b/lmdb-typed.hh @@ -51,11 +51,11 @@ std::string serToString(const T& t) } template -void serFromString(const std::string& str, T& ret) +void serFromString(const string_view& str, T& ret) { ret = T(); - boost::iostreams::array_source source(str.c_str(), str.size()); + boost::iostreams::array_source source(&str[0], str.size()); boost::iostreams::stream stream(source); boost::archive::binary_iarchive in_archive(stream, boost::archive::no_header|boost::archive::no_codecvt); in_archive >> ret;