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.worlddb;
7 
8 import std.experimental.allocator.mallocator;
9 import voxelman.world.db.lmdbworlddb;
10 import voxelman.world.db.sqliteworlddb;
11 
12 version(Windows) {
13 	version = Lmdb;
14 } else {
15 	version = Sqlite;
16 }
17 
18 final class WorldDb
19 {
20 	version(Lmdb) LmdbWorldDb db;
21 	version(Sqlite) SqliteWorldDb db;
22 	private ubyte[] buffer;
23 
24 	//-----------------------------------------------
25 	void open(string filename) {
26 		buffer = cast(ubyte[])Mallocator.instance.allocate(4096*64);
27 		version(Lmdb) mdb_load_libs();
28 		db.open(filename);
29 	}
30 	void close() {
31 		db.close();
32 		Mallocator.instance.deallocate(buffer);
33 	}
34 
35 	ubyte[] tempBuffer() @property { return buffer; }
36 
37 	//-----------------------------------------------
38 	version(Lmdb) {
39 		private enum Table : ulong
40 		{
41 			world,
42 			dimention,
43 			region,
44 			chunk,
45 		}
46 		void putPerWorldValue(K)(K key, ubyte[] value) {
47 			put(formKey(key), Table.world, value);
48 		}
49 		ubyte[] getPerWorldValue(K)(K key) {
50 			return get(formKey(key), Table.world);
51 		}
52 		void putPerChunkValue(ulong key, ubyte[] value) {
53 			put(key, Table.chunk, value);
54 		}
55 		ubyte[] getPerChunkValue(ulong key) {
56 			return get(key, Table.chunk);
57 		}
58 
59 		private void put(ulong key, ulong table, ubyte[] value) {
60 			ubyte[16] dbKey;
61 			(*cast(ulong[2]*)dbKey.ptr)[0] = key;
62 			(*cast(ulong[2]*)dbKey.ptr)[1] = table;
63 			db.put(dbKey, value);
64 		}
65 		private ubyte[] get(ulong key, ulong table) {
66 			ubyte[16] dbKey;
67 			(*cast(ulong[2]*)dbKey.ptr)[0] = key;
68 			(*cast(ulong[2]*)dbKey.ptr)[1] = table;
69 			return db.get(dbKey);
70 		}
71 		private void del(ulong key, ulong table) {
72 			ubyte[16] dbKey;
73 			(*cast(ulong[2]*)dbKey.ptr)[0] = key;
74 			(*cast(ulong[2]*)dbKey.ptr)[1] = table;
75 			return db.del(dbKey);
76 		}
77 	}
78 
79 	version(Sqlite) {
80 		void putPerWorldValue(K)(K key, ubyte[] value) {
81 			db.savePerWorldData(key, value);
82 		}
83 		ubyte[] getPerWorldValue(K)(K key) {
84 			return db.loadPerWorldData(key);
85 		}
86 		void putPerChunkValue(ulong key, ubyte[] value) {
87 			db.savePerChunkData(key, value);
88 		}
89 		ubyte[] getPerChunkValue(ulong key) {
90 			return db.loadPerChunkData(key);
91 		}
92 	}
93 
94 	//-----------------------------------------------
95 	void beginTxn() {
96 		db.beginTxn();
97 	}
98 	void abortTxn() {
99 		db.abortTxn();
100 	}
101 	void commitTxn() {
102 		db.commitTxn();
103 	}
104 }
105 
106 ulong formKey(K)(K _key) @nogc
107 	if (is(K == string) || is(K == ulong))
108 {
109 	static if (is(K == string))
110 		return hashBytes(cast(ubyte[])_key);
111 	else static if (is(K == ulong))
112 		return _key;
113 }
114 
115 ulong hashBytes(ubyte[] bytes) @nogc
116 {
117     ulong hash = 5381;
118 
119     foreach(c; bytes)
120         hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
121 
122     return hash;
123 }