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,796 @@
1
+ #include <stdlib.h>
2
+ #include "rlite.h"
3
+ #include "page_multi_string.h"
4
+ #include "type_set.h"
5
+ #include "page_btree.h"
6
+ #include "util.h"
7
+
8
+ static int rl_set_create(rlite *db, long btree_page, rl_btree **btree)
9
+ {
10
+ rl_btree *set = NULL;
11
+
12
+ int retval;
13
+ RL_CALL(rl_btree_create, RL_OK, db, &set, &rl_btree_type_hash_sha1_long);
14
+ RL_CALL(rl_write, RL_OK, db, &rl_data_type_btree_hash_sha1_long, btree_page, set);
15
+
16
+ if (btree) {
17
+ *btree = set;
18
+ }
19
+ cleanup:
20
+ return retval;
21
+ }
22
+
23
+ static int rl_set_read(rlite *db, long set_page_number, rl_btree **btree)
24
+ {
25
+ void *tmp;
26
+ int retval;
27
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_btree_hash_sha1_long, set_page_number, &rl_btree_type_hash_sha1_long, &tmp, 1);
28
+ if (btree) {
29
+ *btree = tmp;
30
+ }
31
+ retval = RL_OK;
32
+ cleanup:
33
+ return retval;
34
+ }
35
+
36
+ int rl_set_get_objects(rlite *db, const unsigned char *key, long keylen, long *_set_page_number, rl_btree **btree, int update_version, int create)
37
+ {
38
+ long set_page_number, version;
39
+ int retval;
40
+ unsigned long long expires = 0;
41
+ if (create) {
42
+ retval = rl_key_get_or_create(db, key, keylen, RL_TYPE_SET, &set_page_number, &version);
43
+ if (retval != RL_FOUND && retval != RL_NOT_FOUND) {
44
+ goto cleanup;
45
+ }
46
+ else if (retval == RL_NOT_FOUND) {
47
+ retval = rl_set_create(db, set_page_number, btree);
48
+ goto cleanup;
49
+ }
50
+ else {
51
+ RL_CALL(rl_set_read, RL_OK, db, set_page_number, btree);
52
+ }
53
+ }
54
+ else {
55
+ unsigned char type;
56
+ retval = rl_key_get(db, key, keylen, &type, NULL, &set_page_number, NULL, &version);
57
+ if (retval != RL_FOUND) {
58
+ goto cleanup;
59
+ }
60
+ if (type != RL_TYPE_SET) {
61
+ retval = RL_WRONG_TYPE;
62
+ goto cleanup;
63
+ }
64
+ RL_CALL(rl_set_read, RL_OK, db, set_page_number, btree);
65
+ }
66
+ if (update_version) {
67
+ RL_CALL(rl_key_set, RL_OK, db, key, keylen, RL_TYPE_SET, set_page_number, expires, version + 1);
68
+ }
69
+ cleanup:
70
+ if (_set_page_number) {
71
+ *_set_page_number = set_page_number;
72
+ }
73
+ return retval;
74
+ }
75
+ int rl_sadd(struct rlite *db, const unsigned char *key, long keylen, int memberc, unsigned char **members, long *memberslen, long *added)
76
+ {
77
+ int i, retval;
78
+ long set_page_number;
79
+ rl_btree *set;
80
+ unsigned char *digest = NULL;
81
+ long *member = NULL;
82
+ long count = 0;
83
+ void *tmp;
84
+ RL_CALL(rl_set_get_objects, RL_OK, db, key, keylen, &set_page_number, &set, 1, 1);
85
+
86
+ for (i = 0; i < memberc; i++) {
87
+ RL_MALLOC(digest, sizeof(unsigned char) * 20);
88
+ RL_CALL(sha1, RL_OK, members[i], memberslen[i], digest);
89
+
90
+ retval = rl_btree_find_score(db, set, digest, &tmp, NULL, NULL);
91
+ if (retval == RL_NOT_FOUND) {
92
+ RL_MALLOC(member, sizeof(*member));
93
+ RL_CALL(rl_multi_string_set, RL_OK, db, member, members[i], memberslen[i]);
94
+ RL_CALL(rl_btree_add_element, RL_OK, db, set, set_page_number, digest, member);
95
+ count++;
96
+ }
97
+ else if (retval == RL_FOUND) {
98
+ rl_free(digest);
99
+ digest = NULL;
100
+ }
101
+ else {
102
+ goto cleanup;
103
+ }
104
+ }
105
+ if (added) {
106
+ *added = count;
107
+ }
108
+ retval = RL_OK;
109
+ cleanup:
110
+ if (retval != RL_OK) {
111
+ rl_free(digest);
112
+ rl_free(member);
113
+ }
114
+ return retval;
115
+ }
116
+
117
+ int rl_srem(struct rlite *db, const unsigned char *key, long keylen, int membersc, unsigned char **members, long *memberslen, long *delcount)
118
+ {
119
+ int retval;
120
+ long set_page_number;
121
+ rl_btree *set;
122
+ long member;
123
+ void *tmp;
124
+ long i;
125
+ long deleted = 0;
126
+ int keydeleted = 0;
127
+ unsigned char digest[20];
128
+ RL_CALL(rl_set_get_objects, RL_OK, db, key, keylen, &set_page_number, &set, 1, 0);
129
+
130
+ for (i = 0; i < membersc; i++) {
131
+ RL_CALL(sha1, RL_OK, members[i], memberslen[i], digest);
132
+ retval = rl_btree_find_score(db, set, digest, &tmp, NULL, NULL);
133
+ if (retval == RL_FOUND) {
134
+ deleted++;
135
+ member = *(long *)tmp;
136
+ rl_multi_string_delete(db, member);
137
+ retval = rl_btree_remove_element(db, set, set_page_number, digest);
138
+ if (retval != RL_OK && retval != RL_DELETED) {
139
+ goto cleanup;
140
+ }
141
+ if (retval == RL_DELETED) {
142
+ keydeleted = 1;
143
+ break;
144
+ }
145
+ }
146
+ }
147
+ if (delcount) {
148
+ *delcount = deleted;
149
+ }
150
+ if (keydeleted) {
151
+ RL_CALL(rl_key_delete, RL_OK, db, key, keylen);
152
+ }
153
+ retval = RL_OK;
154
+ cleanup:
155
+ return retval;
156
+ }
157
+
158
+ int rl_sismember(struct rlite *db, const unsigned char *key, long keylen, unsigned char *member, long memberlen)
159
+ {
160
+ int retval;
161
+ long set_page_number;
162
+ rl_btree *set;
163
+ unsigned char digest[20];
164
+ RL_CALL(rl_set_get_objects, RL_OK, db, key, keylen, &set_page_number, &set, 0, 0);
165
+
166
+ RL_CALL(sha1, RL_OK, member, memberlen, digest);
167
+
168
+ retval = rl_btree_find_score(db, set, digest, NULL, NULL, NULL);
169
+ cleanup:
170
+ return retval;
171
+ }
172
+
173
+ int rl_scard(struct rlite *db, const unsigned char *key, long keylen, long *card)
174
+ {
175
+ int retval;
176
+ long set_page_number;
177
+ rl_btree *set;
178
+ RL_CALL(rl_set_get_objects, RL_OK, db, key, keylen, &set_page_number, &set, 0, 0);
179
+
180
+ *card = set->number_of_elements;
181
+ cleanup:
182
+ return retval;
183
+ }
184
+
185
+ int rl_smove(struct rlite *db, const unsigned char *source, long sourcelen, const unsigned char *destination, long destinationlen, unsigned char *member, long memberlen)
186
+ {
187
+ rl_btree *source_hash, *target_hash;
188
+ void *tmp;
189
+ long target_page_number, source_page_number, *member_page_number;
190
+ int retval;
191
+ unsigned char *digest = NULL;
192
+ // make sure the target key is a set or does not exist
193
+ RL_CALL2(rl_set_get_objects, RL_OK, RL_NOT_FOUND, db, destination, destinationlen, NULL, NULL, 0, 0);
194
+
195
+ RL_MALLOC(digest, sizeof(unsigned char) * 20);
196
+ RL_CALL(sha1, RL_OK, member, memberlen, digest);
197
+ RL_CALL(rl_set_get_objects, RL_OK, db, source, sourcelen, &source_page_number, &source_hash, 1, 0);
198
+ retval = rl_btree_find_score(db, source_hash, digest, &tmp, NULL, NULL);
199
+ if (retval == RL_FOUND) {
200
+ rl_multi_string_delete(db, *(long *)tmp);
201
+ retval = rl_btree_remove_element(db, source_hash, source_page_number, digest);
202
+ if (retval == RL_DELETED) {
203
+ RL_CALL(rl_key_delete, RL_OK, db, source, sourcelen);
204
+ }
205
+ else if (retval != RL_OK) {
206
+ goto cleanup;
207
+ }
208
+ }
209
+ else {
210
+ goto cleanup;
211
+ }
212
+ RL_CALL(rl_set_get_objects, RL_OK, db, destination, destinationlen, &target_page_number, &target_hash, 1, 1);
213
+ RL_MALLOC(member_page_number, sizeof(*member_page_number))
214
+ RL_CALL(rl_multi_string_set, RL_OK, db, member_page_number, member, memberlen);
215
+ RL_CALL(rl_btree_add_element, RL_OK, db, target_hash, target_page_number, digest, member_page_number);
216
+ cleanup:
217
+ if (retval != RL_OK) {
218
+ rl_free(digest);
219
+ }
220
+ return retval;
221
+ }
222
+
223
+ int rl_set_iterator_next(rl_set_iterator *iterator, unsigned char **member, long *memberlen)
224
+ {
225
+ void *tmp;
226
+ long page;
227
+ int retval = rl_btree_iterator_next(iterator, NULL, &tmp);
228
+ if (retval == RL_OK) {
229
+ page = *(long *)tmp;
230
+ rl_free(tmp);
231
+ RL_CALL(rl_multi_string_get, RL_OK, iterator->db, page, member, memberlen);
232
+ }
233
+ cleanup:
234
+ return retval;
235
+ }
236
+
237
+ int rl_set_iterator_destroy(rl_set_iterator *iterator)
238
+ {
239
+ return rl_btree_iterator_destroy(iterator);
240
+ }
241
+
242
+ int rl_smembers(struct rlite *db, rl_set_iterator **iterator, const unsigned char *key, long keylen)
243
+ {
244
+ int retval;
245
+ rl_btree *set;
246
+ RL_CALL(rl_set_get_objects, RL_OK, db, key, keylen, NULL, &set, 0, 0);
247
+ RL_CALL(rl_btree_iterator_create, RL_OK, db, set, iterator);
248
+ cleanup:
249
+ return retval;
250
+ }
251
+
252
+ static int contains(long size, long *elements, long element)
253
+ {
254
+ long i;
255
+ for (i = 0; i < size; i++) {
256
+ if (element == elements[i]) {
257
+ return 1;
258
+ }
259
+ }
260
+ return 0;
261
+ }
262
+
263
+ int rl_srandmembers(struct rlite *db, const unsigned char *key, long keylen, int repeat, long *memberc, unsigned char ***_members, long **_memberslen)
264
+ {
265
+ long i;
266
+ int retval;
267
+ long *member;
268
+ long *used_members = NULL;
269
+ rl_btree *set;
270
+ unsigned char **members = NULL;
271
+ long *memberslen = NULL;
272
+ RL_CALL(rl_set_get_objects, RL_OK, db, key, keylen, NULL, &set, 0, 0);
273
+ if (!repeat) {
274
+ if (*memberc > set->number_of_elements) {
275
+ *memberc = set->number_of_elements;
276
+ }
277
+ RL_MALLOC(used_members, sizeof(long) * *memberc);
278
+ }
279
+
280
+ RL_MALLOC(members, sizeof(unsigned char *) * *memberc);
281
+ RL_MALLOC(memberslen, sizeof(long) * *memberc);
282
+
283
+ for (i = 0; i < *memberc; i++) {
284
+ RL_CALL(rl_btree_random_element, RL_OK, db, set, NULL, (void **)&member);
285
+ if (!repeat) {
286
+ if (contains(i, used_members, *member)) {
287
+ i--;
288
+ continue;
289
+ }
290
+ else {
291
+ used_members[i] = *member;
292
+ }
293
+ }
294
+ RL_CALL(rl_multi_string_get, RL_OK, db, *member, &members[i], &memberslen[i]);
295
+ }
296
+ *_members = members;
297
+ *_memberslen = memberslen;
298
+ cleanup:
299
+ if (retval != RL_OK) {
300
+ rl_free(members);
301
+ rl_free(memberslen);
302
+ }
303
+ rl_free(used_members);
304
+ return retval;
305
+ }
306
+
307
+ int rl_spop(struct rlite *db, const unsigned char *key, long keylen, unsigned char **member, long *memberlen)
308
+ {
309
+ int retval;
310
+ long set_page_number, *member_page;
311
+ unsigned char *digest;
312
+ rl_btree *set;
313
+ RL_CALL(rl_set_get_objects, RL_OK, db, key, keylen, &set_page_number, &set, 1, 0);
314
+ RL_CALL(rl_btree_random_element, RL_OK, db, set, (void **)&digest, (void **)&member_page);
315
+ RL_CALL(rl_multi_string_get, RL_OK, db, *member_page, member, memberlen);
316
+ rl_multi_string_delete(db, *member_page);
317
+ retval = rl_btree_remove_element(db, set, set_page_number, digest);
318
+ if (retval == RL_DELETED) {
319
+ RL_CALL(rl_key_delete, RL_OK, db, key, keylen);
320
+ }
321
+ else if (retval != RL_OK) {
322
+ goto cleanup;
323
+ }
324
+ retval = RL_OK;
325
+ cleanup:
326
+ return retval;
327
+ }
328
+
329
+ int rl_sdiff(struct rlite *db, int keyc, unsigned char **keys, long *keyslen, long *_membersc, unsigned char ***_members, long **_memberslen)
330
+ {
331
+ int retval, found;
332
+ rl_btree *source = NULL;
333
+ rl_btree **sets = NULL;
334
+ rl_btree_iterator *iterator;
335
+ unsigned char **members = NULL, *digest;
336
+ long *memberslen = NULL, i, member_page, setsc = 0;
337
+ long membersc = 0;
338
+ void *tmp;
339
+
340
+ if (keyc == 0) {
341
+ retval = RL_NOT_FOUND;
342
+ goto cleanup;
343
+ }
344
+
345
+ RL_CALL(rl_set_get_objects, RL_OK, db, keys[0], keyslen[0], NULL, &source, 0, 0);
346
+ RL_MALLOC(members, sizeof(unsigned char *) * source->number_of_elements);
347
+ RL_MALLOC(memberslen, sizeof(long) * source->number_of_elements);
348
+ RL_MALLOC(sets, sizeof(rl_btree *) * (keyc - 1));
349
+ for (i = 1; i < keyc; i++) {
350
+ retval = rl_set_get_objects(db, keys[i], keyslen[i], NULL, &sets[setsc], 0, 0);
351
+ if (retval == RL_OK) {
352
+ setsc++;
353
+ }
354
+ else if (retval != RL_NOT_FOUND) {
355
+ goto cleanup;
356
+ }
357
+ }
358
+
359
+ RL_CALL(rl_btree_iterator_create, RL_OK, db, source, &iterator);
360
+ while ((retval = rl_btree_iterator_next(iterator, (void **)&digest, &tmp)) == RL_OK) {
361
+ found = 0;
362
+ for (i = 0; i < setsc; i++) {
363
+ retval = rl_btree_find_score(db, sets[i], digest, NULL, NULL, NULL);
364
+ if (retval == RL_FOUND) {
365
+ found = 1;
366
+ break;
367
+ }
368
+ }
369
+ if (!found) {
370
+ member_page = *(long *)tmp;
371
+ RL_CALL(rl_multi_string_get, RL_OK, db, member_page, &members[membersc], &memberslen[membersc]);
372
+ membersc++;
373
+ }
374
+ rl_free(digest);
375
+ rl_free(tmp);
376
+ }
377
+ iterator = NULL;
378
+
379
+ if (retval != RL_END) {
380
+ goto cleanup;
381
+ }
382
+
383
+ if (membersc == 0) {
384
+ retval = RL_NOT_FOUND;
385
+ goto cleanup;
386
+ }
387
+ else if (membersc == source->number_of_elements) {
388
+ *_members = members;
389
+ *_memberslen = memberslen;
390
+ }
391
+ else {
392
+ *_members = realloc(members, sizeof(unsigned char *) * membersc);
393
+ if (*_members == NULL) {
394
+ retval = RL_OUT_OF_MEMORY;
395
+ goto cleanup;
396
+ }
397
+ *_memberslen = realloc(memberslen, sizeof(long) * membersc);
398
+ if (*_memberslen == NULL) {
399
+ retval = RL_OUT_OF_MEMORY;
400
+ goto cleanup;
401
+ }
402
+ }
403
+
404
+ retval = RL_OK;
405
+ cleanup:
406
+ *_membersc = membersc;
407
+ if (retval != RL_OK) {
408
+ rl_free(members);
409
+ rl_free(memberslen);
410
+ }
411
+ rl_free(sets);
412
+ return retval;
413
+ }
414
+
415
+ int rl_sdiffstore(struct rlite *db, unsigned char *target, long targetlen, int keyc, unsigned char **keys, long *keyslen, long *added)
416
+ {
417
+ int retval;
418
+ unsigned char **members = NULL;
419
+ long *memberslen = NULL, membersc = 0, i;
420
+
421
+ retval = rl_key_delete_with_value(db, target, targetlen);
422
+ if (retval != RL_NOT_FOUND && retval != RL_OK) {
423
+ goto cleanup;
424
+ }
425
+ *added = 0;
426
+ // this might be done more efficiently since we don't really need to have all members in memory
427
+ // at the same time, but this is so easy to do...
428
+ RL_CALL(rl_sdiff, RL_OK, db, keyc, keys, keyslen, &membersc, &members, &memberslen);
429
+ if (membersc > 0) {
430
+ RL_CALL(rl_sadd, RL_OK, db, target, targetlen, membersc, members, memberslen, added);
431
+ }
432
+ cleanup:
433
+ for (i = 0; i < membersc; i++) {
434
+ rl_free(members[i]);
435
+ }
436
+ rl_free(members);
437
+ rl_free(memberslen);
438
+ return retval;
439
+ }
440
+
441
+ int rl_sinter(struct rlite *db, int keyc, unsigned char **keys, long *keyslen, long *_membersc, unsigned char ***_members, long **_memberslen)
442
+ {
443
+ int retval, found;
444
+ rl_btree **sets = NULL;
445
+ rl_btree_iterator *iterator;
446
+ unsigned char **members = NULL, *digest;
447
+ long *memberslen = NULL, i, member_page;
448
+ long membersc = 0, maxmemberc = 0;
449
+ void *tmp;
450
+
451
+ if (keyc == 0) {
452
+ retval = RL_NOT_FOUND;
453
+ goto cleanup;
454
+ }
455
+
456
+ RL_MALLOC(sets, sizeof(rl_btree *) * keyc);
457
+ for (i = 0; i < keyc; i++) {
458
+ retval = rl_set_get_objects(db, keys[i], keyslen[i], NULL, &sets[i], 0, 0);
459
+ if (retval != RL_OK) {
460
+ goto cleanup;
461
+ }
462
+ if (i == 0 || sets[i]->number_of_elements < maxmemberc) {
463
+ maxmemberc = sets[i]->number_of_elements;
464
+ if (i != 0) {
465
+ tmp = sets[i];
466
+ sets[i] = sets[0];
467
+ sets[0] = tmp;
468
+ }
469
+ }
470
+ }
471
+
472
+ if (maxmemberc == 0) {
473
+ retval = RL_NOT_FOUND;
474
+ goto cleanup;
475
+ }
476
+ RL_MALLOC(members, sizeof(unsigned char *) * maxmemberc);
477
+ RL_MALLOC(memberslen, sizeof(long) * maxmemberc);
478
+
479
+ RL_CALL(rl_btree_iterator_create, RL_OK, db, sets[0], &iterator);
480
+ while ((retval = rl_btree_iterator_next(iterator, (void **)&digest, &tmp)) == RL_OK) {
481
+ found = 1;
482
+ for (i = 1; i < keyc; i++) {
483
+ retval = rl_btree_find_score(db, sets[i], digest, NULL, NULL, NULL);
484
+ if (retval == RL_NOT_FOUND) {
485
+ found = 0;
486
+ break;
487
+ }
488
+ }
489
+ if (found) {
490
+ member_page = *(long *)tmp;
491
+ RL_CALL(rl_multi_string_get, RL_OK, db, member_page, &members[membersc], &memberslen[membersc]);
492
+ membersc++;
493
+ }
494
+ rl_free(digest);
495
+ rl_free(tmp);
496
+ }
497
+ iterator = NULL;
498
+
499
+ if (retval != RL_END) {
500
+ goto cleanup;
501
+ }
502
+
503
+ *_membersc = membersc;
504
+ if (membersc == maxmemberc) {
505
+ *_members = members;
506
+ *_memberslen = memberslen;
507
+ }
508
+ else {
509
+ *_members = realloc(members, sizeof(unsigned char *) * membersc);
510
+ if (*_members == NULL) {
511
+ retval = RL_OUT_OF_MEMORY;
512
+ goto cleanup;
513
+ }
514
+ *_memberslen = realloc(memberslen, sizeof(long) * membersc);
515
+ if (*_memberslen == NULL) {
516
+ retval = RL_OUT_OF_MEMORY;
517
+ goto cleanup;
518
+ }
519
+ }
520
+
521
+ retval = RL_OK;
522
+ cleanup:
523
+ if (retval != RL_OK) {
524
+ *_membersc = 0;
525
+ rl_free(members);
526
+ rl_free(memberslen);
527
+ }
528
+ rl_free(sets);
529
+ return retval;
530
+ }
531
+
532
+ int rl_sinterstore(struct rlite *db, unsigned char *target, long targetlen, int keyc, unsigned char **keys, long *keyslen, long *added)
533
+ {
534
+ int retval;
535
+ unsigned char **members = NULL;
536
+ long *memberslen = NULL, membersc = 0, i;
537
+
538
+ retval = rl_key_delete_with_value(db, target, targetlen);
539
+ if (retval != RL_NOT_FOUND && retval != RL_OK) {
540
+ goto cleanup;
541
+ }
542
+ *added = 0;
543
+ // this might be done more efficiently since we don't really need to have all members in memory
544
+ // at the same time, but this is so easy to do...
545
+ RL_CALL(rl_sinter, RL_OK, db, keyc, keys, keyslen, &membersc, &members, &memberslen);
546
+ if (membersc > 0) {
547
+ RL_CALL(rl_sadd, RL_OK, db, target, targetlen, membersc, members, memberslen, added);
548
+ }
549
+ cleanup:
550
+ for (i = 0; i < membersc; i++) {
551
+ rl_free(members[i]);
552
+ }
553
+ rl_free(members);
554
+ rl_free(memberslen);
555
+ return retval;
556
+ }
557
+
558
+ int rl_sunion(struct rlite *db, int keyc, unsigned char **keys, long *keyslen, long *_membersc, unsigned char ***_members, long **_memberslen)
559
+ {
560
+ int retval, found;
561
+ rl_btree **sets = NULL;
562
+ rl_btree_iterator *iterator;
563
+ unsigned char **members = NULL;
564
+ long *memberslen = NULL, i, j, member_page;
565
+ long membersc = 0, maxmemberc = 0;
566
+ void *tmp;
567
+
568
+ if (keyc == 0) {
569
+ retval = RL_NOT_FOUND;
570
+ goto cleanup;
571
+ }
572
+
573
+ RL_MALLOC(sets, sizeof(rl_btree *) * keyc);
574
+ for (i = 0; i < keyc; i++) {
575
+ retval = rl_set_get_objects(db, keys[i], keyslen[i], NULL, &sets[i], 0, 0);
576
+ if (retval == RL_NOT_FOUND) {
577
+ sets[i] = NULL;
578
+ }
579
+ else if (retval != RL_OK) {
580
+ goto cleanup;
581
+ }
582
+ else {
583
+ maxmemberc += sets[i]->number_of_elements;
584
+ }
585
+ }
586
+
587
+ if (maxmemberc == 0) {
588
+ *_membersc = 0;
589
+ retval = RL_NOT_FOUND;
590
+ goto cleanup;
591
+ }
592
+ RL_MALLOC(members, sizeof(unsigned char *) * maxmemberc);
593
+ RL_MALLOC(memberslen, sizeof(long) * maxmemberc);
594
+
595
+ for (i = 0; i < keyc; i++) {
596
+ if (!sets[i]) {
597
+ continue;
598
+ }
599
+ RL_CALL(rl_btree_iterator_create, RL_OK, db, sets[i], &iterator);
600
+
601
+ while ((retval = rl_btree_iterator_next(iterator, NULL, &tmp)) == RL_OK) {
602
+ member_page = *(long *)tmp;
603
+ rl_free(tmp);
604
+ RL_CALL(rl_multi_string_get, RL_OK, db, member_page, &members[membersc], &memberslen[membersc]);
605
+ found = 0;
606
+ for (j = 0; j < membersc; j++) {
607
+ if (memberslen[membersc] == memberslen[j] && memcmp(members[membersc], members[j], memberslen[membersc]) == 0) {
608
+ found = 1;
609
+ break;
610
+ }
611
+ }
612
+ if (found) {
613
+ rl_free(members[membersc]);
614
+ }
615
+ else {
616
+ membersc++;
617
+ }
618
+ }
619
+ iterator = NULL;
620
+
621
+ if (retval != RL_END) {
622
+ goto cleanup;
623
+ }
624
+ }
625
+
626
+ *_membersc = membersc;
627
+ if (membersc == maxmemberc) {
628
+ *_members = members;
629
+ *_memberslen = memberslen;
630
+ }
631
+ else {
632
+ *_members = realloc(members, sizeof(unsigned char *) * membersc);
633
+ if (*_members == NULL) {
634
+ retval = RL_OUT_OF_MEMORY;
635
+ goto cleanup;
636
+ }
637
+ *_memberslen = realloc(memberslen, sizeof(long) * membersc);
638
+ if (*_memberslen == NULL) {
639
+ retval = RL_OUT_OF_MEMORY;
640
+ goto cleanup;
641
+ }
642
+ }
643
+
644
+ retval = RL_OK;
645
+ cleanup:
646
+ if (retval != RL_OK) {
647
+ rl_free(members);
648
+ rl_free(memberslen);
649
+ }
650
+ rl_free(sets);
651
+ return retval;
652
+ }
653
+
654
+ int rl_sunionstore(struct rlite *db, unsigned char *target, long targetlen, int keyc, unsigned char **keys, long *keyslen, long *added)
655
+ {
656
+ int retval;
657
+ rl_btree *target_set = NULL;
658
+ rl_btree *set = NULL;
659
+ rl_btree_iterator *iterator;
660
+ unsigned char *digest = NULL;
661
+ unsigned char *member;
662
+ long memberlen, i, member_page;
663
+ long target_page_number;
664
+ void *tmp;
665
+ long *member_object = NULL;
666
+ long count = 0;
667
+
668
+ *added = 0;
669
+ retval = rl_key_delete_with_value(db, target, targetlen);
670
+ if (retval != RL_NOT_FOUND && retval != RL_OK) {
671
+ goto cleanup;
672
+ }
673
+ if (keyc == 0) {
674
+ retval = RL_NOT_FOUND;
675
+ goto cleanup;
676
+ }
677
+
678
+ RL_CALL(rl_set_get_objects, RL_OK, db, target, targetlen, &target_page_number, &target_set, 0, 1);
679
+
680
+ for (i = 0; i < keyc; i++) {
681
+ retval = rl_set_get_objects(db, keys[i], keyslen[i], NULL, &set, 0, 0);
682
+ if (retval == RL_NOT_FOUND) {
683
+ continue;
684
+ }
685
+ else if (retval != RL_OK) {
686
+ goto cleanup;
687
+ }
688
+
689
+ RL_CALL(rl_btree_iterator_create, RL_OK, db, set, &iterator);
690
+ while ((retval = rl_btree_iterator_next(iterator, (void **)&digest, &tmp)) == RL_OK) {
691
+ member_page = *(long *)tmp;
692
+ rl_free(tmp);
693
+
694
+ retval = rl_btree_find_score(db, target_set, digest, &tmp, NULL, NULL);
695
+ if (retval == RL_NOT_FOUND) {
696
+ RL_CALL(rl_multi_string_get, RL_OK, db, member_page, &member, &memberlen);
697
+ RL_MALLOC(member_object, sizeof(*member_object));
698
+ RL_CALL(rl_multi_string_set, RL_OK, db, member_object, member, memberlen);
699
+
700
+ retval = rl_btree_add_element(db, target_set, target_page_number, digest, member_object);
701
+ if (retval != RL_OK) {
702
+ goto cleanup;
703
+ }
704
+ count++;
705
+ rl_free(member);
706
+ }
707
+ else if (retval == RL_FOUND) {
708
+ rl_free(digest);
709
+ digest = NULL;
710
+ }
711
+ else {
712
+ goto cleanup;
713
+ }
714
+ }
715
+ iterator = NULL;
716
+
717
+ if (retval != RL_END) {
718
+ goto cleanup;
719
+ }
720
+ }
721
+
722
+ if (count == 0) {
723
+ RL_CALL(rl_key_delete_with_value, RL_OK, db, target, targetlen);
724
+ }
725
+ *added = count;
726
+ retval = RL_OK;
727
+ cleanup:
728
+ return retval;
729
+ }
730
+
731
+ int rl_set_pages(struct rlite *db, long page, short *pages)
732
+ {
733
+ rl_btree *btree;
734
+ rl_btree_iterator *iterator = NULL;
735
+ int retval;
736
+ void *tmp;
737
+ long member;
738
+
739
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_btree_hash_sha1_long, page, &rl_btree_type_hash_sha1_long, &tmp, 1);
740
+ btree = tmp;
741
+
742
+ RL_CALL(rl_btree_pages, RL_OK, db, btree, pages);
743
+
744
+ RL_CALL(rl_btree_iterator_create, RL_OK, db, btree, &iterator);
745
+ while ((retval = rl_btree_iterator_next(iterator, NULL, &tmp)) == RL_OK) {
746
+ member = *(long *)tmp;
747
+ pages[member] = 1;
748
+ RL_CALL(rl_multi_string_pages, RL_OK, db, member, pages);
749
+ rl_free(tmp);
750
+ }
751
+ iterator = NULL;
752
+
753
+ if (retval != RL_END) {
754
+ goto cleanup;
755
+ }
756
+ retval = RL_OK;
757
+ cleanup:
758
+ if (retval != RL_OK) {
759
+ if (iterator) {
760
+ rl_btree_iterator_destroy(iterator);
761
+ }
762
+ }
763
+ return retval;
764
+ }
765
+
766
+ int rl_set_delete(rlite *db, long value_page)
767
+ {
768
+ rl_btree *hash;
769
+ rl_btree_iterator *iterator;
770
+ long member;
771
+ int retval;
772
+ void *tmp;
773
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_btree_hash_sha1_long, value_page, &rl_btree_type_hash_sha1_long, &tmp, 1);
774
+ hash = tmp;
775
+ if (hash->number_of_elements) {
776
+ RL_CALL2(rl_btree_iterator_create, RL_OK, RL_NOT_FOUND, db, hash, &iterator);
777
+ if (retval == RL_OK) {
778
+ while ((retval = rl_btree_iterator_next(iterator, NULL, &tmp)) == RL_OK) {
779
+ member = *(long *)tmp;
780
+ rl_multi_string_delete(db, member);
781
+ rl_free(tmp);
782
+ }
783
+ iterator = NULL;
784
+
785
+ if (retval != RL_END) {
786
+ goto cleanup;
787
+ }
788
+ }
789
+ }
790
+
791
+ RL_CALL(rl_btree_delete, RL_OK, db, hash);
792
+ RL_CALL(rl_delete, RL_OK, db, value_page);
793
+ retval = RL_OK;
794
+ cleanup:
795
+ return retval;
796
+ }