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);