lmdb++
Loading...
Searching...
No Matches
lmdb++.h
Go to the documentation of this file.
1/* This is free and unencumbered software released into the public domain. */
2
3#ifndef LMDBXX_H
4#define LMDBXX_H
5
14#ifndef __cplusplus
15#error "<lmdb++.h> requires a C++ compiler"
16#endif
17
18#if __cplusplus < 201703L
19#error "<lmdb++.h> requires a C++17 compiler (CXXFLAGS='-std=c++17')"
20#endif
21
23
24#include <lmdb.h> /* for MDB_*, mdb_*() */
25
26#ifdef LMDBXX_DEBUG
27#include <cassert> /* for assert() */
28#endif
29#include <cstddef> /* for std::size_t */
30#include <cstdio> /* for std::snprintf() */
31#include <cstring> /* for std::memcpy() */
32#include <stdexcept> /* for std::runtime_error */
33#include <string_view> /* for std::string_view */
34#include <limits> /* for std::numeric_limits<> */
35#include <memory> /* for std::addressof */
36
37namespace lmdb {
38 using mode = mdb_mode_t;
39}
40
42/* Error Handling */
43
44namespace lmdb {
45 class error;
46 class logic_error;
47 class fatal_error;
48 class runtime_error;
49 class key_exist_error;
50 class not_found_error;
51 class corrupted_error;
52 class panic_error;
53 class version_mismatch_error;
54 class map_full_error;
55 class bad_dbi_error;
56}
57
63class lmdb::error : public std::runtime_error {
64protected:
65 const int _code;
66
67public:
71 [[noreturn]] static inline void raise(const char* origin, int rc);
72
76 error(const char* const origin,
77 const int rc) noexcept
79 _code{rc} {}
80
84 int code() const noexcept {
85 return _code;
86 }
87
91 const char* origin() const noexcept {
92 return runtime_error::what();
93 }
94
98 virtual const char* what() const noexcept {
99 static thread_local char buffer[1024];
100 std::snprintf(buffer, sizeof(buffer),
101 "%s: %s", origin(), ::mdb_strerror(code()));
102 return buffer;
103 }
104};
105
110public:
111 using error::error;
112};
113
118public:
119 using error::error;
120};
121
126public:
127 using error::error;
128};
129
136public:
137 using runtime_error::runtime_error;
138};
139
146public:
147 using runtime_error::runtime_error;
148};
149
156public:
157 using fatal_error::fatal_error;
158};
159
166public:
167 using fatal_error::fatal_error;
168};
169
176public:
177 using fatal_error::fatal_error;
178};
179
186public:
187 using runtime_error::runtime_error;
188};
189
197public:
198 using runtime_error::runtime_error;
199};
200
201inline void
202lmdb::error::raise(const char* const origin,
203 const int rc) {
204 switch (rc) {
205 case MDB_KEYEXIST: throw key_exist_error{origin, rc};
206 case MDB_NOTFOUND: throw not_found_error{origin, rc};
207 case MDB_CORRUPTED: throw corrupted_error{origin, rc};
208 case MDB_PANIC: throw panic_error{origin, rc};
209 case MDB_VERSION_MISMATCH: throw version_mismatch_error{origin, rc};
210 case MDB_MAP_FULL: throw map_full_error{origin, rc};
211#ifdef MDB_BAD_DBI
212 case MDB_BAD_DBI: throw bad_dbi_error{origin, rc};
213#endif
214 default: throw lmdb::runtime_error{origin, rc};
215 }
216}
217
219/* Procedural Interface: Metadata */
220
221namespace lmdb {
222 // TODO: mdb_version()
223 // TODO: mdb_strerror()
224}
225
227/* Procedural Interface: Environment */
228
229namespace lmdb {
230 static inline void env_create(MDB_env** env);
231 static inline void env_open(MDB_env* env,
232 const char* path, unsigned int flags, mode mode);
233#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 14)
234 static inline void env_copy(MDB_env* env, const char* path, unsigned int flags);
235 static inline void env_copy_fd(MDB_env* env, mdb_filehandle_t fd, unsigned int flags);
236#else
237 static inline void env_copy(MDB_env* env, const char* path);
238 static inline void env_copy_fd(MDB_env* env, mdb_filehandle_t fd);
239#endif
240 static inline void env_stat(MDB_env* env, MDB_stat* stat);
241 static inline void env_info(MDB_env* env, MDB_envinfo* stat);
242 static inline void env_sync(MDB_env* env, bool force);
243 static inline void env_close(MDB_env* env) noexcept;
244 static inline void env_set_flags(MDB_env* env, unsigned int flags, bool onoff);
245 static inline void env_get_flags(MDB_env* env, unsigned int* flags);
246 static inline void env_get_path(MDB_env* env, const char** path);
247 static inline void env_get_fd(MDB_env* env, mdb_filehandle_t* fd);
248 static inline void env_set_mapsize(MDB_env* env, std::size_t size);
249 static inline void env_set_max_readers(MDB_env* env, unsigned int count);
250 static inline void env_get_max_readers(MDB_env* env, unsigned int* count);
251 static inline void env_set_max_dbs(MDB_env* env, MDB_dbi count);
252 static inline unsigned int env_get_max_keysize(MDB_env* env);
253#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 11)
254 static inline void env_set_userctx(MDB_env* env, void* ctx);
255 static inline void* env_get_userctx(MDB_env* env);
256#endif
257 // TODO: mdb_env_set_assert()
258 // TODO: mdb_reader_list()
259 static inline void reader_check(MDB_env *env, int *dead);
260}
261
266static inline void
268 const int rc = ::mdb_env_create(env);
269 if (rc != MDB_SUCCESS) {
270 error::raise("mdb_env_create", rc);
271 }
272}
273
278static inline void
279lmdb::env_open(MDB_env* const env,
280 const char* const path,
281 const unsigned int flags,
282 const mode mode) {
283 const int rc = ::mdb_env_open(env, path, flags, mode);
284 if (rc != MDB_SUCCESS) {
285 error::raise("mdb_env_open", rc);
286 }
287}
288
294static inline void
295lmdb::env_copy(MDB_env* const env,
296#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 14)
297 const char* const path,
298 const unsigned int flags = 0) {
299 const int rc = ::mdb_env_copy2(env, path, flags);
300#else
301 const char* const path) {
302 const int rc = ::mdb_env_copy(env, path);
303#endif
304 if (rc != MDB_SUCCESS) {
305 error::raise("mdb_env_copy2", rc);
306 }
307}
308
314static inline void
315lmdb::env_copy_fd(MDB_env* const env,
316#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 14)
317 const mdb_filehandle_t fd,
318 const unsigned int flags = 0) {
319 const int rc = ::mdb_env_copyfd2(env, fd, flags);
320#else
321 const mdb_filehandle_t fd) {
322 const int rc = ::mdb_env_copyfd(env, fd);
323#endif
324 if (rc != MDB_SUCCESS) {
325 error::raise("mdb_env_copyfd2", rc);
326 }
327}
328
333static inline void
334lmdb::env_stat(MDB_env* const env,
335 MDB_stat* const stat) {
336 const int rc = ::mdb_env_stat(env, stat);
337 if (rc != MDB_SUCCESS) {
338 error::raise("mdb_env_stat", rc);
339 }
340}
341
346static inline void
347lmdb::env_info(MDB_env* const env,
348 MDB_envinfo* const stat) {
349 const int rc = ::mdb_env_info(env, stat);
350 if (rc != MDB_SUCCESS) {
351 error::raise("mdb_env_info", rc);
352 }
353}
354
359static inline void
360lmdb::env_sync(MDB_env* const env,
361 const bool force = true) {
362 const int rc = ::mdb_env_sync(env, force);
363 if (rc != MDB_SUCCESS) {
364 error::raise("mdb_env_sync", rc);
365 }
366}
367
371static inline void
372lmdb::env_close(MDB_env* const env) noexcept {
373 ::mdb_env_close(env);
374}
375
380static inline void
382 const unsigned int flags,
383 const bool onoff = true) {
384 const int rc = ::mdb_env_set_flags(env, flags, onoff ? 1 : 0);
385 if (rc != MDB_SUCCESS) {
386 error::raise("mdb_env_set_flags", rc);
387 }
388}
389
394static inline void
396 unsigned int* const flags) {
397 const int rc = ::mdb_env_get_flags(env, flags);
398 if (rc != MDB_SUCCESS) {
399 error::raise("mdb_env_get_flags", rc);
400 }
401}
402
407static inline void
408lmdb::env_get_path(MDB_env* const env,
409 const char** path) {
410 const int rc = ::mdb_env_get_path(env, path);
411 if (rc != MDB_SUCCESS) {
412 error::raise("mdb_env_get_path", rc);
413 }
414}
415
420static inline void
421lmdb::env_get_fd(MDB_env* const env,
422 mdb_filehandle_t* const fd) {
423 const int rc = ::mdb_env_get_fd(env, fd);
424 if (rc != MDB_SUCCESS) {
425 error::raise("mdb_env_get_fd", rc);
426 }
427}
428
433static inline void
435 const std::size_t size) {
436 const int rc = ::mdb_env_set_mapsize(env, size);
437 if (rc != MDB_SUCCESS) {
438 error::raise("mdb_env_set_mapsize", rc);
439 }
440}
441
446static inline void
448 const unsigned int count) {
449 const int rc = ::mdb_env_set_maxreaders(env, count);
450 if (rc != MDB_SUCCESS) {
451 error::raise("mdb_env_set_maxreaders", rc);
452 }
453}
454
459static inline void
461 unsigned int* const count) {
462 const int rc = ::mdb_env_get_maxreaders(env, count);
463 if (rc != MDB_SUCCESS) {
464 error::raise("mdb_env_get_maxreaders", rc);
465 }
466}
467
472static inline void
474 const MDB_dbi count) {
475 const int rc = ::mdb_env_set_maxdbs(env, count);
476 if (rc != MDB_SUCCESS) {
477 error::raise("mdb_env_set_maxdbs", rc);
478 }
479}
480
484static inline unsigned int
486 const int rc = ::mdb_env_get_maxkeysize(env);
487#ifdef LMDBXX_DEBUG
488 assert(rc >= 0);
489#endif
490 return static_cast<unsigned int>(rc);
491}
492
493#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 11)
499static inline void
501 void* const ctx) {
502 const int rc = ::mdb_env_set_userctx(env, ctx);
503 if (rc != MDB_SUCCESS) {
504 error::raise("mdb_env_set_userctx", rc);
505 }
506}
507#endif
508
509#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 11)
514static inline void*
515lmdb::env_get_userctx(MDB_env* const env) {
516 return ::mdb_env_get_userctx(env);
517}
518#endif
519
520static inline void
521lmdb::reader_check(MDB_env *env, int *dead) {
522 const int rc = ::mdb_reader_check(env, dead);
523 if (rc != MDB_SUCCESS) {
524 error::raise("reader_check", rc);
525 }
526}
527
529/* Procedural Interface: Transactions */
530
531namespace lmdb {
532 static inline void txn_begin(
533 MDB_env* env, MDB_txn* parent, unsigned int flags, MDB_txn** txn);
534 static inline MDB_env* txn_env(MDB_txn* txn) noexcept;
535#ifdef LMDBXX_TXN_ID
536 static inline std::size_t txn_id(MDB_txn* txn) noexcept;
537#endif
538 static inline void txn_commit(MDB_txn* txn);
539 static inline void txn_abort(MDB_txn* txn) noexcept;
540 static inline void txn_reset(MDB_txn* txn) noexcept;
541 static inline void txn_renew(MDB_txn* txn);
542}
543
548static inline void
549lmdb::txn_begin(MDB_env* const env,
550 MDB_txn* const parent,
551 const unsigned int flags,
552 MDB_txn** txn) {
553 const int rc = ::mdb_txn_begin(env, parent, flags, txn);
554 if (rc != MDB_SUCCESS) {
555 error::raise("mdb_txn_begin", rc);
556 }
557}
558
562static inline MDB_env*
563lmdb::txn_env(MDB_txn* const txn) noexcept {
564 return ::mdb_txn_env(txn);
565}
566
567#ifdef LMDBXX_TXN_ID
571static inline std::size_t
572lmdb::txn_id(MDB_txn* const txn) noexcept {
573 return ::mdb_txn_id(txn);
574}
575#endif
576
581static inline void
582lmdb::txn_commit(MDB_txn* const txn) {
583 const int rc = ::mdb_txn_commit(txn);
584 if (rc != MDB_SUCCESS) {
585 error::raise("mdb_txn_commit", rc);
586 }
587}
588
592static inline void
593lmdb::txn_abort(MDB_txn* const txn) noexcept {
594 ::mdb_txn_abort(txn);
595}
596
600static inline void
601lmdb::txn_reset(MDB_txn* const txn) noexcept {
602 ::mdb_txn_reset(txn);
603}
604
609static inline void
610lmdb::txn_renew(MDB_txn* const txn) {
611 const int rc = ::mdb_txn_renew(txn);
612 if (rc != MDB_SUCCESS) {
613 error::raise("mdb_txn_renew", rc);
614 }
615}
616
618/* Procedural Interface: Databases */
619
620namespace lmdb {
621 static inline void dbi_open(
622 MDB_txn* txn, const char* name, unsigned int flags, MDB_dbi* dbi);
623 static inline void dbi_stat(MDB_txn* txn, MDB_dbi dbi, MDB_stat* stat);
624 static inline void dbi_flags(MDB_txn* txn, MDB_dbi dbi, unsigned int* flags);
625 static inline void dbi_close(MDB_env* env, MDB_dbi dbi) noexcept;
626 static inline void dbi_drop(MDB_txn* txn, MDB_dbi dbi, bool del);
627 static inline void dbi_set_compare(MDB_txn* txn, MDB_dbi dbi, MDB_cmp_func* cmp);
628 static inline void dbi_set_dupsort(MDB_txn* txn, MDB_dbi dbi, MDB_cmp_func* cmp);
629 static inline void dbi_set_relfunc(MDB_txn* txn, MDB_dbi dbi, MDB_rel_func* rel);
630 static inline void dbi_set_relctx(MDB_txn* txn, MDB_dbi dbi, void* ctx);
631 static inline bool dbi_get(MDB_txn* txn, MDB_dbi dbi, const MDB_val* key, MDB_val* data);
632 static inline bool dbi_put(MDB_txn* txn, MDB_dbi dbi, const MDB_val* key, MDB_val* data, unsigned int flags);
633 static inline bool dbi_del(MDB_txn* txn, MDB_dbi dbi, const MDB_val* key, const MDB_val* data);
634 // TODO: mdb_cmp()
635 // TODO: mdb_dcmp()
636}
637
642static inline void
643lmdb::dbi_open(MDB_txn* const txn,
644 const char* const name,
645 const unsigned int flags,
646 MDB_dbi* const dbi) {
647 const int rc = ::mdb_dbi_open(txn, name, flags, dbi);
648 if (rc != MDB_SUCCESS) {
649 error::raise("mdb_dbi_open", rc);
650 }
651}
652
657static inline void
658lmdb::dbi_stat(MDB_txn* const txn,
659 const MDB_dbi dbi,
660 MDB_stat* const result) {
661 const int rc = ::mdb_stat(txn, dbi, result);
662 if (rc != MDB_SUCCESS) {
663 error::raise("mdb_stat", rc);
664 }
665}
666
671static inline void
672lmdb::dbi_flags(MDB_txn* const txn,
673 const MDB_dbi dbi,
674 unsigned int* const flags) {
675 const int rc = ::mdb_dbi_flags(txn, dbi, flags);
676 if (rc != MDB_SUCCESS) {
677 error::raise("mdb_dbi_flags", rc);
678 }
679}
680
684static inline void
685lmdb::dbi_close(MDB_env* const env,
686 const MDB_dbi dbi) noexcept {
687 ::mdb_dbi_close(env, dbi);
688}
689
693static inline void
694lmdb::dbi_drop(MDB_txn* const txn,
695 const MDB_dbi dbi,
696 const bool del = false) {
697 const int rc = ::mdb_drop(txn, dbi, del ? 1 : 0);
698 if (rc != MDB_SUCCESS) {
699 error::raise("mdb_drop", rc);
700 }
701}
702
707static inline void
709 const MDB_dbi dbi,
710 MDB_cmp_func* const cmp = nullptr) {
711 const int rc = ::mdb_set_compare(txn, dbi, cmp);
712 if (rc != MDB_SUCCESS) {
713 error::raise("mdb_set_compare", rc);
714 }
715}
716
721static inline void
723 const MDB_dbi dbi,
724 MDB_cmp_func* const cmp = nullptr) {
725 const int rc = ::mdb_set_dupsort(txn, dbi, cmp);
726 if (rc != MDB_SUCCESS) {
727 error::raise("mdb_set_dupsort", rc);
728 }
729}
730
735static inline void
737 const MDB_dbi dbi,
738 MDB_rel_func* const rel) {
739 const int rc = ::mdb_set_relfunc(txn, dbi, rel);
740 if (rc != MDB_SUCCESS) {
741 error::raise("mdb_set_relfunc", rc);
742 }
743}
744
749static inline void
751 const MDB_dbi dbi,
752 void* const ctx) {
753 const int rc = ::mdb_set_relctx(txn, dbi, ctx);
754 if (rc != MDB_SUCCESS) {
755 error::raise("mdb_set_relctx", rc);
756 }
757}
758
764static inline bool
765lmdb::dbi_get(MDB_txn* const txn,
766 const MDB_dbi dbi,
767 const MDB_val* const key,
768 MDB_val* const data) {
769 const int rc = ::mdb_get(txn, dbi, const_cast<MDB_val*>(key), data);
770 if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) {
771 error::raise("mdb_get", rc);
772 }
773 return (rc == MDB_SUCCESS);
774}
775
781static inline bool
782lmdb::dbi_put(MDB_txn* const txn,
783 const MDB_dbi dbi,
784 const MDB_val* const key,
785 MDB_val* const data,
786 const unsigned int flags = 0) {
787 const int rc = ::mdb_put(txn, dbi, const_cast<MDB_val*>(key), data, flags);
788 if (rc != MDB_SUCCESS && rc != MDB_KEYEXIST) {
789 error::raise("mdb_put", rc);
790 }
791 return (rc == MDB_SUCCESS);
792}
793
799static inline bool
800lmdb::dbi_del(MDB_txn* const txn,
801 const MDB_dbi dbi,
802 const MDB_val* const key,
803 const MDB_val* const data = nullptr) {
804 const int rc = ::mdb_del(txn, dbi, const_cast<MDB_val*>(key), const_cast<MDB_val*>(data));
805 if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) {
806 error::raise("mdb_del", rc);
807 }
808 return (rc == MDB_SUCCESS);
809}
810
812/* Procedural Interface: Cursors */
813
814namespace lmdb {
815 static inline void cursor_open(MDB_txn* txn, MDB_dbi dbi, MDB_cursor** cursor);
816 static inline void cursor_close(MDB_cursor* cursor) noexcept;
817 static inline void cursor_renew(MDB_txn* txn, MDB_cursor* cursor);
818 static inline MDB_txn* cursor_txn(MDB_cursor* cursor) noexcept;
819 static inline MDB_dbi cursor_dbi(MDB_cursor* cursor) noexcept;
820 static inline bool cursor_get(MDB_cursor* cursor, MDB_val* key, MDB_val* data, MDB_cursor_op op);
821 static inline bool cursor_put(MDB_cursor* cursor, MDB_val* key, MDB_val* data, unsigned int flags);
822 static inline void cursor_del(MDB_cursor* cursor, unsigned int flags);
823 static inline void cursor_count(MDB_cursor* cursor, std::size_t& count);
824}
825
830static inline void
831lmdb::cursor_open(MDB_txn* const txn,
832 const MDB_dbi dbi,
833 MDB_cursor** const cursor) {
834 const int rc = ::mdb_cursor_open(txn, dbi, cursor);
835 if (rc != MDB_SUCCESS) {
836 error::raise("mdb_cursor_open", rc);
837 }
838}
839
843static inline void
844lmdb::cursor_close(MDB_cursor* const cursor) noexcept {
845 ::mdb_cursor_close(cursor);
846}
847
852static inline void
853lmdb::cursor_renew(MDB_txn* const txn,
854 MDB_cursor* const cursor) {
855 const int rc = ::mdb_cursor_renew(txn, cursor);
856 if (rc != MDB_SUCCESS) {
857 error::raise("mdb_cursor_renew", rc);
858 }
859}
860
864static inline MDB_txn*
865lmdb::cursor_txn(MDB_cursor* const cursor) noexcept {
866 return ::mdb_cursor_txn(cursor);
867}
868
872static inline MDB_dbi
873lmdb::cursor_dbi(MDB_cursor* const cursor) noexcept {
874 return ::mdb_cursor_dbi(cursor);
875}
876
881static inline bool
882lmdb::cursor_get(MDB_cursor* const cursor,
883 MDB_val* const key,
884 MDB_val* const data,
885 const MDB_cursor_op op) {
886 const int rc = ::mdb_cursor_get(cursor, key, data, op);
887 if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) {
888 error::raise("mdb_cursor_get", rc);
889 }
890 return (rc == MDB_SUCCESS);
891}
892
897static inline bool
898lmdb::cursor_put(MDB_cursor* const cursor,
899 MDB_val* const key,
900 MDB_val* const data,
901 const unsigned int flags = 0) {
902 const int rc = ::mdb_cursor_put(cursor, key, data, flags);
903 if (rc != MDB_SUCCESS && rc != MDB_KEYEXIST) {
904 error::raise("mdb_cursor_put", rc);
905 }
906 return (rc == MDB_SUCCESS);
907}
908
913static inline void
914lmdb::cursor_del(MDB_cursor* const cursor,
915 const unsigned int flags = 0) {
916 const int rc = ::mdb_cursor_del(cursor, flags);
917 if (rc != MDB_SUCCESS) {
918 error::raise("mdb_cursor_del", rc);
919 }
920}
921
926static inline void
927lmdb::cursor_count(MDB_cursor* const cursor,
928 std::size_t& count) {
929 const int rc = ::mdb_cursor_count(cursor, &count);
930 if (rc != MDB_SUCCESS) {
931 error::raise("mdb_cursor_count", rc);
932 }
933}
934
936/* Resource Interface: Environment */
937
938namespace lmdb {
939 class env;
940}
941
949protected:
950 MDB_env* _handle{nullptr};
951
952public:
953 static constexpr unsigned int default_flags = 0;
954 static constexpr mode default_mode = 0644; /* -rw-r--r-- */
955
962 static env create(const unsigned int flags = default_flags) {
963 MDB_env* handle{nullptr};
964 lmdb::env_create(&handle);
965#ifdef LMDBXX_DEBUG
966 assert(handle != nullptr);
967#endif
968 if (flags) {
969 try {
970 lmdb::env_set_flags(handle, flags);
971 }
972 catch (const lmdb::error&) {
973 lmdb::env_close(handle);
974 throw;
975 }
976 }
977 return env{handle};
978 }
979
985 env(MDB_env* const handle) noexcept
986 : _handle{handle} {}
987
991 env(env&& other) noexcept {
992 std::swap(_handle, other._handle);
993 }
994
998 env& operator=(env&& other) noexcept {
999 if (this != &other) {
1000 std::swap(_handle, other._handle);
1001 }
1002 return *this;
1003 }
1004
1008 ~env() noexcept {
1009 try { close(); } catch (...) {}
1010 }
1011
1015 operator MDB_env*() const noexcept {
1016 return _handle;
1017 }
1018
1022 MDB_env* handle() const noexcept {
1023 return _handle;
1024 }
1025
1032 void sync(const bool force = true) {
1033 lmdb::env_sync(handle(), force);
1034 }
1035
1042 void close() noexcept {
1043 if (handle()) {
1044 lmdb::env_close(handle());
1045 _handle = nullptr;
1046 }
1047 }
1048
1050 int dead;
1051 lmdb::reader_check(handle(), &dead);
1052 return dead;
1053 }
1054
1063 env& open(const char* const path,
1064 const unsigned int flags = default_flags,
1065 const mode mode = default_mode) {
1066 lmdb::env_open(handle(), path, flags, mode);
1067 return *this;
1068 }
1069
1075 env& set_flags(const unsigned int flags,
1076 const bool onoff = true) {
1077 lmdb::env_set_flags(handle(), flags, onoff);
1078 return *this;
1079 }
1080
1085 env& set_mapsize(const std::size_t size) {
1086 lmdb::env_set_mapsize(handle(), size);
1087 return *this;
1088 }
1089
1094 env& set_max_readers(const unsigned int count) {
1095 lmdb::env_set_max_readers(handle(), count);
1096 return *this;
1097 }
1098
1103 env& set_max_dbs(const MDB_dbi count) {
1104 lmdb::env_set_max_dbs(handle(), count);
1105 return *this;
1106 }
1107};
1108
1110/* Resource Interface: Transactions */
1111
1112namespace lmdb {
1113 class txn;
1114}
1115
1123protected:
1124 MDB_txn* _handle{nullptr};
1125
1126public:
1127 static constexpr unsigned int default_flags = 0;
1128
1137 static txn begin(MDB_env* const env,
1138 MDB_txn* const parent = nullptr,
1139 const unsigned int flags = default_flags) {
1140 MDB_txn* handle{nullptr};
1141 lmdb::txn_begin(env, parent, flags, &handle);
1142#ifdef LMDBXX_DEBUG
1143 assert(handle != nullptr);
1144#endif
1145 return txn{handle};
1146 }
1147
1153 txn(MDB_txn* const handle) noexcept
1154 : _handle{handle} {}
1155
1159 txn(txn&& other) noexcept {
1160 std::swap(_handle, other._handle);
1161 }
1162
1166 txn& operator=(txn&& other) noexcept {
1167 if (this != &other) {
1168 std::swap(_handle, other._handle);
1169 }
1170 return *this;
1171 }
1172
1176 ~txn() noexcept {
1177 if (_handle) {
1178 try { abort(); } catch (...) {}
1179 _handle = nullptr;
1180 }
1181 }
1182
1186 operator MDB_txn*() const noexcept {
1187 return _handle;
1188 }
1189
1193 MDB_txn* handle() const noexcept {
1194 return _handle;
1195 }
1196
1200 MDB_env* env() const noexcept {
1201 return lmdb::txn_env(handle());
1202 }
1203
1210 void commit() {
1211 auto h = _handle;
1212 _handle = nullptr;
1214 }
1215
1221 void abort() noexcept {
1222 auto h = _handle;
1223 _handle = nullptr;
1224 lmdb::txn_abort(h);
1225 }
1226
1230 void reset() noexcept {
1231 lmdb::txn_reset(_handle);
1232 }
1233
1239 void renew() {
1240 lmdb::txn_renew(_handle);
1241 }
1242};
1243
1245/* Resource Interface: Databases */
1246
1247namespace lmdb {
1248 class dbi;
1249}
1250
1257protected:
1258 MDB_dbi _handle{(std::numeric_limits<MDB_dbi>::max)()};
1259
1260public:
1261 static constexpr unsigned int default_flags = 0;
1262 static constexpr unsigned int default_put_flags = 0;
1263
1272 static dbi
1273 open(MDB_txn* const txn,
1274 const char* const name = nullptr,
1275 const unsigned int flags = default_flags) {
1276 MDB_dbi handle{};
1277 lmdb::dbi_open(txn, name, flags, &handle);
1278 return dbi{handle};
1279 }
1280
1286 dbi() noexcept
1287 : _handle{(std::numeric_limits<MDB_dbi>::max)()} {}
1288
1294 dbi(const MDB_dbi handle) noexcept
1295 : _handle{handle} {}
1296
1300 ~dbi() noexcept {
1301 if (_handle) {
1302 /* No need to call close() here. */
1303 }
1304 }
1305
1309 operator MDB_dbi() const noexcept {
1310 return _handle;
1311 }
1312
1316 MDB_dbi handle() const noexcept {
1317 return _handle;
1318 }
1319
1326 MDB_stat stat(MDB_txn* const txn) const {
1327 MDB_stat result;
1328 lmdb::dbi_stat(txn, handle(), &result);
1329 return result;
1330 }
1331
1338 unsigned int flags(MDB_txn* const txn) const {
1339 unsigned int result{};
1340 lmdb::dbi_flags(txn, handle(), &result);
1341 return result;
1342 }
1343
1350 std::size_t size(MDB_txn* const txn) const {
1351 return stat(txn).ms_entries;
1352 }
1353
1359 void drop(MDB_txn* const txn,
1360 const bool del = false) {
1361 lmdb::dbi_drop(txn, handle(), del);
1362 }
1363
1371 dbi& set_compare(MDB_txn* const txn,
1372 MDB_cmp_func* const cmp = nullptr) {
1373 lmdb::dbi_set_compare(txn, handle(), cmp);
1374 return *this;
1375 }
1376
1386 bool get(MDB_txn* const txn,
1387 const std::string_view key,
1388 std::string_view& data) {
1389 const MDB_val keyV{key.size(), const_cast<char*>(key.data())};
1390 MDB_val dataV{data.size(), const_cast<char*>(data.data())};
1391 bool ret = lmdb::dbi_get(txn, handle(), &keyV, &dataV);
1392 if (ret) {
1393 data = std::string_view(static_cast<char*>(dataV.mv_data), dataV.mv_size);
1394 }
1395 return ret;
1396 }
1397
1407 bool put(MDB_txn* const txn,
1408 const std::string_view key,
1409 std::string_view data,
1410 const unsigned int flags = default_put_flags) {
1411 const MDB_val keyV{key.size(), const_cast<char*>(key.data())};
1412 MDB_val dataV{data.size(), const_cast<char*>(data.data())};
1413 return lmdb::dbi_put(txn, handle(), &keyV, &dataV, flags);
1414 }
1415
1423 bool del(MDB_txn* const txn,
1424 const std::string_view key) {
1425 const MDB_val keyV{key.size(), const_cast<char*>(key.data())};
1426 return lmdb::dbi_del(txn, handle(), &keyV);
1427 }
1428
1437 bool del(MDB_txn* const txn,
1438 const std::string_view key,
1439 const std::string_view val) {
1440 const MDB_val keyV{key.size(), const_cast<char*>(key.data())};
1441 const MDB_val valV{val.size(), const_cast<char*>(val.data())};
1442 return lmdb::dbi_del(txn, handle(), &keyV, &valV);
1443 }
1444};
1445
1447/* Resource Interface: Cursors */
1448
1449namespace lmdb {
1450 class cursor;
1451}
1452
1460protected:
1461 MDB_cursor* _handle{nullptr};
1462
1463public:
1464 static constexpr unsigned int default_flags = 0;
1465
1473 static cursor
1474 open(MDB_txn* const txn,
1475 const MDB_dbi dbi) {
1476 MDB_cursor* handle{};
1477 lmdb::cursor_open(txn, dbi, &handle);
1478#ifdef LMDBXX_DEBUG
1479 assert(handle != nullptr);
1480#endif
1481 return cursor{handle};
1482 }
1483
1489 cursor(MDB_cursor* const handle) noexcept
1490 : _handle{handle} {}
1491
1495 cursor(cursor&& other) noexcept {
1496 std::swap(_handle, other._handle);
1497 }
1498
1502 cursor& operator=(cursor&& other) noexcept {
1503 if (this != &other) {
1504 std::swap(_handle, other._handle);
1505 }
1506 return *this;
1507 }
1508
1512 ~cursor() noexcept {
1513 try { close(); } catch (...) {}
1514 }
1515
1519 operator MDB_cursor*() const noexcept {
1520 return _handle;
1521 }
1522
1526 MDB_cursor* handle() const noexcept {
1527 return _handle;
1528 }
1529
1536 void close() noexcept {
1537 if (_handle) {
1538 lmdb::cursor_close(_handle);
1539 _handle = nullptr;
1540 }
1541 }
1542
1549 void renew(MDB_txn* const txn) {
1550 lmdb::cursor_renew(txn, handle());
1551 }
1552
1556 MDB_txn* txn() const noexcept {
1557 return lmdb::cursor_txn(handle());
1558 }
1559
1563 MDB_dbi dbi() const noexcept {
1564 return lmdb::cursor_dbi(handle());
1565 }
1566
1574 bool get(std::string_view &key,
1575 const MDB_cursor_op op) {
1576 MDB_val keyV{key.size(), const_cast<char*>(key.data())};
1577 bool ret = lmdb::cursor_get(handle(), &keyV, nullptr, op);
1578 if (ret) {
1579 key = std::string_view(static_cast<char*>(keyV.mv_data), keyV.mv_size);
1580 }
1581 return ret;
1582 }
1583
1592 bool get(std::string_view &key,
1593 std::string_view &val,
1594 const MDB_cursor_op op) {
1595 MDB_val keyV{key.size(), const_cast<char*>(key.data())};
1596 MDB_val valV{val.size(), const_cast<char*>(val.data())};
1597 bool ret = lmdb::cursor_get(handle(), &keyV, &valV, op);
1598 if (ret) {
1599 key = std::string_view(static_cast<char*>(keyV.mv_data), keyV.mv_size);
1600 val = std::string_view(static_cast<char*>(valV.mv_data), valV.mv_size);
1601 }
1602 return ret;
1603 }
1604
1615 bool put(const std::string_view &key,
1616 const std::string_view &val,
1617 const unsigned int flags = 0) {
1618 MDB_val keyV{key.size(), const_cast<char*>(key.data())};
1619 MDB_val valV{val.size(), const_cast<char*>(val.data())};
1620 return lmdb::cursor_put(handle(), &keyV, &valV, flags);
1621 }
1622
1629 void del(unsigned int flags = 0) {
1630 lmdb::cursor_del(handle(), flags);
1631 }
1632
1636 size_t count() {
1637 std::size_t countp;
1638 lmdb::cursor_count(handle(), countp);
1639 return countp;
1640 }
1641};
1642
1643namespace lmdb {
1649 template<typename T>
1650 static inline std::string_view ptr_to_sv(T* v) {
1651 return std::string_view(reinterpret_cast<char*>(v), sizeof(*v));
1652 }
1653
1659 template<typename T>
1660 static inline std::string_view to_sv(const T &v) {
1661 return std::string_view(reinterpret_cast<const char*>(std::addressof(v)), sizeof(v));
1662 }
1663
1669 template<typename T>
1670 static inline T* ptr_from_sv(std::string_view v) {
1671 if (v.size() != sizeof(T)) error::raise("from_sv", MDB_BAD_VALSIZE);
1672 return reinterpret_cast<T*>(const_cast<char*>(v.data()));
1673 }
1674
1680 template<typename T>
1681 static inline T from_sv(std::string_view v) {
1682 if (v.size() != sizeof(T)) error::raise("from_sv", MDB_BAD_VALSIZE);
1683 T ret;
1684 std::memcpy(&ret, const_cast<char*>(v.data()), sizeof(T));
1685 return ret;
1686 }
1687}
1688
1690
1691#endif /* LMDBXX_H */
Exception class for MDB_BAD_DBI errors.
Definition lmdb++.h:196
Exception class for MDB_CORRUPTED errors.
Definition lmdb++.h:155
Resource class for MDB_cursor* handles.
Definition lmdb++.h:1459
MDB_cursor * handle() const noexcept
Returns the underlying MDB_cursor* handle.
Definition lmdb++.h:1526
void close() noexcept
Closes this cursor.
Definition lmdb++.h:1536
~cursor() noexcept
Destructor.
Definition lmdb++.h:1512
bool put(const std::string_view &key, const std::string_view &val, const unsigned int flags=0)
Stores key/data pairs into the database.
Definition lmdb++.h:1615
bool get(std::string_view &key, std::string_view &val, const MDB_cursor_op op)
Retrieves a key/value pair from the database.
Definition lmdb++.h:1592
MDB_txn * txn() const noexcept
Returns the cursor's transaction handle.
Definition lmdb++.h:1556
size_t count()
Return count of duplicates for current key.
Definition lmdb++.h:1636
cursor(cursor &&other) noexcept
Move constructor.
Definition lmdb++.h:1495
MDB_dbi dbi() const noexcept
Returns the cursor's database handle.
Definition lmdb++.h:1563
static cursor open(MDB_txn *const txn, const MDB_dbi dbi)
Creates an LMDB cursor.
Definition lmdb++.h:1474
cursor & operator=(cursor &&other) noexcept
Move assignment operator.
Definition lmdb++.h:1502
cursor(MDB_cursor *const handle) noexcept
Constructor.
Definition lmdb++.h:1489
void del(unsigned int flags=0)
Delete current key/data pair.
Definition lmdb++.h:1629
bool get(std::string_view &key, const MDB_cursor_op op)
Retrieves a key from the database.
Definition lmdb++.h:1574
void renew(MDB_txn *const txn)
Renews this cursor.
Definition lmdb++.h:1549
Resource class for MDB_dbi handles.
Definition lmdb++.h:1256
bool put(MDB_txn *const txn, const std::string_view key, std::string_view data, const unsigned int flags=default_put_flags)
Stores a key/value pair into this database.
Definition lmdb++.h:1407
std::size_t size(MDB_txn *const txn) const
Returns the number of records in this database.
Definition lmdb++.h:1350
dbi(const MDB_dbi handle) noexcept
Constructor.
Definition lmdb++.h:1294
bool del(MDB_txn *const txn, const std::string_view key)
Removes a key from this database.
Definition lmdb++.h:1423
dbi & set_compare(MDB_txn *const txn, MDB_cmp_func *const cmp=nullptr)
Sets a custom key comparison function for this database.
Definition lmdb++.h:1371
~dbi() noexcept
Destructor.
Definition lmdb++.h:1300
MDB_stat stat(MDB_txn *const txn) const
Returns statistics for this database.
Definition lmdb++.h:1326
unsigned int flags(MDB_txn *const txn) const
Retrieves the flags for this database handle.
Definition lmdb++.h:1338
dbi() noexcept
Constructor.
Definition lmdb++.h:1286
static dbi open(MDB_txn *const txn, const char *const name=nullptr, const unsigned int flags=default_flags)
Opens a database handle.
Definition lmdb++.h:1273
bool del(MDB_txn *const txn, const std::string_view key, const std::string_view val)
Removes a key/value pair from this database.
Definition lmdb++.h:1437
void drop(MDB_txn *const txn, const bool del=false)
Definition lmdb++.h:1359
MDB_dbi handle() const noexcept
Returns the underlying MDB_dbi handle.
Definition lmdb++.h:1316
bool get(MDB_txn *const txn, const std::string_view key, std::string_view &data)
Retrieves a key/value pair from this database.
Definition lmdb++.h:1386
Resource class for MDB_env* handles.
Definition lmdb++.h:948
env & set_flags(const unsigned int flags, const bool onoff=true)
Definition lmdb++.h:1075
void close() noexcept
Closes this environment, releasing the memory map.
Definition lmdb++.h:1042
env & set_mapsize(const std::size_t size)
Definition lmdb++.h:1085
env & set_max_dbs(const MDB_dbi count)
Definition lmdb++.h:1103
~env() noexcept
Destructor.
Definition lmdb++.h:1008
env(MDB_env *const handle) noexcept
Constructor.
Definition lmdb++.h:985
env(env &&other) noexcept
Move constructor.
Definition lmdb++.h:991
void sync(const bool force=true)
Flushes data buffers to disk.
Definition lmdb++.h:1032
MDB_env * handle() const noexcept
Returns the underlying MDB_env* handle.
Definition lmdb++.h:1022
env & operator=(env &&other) noexcept
Move assignment operator.
Definition lmdb++.h:998
static env create(const unsigned int flags=default_flags)
Creates a new LMDB environment.
Definition lmdb++.h:962
env & open(const char *const path, const unsigned int flags=default_flags, const mode mode=default_mode)
Opens this environment.
Definition lmdb++.h:1063
int reader_check()
Definition lmdb++.h:1049
env & set_max_readers(const unsigned int count)
Definition lmdb++.h:1094
Base class for LMDB exception conditions.
Definition lmdb++.h:63
const char * origin() const noexcept
Returns the origin of the LMDB error.
Definition lmdb++.h:91
const int _code
Definition lmdb++.h:65
virtual const char * what() const noexcept
Returns the underlying LMDB error code.
Definition lmdb++.h:98
error(const char *const origin, const int rc) noexcept
Constructor.
Definition lmdb++.h:76
static void raise(const char *origin, int rc)
Throws an error based on the given LMDB return code.
Definition lmdb++.h:202
int code() const noexcept
Returns the underlying LMDB error code.
Definition lmdb++.h:84
Base class for fatal error conditions.
Definition lmdb++.h:117
Exception class for MDB_KEYEXIST errors.
Definition lmdb++.h:135
Base class for logic error conditions.
Definition lmdb++.h:109
Exception class for MDB_MAP_FULL errors.
Definition lmdb++.h:185
Exception class for MDB_NOTFOUND errors.
Definition lmdb++.h:145
Exception class for MDB_PANIC errors.
Definition lmdb++.h:165
Base class for runtime error conditions.
Definition lmdb++.h:125
Resource class for MDB_txn* handles.
Definition lmdb++.h:1122
MDB_txn * handle() const noexcept
Returns the underlying MDB_txn* handle.
Definition lmdb++.h:1193
void commit()
Commits this transaction.
Definition lmdb++.h:1210
MDB_env * env() const noexcept
Returns the transaction's MDB_env* handle.
Definition lmdb++.h:1200
void abort() noexcept
Aborts this transaction.
Definition lmdb++.h:1221
void reset() noexcept
Resets this read-only transaction.
Definition lmdb++.h:1230
txn & operator=(txn &&other) noexcept
Move assignment operator.
Definition lmdb++.h:1166
~txn() noexcept
Destructor.
Definition lmdb++.h:1176
void renew()
Renews this read-only transaction.
Definition lmdb++.h:1239
txn(txn &&other) noexcept
Move constructor.
Definition lmdb++.h:1159
txn(MDB_txn *const handle) noexcept
Constructor.
Definition lmdb++.h:1153
static txn begin(MDB_env *const env, MDB_txn *const parent=nullptr, const unsigned int flags=default_flags)
Creates a new LMDB transaction.
Definition lmdb++.h:1137
Exception class for MDB_VERSION_MISMATCH errors.
Definition lmdb++.h:175
<lmdb++.h> - C++17 wrapper for LMDB.
Definition lmdb++.h:37
static void env_info(MDB_env *env, MDB_envinfo *stat)
Definition lmdb++.h:347
static void * env_get_userctx(MDB_env *env)
Definition lmdb++.h:515
static void dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags)
Definition lmdb++.h:672
static void cursor_renew(MDB_txn *txn, MDB_cursor *cursor)
Definition lmdb++.h:853
static void env_copy_fd(MDB_env *env, mdb_filehandle_t fd, unsigned int flags)
Definition lmdb++.h:315
static void txn_commit(MDB_txn *txn)
Definition lmdb++.h:582
static void env_open(MDB_env *env, const char *path, unsigned int flags, mode mode)
Definition lmdb++.h:279
static MDB_txn * cursor_txn(MDB_cursor *cursor) noexcept
Definition lmdb++.h:865
static void dbi_drop(MDB_txn *txn, MDB_dbi dbi, bool del)
Definition lmdb++.h:694
static bool dbi_put(MDB_txn *txn, MDB_dbi dbi, const MDB_val *key, MDB_val *data, unsigned int flags)
Definition lmdb++.h:782
static void env_create(MDB_env **env)
Definition lmdb++.h:267
static std::string_view to_sv(const T &v)
Creates a std::string_view that points to the memory occupied by v.
Definition lmdb++.h:1660
static unsigned int env_get_max_keysize(MDB_env *env)
Definition lmdb++.h:485
static void cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **cursor)
Definition lmdb++.h:831
static void reader_check(MDB_env *env, int *dead)
Definition lmdb++.h:521
static void env_get_fd(MDB_env *env, mdb_filehandle_t *fd)
Definition lmdb++.h:421
static void cursor_del(MDB_cursor *cursor, unsigned int flags)
Definition lmdb++.h:914
static T from_sv(std::string_view v)
Takes a std::string_view and dereferences it, returning a value of the parameterized type.
Definition lmdb++.h:1681
static void dbi_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel)
Definition lmdb++.h:736
static void dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *dbi)
Definition lmdb++.h:643
static void dbi_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
Definition lmdb++.h:708
static void env_set_max_readers(MDB_env *env, unsigned int count)
Definition lmdb++.h:447
static MDB_env * txn_env(MDB_txn *txn) noexcept
Definition lmdb++.h:563
static void env_set_mapsize(MDB_env *env, std::size_t size)
Definition lmdb++.h:434
static void env_set_max_dbs(MDB_env *env, MDB_dbi count)
Definition lmdb++.h:473
static void env_close(MDB_env *env) noexcept
Definition lmdb++.h:372
static void env_set_flags(MDB_env *env, unsigned int flags, bool onoff)
Definition lmdb++.h:381
static void txn_renew(MDB_txn *txn)
Definition lmdb++.h:610
static bool cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data, unsigned int flags)
Definition lmdb++.h:898
static void cursor_close(MDB_cursor *cursor) noexcept
Definition lmdb++.h:844
static bool cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op op)
Definition lmdb++.h:882
static void cursor_count(MDB_cursor *cursor, std::size_t &count)
Definition lmdb++.h:927
static void env_get_max_readers(MDB_env *env, unsigned int *count)
Definition lmdb++.h:460
static MDB_dbi cursor_dbi(MDB_cursor *cursor) noexcept
Definition lmdb++.h:873
static void txn_abort(MDB_txn *txn) noexcept
Definition lmdb++.h:593
static void env_get_path(MDB_env *env, const char **path)
Definition lmdb++.h:408
static void dbi_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *stat)
Definition lmdb++.h:658
static bool dbi_del(MDB_txn *txn, MDB_dbi dbi, const MDB_val *key, const MDB_val *data)
Definition lmdb++.h:800
static bool dbi_get(MDB_txn *txn, MDB_dbi dbi, const MDB_val *key, MDB_val *data)
Definition lmdb++.h:765
static void env_copy(MDB_env *env, const char *path, unsigned int flags)
Definition lmdb++.h:295
static void txn_reset(MDB_txn *txn) noexcept
Definition lmdb++.h:601
static void env_set_userctx(MDB_env *env, void *ctx)
Definition lmdb++.h:500
static void dbi_close(MDB_env *env, MDB_dbi dbi) noexcept
Definition lmdb++.h:685
static void env_stat(MDB_env *env, MDB_stat *stat)
Definition lmdb++.h:334
static T * ptr_from_sv(std::string_view v)
Takes a std::string_view and casts its pointer as a pointer to the parameterized type.
Definition lmdb++.h:1670
static void env_sync(MDB_env *env, bool force)
Definition lmdb++.h:360
static void dbi_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
Definition lmdb++.h:722
static void env_get_flags(MDB_env *env, unsigned int *flags)
Definition lmdb++.h:395
static void txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **txn)
Definition lmdb++.h:549
mdb_mode_t mode
Definition lmdb++.h:38
static std::string_view ptr_to_sv(T *v)
Creates a std::string_view that points to the memory pointed to by v.
Definition lmdb++.h:1650
static void dbi_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx)
Definition lmdb++.h:750