1 /** 2 Copyright: Copyright (c) 2016 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module voxelman.world.db.lmdbworlddb; 7 8 import std.experimental.logger; 9 10 version(Windows): 11 12 import std.string : fromStringz, toStringz; 13 struct LmdbWorldDb 14 { 15 private MDB_env* env; 16 private MDB_txn* txn; 17 private uint txnFlags; 18 private MDB_dbi dbi; 19 20 // filename needs to have /0 after end 21 void open(string filename, size_t mapSize = 1 * 1024 * 1024 * 1024) { 22 assert(env is null); 23 assert(txn is null); 24 checked!mdb_env_create(&env); 25 26 checked!mdb_env_set_mapsize(env, mapSize); 27 28 checked!mdb_env_open(env, filename.toStringz, 29 MDB_NOSUBDIR| 30 MDB_NOMETASYNC| 31 MDB_NOSYNC| 32 MDB_WRITEMAP| 33 MDB_NOLOCK| 34 MDB_NOMEMINIT, 35 0); 36 } 37 38 static string libVersion() @nogc { 39 return cast(string)mdb_version(null, null, null).fromStringz; 40 } 41 42 void close() @nogc { 43 mdb_env_close(env); 44 } 45 46 void beginTxn(uint flags = 0) @nogc { 47 checked!mdb_txn_begin(env, null, flags, &txn); 48 checked!mdb_dbi_open(txn, null/*main DB*/, 0/*flags*/, &dbi); 49 checked!mdb_set_compare(txn, dbi, &mdb_cmp_long); 50 } 51 52 void abortTxn() @nogc { 53 mdb_txn_abort(txn); 54 } 55 56 void commitTxn() @nogc { 57 checked!mdb_txn_commit(txn); 58 } 59 60 void put(ubyte[] key, ubyte[] value) @nogc { 61 checked!mdb_put(txn, dbi, &key, &value, 0); 62 } 63 64 ubyte[] get(ubyte[] key) @nogc { 65 ubyte[] value; 66 checked!mdb_get(txn, dbi, &key, &value); 67 return value; 68 } 69 70 void del(ubyte[] key) @nogc { 71 checked!mdb_del(txn, dbi, &key, null); 72 } 73 74 void dropDB() @nogc { 75 checked!mdb_drop(txn, dbi, 0); 76 checked!mdb_drop(txn, dbi, 1); 77 } 78 } 79 80 template checked(alias func) 81 { 82 import std.traits; 83 debug auto checked(string file = __FILE__, int line = __LINE__)(auto ref Parameters!func args) 84 { 85 int rc = func(args); 86 checkCode(rc, file, line); 87 return rc; 88 } else 89 alias checked = func; 90 } 91 92 void checkCode(int code, string file = __FILE__, int line = __LINE__) @nogc 93 { 94 if (code != MDB_SUCCESS && code != MDB_NOTFOUND) 95 { 96 //errorf("%s@%s: MDB error: %s", file, line, mdb_strerror(code).fromStringz); 97 import core.stdc.stdio; 98 printf("%s@%s: MDB error: %s", file.ptr, line, mdb_strerror(code)); 99 assert(false); 100 } 101 } 102 103 extern(C): 104 nothrow: 105 @nogc: 106 107 static int mdb_cmp_long(const MDB_val *a, const MDB_val *b) 108 { 109 return (*cast(size_t*)a.ptr < *cast(size_t*)b.ptr) ? -1 : 110 *cast(size_t*)a.ptr > *cast(size_t*)b.ptr; 111 } 112 113 void mdb_load_libs(); 114 115 alias mdb_mode_t = uint; 116 struct mdb_filehandle_ts {} 117 alias mdb_filehandle_t = mdb_filehandle_ts*; 118 119 struct MDB_env {} 120 struct MDB_txn {} 121 alias MDB_dbi = uint; 122 struct MDB_cursor {} 123 124 alias MDB_val = ubyte[]; 125 126 enum { 127 MDB_FIXEDMAP = 0x01, 128 MDB_NOSUBDIR = 0x4000, 129 MDB_NOSYNC = 0x10000, 130 MDB_RDONLY = 0x20000, 131 MDB_NOMETASYNC = 0x40000, 132 MDB_WRITEMAP = 0x80000, 133 MDB_MAPASYNC = 0x100000, 134 MDB_NOTLS = 0x200000, 135 MDB_NOLOCK = 0x400000, 136 MDB_NORDAHEAD = 0x800000, 137 MDB_NOMEMINIT = 0x1000000 138 } 139 140 enum { 141 MDB_REVERSEKEY = 0x02, 142 MDB_DUPSORT = 0x04, 143 MDB_INTEGERKEY = 0x08, 144 MDB_DUPFIXED = 0x10, 145 MDB_INTEGERDUP = 0x20, 146 MDB_REVERSEDUP = 0x40, 147 MDB_CREATE = 0x40000 148 } 149 150 enum { 151 MDB_NOOVERWRITE = 0x10, 152 MDB_NODUPDATA = 0x20, 153 MDB_RESERVE = 0x10000, 154 MDB_APPEND = 0x20000, 155 MDB_APPENDDUP = 0x40000, 156 MDB_MULTIPLE = 0x80000 157 } 158 159 enum /*MDB_cursor_op*/ { 160 MDB_FIRST, 161 MDB_FIRST_DUP, 162 MDB_GET_BOTH, 163 MDB_GET_BOTH_RANGE, 164 MDB_GET_CURRENT, 165 MDB_GET_MULTIPLE, 166 MDB_LAST, 167 MDB_LAST_DUP, 168 MDB_NEXT, 169 MDB_NEXT_DUP, 170 MDB_NEXT_MULTIPLE, 171 MDB_NEXT_NODUP, 172 MDB_PREV, 173 MDB_PREV_DUP, 174 MDB_PREV_NODUP, 175 MDB_SET, 176 MDB_SET_KEY, 177 MDB_SET_RANGE, 178 } 179 180 enum { 181 MDB_SUCCESS = 0, 182 MDB_KEYEXIST = (-30799), 183 MDB_NOTFOUND = (-30798), 184 MDB_PAGE_NOTFOUND = (-30797), 185 MDB_CORRUPTED = (-30796), 186 MDB_PANIC = (-30795), 187 MDB_VERSION_MISMATCH = (-30794), 188 MDB_INVALID = (-30793), 189 MDB_MAP_FULL = (-30792), 190 MDB_DBS_FULL = (-30791), 191 MDB_READERS_FULL = (-30790), 192 MDB_TLS_FULL = (-30789), 193 MDB_TXN_FULL = (-30788), 194 MDB_CURSOR_FULL = (-30787), 195 MDB_PAGE_FULL = (-30786), 196 MDB_MAP_RESIZED = (-30785), 197 MDB_INCOMPATIBLE = (-30784), 198 MDB_BAD_RSLOT = (-30783), 199 MDB_BAD_TXN = (-30782), 200 MDB_BAD_VALSIZE = (-30781), 201 MDB_BAD_DBI = (-30780), 202 MDB_LAST_ERRCODE = MDB_BAD_DBI 203 } 204 205 struct MDB_stat { 206 uint ms_psize; 207 uint ms_depth; 208 size_t ms_branch_pages; 209 size_t ms_leaf_pages; 210 size_t ms_overflow_pages; 211 size_t ms_entries; 212 } 213 214 struct MDB_envinfo { 215 void* me_mapaddr; 216 size_t me_mapsize; 217 size_t me_last_pgno; 218 size_t me_last_txnid; 219 uint me_maxreaders; 220 uint me_numreaders; 221 } 222 223 const(char)* mdb_version (int* major, int* minor, int* patch); 224 const(char)* mdb_strerror (int err); 225 226 int mdb_env_create (MDB_env** env); 227 int mdb_env_open (MDB_env* env, const(char)* path, uint flags, mdb_mode_t mode); 228 int mdb_env_copy (MDB_env* env, const(char)* path); 229 int mdb_env_copyfd (MDB_env* env, mdb_filehandle_t fd); 230 int mdb_env_stat (MDB_env* env, MDB_stat* stat); 231 int mdb_env_info (MDB_env* env, MDB_envinfo* stat); 232 int mdb_env_sync (MDB_env* env, int force); 233 void mdb_env_close (MDB_env* env); 234 int mdb_env_set_flags (MDB_env* env, uint flags, int onoff); 235 int mdb_env_get_flags (MDB_env* env, uint* flags); 236 int mdb_env_get_path (MDB_env* env, const(char)** path); 237 int mdb_env_get_fd (MDB_env* env, mdb_filehandle_t* fd); 238 int mdb_env_set_mapsize (MDB_env* env, size_t size); 239 int mdb_env_set_maxreaders (MDB_env* env, uint readers); 240 int mdb_env_get_maxreaders (MDB_env* env, uint* readers); 241 int mdb_env_set_maxdbs (MDB_env* env, MDB_dbi dbs); 242 int mdb_env_get_maxkeysize (MDB_env* env); 243 int mdb_env_set_userctx (MDB_env* env, void* ctx); 244 void* mdb_env_get_userctx (MDB_env* env); 245 int mdb_env_set_assert (MDB_env* env, void function (MDB_env* env, const(char)* msg) func); 246 247 int mdb_txn_begin (MDB_env* env, MDB_txn* parent, uint flags, MDB_txn** txn); 248 MDB_env* mdb_txn_env (MDB_txn* txn); 249 size_t mdb_txn_id (MDB_txn* txn); 250 int mdb_txn_commit (MDB_txn* txn); 251 void mdb_txn_abort (MDB_txn* txn); 252 void mdb_txn_reset (MDB_txn* txn); 253 int mdb_txn_renew (MDB_txn* txn); 254 255 int mdb_dbi_open (MDB_txn* txn, const(char)* name, uint flags, MDB_dbi* dbi); 256 int mdb_stat (MDB_txn* txn, MDB_dbi dbi, MDB_stat* stat); 257 int mdb_dbi_flags (MDB_txn* txn, MDB_dbi dbi, uint* flags); 258 void mdb_dbi_close (MDB_env* env, MDB_dbi dbi); 259 int mdb_drop (MDB_txn* txn, MDB_dbi dbi, int del); 260 int mdb_set_compare (MDB_txn* txn, MDB_dbi dbi, int function (const MDB_val* a, const MDB_val* b) cmp); 261 int mdb_set_dupsort (MDB_txn* txn, MDB_dbi dbi, int function (MDB_val* a, MDB_val* b) cmp); 262 int mdb_set_relfunc (MDB_txn* txn, MDB_dbi dbi, void function (MDB_val* item, void* oldptr, void* newptr, void* relctx) rel); 263 int mdb_set_relctx (MDB_txn* txn, MDB_dbi dbi, void* ctx); 264 int mdb_get (MDB_txn* txn, MDB_dbi dbi, MDB_val* key, MDB_val* data); 265 int mdb_put (MDB_txn* txn, MDB_dbi dbi, MDB_val* key, MDB_val* data, uint flags); 266 int mdb_del (MDB_txn* txn, MDB_dbi dbi, MDB_val* key, MDB_val* data); 267 int mdb_cursor_open (MDB_txn* txn, MDB_dbi dbi, MDB_cursor** cursor); 268 void mdb_cursor_close (MDB_cursor* cursor); 269 int mdb_cursor_renew (MDB_txn* txn, MDB_cursor* cursor); 270 MDB_txn* mdb_cursor_txn (MDB_cursor* cursor); 271 MDB_dbi mdb_cursor_dbi (MDB_cursor* cursor); 272 int mdb_cursor_get (MDB_cursor* cursor, MDB_val* key, MDB_val* data, /*MDB_cursor_op*/uint op); 273 int mdb_cursor_put (MDB_cursor* cursor, MDB_val* key, MDB_val* data, uint flags); 274 int mdb_cursor_del (MDB_cursor* cursor, uint flags); 275 int mdb_cursor_count (MDB_cursor* cursor, size_t* countp); 276 int mdb_cmp (MDB_txn* txn, MDB_dbi dbi, MDB_val* a, MDB_val* b); 277 int mdb_dcmp (MDB_txn* txn, MDB_dbi dbi, MDB_val* a, MDB_val* b); 278 int mdb_reader_list (MDB_env* env, int function (const(char)* msg, void* ctx) func, void* ctx); 279 int mdb_reader_check (MDB_env* env, int* dead);