hirlite 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }