-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathTrailDB.d
270 lines (232 loc) · 6.65 KB
/
TrailDB.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
module TrailDB;
import std.algorithm;
import std.conv;
import std.datetime;
import std.path : buildPath;
import std.range;
import std.stdint;
import std.stdio;
import std.string : fromStringz, format, toStringz;
import std.typecons;
import traildbc;
immutable static BUFFER_SIZE = 1 << 18;
alias RawUuid = ubyte[16];
alias HexUuid = ubyte[32];
RawUuid hexToRaw(HexUuid hexId)
{
RawUuid rawId;
if(int err = tdb_uuid_raw(hexId, rawId))
{
throw new Exception("Failure to convert hex uuid to raw.\n\t"
~ cast(string)fromStringz(tdb_error_str(err)));
}
return rawId;
}
HexUuid rawToHex(RawUuid rawId)
{
HexUuid hexId;
tdb_uuid_hex(rawId, hexId);
return hexId;
}
/* Event in a TrailDB trail. Indexing returns immutable reference to field values. */
/* The reference returned should be deep copied if another trail is loaded before use. */
struct Event
{
void* db; // Needed to get item value
tdb_event* event;
@property ulong timestamp() { return event.timestamp; }
string opIndex(ulong i)
{
uint64_t valueLength;
auto ret = tdb_get_item_value(db, (cast(tdb_item*)(event.items))[i], &valueLength);
return cast(string)ret[0 .. valueLength];
}
}
/* D Range representing trail of events */
struct Trail
{
void* db;
void* cursor;
int opApply(int delegate(ref Event) foreach_body)
{
tdb_event* event;
while((event = tdb_cursor_next(cursor)) != null)
{
Event e = Event(db, event);
if(int result = foreach_body(e))
{
return result;
}
}
return 0;
}
}
class TrailDB
{
void* db;
void* cursor;
bool open = false;
immutable uint64_t numTrails;
immutable uint64_t numEvents;
immutable uint64_t numFields;
immutable uint64_t minTimestamp;
immutable uint64_t maxTimestamp;
immutable string[] fieldNames;
immutable uint64_t vers;
this(string db_path)
{
db = tdb_init();
if(int err = tdb_open(db, toStringz(db_path)))
{
throw new Exception("Failure to open traildb " ~ db_path ~ ".\n\t"
~ cast(string)fromStringz(tdb_error_str(err)));
}
open = true;
numTrails = tdb_num_trails(db);
numEvents = tdb_num_events(db);
numFields = tdb_num_fields(db);
minTimestamp = tdb_min_timestamp(db);
maxTimestamp = tdb_max_timestamp(db);
fieldNames = cast(immutable)map!(i => cast(string)fromStringz(tdb_get_field_name(db, cast(uint)i)))(iota(0, numFields)).array();
vers = tdb_version(db);
cursor = tdb_cursor_new(db);
}
~this()
{
close();
}
void close()
{
if(open)
{
tdb_close(db);
tdb_cursor_free(cursor);
open = false;
}
}
ulong fieldLexiconSize(uint field)
{
return tdb_lexicon_size(db, field);
}
/* Returns trail of events (a D Range)*/
Trail opIndex(ulong trailIndex)
{
tdb_get_trail(cursor, trailIndex);
return Trail(db, cursor);
}
Trail opIndex(HexUuid uuid)
{
return opIndex(uuidIndex(hexToRaw(uuid)));
}
Trail opIndex(RawUuid uuid)
{
return opIndex(uuidIndex(uuid));
}
int opApply(int delegate(ref Trail) foreach_body)
{
tdb_willneed(db);
scope(exit) tdb_dontneed(db);
foreach(i; 0 .. numTrails)
{
Trail t = opIndex(i);
if(int result = foreach_body(t))
{
return result;
}
}
return 0;
}
RawUuid indexUuid(ulong index)
{
auto uuidPtr = tdb_get_uuid(db, index);
if(uuidPtr == null)
{
throw new Exception("No trail with index " ~ to!string(index) ~ " found.");
}
RawUuid uuid = uuidPtr[0 .. 16];
return uuid;
}
long uuidIndex(RawUuid uuid)
{
ulong index;
if(int err = tdb_get_trail_id(db, uuid, &index))
{
throw new Exception("No trail with uuid " ~ cast(string)(rawToHex(uuid)) ~ " found.");
}
return index;
}
}
class TrailDBConstructor
{
void* cons;
string name;
bool finalized = false;
ulong[] lengthBuffer;
char*[] valuePointersBuffer;
this(string name_, string[] fields)
{
lengthBuffer.length = fields.length;
valuePointersBuffer.length = fields.length;
name = name_;
cons = tdb_cons_init();
// Retain pointer to avoid GC madness
char* namePtr = cast(char*)toStringz(name);
char*[] fieldsPtrs = cast(char*[])fields.map!(s => toStringz(s)).array();
if(int err = tdb_cons_open(cons, namePtr, cast(char**)fieldsPtrs, fields.length))
{
throw new Exception("Failure to open traildb constructor" ~ name ~ ".\n\t"
~ cast(string)fromStringz(tdb_error_str(err)));
}
}
void append(TrailDB db)
{
if(int err = tdb_cons_append(cons, db.db))
{
throw new Exception("Failure to finalize traildb constructor" ~ name ~ ".\n\t"
~ cast(string)fromStringz(tdb_error_str(err)));
}
}
void add(RawUuid uuid, ulong timestamp, string[] values)
{
ulong i = 0;
foreach(length; values.map!(v => v.length))
{
lengthBuffer[i++] = length;
}
i = 0;
foreach(pointer; values.map!(v => v.ptr))
{
valuePointersBuffer[i++] = cast(char*)pointer;
}
if(int err = tdb_cons_add(cons, uuid, timestamp, cast(const char**)valuePointersBuffer, cast(const ulong*)lengthBuffer))
{
throw new Exception("Failure to finalize traildb constructor" ~ name ~ ".\n\t"
~ cast(string)fromStringz(tdb_error_str(err)));
}
}
void finalize()
{
if(!finalized)
{
if(int err = tdb_cons_finalize(cons))
{
throw new Exception("Failure to finalize traildb constructor" ~ name ~ ".\n\t"
~ cast(string)fromStringz(tdb_error_str(err)));
}
finalized = true;
}
}
// Can't throw in destructor
~this()
{
if(!finalized)
{
if(int err = tdb_cons_finalize(cons))
{
writeln("Failure to finalize traildb constructor" ~ name ~ ".\n\t"
~ cast(string)fromStringz(tdb_error_str(err)));
}
}
tdb_cons_close(cons);
}
}