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