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.
- checksums.yaml +15 -0
- data/LICENSE +28 -0
- data/Rakefile +51 -0
- data/ext/hirlite_ext/extconf.rb +33 -0
- data/ext/hirlite_ext/hirlite_ext.c +14 -0
- data/ext/hirlite_ext/hirlite_ext.h +38 -0
- data/ext/hirlite_ext/rlite.c +351 -0
- data/lib/hirlite/rlite.rb +1 -0
- data/lib/hirlite/version.rb +3 -0
- data/lib/hirlite.rb +2 -0
- data/vendor/rlite/Makefile +6 -0
- data/vendor/rlite/deps/crc64.c +191 -0
- data/vendor/rlite/deps/crc64.h +3 -0
- data/vendor/rlite/deps/endianconv.h +73 -0
- data/vendor/rlite/deps/hyperloglog.c +1547 -0
- data/vendor/rlite/deps/hyperloglog.h +14 -0
- data/vendor/rlite/deps/lzf.h +100 -0
- data/vendor/rlite/deps/lzfP.h +159 -0
- data/vendor/rlite/deps/lzf_c.c +295 -0
- data/vendor/rlite/deps/lzf_d.c +150 -0
- data/vendor/rlite/deps/sha1.c +227 -0
- data/vendor/rlite/deps/sha1.h +19 -0
- data/vendor/rlite/deps/utilfromredis.c +397 -0
- data/vendor/rlite/deps/utilfromredis.h +11 -0
- data/vendor/rlite/src/Makefile +79 -0
- data/vendor/rlite/src/constants.h +15 -0
- data/vendor/rlite/src/dump.c +191 -0
- data/vendor/rlite/src/dump.h +3 -0
- data/vendor/rlite/src/hirlite.c +3985 -0
- data/vendor/rlite/src/hirlite.h +186 -0
- data/vendor/rlite/src/page_btree.c +1556 -0
- data/vendor/rlite/src/page_btree.h +133 -0
- data/vendor/rlite/src/page_key.c +283 -0
- data/vendor/rlite/src/page_key.h +25 -0
- data/vendor/rlite/src/page_list.c +718 -0
- data/vendor/rlite/src/page_list.h +70 -0
- data/vendor/rlite/src/page_long.c +61 -0
- data/vendor/rlite/src/page_long.h +14 -0
- data/vendor/rlite/src/page_multi_string.c +538 -0
- data/vendor/rlite/src/page_multi_string.h +18 -0
- data/vendor/rlite/src/page_skiplist.c +689 -0
- data/vendor/rlite/src/page_skiplist.h +70 -0
- data/vendor/rlite/src/page_string.c +55 -0
- data/vendor/rlite/src/page_string.h +12 -0
- data/vendor/rlite/src/pqsort.c +185 -0
- data/vendor/rlite/src/pqsort.h +40 -0
- data/vendor/rlite/src/restore.c +401 -0
- data/vendor/rlite/src/restore.h +3 -0
- data/vendor/rlite/src/rlite.c +1309 -0
- data/vendor/rlite/src/rlite.h +159 -0
- data/vendor/rlite/src/sort.c +530 -0
- data/vendor/rlite/src/sort.h +18 -0
- data/vendor/rlite/src/status.h +19 -0
- data/vendor/rlite/src/type_hash.c +607 -0
- data/vendor/rlite/src/type_hash.h +29 -0
- data/vendor/rlite/src/type_list.c +477 -0
- data/vendor/rlite/src/type_list.h +23 -0
- data/vendor/rlite/src/type_set.c +796 -0
- data/vendor/rlite/src/type_set.h +34 -0
- data/vendor/rlite/src/type_string.c +613 -0
- data/vendor/rlite/src/type_string.h +34 -0
- data/vendor/rlite/src/type_zset.c +1147 -0
- data/vendor/rlite/src/type_zset.h +50 -0
- data/vendor/rlite/src/util.c +334 -0
- data/vendor/rlite/src/util.h +71 -0
- 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
|
+
}
|