hirlite 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE +28 -0
  3. data/Rakefile +51 -0
  4. data/ext/hirlite_ext/extconf.rb +33 -0
  5. data/ext/hirlite_ext/hirlite_ext.c +14 -0
  6. data/ext/hirlite_ext/hirlite_ext.h +38 -0
  7. data/ext/hirlite_ext/rlite.c +351 -0
  8. data/lib/hirlite/rlite.rb +1 -0
  9. data/lib/hirlite/version.rb +3 -0
  10. data/lib/hirlite.rb +2 -0
  11. data/vendor/rlite/Makefile +6 -0
  12. data/vendor/rlite/deps/crc64.c +191 -0
  13. data/vendor/rlite/deps/crc64.h +3 -0
  14. data/vendor/rlite/deps/endianconv.h +73 -0
  15. data/vendor/rlite/deps/hyperloglog.c +1547 -0
  16. data/vendor/rlite/deps/hyperloglog.h +14 -0
  17. data/vendor/rlite/deps/lzf.h +100 -0
  18. data/vendor/rlite/deps/lzfP.h +159 -0
  19. data/vendor/rlite/deps/lzf_c.c +295 -0
  20. data/vendor/rlite/deps/lzf_d.c +150 -0
  21. data/vendor/rlite/deps/sha1.c +227 -0
  22. data/vendor/rlite/deps/sha1.h +19 -0
  23. data/vendor/rlite/deps/utilfromredis.c +397 -0
  24. data/vendor/rlite/deps/utilfromredis.h +11 -0
  25. data/vendor/rlite/src/Makefile +79 -0
  26. data/vendor/rlite/src/constants.h +15 -0
  27. data/vendor/rlite/src/dump.c +191 -0
  28. data/vendor/rlite/src/dump.h +3 -0
  29. data/vendor/rlite/src/hirlite.c +3985 -0
  30. data/vendor/rlite/src/hirlite.h +186 -0
  31. data/vendor/rlite/src/page_btree.c +1556 -0
  32. data/vendor/rlite/src/page_btree.h +133 -0
  33. data/vendor/rlite/src/page_key.c +283 -0
  34. data/vendor/rlite/src/page_key.h +25 -0
  35. data/vendor/rlite/src/page_list.c +718 -0
  36. data/vendor/rlite/src/page_list.h +70 -0
  37. data/vendor/rlite/src/page_long.c +61 -0
  38. data/vendor/rlite/src/page_long.h +14 -0
  39. data/vendor/rlite/src/page_multi_string.c +538 -0
  40. data/vendor/rlite/src/page_multi_string.h +18 -0
  41. data/vendor/rlite/src/page_skiplist.c +689 -0
  42. data/vendor/rlite/src/page_skiplist.h +70 -0
  43. data/vendor/rlite/src/page_string.c +55 -0
  44. data/vendor/rlite/src/page_string.h +12 -0
  45. data/vendor/rlite/src/pqsort.c +185 -0
  46. data/vendor/rlite/src/pqsort.h +40 -0
  47. data/vendor/rlite/src/restore.c +401 -0
  48. data/vendor/rlite/src/restore.h +3 -0
  49. data/vendor/rlite/src/rlite.c +1309 -0
  50. data/vendor/rlite/src/rlite.h +159 -0
  51. data/vendor/rlite/src/sort.c +530 -0
  52. data/vendor/rlite/src/sort.h +18 -0
  53. data/vendor/rlite/src/status.h +19 -0
  54. data/vendor/rlite/src/type_hash.c +607 -0
  55. data/vendor/rlite/src/type_hash.h +29 -0
  56. data/vendor/rlite/src/type_list.c +477 -0
  57. data/vendor/rlite/src/type_list.h +23 -0
  58. data/vendor/rlite/src/type_set.c +796 -0
  59. data/vendor/rlite/src/type_set.h +34 -0
  60. data/vendor/rlite/src/type_string.c +613 -0
  61. data/vendor/rlite/src/type_string.h +34 -0
  62. data/vendor/rlite/src/type_zset.c +1147 -0
  63. data/vendor/rlite/src/type_zset.h +50 -0
  64. data/vendor/rlite/src/util.c +334 -0
  65. data/vendor/rlite/src/util.h +71 -0
  66. metadata +151 -0
@@ -0,0 +1,1309 @@
1
+ #include <sys/file.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include <unistd.h>
5
+ #include <errno.h>
6
+ #include "page_btree.h"
7
+ #include "page_list.h"
8
+ #include "page_long.h"
9
+ #include "page_string.h"
10
+ #include "page_skiplist.h"
11
+ #include "page_multi_string.h"
12
+ #include "type_string.h"
13
+ #include "type_zset.h"
14
+ #include "type_hash.h"
15
+ #include "rlite.h"
16
+ #include "util.h"
17
+ #include "../deps/sha1.h"
18
+ #ifdef DEBUG
19
+ #include <valgrind/valgrind.h>
20
+ #endif
21
+
22
+ #define DEFAULT_READ_PAGES_LEN 16
23
+ #define DEFAULT_WRITE_PAGES_LEN 8
24
+ #define DEFAULT_PAGE_SIZE 1024
25
+ #define HEADER_SIZE 100
26
+
27
+ int rl_header_serialize(struct rlite *db, void *obj, unsigned char *data);
28
+ int rl_header_deserialize(struct rlite *db, void **obj, void *context, unsigned char *data);
29
+ int rl_has_flag(rlite *db, int flag);
30
+
31
+ rl_data_type rl_data_type_btree_hash_sha1_long = {
32
+ "rl_data_type_btree_hash_sha1_long",
33
+ rl_btree_serialize,
34
+ rl_btree_deserialize,
35
+ rl_btree_destroy,
36
+ };
37
+ rl_data_type rl_data_type_btree_node_hash_sha1_long = {
38
+ "rl_data_type_btree_node_hash_sha1_long",
39
+ rl_btree_node_serialize_hash_sha1_long,
40
+ rl_btree_node_deserialize_hash_sha1_long,
41
+ rl_btree_node_destroy,
42
+ };
43
+ rl_data_type rl_data_type_btree_hash_sha1_double = {
44
+ "rl_data_type_btree_hash_sha1_double",
45
+ rl_btree_serialize,
46
+ rl_btree_deserialize,
47
+ rl_btree_destroy,
48
+ };
49
+ rl_data_type rl_data_type_btree_node_hash_sha1_double = {
50
+ "rl_data_type_btree_node_hash_sha1_double",
51
+ rl_btree_node_serialize_hash_sha1_double,
52
+ rl_btree_node_deserialize_hash_sha1_double,
53
+ rl_btree_node_destroy,
54
+ };
55
+ rl_data_type rl_data_type_btree_hash_sha1_key = {
56
+ "rl_data_type_btree_hash_sha1_key",
57
+ rl_btree_serialize,
58
+ rl_btree_deserialize,
59
+ rl_btree_destroy,
60
+ };
61
+ rl_data_type rl_data_type_btree_node_hash_sha1_key = {
62
+ "rl_data_type_btree_node_hash_sha1_key",
63
+ rl_btree_node_serialize_hash_sha1_key,
64
+ rl_btree_node_deserialize_hash_sha1_key,
65
+ rl_btree_node_destroy,
66
+ };
67
+ rl_data_type rl_data_type_btree_hash_sha1_hashkey = {
68
+ "rl_data_type_btree_hash_sha1_hashkey",
69
+ rl_btree_serialize,
70
+ rl_btree_deserialize,
71
+ rl_btree_destroy,
72
+ };
73
+ rl_data_type rl_data_type_btree_node_hash_sha1_hashkey = {
74
+ "rl_data_type_btree_node_hash_sha1_hashkey",
75
+ rl_btree_node_serialize_hash_sha1_hashkey,
76
+ rl_btree_node_deserialize_hash_sha1_hashkey,
77
+ rl_btree_node_destroy,
78
+ };
79
+ rl_data_type rl_data_type_header = {
80
+ "rl_data_type_header",
81
+ rl_header_serialize,
82
+ rl_header_deserialize,
83
+ NULL
84
+ };
85
+ rl_data_type rl_data_type_btree_set_long = {
86
+ "rl_data_type_btree_set_long",
87
+ rl_btree_serialize,
88
+ rl_btree_deserialize,
89
+ rl_btree_destroy,
90
+ };
91
+ rl_data_type rl_data_type_btree_node_set_long = {
92
+ "rl_data_type_btree_node_set_long",
93
+ rl_btree_node_serialize_set_long,
94
+ rl_btree_node_deserialize_set_long,
95
+ rl_btree_node_destroy,
96
+ };
97
+ rl_data_type rl_data_type_btree_hash_long_long = {
98
+ "rl_data_type_btree_hash_long_long",
99
+ rl_btree_serialize,
100
+ rl_btree_deserialize,
101
+ rl_btree_destroy,
102
+ };
103
+ rl_data_type rl_data_type_btree_node_hash_long_long = {
104
+ "rl_data_type_btree_node_hash_long_long",
105
+ rl_btree_node_serialize_hash_long_long,
106
+ rl_btree_node_deserialize_hash_long_long,
107
+ rl_btree_node_destroy,
108
+ };
109
+ rl_data_type rl_data_type_btree_hash_double_long = {
110
+ "rl_data_type_btree_hash_double_long",
111
+ rl_btree_serialize,
112
+ rl_btree_deserialize,
113
+ rl_btree_destroy,
114
+ };
115
+ rl_data_type rl_data_type_list_long = {
116
+ "rl_data_type_list_long",
117
+ rl_list_serialize,
118
+ rl_list_deserialize,
119
+ rl_list_destroy,
120
+ };
121
+ rl_data_type rl_data_type_list_node_long = {
122
+ "rl_data_type_list_node_long",
123
+ rl_list_node_serialize_long,
124
+ rl_list_node_deserialize_long,
125
+ rl_list_node_destroy,
126
+ };
127
+ rl_data_type rl_data_type_string = {
128
+ "rl_data_type_string",
129
+ rl_string_serialize,
130
+ rl_string_deserialize,
131
+ rl_string_destroy,
132
+ };
133
+
134
+ rl_data_type rl_data_type_skiplist = {
135
+ "rl_data_type_skiplist",
136
+ rl_skiplist_serialize,
137
+ rl_skiplist_deserialize,
138
+ rl_skiplist_destroy,
139
+ };
140
+
141
+ rl_data_type rl_data_type_skiplist_node = {
142
+ "rl_data_type_skiplist_node",
143
+ rl_skiplist_node_serialize,
144
+ rl_skiplist_node_deserialize,
145
+ rl_skiplist_node_destroy,
146
+ };
147
+ rl_data_type rl_data_type_long = {
148
+ "rl_data_type_long",
149
+ rl_long_serialize,
150
+ rl_long_deserialize,
151
+ rl_long_destroy,
152
+ };
153
+
154
+ rl_data_type rl_data_type_skiplist_node;
155
+
156
+ static const unsigned char *identifier = (unsigned char *)"rlite0.0";
157
+
158
+ static int file_driver_fp(rlite *db, int readonly)
159
+ {
160
+ int retval = RL_OK;
161
+ rl_file_driver *driver = db->driver;
162
+ if (driver->fp == NULL) {
163
+ if (!readonly && (driver->mode & RLITE_OPEN_READWRITE) == 0) {
164
+ fprintf(stderr, "Trying to write but open as readonly\n");
165
+ retval = RL_INVALID_PARAMETERS;
166
+ goto cleanup;
167
+ }
168
+ char *mode;
169
+ if (access(driver->filename, F_OK) == 0) {
170
+ if (readonly) {
171
+ mode = "r";
172
+ }
173
+ else {
174
+ mode = "r+";
175
+ }
176
+ }
177
+ else {
178
+ if ((driver->mode & RLITE_OPEN_READWRITE) == 0) {
179
+ fprintf(stderr, "Opening unexisting file in readonly mode\n");
180
+ retval = RL_INVALID_PARAMETERS;
181
+ goto cleanup;
182
+ }
183
+ mode = "w+";
184
+ }
185
+ driver->fp = fopen(driver->filename, mode);
186
+ if (driver->fp == NULL) {
187
+ fprintf(stderr, "Cannot open file %s, errno %d, mode %s\n", driver->filename, errno, mode);
188
+ perror(NULL);
189
+ retval = RL_UNEXPECTED;
190
+ goto cleanup;
191
+ }
192
+ }
193
+ cleanup:
194
+ return retval;
195
+ }
196
+
197
+ int rl_header_serialize(struct rlite *db, void *UNUSED(obj), unsigned char *data)
198
+ {
199
+ int identifier_len = strlen((char *)identifier);
200
+ memcpy(data, identifier, identifier_len);
201
+ put_4bytes(&data[identifier_len], db->page_size);
202
+ put_4bytes(&data[identifier_len + 4], db->next_empty_page);
203
+ put_4bytes(&data[identifier_len + 8], db->number_of_pages);
204
+ put_4bytes(&data[identifier_len + 12], db->number_of_databases);
205
+ long i, pos = identifier_len + 16;
206
+ for (i = 0; i < db->number_of_databases; i++) {
207
+ put_4bytes(&data[pos], db->databases[i]);
208
+ pos += 4;
209
+ }
210
+ return RL_OK;
211
+ }
212
+
213
+ int rl_header_deserialize(struct rlite *db, void **UNUSED(obj), void *UNUSED(context), unsigned char *data)
214
+ {
215
+ int retval = RL_OK;
216
+ int identifier_len = strlen((char *)identifier);
217
+ if (memcmp(data, identifier, identifier_len) != 0) {
218
+ fprintf(stderr, "Unexpected header, expecting %s\n", identifier);
219
+ return RL_INVALID_STATE;
220
+ }
221
+ db->page_size = get_4bytes(&data[identifier_len]);
222
+ db->next_empty_page = get_4bytes(&data[identifier_len + 4]);
223
+ db->initial_number_of_pages =
224
+ db->number_of_pages = get_4bytes(&data[identifier_len + 8]);
225
+ db->initial_number_of_databases =
226
+ db->number_of_databases = get_4bytes(&data[identifier_len + 12]);
227
+ RL_MALLOC(db->databases, sizeof(long) * db->number_of_databases);
228
+ RL_MALLOC(db->initial_databases, sizeof(long) * db->number_of_databases);
229
+
230
+ long i, pos = identifier_len + 16;
231
+ for (i = 0; i < db->number_of_databases; i++) {
232
+ db->initial_databases[i] =
233
+ db->databases[i] = get_4bytes(&data[pos]);
234
+ pos += 4;
235
+ }
236
+ cleanup:
237
+ return retval;
238
+ }
239
+
240
+ static int rl_ensure_pages(rlite *db)
241
+ {
242
+ int retval = RL_OK;
243
+ void *tmp;
244
+ if (rl_has_flag(db, RLITE_OPEN_READWRITE)) {
245
+ if (db->write_pages_len == db->write_pages_alloc) {
246
+ RL_REALLOC(db->write_pages, sizeof(rl_page *) * db->write_pages_alloc * 2)
247
+ db->write_pages_alloc *= 2;
248
+ }
249
+ }
250
+ if (db->read_pages_len == db->read_pages_alloc) {
251
+ RL_REALLOC(db->read_pages, sizeof(rl_page *) * db->read_pages_alloc * 2)
252
+ db->read_pages_alloc *= 2;
253
+ }
254
+ cleanup:
255
+ return retval;
256
+ }
257
+
258
+ int rl_open(const char *filename, rlite **_db, int flags)
259
+ {
260
+ rl_btree_init();
261
+ rl_list_init();
262
+ int retval = RL_OK;
263
+ rlite *db;
264
+ RL_MALLOC(db, sizeof(*db));
265
+
266
+ db->selected_database = 0;
267
+ db->page_size = DEFAULT_PAGE_SIZE;
268
+ db->read_pages = db->write_pages = NULL;
269
+ db->read_pages_alloc = db->read_pages_len = db->write_pages_len = db->write_pages_alloc = 0;
270
+
271
+ RL_MALLOC(db->read_pages, sizeof(rl_page *) * DEFAULT_READ_PAGES_LEN)
272
+ db->read_pages_len = 0;
273
+ db->read_pages_alloc = DEFAULT_READ_PAGES_LEN;
274
+ db->write_pages_len = 0;
275
+ if ((flags & RLITE_OPEN_READWRITE) > 0) {
276
+ db->write_pages_alloc = DEFAULT_WRITE_PAGES_LEN;
277
+ RL_MALLOC(db->write_pages, sizeof(rl_page *) * DEFAULT_WRITE_PAGES_LEN);
278
+ }
279
+ else {
280
+ db->write_pages_alloc = 0;
281
+ }
282
+
283
+ if (memcmp(filename, ":memory:", 9) == 0) {
284
+ rl_memory_driver *driver;
285
+ RL_MALLOC(driver, sizeof(*driver));
286
+ db->driver_type = RL_MEMORY_DRIVER;
287
+ db->driver = driver;
288
+ driver->data = NULL;
289
+ driver->datalen = 0;
290
+ }
291
+ else {
292
+ if ((flags & RLITE_OPEN_CREATE) == 0) {
293
+ int _access_flags;
294
+ if ((flags & RLITE_OPEN_READWRITE) != 0) {
295
+ _access_flags = W_OK;
296
+ }
297
+ else {
298
+ _access_flags = R_OK | F_OK;
299
+ }
300
+ if (access(filename, _access_flags) != 0) {
301
+ retval = RL_INVALID_PARAMETERS;
302
+ goto cleanup;
303
+ }
304
+ }
305
+
306
+ rl_file_driver *driver;
307
+ RL_MALLOC(driver, sizeof(*driver));
308
+ driver->fp = NULL;
309
+ driver->filename = rl_malloc(sizeof(char) * (strlen(filename) + 1));
310
+ if (!driver->filename) {
311
+ rl_free(driver);
312
+ retval = RL_OUT_OF_MEMORY;
313
+ goto cleanup;
314
+ }
315
+ strcpy(driver->filename, filename);
316
+ driver->mode = flags;
317
+ db->driver = driver;
318
+ db->driver_type = RL_FILE_DRIVER;
319
+ }
320
+
321
+ RL_CALL(rl_read_header, RL_OK, db);
322
+
323
+ *_db = db;
324
+ cleanup:
325
+ if (retval != RL_OK && db != NULL) {
326
+ rl_close(db);
327
+ }
328
+ return retval;
329
+ }
330
+
331
+ int rl_close(rlite *db)
332
+ {
333
+ if (!db) {
334
+ return RL_OK;
335
+ }
336
+ if (db->driver_type == RL_FILE_DRIVER) {
337
+ rl_file_driver *driver = db->driver;
338
+ if (driver->fp) {
339
+ fclose(driver->fp);
340
+ }
341
+ rl_free(driver->filename);
342
+ rl_free(db->driver);
343
+ }
344
+ else if (db->driver_type == RL_MEMORY_DRIVER) {
345
+ rl_memory_driver* driver = db->driver;
346
+ rl_free(driver->data);
347
+ rl_free(driver);
348
+ }
349
+ rl_discard(db);
350
+ rl_free(db->read_pages);
351
+ rl_free(db->write_pages);
352
+ rl_free(db->databases);
353
+ rl_free(db->initial_databases);
354
+ rl_free(db);
355
+ return RL_OK;
356
+ }
357
+
358
+ int rl_has_flag(rlite *db, int flag)
359
+ {
360
+ if (db->driver_type == RL_FILE_DRIVER) {
361
+ return (((rl_file_driver *)db->driver)->mode & flag) > 0;
362
+ }
363
+ else if (db->driver_type == RL_MEMORY_DRIVER) {
364
+ return 1;
365
+ }
366
+ fprintf(stderr, "Unknown driver_type %d\n", db->driver_type);
367
+ return RL_UNEXPECTED;
368
+ }
369
+
370
+ int rl_create_db(rlite *db)
371
+ {
372
+ int retval, i;
373
+ RL_CALL(rl_ensure_pages, RL_OK, db);
374
+ db->next_empty_page = 1;
375
+ db->initial_number_of_pages =
376
+ db->number_of_pages = 1;
377
+ db->selected_database = 0;
378
+ db->initial_number_of_databases =
379
+ db->number_of_databases = 16;
380
+ RL_MALLOC(db->databases, sizeof(long) * db->number_of_databases);
381
+ RL_MALLOC(db->initial_databases, sizeof(long) * db->number_of_databases);
382
+ for (i = 0; i < db->number_of_databases; i++) {
383
+ db->initial_databases[i] =
384
+ db->databases[i] = 0;
385
+ }
386
+ cleanup:
387
+ return retval;
388
+ }
389
+
390
+ int rl_get_key_btree(rlite *db, rl_btree **retbtree, int create)
391
+ {
392
+ void *_btree;
393
+ int retval;
394
+ if (!db->databases[db->selected_database]) {
395
+ if (!create) {
396
+ return RL_NOT_FOUND;
397
+ }
398
+ rl_btree *btree;
399
+ RL_CALL(rl_btree_create, RL_OK, db, &btree, &rl_btree_type_hash_sha1_key);
400
+ db->databases[db->selected_database] = db->next_empty_page;
401
+ RL_CALL(rl_write, RL_OK, db, &rl_data_type_btree_hash_sha1_key, db->databases[db->selected_database], btree);
402
+ }
403
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_btree_hash_sha1_key, db->databases[db->selected_database], &rl_btree_type_hash_sha1_key, &_btree, 1);
404
+ *retbtree = _btree;
405
+ retval = RL_OK;
406
+ cleanup:
407
+ return retval;
408
+ }
409
+
410
+ int rl_read_header(rlite *db)
411
+ {
412
+ db->page_size = HEADER_SIZE;
413
+ int retval;
414
+ if (db->driver_type == RL_MEMORY_DRIVER) {
415
+ db->page_size = DEFAULT_PAGE_SIZE;
416
+ RL_CALL(rl_create_db, RL_OK, db);
417
+ }
418
+ else {
419
+ retval = rl_read(db, &rl_data_type_header, 0, NULL, NULL, 1);
420
+ if (retval == RL_NOT_FOUND && rl_has_flag(db, RLITE_OPEN_CREATE)) {
421
+ db->page_size = DEFAULT_PAGE_SIZE;
422
+ RL_CALL(rl_create_db, RL_OK, db);
423
+ RL_CALL(rl_write, RL_OK, db, &rl_data_type_header, 0, NULL);
424
+ }
425
+ else if (retval != RL_FOUND) {
426
+ goto cleanup;
427
+ }
428
+ }
429
+ retval = RL_OK;
430
+ cleanup:
431
+ return retval;
432
+ }
433
+
434
+ #ifdef DEBUG
435
+ void print_cache(rlite *db)
436
+ {
437
+ printf("Cache read pages:");
438
+ long i;
439
+ rl_page *page;
440
+ for (i = 0; i < db->read_pages_len; i++) {
441
+ page = db->read_pages[i];
442
+ printf("%ld, ", page->page_number);
443
+ }
444
+ printf("\nCache write pages:");
445
+ for (i = 0; i < db->write_pages_len; i++) {
446
+ page = db->write_pages[i];
447
+ printf("%ld, ", page->page_number);
448
+ }
449
+ printf("\n");
450
+ }
451
+ #endif
452
+
453
+ #ifdef DEBUG
454
+ static int rl_search_cache(rlite *db, rl_data_type *type, long page_number, void **obj, long *position, rl_page **pages, long page_len)
455
+ #else
456
+ static int rl_search_cache(rlite *UNUSED(db), rl_data_type *UNUSED(type), long page_number, void **obj, long *position, rl_page **pages, long page_len)
457
+ #endif
458
+ {
459
+ long pos, min = 0, max = page_len - 1;
460
+ rl_page *page;
461
+ if (max >= 0) {
462
+ do {
463
+ pos = min + (max - min) / 2;
464
+ page = pages[pos];
465
+ if (page->page_number == page_number) {
466
+ #ifdef DEBUG
467
+ if (page->type != &rl_data_type_long && type != &rl_data_type_long && type != NULL && page->type != type) {
468
+ fprintf(stderr, "Type of page in cache (%s) doesn't match the asked one (%s)\n", page->type->name, type->name);
469
+ return RL_UNEXPECTED;
470
+ }
471
+ #endif
472
+ if (obj) {
473
+ *obj = page->obj;
474
+ }
475
+ if (position) {
476
+ *position = pos;
477
+ }
478
+ return RL_FOUND;
479
+ }
480
+ else if (page->page_number > page_number) {
481
+ max = pos - 1;
482
+ }
483
+ else {
484
+ min = pos + 1;
485
+ }
486
+ }
487
+ while (max >= min);
488
+ if (position) {
489
+ if (pages[pos]->page_number > page_number && pos > 0) {
490
+ pos--;
491
+ }
492
+ if (pages[pos]->page_number < page_number && pos < page_len) {
493
+ pos++;
494
+ }
495
+ #ifdef DEBUG
496
+ long i, prev;
497
+ rl_page *p;
498
+ for (i = 0; i < db->read_pages_len; i++) {
499
+ p = db->read_pages[i];
500
+ if (i > 0) {
501
+ if (prev >= p->page_number) {
502
+ fprintf(stderr, "Reading cache is broken\n");
503
+ print_cache(db);
504
+ return RL_UNEXPECTED;
505
+ }
506
+ }
507
+ prev = p->page_number;
508
+ }
509
+ for (i = 0; i < db->write_pages_len; i++) {
510
+ p = db->write_pages[i];
511
+ if (i > 0) {
512
+ if (prev >= p->page_number) {
513
+ fprintf(stderr, "Writing cache is broken\n");
514
+ print_cache(db);
515
+ return RL_UNEXPECTED;
516
+ }
517
+ }
518
+ prev = p->page_number;
519
+ }
520
+ #endif
521
+ *position = pos;
522
+ }
523
+ }
524
+ else {
525
+ if (position) {
526
+ *position = 0;
527
+ }
528
+ }
529
+ return RL_NOT_FOUND;
530
+ }
531
+
532
+ int rl_read_from_cache(rlite *db, rl_data_type *type, long page_number, void **obj)
533
+ {
534
+ int retval = rl_search_cache(db, type, page_number, obj, NULL, db->write_pages, db->write_pages_len);
535
+ if (retval == RL_NOT_FOUND) {
536
+ retval = rl_search_cache(db, type, page_number, obj, NULL, db->read_pages, db->read_pages_len);
537
+ }
538
+ return retval;
539
+ }
540
+
541
+ int rl_read(rlite *db, rl_data_type *type, long page, void *context, void **obj, int cache)
542
+ {
543
+ // fprintf(stderr, "r %ld %s\n", page, type->name);
544
+ #ifdef DEBUG
545
+ int keep = 0;
546
+ long initial_page_size = db->page_size;
547
+ if (page == 0 && type != &rl_data_type_header) {
548
+ VALGRIND_PRINTF_BACKTRACE("Unexpected");
549
+ return RL_UNEXPECTED;
550
+ }
551
+ #endif
552
+ unsigned char *data = NULL;
553
+ int retval;
554
+ unsigned char *serialize_data;
555
+ retval = rl_read_from_cache(db, type, page, obj);
556
+ if (retval != RL_NOT_FOUND) {
557
+ if (!cache) {
558
+ RL_MALLOC(serialize_data, db->page_size * sizeof(unsigned char));
559
+ retval = type->serialize(db, *obj, serialize_data);
560
+ if (retval != RL_OK) {
561
+ rl_free(serialize_data);
562
+ return retval;
563
+ }
564
+ retval = type->deserialize(db, obj, context, serialize_data);
565
+ rl_free(serialize_data);
566
+ if (retval != RL_OK) {
567
+ return retval;
568
+ }
569
+ retval = RL_FOUND;
570
+ }
571
+ return retval;
572
+ }
573
+ RL_MALLOC(data, db->page_size * sizeof(unsigned char));
574
+ if (db->driver_type == RL_FILE_DRIVER) {
575
+ RL_CALL(file_driver_fp, RL_OK, db, 1);
576
+ rl_file_driver *driver = db->driver;
577
+ fseek(driver->fp, page * db->page_size, SEEK_SET);
578
+ size_t read = fread(data, sizeof(unsigned char), db->page_size, driver->fp);
579
+ if (read != (size_t)db->page_size) {
580
+ if (page > 0) {
581
+ #ifdef DEBUG
582
+ print_cache(db);
583
+ #endif
584
+ fprintf(stderr, "Unable to read page %ld on line %d\n", page, __LINE__);
585
+ perror(NULL);
586
+ }
587
+ retval = RL_NOT_FOUND;
588
+ goto cleanup;
589
+ }
590
+ }
591
+ else if (db->driver_type == RL_MEMORY_DRIVER) {
592
+ rl_memory_driver *driver = db->driver;
593
+ if ((page + 1) * db->page_size > driver->datalen) {
594
+ fprintf(stderr, "Unable to read page %ld on line %d\n", page, __LINE__);
595
+ retval = RL_NOT_FOUND;
596
+ goto cleanup;
597
+ }
598
+ memcpy(data, &driver->data[page * db->page_size], sizeof(unsigned char) * db->page_size);
599
+ }
600
+ else {
601
+ fprintf(stderr, "Unexpected driver %d when asking for page %ld\n", db->driver_type, page);
602
+ retval = RL_UNEXPECTED;
603
+ goto cleanup;
604
+ }
605
+
606
+ long pos;
607
+ retval = rl_search_cache(db, type, page, NULL, &pos, db->read_pages, db->read_pages_len);
608
+ if (retval != RL_NOT_FOUND) {
609
+ fprintf(stderr, "Unexpectedly found page in cache\n");
610
+ retval = RL_UNEXPECTED;
611
+ goto cleanup;
612
+ }
613
+
614
+ retval = type->deserialize(db, obj, context ? context : type, data);
615
+ if (retval != RL_OK) {
616
+ goto cleanup;
617
+ }
618
+
619
+ if (cache) {
620
+ rl_ensure_pages(db);
621
+ rl_page *page_obj;
622
+ page_obj = rl_malloc(sizeof(*page_obj));
623
+ if (!page_obj) {
624
+ if (obj) {
625
+ if (type->destroy && *obj) {
626
+ type->destroy(db, *obj);
627
+ }
628
+ *obj = NULL;
629
+ }
630
+ retval = RL_OUT_OF_MEMORY;
631
+ goto cleanup;
632
+ }
633
+ page_obj->page_number = page;
634
+ page_obj->type = type;
635
+ page_obj->obj = obj ? *obj : NULL;
636
+ #ifdef DEBUG
637
+ keep = 1;
638
+ if (initial_page_size != db->page_size) {
639
+ page_obj->serialized_data = realloc(data, db->page_size * sizeof(unsigned char));
640
+ if (page_obj->serialized_data == NULL) {
641
+ fprintf(stderr, "realloc failed\n");
642
+ retval = RL_OUT_OF_MEMORY;
643
+ goto cleanup;
644
+ }
645
+ data = page_obj->serialized_data;
646
+ if (db->page_size > initial_page_size) {
647
+ memset(&data[initial_page_size], 0, db->page_size - initial_page_size);
648
+ }
649
+ }
650
+ else {
651
+ page_obj->serialized_data = data;
652
+ }
653
+
654
+ serialize_data = calloc(db->page_size, sizeof(unsigned char));
655
+ retval = type->serialize(db, obj ? *obj : NULL, serialize_data);
656
+ if (retval != RL_OK) {
657
+ goto cleanup;
658
+ }
659
+ if (memcmp(data, serialize_data, db->page_size) != 0) {
660
+ fprintf(stderr, "serialize unserialized data mismatch\n");
661
+ long i;
662
+ for (i = 0; i < db->page_size; i++) {
663
+ if (serialize_data[i] != data[i]) {
664
+ fprintf(stderr, "at position %ld expected %d, got %d\n", i, serialize_data[i], data[i]);
665
+ }
666
+ }
667
+ }
668
+ rl_free(serialize_data);
669
+ #endif
670
+ if (pos < db->read_pages_len) {
671
+ memmove(&db->read_pages[pos + 1], &db->read_pages[pos], sizeof(rl_page *) * (db->read_pages_len - pos));
672
+ }
673
+ db->read_pages[pos] = page_obj;
674
+ db->read_pages_len++;
675
+ }
676
+ if (retval == RL_OK) {
677
+ retval = RL_FOUND;
678
+ }
679
+ cleanup:
680
+ #ifdef DEBUG
681
+ if (!keep) {
682
+ rl_free(data);
683
+ }
684
+ #endif
685
+ #ifndef DEBUG
686
+ rl_free(data);
687
+ #endif
688
+ return retval;
689
+ }
690
+
691
+ int rl_alloc_page_number(rlite *db, long *_page_number)
692
+ {
693
+ int retval = RL_OK;
694
+ long page_number = db->next_empty_page;
695
+ if (page_number == db->number_of_pages) {
696
+ db->next_empty_page++;
697
+ db->number_of_pages++;
698
+ }
699
+ else {
700
+ RL_CALL(rl_long_get, RL_OK, db, &db->next_empty_page, db->next_empty_page);
701
+ }
702
+ if (_page_number) {
703
+ *_page_number = page_number;
704
+ }
705
+ cleanup:
706
+ return retval;
707
+ }
708
+
709
+ int rl_write(struct rlite *db, rl_data_type *type, long page_number, void *obj)
710
+ {
711
+ // fprintf(stderr, "w %ld %s\n", page_number, type->name);
712
+ rl_page *page = NULL;
713
+ long pos;
714
+ int retval;
715
+
716
+ if (page_number == db->next_empty_page) {
717
+ RL_CALL(rl_alloc_page_number, RL_OK, db, NULL);
718
+ retval = rl_write(db, &rl_data_type_header, 0, NULL);
719
+ if (retval != RL_OK) {
720
+ goto cleanup;
721
+ }
722
+ }
723
+
724
+ retval = rl_search_cache(db, type, page_number, NULL, &pos, db->write_pages, db->write_pages_len);
725
+ if (retval == RL_FOUND) {
726
+ if (obj != db->write_pages[pos]->obj) {
727
+ if (db->write_pages[pos]->obj) {
728
+ db->write_pages[pos]->type->destroy(db, db->write_pages[pos]->obj);
729
+ }
730
+ db->write_pages[pos]->obj = obj;
731
+ db->write_pages[pos]->type = type;
732
+ }
733
+ retval = RL_OK;
734
+ }
735
+ else if (retval == RL_NOT_FOUND) {
736
+ rl_ensure_pages(db);
737
+ RL_MALLOC(page, sizeof(*page));
738
+ #ifdef DEBUG
739
+ page->serialized_data = NULL;
740
+ #endif
741
+ page->page_number = page_number;
742
+ page->type = type;
743
+ page->obj = obj;
744
+ if (pos < db->write_pages_len) {
745
+ memmove(&db->write_pages[pos + 1], &db->write_pages[pos], sizeof(rl_page *) * (db->write_pages_len - pos));
746
+ }
747
+ db->write_pages[pos] = page;
748
+ db->write_pages_len++;
749
+
750
+ retval = rl_search_cache(db, type, page_number, NULL, &pos, db->read_pages, db->read_pages_len);
751
+ if (retval == RL_FOUND) {
752
+ #ifdef DEBUG
753
+ rl_free(db->read_pages[pos]->serialized_data);
754
+ #endif
755
+ if (db->read_pages[pos]->obj != obj) {
756
+ db->read_pages[pos]->type->destroy(db, db->read_pages[pos]->obj);
757
+ }
758
+ rl_free(db->read_pages[pos]);
759
+ memmove(&db->read_pages[pos], &db->read_pages[pos + 1], sizeof(rl_page *) * (db->read_pages_len - pos));
760
+ db->read_pages_len--;
761
+ retval = RL_OK;
762
+ }
763
+ else if (retval != RL_NOT_FOUND) {
764
+ goto cleanup;
765
+ }
766
+ retval = RL_OK;
767
+ }
768
+
769
+ cleanup:
770
+ if (retval != RL_OK) {
771
+ if (obj) {
772
+ type->destroy(db, obj);
773
+ rl_purge_cache(db, page_number);
774
+ }
775
+ if (page_number != 0) {
776
+ rl_discard(db);
777
+ }
778
+ }
779
+ return retval;
780
+ }
781
+
782
+ int rl_purge_cache(struct rlite *db, long page_number)
783
+ {
784
+ long pos;
785
+ int retval;
786
+ retval = rl_search_cache(db, NULL, page_number, NULL, &pos, db->write_pages, db->write_pages_len);
787
+ if (retval == RL_FOUND) {
788
+ db->write_pages[pos]->obj = NULL;
789
+ }
790
+ else if (retval != RL_NOT_FOUND) {
791
+ goto cleanup;
792
+ }
793
+ retval = rl_search_cache(db, NULL, page_number, NULL, &pos, db->read_pages, db->read_pages_len);
794
+ if (retval == RL_FOUND) {
795
+ db->read_pages[pos]->obj = NULL;
796
+ }
797
+ else if (retval != RL_NOT_FOUND) {
798
+ goto cleanup;
799
+ }
800
+ retval = RL_OK;
801
+ cleanup:
802
+ return retval;
803
+ }
804
+
805
+ int rl_delete(struct rlite *db, long page_number)
806
+ {
807
+ int retval;
808
+ RL_CALL(rl_long_set, RL_OK, db, db->next_empty_page, page_number);
809
+ db->next_empty_page = page_number;
810
+ cleanup:
811
+ return retval;
812
+ }
813
+
814
+ int rl_dirty_hash(struct rlite *db, unsigned char **hash)
815
+ {
816
+ long i;
817
+ int retval = RL_OK;
818
+ rl_page *page;
819
+ SHA1_CTX sha;
820
+ unsigned char *data = NULL;
821
+
822
+ if (db->write_pages_len == 0) {
823
+ *hash = NULL;
824
+ goto cleanup;
825
+ }
826
+
827
+ RL_MALLOC(data, db->page_size * sizeof(unsigned char));
828
+ RL_MALLOC(*hash, sizeof(unsigned char) * 20);
829
+ SHA1Init(&sha);
830
+ for (i = 0; i < db->write_pages_len; i++) {
831
+ page = db->write_pages[i];
832
+ memset(data, 0, db->page_size);
833
+ if (page->type) {
834
+ retval = page->type->serialize(db, page->obj, data);
835
+ }
836
+ SHA1Update(&sha, data, db->page_size);
837
+ }
838
+ SHA1Final(*hash, &sha);
839
+ cleanup:
840
+ rl_free(data);
841
+ if (retval != RL_OK) {
842
+ rl_free(*hash);
843
+ *hash = NULL;
844
+ }
845
+ return retval;
846
+ }
847
+
848
+ int rl_commit(struct rlite *db)
849
+ {
850
+ int retval = RL_OK;
851
+ long i, page_number;
852
+ rl_page *page;
853
+ size_t written;
854
+ unsigned char *data;
855
+ RL_MALLOC(data, db->page_size * sizeof(unsigned char));
856
+ #ifdef DEBUG
857
+ for (i = 0; i < db->read_pages_len; i++) {
858
+ page = db->read_pages[i];
859
+ memset(data, 0, db->page_size);
860
+ retval = page->type->serialize(db, page->obj, data);
861
+ if (retval != RL_OK) {
862
+ goto cleanup;
863
+ }
864
+ if (memcmp(data, page->serialized_data, db->page_size) != 0) {
865
+ fprintf(stderr, "Read page %ld (%s) has changed\n", page->page_number, page->type->name);
866
+ for (i = 0; i < db->page_size; i++) {
867
+ if (page->serialized_data[i] != data[i]) {
868
+ fprintf(stderr, "Different data in position %ld (expected %d, got %d)\n", i, page->serialized_data[i], data[i]);
869
+ }
870
+ }
871
+ retval = rl_search_cache(db, page->type, page->page_number, NULL, NULL, db->write_pages, db->write_pages_len);
872
+ if (retval == RL_FOUND) {
873
+ fprintf(stderr, "Page found in write_pages\n");
874
+ }
875
+ else {
876
+ fprintf(stderr, "Page not found in write_pages\n");
877
+ }
878
+ exit(1);
879
+ }
880
+ }
881
+ #endif
882
+ if (db->driver_type == RL_FILE_DRIVER) {
883
+ rl_file_driver *driver = db->driver;
884
+ if (driver->fp) {
885
+ fclose(driver->fp);
886
+ driver->fp = NULL;
887
+ }
888
+ RL_CALL(file_driver_fp, RL_OK, db, 0);
889
+ for (i = 0; i < db->write_pages_len; i++) {
890
+ page = db->write_pages[i];
891
+ page_number = page->page_number;
892
+ memset(data, 0, db->page_size);
893
+ if (page->type) {
894
+ retval = page->type->serialize(db, page->obj, data);
895
+ }
896
+ fseek(driver->fp, page_number * db->page_size, SEEK_SET);
897
+ written = fwrite(data, sizeof(unsigned char), db->page_size, driver->fp);
898
+ if ((size_t)db->page_size != written) {
899
+ #ifdef DEBUG
900
+ print_cache(db);
901
+ #endif
902
+ retval = RL_UNEXPECTED;
903
+ goto cleanup;
904
+ }
905
+ }
906
+ }
907
+ else if (db->driver_type == RL_MEMORY_DRIVER) {
908
+ rl_memory_driver *driver = db->driver;
909
+ if (db->write_pages_len > 0) {
910
+ page = db->write_pages[db->write_pages_len - 1];
911
+ if ((page->page_number + 1) * db->page_size > driver->datalen) {
912
+ void *tmp = realloc(driver->data, (page->page_number + 1) * db->page_size * sizeof(unsigned char));
913
+ if (!tmp) {
914
+ retval = RL_OUT_OF_MEMORY;
915
+ goto cleanup;
916
+ }
917
+ driver->data = tmp;
918
+ driver->datalen = (page->page_number + 1) * db->page_size;
919
+ }
920
+ }
921
+ for (i = 0; i < db->write_pages_len; i++) {
922
+ page = db->write_pages[i];
923
+ page_number = page->page_number;
924
+ memset(data, 0, db->page_size);
925
+ if (page->type) {
926
+ retval = page->type->serialize(db, page->obj, data);
927
+ }
928
+ memcpy(&driver->data[page_number * db->page_size], data, db->page_size);
929
+ }
930
+ }
931
+ db->initial_number_of_pages = db->number_of_pages;
932
+ db->initial_number_of_databases = db->number_of_databases;
933
+ rl_free(db->initial_databases);
934
+ RL_MALLOC(db->initial_databases, sizeof(long) * db->number_of_databases);
935
+ memcpy(db->initial_databases, db->databases, sizeof(long) * db->number_of_databases);
936
+ rl_discard(db);
937
+ rl_free(data);
938
+ cleanup:
939
+ return retval;
940
+ }
941
+
942
+ int rl_discard(struct rlite *db)
943
+ {
944
+ long i;
945
+ void *tmp;
946
+ int retval = RL_OK;
947
+
948
+ db->number_of_pages = db->initial_number_of_pages;
949
+ db->number_of_databases = db->initial_number_of_databases;
950
+ rl_free(db->databases);
951
+ RL_MALLOC(db->databases, sizeof(long) * db->number_of_databases);
952
+ memcpy(db->databases, db->initial_databases, sizeof(long) * db->number_of_databases);
953
+ rl_page *page;
954
+ for (i = 0; i < db->read_pages_len; i++) {
955
+ page = db->read_pages[i];
956
+ if (page->type->destroy && page->obj) {
957
+ page->type->destroy(db, page->obj);
958
+ }
959
+ #ifdef DEBUG
960
+ rl_free(page->serialized_data);
961
+ #endif
962
+ rl_free(page);
963
+ }
964
+ for (i = 0; i < db->write_pages_len; i++) {
965
+ page = db->write_pages[i];
966
+ if (page->type && page->type->destroy && page->obj) {
967
+ page->type->destroy(db, page->obj);
968
+ }
969
+ #ifdef DEBUG
970
+ rl_free(page->serialized_data);
971
+ #endif
972
+ rl_free(page);
973
+ }
974
+ db->read_pages_len = 0;
975
+ db->write_pages_len = 0;
976
+
977
+ if (db->read_pages_alloc != DEFAULT_READ_PAGES_LEN) {
978
+ tmp = realloc(db->read_pages, sizeof(rl_page *) * DEFAULT_READ_PAGES_LEN);
979
+ if (!tmp) {
980
+ retval = RL_OUT_OF_MEMORY;
981
+ goto cleanup;
982
+ }
983
+ db->read_pages = tmp;
984
+ db->read_pages_alloc = DEFAULT_READ_PAGES_LEN;
985
+ }
986
+ if (db->write_pages_alloc > 0) {
987
+ if (db->write_pages_alloc != DEFAULT_WRITE_PAGES_LEN) {
988
+ db->write_pages_alloc = DEFAULT_WRITE_PAGES_LEN;
989
+ tmp = realloc(db->write_pages, sizeof(rl_page *) * DEFAULT_WRITE_PAGES_LEN);
990
+ if (!tmp) {
991
+ retval = RL_OUT_OF_MEMORY;
992
+ goto cleanup;
993
+ }
994
+ db->write_pages = tmp;
995
+ }
996
+ }
997
+ cleanup:
998
+ return retval;
999
+ }
1000
+
1001
+ int rl_database_is_balanced(rlite *db, short *pages)
1002
+ {
1003
+ int retval;
1004
+ void *tmp = NULL;
1005
+ rl_key *key;
1006
+ rl_btree *btree;
1007
+ rl_btree_iterator *iterator = NULL;
1008
+ retval = rl_get_key_btree(db, &btree, 0);
1009
+ if (retval == RL_NOT_FOUND) {
1010
+ retval = RL_OK;
1011
+ goto cleanup;
1012
+ }
1013
+ else if (retval != RL_OK) {
1014
+ goto cleanup;
1015
+ }
1016
+
1017
+ RL_CALL(rl_btree_pages, RL_OK, db, btree, pages);
1018
+ RL_CALL(rl_btree_iterator_create, RL_OK, db, btree, &iterator);
1019
+
1020
+ while ((retval = rl_btree_iterator_next(iterator, NULL, &tmp)) == RL_OK) {
1021
+ key = tmp;
1022
+ pages[key->string_page] = 1;
1023
+ pages[key->value_page] = 1;
1024
+ RL_CALL(rl_multi_string_pages, RL_OK, db, key->string_page, pages);
1025
+ if (key->type == RL_TYPE_ZSET) {
1026
+ retval = rl_zset_pages(db, key->value_page, pages);
1027
+ }
1028
+ else if (key->type == RL_TYPE_HASH) {
1029
+ retval = rl_hash_pages(db, key->value_page, pages);
1030
+ }
1031
+ else if (key->type == RL_TYPE_SET) {
1032
+ retval = rl_set_pages(db, key->value_page, pages);
1033
+ }
1034
+ else if (key->type == RL_TYPE_LIST) {
1035
+ retval = rl_llist_pages(db, key->value_page, pages);
1036
+ }
1037
+ else if (key->type == RL_TYPE_STRING) {
1038
+ retval = rl_string_pages(db, key->value_page, pages);
1039
+ }
1040
+ else {
1041
+ fprintf(stderr, "Unknown type %d\n", key->type);
1042
+ goto cleanup;
1043
+ }
1044
+ if (retval != RL_OK) {
1045
+ goto cleanup;
1046
+ }
1047
+ rl_free(tmp);
1048
+ }
1049
+ tmp = NULL;
1050
+ iterator = NULL;
1051
+
1052
+ if (retval != RL_END) {
1053
+ goto cleanup;
1054
+ }
1055
+
1056
+ retval = RL_OK;
1057
+
1058
+ cleanup:
1059
+ rl_free(tmp);
1060
+ if (iterator) {
1061
+ rl_btree_iterator_destroy(iterator);
1062
+ }
1063
+ return retval;
1064
+ }
1065
+
1066
+ int rl_is_balanced(rlite *db)
1067
+ {
1068
+ int retval;
1069
+ long i, selected_database = db->selected_database;
1070
+ short *pages = NULL;
1071
+ long missing_pages = 0;
1072
+ RL_MALLOC(pages, sizeof(short) * db->number_of_pages);
1073
+
1074
+ for (i = 1; i < db->number_of_pages; i++) {
1075
+ pages[i] = 0;
1076
+ }
1077
+
1078
+ for (i = 0; i < db->number_of_databases; i++) {
1079
+ if (db->databases[i] == 0) {
1080
+ continue;
1081
+ }
1082
+ pages[db->databases[i]] = 1;
1083
+ RL_CALL(rl_select, RL_OK, db, i);
1084
+ RL_CALL(rl_database_is_balanced, RL_OK, db, pages);
1085
+ }
1086
+
1087
+ RL_CALL(rl_select, RL_OK, db, selected_database);
1088
+
1089
+ long page_number = db->next_empty_page;
1090
+ while (page_number != db->number_of_pages) {
1091
+ pages[page_number] = 1;
1092
+ RL_CALL(rl_long_get, RL_OK, db, &page_number, page_number);
1093
+ }
1094
+
1095
+ for (i = 1; i < db->number_of_pages; i++) {
1096
+ if (pages[i] == 0) {
1097
+ fprintf(stderr, "Found orphan page %ld\n", i);
1098
+ missing_pages++;
1099
+ }
1100
+ }
1101
+
1102
+ if (missing_pages) {
1103
+ fprintf(stderr, "Missing %ld pages\n", missing_pages);
1104
+ retval = RL_UNEXPECTED;
1105
+ }
1106
+ cleanup:
1107
+ rl_free(pages);
1108
+ return retval;
1109
+ }
1110
+
1111
+ int rl_select(struct rlite *db, int selected_database)
1112
+ {
1113
+ if (selected_database < 0 || selected_database >= db->number_of_databases) {
1114
+ return RL_INVALID_PARAMETERS;
1115
+ }
1116
+ db->selected_database = selected_database;
1117
+ return RL_OK;
1118
+ }
1119
+
1120
+ int rl_move(struct rlite *db, unsigned char *key, long keylen, int database)
1121
+ {
1122
+ int retval;
1123
+ int olddb = db->selected_database;
1124
+ unsigned char type;
1125
+ unsigned long long expires;
1126
+ long value_page;
1127
+ // this could be more efficient, if we don't delete the value page
1128
+ RL_CALL(rl_key_get, RL_FOUND, db, key, keylen, &type, NULL, &value_page, &expires, NULL);
1129
+ RL_CALL(rl_select, RL_OK, db, database);
1130
+ RL_CALL(rl_key_get, RL_NOT_FOUND, db, key, keylen, NULL, NULL, NULL, NULL, NULL);
1131
+ RL_CALL(rl_select, RL_OK, db, olddb);
1132
+ RL_CALL(rl_key_delete, RL_OK, db, key, keylen);
1133
+ RL_CALL(rl_select, RL_OK, db, database);
1134
+ RL_CALL(rl_key_set, RL_OK, db, key, keylen, type, value_page, expires, 0);
1135
+ retval = RL_OK;
1136
+ cleanup:
1137
+ rl_select(db, olddb);
1138
+ return retval;
1139
+ }
1140
+
1141
+ int rl_rename(struct rlite *db, const unsigned char *src, long srclen, const unsigned char *target, long targetlen, int overwrite)
1142
+ {
1143
+ int retval;
1144
+ unsigned char type;
1145
+ unsigned long long expires;
1146
+ long value_page;
1147
+ long version = 0;
1148
+ if (overwrite) {
1149
+ RL_CALL2(rl_key_get, RL_FOUND, RL_NOT_FOUND, db, target, targetlen, NULL, NULL, NULL, NULL, &version);
1150
+ if (retval == RL_FOUND) {
1151
+ RL_CALL(rl_key_delete_with_value, RL_OK, db, target, targetlen);
1152
+ version++;
1153
+ }
1154
+ }
1155
+ else {
1156
+ RL_CALL(rl_key_get, RL_NOT_FOUND, db, target, targetlen, NULL, NULL, NULL, NULL, NULL);
1157
+ }
1158
+ // this could be more efficient, if we don't delete the value page
1159
+ RL_CALL(rl_key_get, RL_FOUND, db, src, srclen, &type, NULL, &value_page, &expires, NULL);
1160
+ RL_CALL(rl_key_delete, RL_OK, db, src, srclen);
1161
+ RL_CALL(rl_key_set, RL_OK, db, target, targetlen, type, value_page, expires, version);
1162
+ retval = RL_OK;
1163
+ cleanup:
1164
+ return retval;
1165
+ }
1166
+
1167
+ int rl_dbsize(struct rlite *db, long *size)
1168
+ {
1169
+ int retval;
1170
+ rl_btree *btree;
1171
+ retval = rl_get_key_btree(db, &btree, 0);
1172
+ if (retval == RL_NOT_FOUND) {
1173
+ *size = 0;
1174
+ retval = RL_OK;
1175
+ goto cleanup;
1176
+ }
1177
+ else if (retval != RL_OK) {
1178
+ goto cleanup;
1179
+ }
1180
+ *size = btree->number_of_elements;
1181
+ retval = RL_OK;
1182
+ cleanup:
1183
+ return retval;
1184
+ }
1185
+
1186
+ int rl_keys(struct rlite *db, unsigned char *pattern, long patternlen, long *_len, unsigned char ***_result, long **_resultlen)
1187
+ {
1188
+ int retval;
1189
+ rl_btree *btree;
1190
+ rl_btree_iterator *iterator;
1191
+ rl_key *key;
1192
+ void *tmp;
1193
+ long alloc, len;
1194
+ unsigned char **result = NULL, *keystr;
1195
+ long *resultlen = NULL, keystrlen;
1196
+ retval = rl_get_key_btree(db, &btree, 0);
1197
+ if (retval == RL_NOT_FOUND) {
1198
+ *_len = 0;
1199
+ *_result = NULL;
1200
+ *_resultlen = NULL;
1201
+ retval = RL_OK;
1202
+ goto cleanup;
1203
+ }
1204
+ else if (retval != RL_OK) {
1205
+ goto cleanup;
1206
+ }
1207
+
1208
+ RL_CALL(rl_btree_iterator_create, RL_OK, db, btree, &iterator);
1209
+
1210
+ len = 0;
1211
+ alloc = 16;
1212
+ RL_MALLOC(result, sizeof(unsigned char *) * alloc);
1213
+ RL_MALLOC(resultlen, sizeof(long) * alloc);
1214
+ int allkeys = patternlen == 1 && pattern[0] == '*';
1215
+ while ((retval = rl_btree_iterator_next(iterator, NULL, &tmp)) == RL_OK) {
1216
+ key = tmp;
1217
+ RL_CALL(rl_multi_string_get, RL_OK, db, key->string_page, &keystr, &keystrlen);
1218
+ if (allkeys || rl_stringmatchlen((char *)pattern, patternlen, (char *)keystr, keystrlen, 0)) {
1219
+ if (len + 1 == alloc) {
1220
+ RL_REALLOC(result, sizeof(unsigned char *) * alloc * 2)
1221
+ RL_REALLOC(resultlen, sizeof(long) * alloc * 2)
1222
+ alloc *= 2;
1223
+ }
1224
+ result[len] = keystr;
1225
+ resultlen[len] = keystrlen;
1226
+ len++;
1227
+ }
1228
+ else {
1229
+ rl_free(keystr);
1230
+ }
1231
+ rl_free(key);
1232
+ }
1233
+
1234
+ if (retval != RL_END) {
1235
+ goto cleanup;
1236
+ }
1237
+
1238
+ // TODO: should we realloc to shrink the result?
1239
+ *_len = len;
1240
+ *_result = result;
1241
+ *_resultlen = resultlen;
1242
+
1243
+ retval = RL_OK;
1244
+ cleanup:
1245
+ if (retval != RL_OK) {
1246
+ rl_free(result);
1247
+ rl_free(resultlen);
1248
+ }
1249
+ return retval;
1250
+ }
1251
+
1252
+ int rl_randomkey(struct rlite *db, unsigned char **key, long *keylen)
1253
+ {
1254
+ int retval;
1255
+ rl_btree *btree;
1256
+ rl_key *key_obj;
1257
+ RL_CALL(rl_get_key_btree, RL_OK, db, &btree, 0);
1258
+ RL_CALL(rl_btree_random_element, RL_OK, db, btree, NULL, (void **)&key_obj);
1259
+ RL_CALL(rl_multi_string_get, RL_OK, db, key_obj->string_page, key, keylen);
1260
+ cleanup:
1261
+ return retval;
1262
+ }
1263
+
1264
+ int rl_flushdb(struct rlite *db)
1265
+ {
1266
+ int retval;
1267
+ rl_btree *btree;
1268
+ rl_btree_iterator *iterator = NULL;
1269
+ rl_key *key;
1270
+ void *tmp;
1271
+ RL_CALL2(rl_get_key_btree, RL_OK, RL_NOT_FOUND, db, &btree, 0);
1272
+ if (retval == RL_NOT_FOUND) {
1273
+ retval = RL_OK;
1274
+ goto cleanup;
1275
+ }
1276
+
1277
+ RL_CALL(rl_btree_iterator_create, RL_OK, db, btree, &iterator);
1278
+
1279
+ while ((retval = rl_btree_iterator_next(iterator, NULL, &tmp)) == RL_OK) {
1280
+ key = tmp;
1281
+ RL_CALL(rl_key_delete_value, RL_OK, db, key->type, key->value_page);
1282
+ RL_CALL(rl_multi_string_delete, RL_OK, db, key->string_page);
1283
+ rl_free(key);
1284
+ }
1285
+ if (retval != RL_END) {
1286
+ goto cleanup;
1287
+ }
1288
+ RL_CALL(rl_btree_delete, RL_OK, db, btree);
1289
+ RL_CALL(rl_delete, RL_OK, db, db->databases[db->selected_database]);
1290
+ db->databases[db->selected_database] = 0;
1291
+ RL_CALL(rl_write, RL_OK, db, &rl_data_type_header, 0, NULL);
1292
+ retval = RL_OK;
1293
+ cleanup:
1294
+ return retval;
1295
+ }
1296
+
1297
+ int rl_flushall(struct rlite *db)
1298
+ {
1299
+ int retval, i;
1300
+ int selected_database = db->selected_database;
1301
+
1302
+ for (i = 0; i < db->number_of_databases; i++) {
1303
+ db->selected_database = i;
1304
+ RL_CALL(rl_flushdb, RL_OK, db);
1305
+ }
1306
+ db->selected_database = selected_database;
1307
+ cleanup:
1308
+ return retval;
1309
+ }