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,1147 @@
1
+ #include <math.h>
2
+ #include <stdlib.h>
3
+ #include "rlite.h"
4
+ #include "page_key.h"
5
+ #include "page_multi_string.h"
6
+ #include "type_zset.h"
7
+ #include "page_btree.h"
8
+ #include "page_list.h"
9
+ #include "page_skiplist.h"
10
+ #include "util.h"
11
+
12
+ static int rl_zset_create(rlite *db, long levels_page_number, rl_btree **btree, long *btree_page, rl_skiplist **_skiplist, long *skiplist_page)
13
+ {
14
+ rl_list *levels;
15
+ rl_btree *scores = NULL;
16
+ rl_skiplist *skiplist = NULL;
17
+ long scores_page_number;
18
+ long skiplist_page_number;
19
+
20
+ int retval;
21
+ RL_CALL(rl_btree_create, RL_OK, db, &scores, &rl_btree_type_hash_sha1_double);
22
+ scores_page_number = db->next_empty_page;
23
+ RL_CALL(rl_write, RL_OK, db, &rl_data_type_btree_hash_sha1_double, scores_page_number, scores);
24
+ RL_CALL(rl_skiplist_create, RL_OK, db, &skiplist);
25
+ skiplist_page_number = db->next_empty_page;
26
+ RL_CALL(rl_write, RL_OK, db, &rl_data_type_skiplist, skiplist_page_number, skiplist);
27
+ RL_CALL(rl_list_create, RL_OK, db, &levels, &rl_list_type_long);
28
+ RL_CALL(rl_write, RL_OK, db, &rl_data_type_list_long, levels_page_number, levels);
29
+
30
+ long *scores_element;
31
+ RL_MALLOC(scores_element, sizeof(long));
32
+ *scores_element = scores_page_number;
33
+ RL_CALL(rl_list_add_element, RL_OK, db, levels, levels_page_number, scores_element, 0);
34
+
35
+ long *skiplist_element;
36
+ RL_MALLOC(skiplist_element, sizeof(long))
37
+ *skiplist_element = skiplist_page_number;
38
+ RL_CALL(rl_list_add_element, RL_OK, db, levels, levels_page_number, skiplist_element, 1);
39
+
40
+ if (btree) {
41
+ *btree = scores;
42
+ }
43
+ if (btree_page) {
44
+ *btree_page = scores_page_number;
45
+ }
46
+ if (_skiplist) {
47
+ *_skiplist = skiplist;
48
+ }
49
+ if (skiplist_page) {
50
+ *skiplist_page = skiplist_page_number;
51
+ }
52
+ cleanup:
53
+ return retval;
54
+ }
55
+
56
+ static int rl_zset_read(rlite *db, long levels_page_number, rl_btree **btree, long *btree_page, rl_skiplist **skiplist, long *skiplist_page)
57
+ {
58
+ void *tmp;
59
+ long scores_page_number, skiplist_page_number;
60
+ rl_list *levels;
61
+ int retval;
62
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_list_long, levels_page_number, &rl_list_type_long, &tmp, 1);
63
+ levels = tmp;
64
+ if (btree || btree_page) {
65
+ RL_CALL(rl_list_get_element, RL_FOUND, db, levels, &tmp, 0);
66
+ scores_page_number = *(long *)tmp;
67
+ if (btree) {
68
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_btree_hash_sha1_double, scores_page_number, &rl_btree_type_hash_sha1_double, &tmp, 1);
69
+ *btree = tmp;
70
+ }
71
+ if (btree_page) {
72
+ *btree_page = scores_page_number;
73
+ }
74
+ }
75
+ if (skiplist || skiplist_page) {
76
+ RL_CALL(rl_list_get_element, RL_FOUND, db, levels, &tmp, 1);
77
+ if (retval != RL_FOUND) {
78
+ goto cleanup;
79
+ }
80
+ skiplist_page_number = *(long *)tmp;
81
+ if (skiplist) {
82
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_skiplist, skiplist_page_number, NULL, &tmp, 1);
83
+ *skiplist = tmp;
84
+ }
85
+ if (skiplist_page) {
86
+ *skiplist_page = skiplist_page_number;
87
+ }
88
+ }
89
+ retval = RL_OK;
90
+ cleanup:
91
+ return retval;
92
+ }
93
+
94
+ static int rl_zset_get_objects(rlite *db, const unsigned char *key, long keylen, long *_levels_page_number, rl_btree **btree, long *btree_page, rl_skiplist **skiplist, long *skiplist_page, int update_version, int create)
95
+ {
96
+ long levels_page_number = 0, version = 0;
97
+ int retval;
98
+ unsigned long long expires = 0;
99
+ if (create) {
100
+ retval = rl_key_get_or_create(db, key, keylen, RL_TYPE_ZSET, &levels_page_number, &version);
101
+ if (retval != RL_FOUND && retval != RL_NOT_FOUND) {
102
+ goto cleanup;
103
+ }
104
+ else if (retval == RL_NOT_FOUND) {
105
+ retval = rl_zset_create(db, levels_page_number, btree, btree_page, skiplist, skiplist_page);
106
+ goto cleanup;
107
+ }
108
+ else {
109
+ RL_CALL(rl_zset_read, RL_OK, db, levels_page_number, btree, btree_page, skiplist, skiplist_page);
110
+ }
111
+ }
112
+ else {
113
+ unsigned char type;
114
+ retval = rl_key_get(db, key, keylen, &type, NULL, &levels_page_number, &expires, &version);
115
+ if (retval != RL_FOUND) {
116
+ goto cleanup;
117
+ }
118
+ if (type != RL_TYPE_ZSET) {
119
+ retval = RL_WRONG_TYPE;
120
+ goto cleanup;
121
+ }
122
+ RL_CALL(rl_zset_read, RL_OK, db, levels_page_number, btree, btree_page, skiplist, skiplist_page);
123
+ }
124
+ if (update_version) {
125
+ RL_CALL(rl_key_set, RL_OK, db, key, keylen, RL_TYPE_ZSET, levels_page_number, expires, version + 1);
126
+ }
127
+ cleanup:
128
+ if (_levels_page_number) {
129
+ *_levels_page_number = levels_page_number;
130
+ }
131
+ return retval;
132
+ }
133
+
134
+ static int remove_member_score_sha1(rlite *db, const unsigned char *key, long keylen, long levels_page_number, rl_btree *scores, long scores_page, rl_skiplist *skiplist, long skiplist_page, unsigned char *member, long member_len, double score, unsigned char digest[20])
135
+ {
136
+ void *tmp;
137
+ int retval;
138
+ retval = rl_btree_remove_element(db, scores, scores_page, digest);
139
+ if (retval != RL_OK && retval != RL_DELETED) {
140
+ goto cleanup;
141
+ }
142
+ retval = rl_skiplist_delete(db, skiplist, skiplist_page, score, member, member_len);
143
+ if (retval != RL_OK && retval != RL_DELETED) {
144
+ goto cleanup;
145
+ }
146
+ if (retval == RL_DELETED) {
147
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_list_long, levels_page_number, &rl_list_type_long, &tmp, 1);
148
+ RL_CALL(rl_list_delete, RL_OK, db, tmp);
149
+ RL_CALL(rl_delete, RL_OK, db, levels_page_number);
150
+ RL_CALL(rl_key_delete, RL_OK, db, key, keylen);
151
+ retval = RL_DELETED;
152
+ }
153
+ cleanup:
154
+ return retval;
155
+ }
156
+
157
+ static int remove_member_score(rlite *db, const unsigned char *key, long keylen, long levels_page_number, rl_btree *scores, long scores_page, rl_skiplist *skiplist, long skiplist_page, unsigned char *member, long member_len, double score)
158
+ {
159
+ unsigned char digest[20];
160
+ int retval;
161
+ RL_CALL(sha1, RL_OK, member, member_len, digest);
162
+ RL_CALL(remove_member_score_sha1, RL_OK, db, key, keylen, levels_page_number, scores, scores_page, skiplist, skiplist_page, member, member_len, score, digest);
163
+ cleanup:
164
+ return retval;
165
+ }
166
+
167
+ static int remove_member(rlite *db, const unsigned char *key, long keylen, long levels_page_number, rl_btree *scores, long scores_page, rl_skiplist *skiplist, long skiplist_page, unsigned char *member, long member_len)
168
+ {
169
+ double score;
170
+ void *tmp;
171
+ unsigned char digest[20];
172
+ int retval;
173
+ RL_CALL(sha1, RL_OK, member, member_len, digest);
174
+ retval = rl_btree_find_score(db, scores, digest, &tmp, NULL, NULL);
175
+ if (retval != RL_FOUND && retval != RL_NOT_FOUND) {
176
+ goto cleanup;
177
+ }
178
+ if (retval == RL_FOUND) {
179
+ score = *(double *)tmp;
180
+ RL_CALL(remove_member_score_sha1, RL_OK, db, key, keylen, levels_page_number, scores, scores_page, skiplist, skiplist_page, member, member_len, score, digest);
181
+ }
182
+ cleanup:
183
+ return retval;
184
+ }
185
+ static int add_member(rlite *db, rl_btree *scores, long scores_page, rl_skiplist *skiplist, long skiplist_page, double score, unsigned char *member, long memberlen)
186
+ {
187
+ int retval;
188
+ unsigned char *digest = NULL;
189
+ void *value_ptr;
190
+ RL_MALLOC(value_ptr, sizeof(double));
191
+ digest = rl_malloc(sizeof(unsigned char) * 20);
192
+ if (!digest) {
193
+ rl_free(value_ptr);
194
+ retval = RL_OUT_OF_MEMORY;
195
+ goto cleanup;
196
+ }
197
+ *(double *)value_ptr = score;
198
+ retval = sha1(member, memberlen, digest);
199
+ if (retval != RL_OK) {
200
+ rl_free(value_ptr);
201
+ rl_free(digest);
202
+ goto cleanup;
203
+ }
204
+ RL_CALL(rl_btree_add_element, RL_OK, db, scores, scores_page, digest, value_ptr);
205
+
206
+ retval = rl_skiplist_add(db, skiplist, skiplist_page, score, member, memberlen);
207
+ if (retval != RL_OK) {
208
+ // This failure is critical. The btree already has the element, but
209
+ // the skiplist failed to add it. If left as is, it would be in an
210
+ // inconsistent state. Dropping all the transaction in progress.
211
+ rl_discard(db);
212
+ goto cleanup;
213
+ }
214
+ cleanup:
215
+ return retval;
216
+ }
217
+
218
+ int rl_zadd(rlite *db, const unsigned char *key, long keylen, double score, unsigned char *member, long memberlen)
219
+ {
220
+ int existed;
221
+ rl_btree *scores;
222
+ rl_skiplist *skiplist;
223
+ long scores_page, skiplist_page, levels_page_number;
224
+ int retval;
225
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, &levels_page_number, &scores, &scores_page, &skiplist, &skiplist_page, 1, 1);
226
+ retval = remove_member(db, key, keylen, levels_page_number, scores, scores_page, skiplist, skiplist_page, member, memberlen);
227
+ if (retval != RL_OK && retval != RL_NOT_FOUND && retval != RL_DELETED) {
228
+ goto cleanup;
229
+ }
230
+ else if (retval == RL_DELETED) {
231
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, &levels_page_number, &scores, &scores_page, &skiplist, &skiplist_page, 1, 1);
232
+ }
233
+ existed = retval != RL_NOT_FOUND; // ok or deleted means there was a value
234
+ RL_CALL(add_member, RL_OK, db, scores, scores_page, skiplist, skiplist_page, score, member, memberlen);
235
+ retval = existed ? RL_FOUND : RL_OK;
236
+ cleanup:
237
+ return retval;
238
+ }
239
+
240
+ static int rl_get_zscore(rlite *db, rl_btree *scores, unsigned char *member, long memberlen, double *score)
241
+ {
242
+ unsigned char *digest = NULL;
243
+ int retval;
244
+ RL_MALLOC(digest, sizeof(unsigned char) * 20);
245
+ RL_CALL(sha1, RL_OK, member, memberlen, digest);
246
+ void *value;
247
+ RL_CALL(rl_btree_find_score, RL_FOUND, db, scores, digest, &value, NULL, NULL);
248
+ *score = *(double *)value;
249
+ retval = RL_FOUND;
250
+ cleanup:
251
+ rl_free(digest);
252
+ return retval;
253
+ }
254
+
255
+ int rl_zscore(rlite *db, const unsigned char *key, long keylen, unsigned char *member, long memberlen, double *score)
256
+ {
257
+ rl_btree *scores;
258
+ int retval;
259
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, &scores, NULL, NULL, NULL, 0, 0);
260
+ RL_CALL(rl_get_zscore, RL_FOUND, db, scores, member, memberlen, score);
261
+ cleanup:
262
+ return retval;
263
+ }
264
+
265
+ int rl_zrank(rlite *db, const unsigned char *key, long keylen, unsigned char *member, long memberlen, long *rank)
266
+ {
267
+ double score;
268
+ rl_btree *scores;
269
+ rl_skiplist *skiplist;
270
+ int retval;
271
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, &scores, NULL, &skiplist, NULL, 0, 0);
272
+ RL_CALL(rl_get_zscore, RL_FOUND, db, scores, member, memberlen, &score);
273
+ RL_CALL(rl_skiplist_first_node, RL_FOUND, db, skiplist, score, RL_SKIPLIST_INCLUDE_SCORE, member, memberlen, NULL, rank);
274
+ cleanup:
275
+ return retval;
276
+ }
277
+
278
+ int rl_zrevrank(rlite *db, const unsigned char *key, long keylen, unsigned char *member, long memberlen, long *revrank)
279
+ {
280
+ double score;
281
+ rl_btree *scores;
282
+ rl_skiplist *skiplist;
283
+ int retval;
284
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, &scores, NULL, &skiplist, NULL, 0, 0);
285
+ RL_CALL(rl_get_zscore, RL_FOUND, db, scores, member, memberlen, &score);
286
+ RL_CALL(rl_skiplist_first_node, RL_FOUND, db, skiplist, score, RL_SKIPLIST_INCLUDE_SCORE, member, memberlen, NULL, revrank);
287
+ *revrank = skiplist->size - (*revrank) - 1;
288
+ cleanup:
289
+ return retval;
290
+ }
291
+
292
+ int rl_zcard(rlite *db, const unsigned char *key, long keylen, long *card)
293
+ {
294
+ rl_skiplist *skiplist;
295
+ int retval;
296
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, NULL, NULL, &skiplist, NULL, 0, 0);
297
+ *card = skiplist->size;
298
+ retval = RL_OK;
299
+ cleanup:
300
+ return retval;
301
+ }
302
+
303
+ int rl_zcount(rlite *db, const unsigned char *key, long keylen, rl_zrangespec *range, long *count)
304
+ {
305
+ rl_skiplist *skiplist;
306
+ long maxrank, minrank;
307
+ int retval;
308
+ if (range->max < range->min) {
309
+ *count = 0;
310
+ retval = RL_OK;
311
+ goto cleanup;
312
+ }
313
+
314
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, NULL, NULL, &skiplist, NULL, 0, 0);
315
+
316
+ retval = rl_skiplist_first_node(db, skiplist, range->max, range->maxex ? RL_SKIPLIST_BEFORE_SCORE : RL_SKIPLIST_UPTO_SCORE, NULL, 0, NULL, &maxrank);
317
+ if (retval == RL_NOT_FOUND) {
318
+ maxrank = skiplist->size - 1;
319
+ }
320
+ else if (retval != RL_FOUND) {
321
+ goto cleanup;
322
+ }
323
+ retval = rl_skiplist_first_node(db, skiplist, range->min, range->minex ? RL_SKIPLIST_EXCLUDE_SCORE : RL_SKIPLIST_INCLUDE_SCORE, NULL, 0, NULL, &minrank);
324
+ if (retval != RL_FOUND) {
325
+ goto cleanup;
326
+ }
327
+ else if (minrank < 0) {
328
+ minrank = 0;
329
+ }
330
+
331
+ *count = maxrank - minrank + 1;
332
+ retval = RL_OK;
333
+ cleanup:
334
+ return retval;
335
+ }
336
+
337
+ static int _rl_zrange(rlite *db, rl_skiplist *skiplist, long start, long end, int direction, rl_zset_iterator **iterator)
338
+ {
339
+ int retval = RL_OK;
340
+ long size, node_page;
341
+ long card = skiplist->size;
342
+
343
+ if (start < 0) {
344
+ start += card;
345
+ if (start < 0) {
346
+ start = 0;
347
+ }
348
+ }
349
+ if (end < 0) {
350
+ end += card;
351
+ }
352
+ if (start > end || start >= card) {
353
+ retval = RL_NOT_FOUND;
354
+ goto cleanup;
355
+ }
356
+ if (end >= card) {
357
+ end = card - 1;
358
+ }
359
+
360
+ size = end - start + 1;
361
+
362
+ RL_CALL(rl_skiplist_node_by_rank, RL_OK, db, skiplist, direction > 0 ? start : end, NULL, &node_page);
363
+ RL_CALL(rl_skiplist_iterator_create, RL_OK, db, iterator, skiplist, node_page, direction, size);
364
+ cleanup:
365
+ return retval;
366
+ }
367
+
368
+ static int _rl_zrangebyscore(rlite *db, rl_skiplist *skiplist, rl_zrangespec *range, long *_start, long *_end)
369
+ {
370
+ long start, end;
371
+ rl_skiplist_node *node;
372
+ int retval;
373
+ RL_CALL(rl_skiplist_first_node, RL_FOUND, db, skiplist, range->min, range->minex ? RL_SKIPLIST_EXCLUDE_SCORE : RL_SKIPLIST_INCLUDE_SCORE, NULL, 0, NULL, &start);
374
+ retval = rl_skiplist_first_node(db, skiplist, range->max, range->maxex ? RL_SKIPLIST_BEFORE_SCORE : RL_SKIPLIST_UPTO_SCORE, NULL, 0, &node, &end);
375
+ if (retval != RL_FOUND && retval != RL_NOT_FOUND) {
376
+ goto cleanup;
377
+ }
378
+
379
+ if (retval == RL_FOUND && end == 0 && ((range->maxex && node->score == range->max) || node->score > range->max)) {
380
+ retval = RL_NOT_FOUND;
381
+ goto cleanup;
382
+ }
383
+ if (end < start) {
384
+ retval = RL_NOT_FOUND;
385
+ goto cleanup;
386
+ }
387
+ *_start = start;
388
+ *_end = end;
389
+ retval = RL_OK;
390
+ cleanup:
391
+ return retval;
392
+ }
393
+
394
+ int rl_zrangebyscore(rlite *db, const unsigned char *key, long keylen, rl_zrangespec *range, long offset, long count, rl_zset_iterator **iterator)
395
+ {
396
+ long start, end;
397
+ rl_skiplist *skiplist;
398
+ int retval;
399
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, NULL, NULL, &skiplist, NULL, 0, 0);
400
+ RL_CALL(_rl_zrangebyscore, RL_OK, db, skiplist, range, &start, &end);
401
+
402
+ start += offset;
403
+
404
+ RL_CALL(_rl_zrange, RL_OK, db, skiplist, start, end, 1, iterator);
405
+ if (count >= 0 && (*iterator)->size > count) {
406
+ (*iterator)->size = count;
407
+ }
408
+ cleanup:
409
+ return retval;
410
+ }
411
+
412
+ int rl_zrevrangebyscore(rlite *db, const unsigned char *key, long keylen, rl_zrangespec *range, long offset, long count, rl_zset_iterator **iterator)
413
+ {
414
+ long start, end;
415
+ rl_skiplist *skiplist;
416
+ int retval;
417
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, NULL, NULL, &skiplist, NULL, 0, 0);
418
+ RL_CALL(_rl_zrangebyscore, RL_OK, db, skiplist, range, &start, &end);
419
+
420
+ end -= offset;
421
+
422
+ RL_CALL(_rl_zrange, RL_OK, db, skiplist, start, end, -1, iterator);
423
+ if (count >= 0 && (*iterator)->size > count) {
424
+ (*iterator)->size = count;
425
+ }
426
+ cleanup:
427
+ return retval;
428
+ }
429
+
430
+ static int validate_lex_range(unsigned char *min, long minlen, unsigned char *max, long maxlen)
431
+ {
432
+ if ((minlen != 1 || min[0] != '-') && min[0] != '(' && min[0] != '[') {
433
+ return RL_UNEXPECTED;
434
+ }
435
+
436
+ if ((maxlen != 1 || max[0] != '+') && max[0] != '(' && max[0] != '[') {
437
+ return RL_UNEXPECTED;
438
+ }
439
+ return RL_OK;
440
+ }
441
+
442
+ static int lex_get_range(rlite *db, unsigned char *min, long minlen, unsigned char *max, long maxlen, rl_skiplist *skiplist, long *_start, long *_end)
443
+ {
444
+ int retval;
445
+ RL_CALL(validate_lex_range, RL_OK, min, minlen, max, maxlen);
446
+
447
+ rl_skiplist_node *node;
448
+ double score;
449
+ RL_CALL(rl_skiplist_first_node, RL_FOUND, db, skiplist, -INFINITY, RL_SKIPLIST_EXCLUDE_SCORE, NULL, 0, &node, NULL);
450
+ score = node->score;
451
+
452
+ long start, end;
453
+ if (min[0] == '-') {
454
+ start = 0;
455
+ }
456
+ else {
457
+ RL_CALL(rl_skiplist_first_node, RL_FOUND, db, skiplist, score, min[0] == '(' ? RL_SKIPLIST_EXCLUDE_SCORE : RL_SKIPLIST_INCLUDE_SCORE, &min[1], minlen - 1, &node, &start);
458
+ }
459
+
460
+ if (max[0] == '+') {
461
+ end = -1;
462
+ }
463
+ else {
464
+ RL_CALL(rl_skiplist_first_node, RL_FOUND, db, skiplist, score, max[0] == '(' ? RL_SKIPLIST_BEFORE_SCORE : RL_SKIPLIST_UPTO_SCORE, &max[1], maxlen - 1, NULL, &end);
465
+ if (retval != RL_FOUND) {
466
+ goto cleanup;
467
+ }
468
+ if (end < 0) {
469
+ retval = RL_NOT_FOUND;
470
+ goto cleanup;
471
+ }
472
+ }
473
+
474
+ if (_start) {
475
+ *_start = start;
476
+ }
477
+ if (_end) {
478
+ *_end = end;
479
+ }
480
+ retval = RL_OK;
481
+ cleanup:
482
+ return retval;
483
+ }
484
+
485
+ int rl_zlexcount(rlite *db, const unsigned char *key, long keylen, unsigned char *min, long minlen, unsigned char *max, long maxlen, long *lexcount)
486
+ {
487
+ long start, end;
488
+ rl_skiplist *skiplist;
489
+ int retval;
490
+ RL_CALL(validate_lex_range, RL_OK, min, minlen, max, maxlen);
491
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, NULL, NULL, &skiplist, NULL, 0, 0);
492
+ RL_CALL(lex_get_range, RL_OK, db, min, minlen, max, maxlen, skiplist, &start, &end);
493
+ if (end < 0) {
494
+ end += skiplist->size;
495
+ }
496
+
497
+ if (end >= start) {
498
+ *lexcount = end - start + 1;
499
+ }
500
+ else {
501
+ *lexcount = 0;
502
+ }
503
+ retval = RL_OK;
504
+ cleanup:
505
+ return retval;
506
+ }
507
+
508
+ int rl_zrevrangebylex(rlite *db, const unsigned char *key, long keylen, unsigned char *max, long maxlen, unsigned char *min, long minlen, long offset, long count, rl_zset_iterator **iterator)
509
+ {
510
+ long start, end;
511
+ rl_skiplist *skiplist;
512
+ int retval;
513
+ RL_CALL(validate_lex_range, RL_OK, min, minlen, max, maxlen);
514
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, NULL, NULL, &skiplist, NULL, 0, 0);
515
+ RL_CALL(lex_get_range, RL_OK, db, min, minlen, max, maxlen, skiplist, &start, &end);
516
+
517
+ end -= offset;
518
+
519
+ RL_CALL(_rl_zrange, RL_OK, db, skiplist, start, end, -1, iterator);
520
+ if (count >= 0 && (*iterator)->size > count) {
521
+ (*iterator)->size = count;
522
+ }
523
+ cleanup:
524
+ return retval;
525
+ }
526
+
527
+ int rl_zrangebylex(rlite *db, const unsigned char *key, long keylen, unsigned char *min, long minlen, unsigned char *max, long maxlen, long offset, long count, rl_zset_iterator **iterator)
528
+ {
529
+ long start, end;
530
+ rl_skiplist *skiplist;
531
+ int retval;
532
+ RL_CALL(validate_lex_range, RL_OK, min, minlen, max, maxlen);
533
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, NULL, NULL, &skiplist, NULL, 0, 0);
534
+ RL_CALL(lex_get_range, RL_OK, db, min, minlen, max, maxlen, skiplist, &start, &end);
535
+
536
+ start += offset;
537
+
538
+ RL_CALL(_rl_zrange, RL_OK, db, skiplist, start, end, 1, iterator);
539
+ if (count >= 0 && (*iterator)->size > count) {
540
+ (*iterator)->size = count;
541
+ }
542
+ cleanup:
543
+ return retval;
544
+ }
545
+
546
+ int rl_zrevrange(rlite *db, const unsigned char *key, long keylen, long start, long end, rl_zset_iterator **iterator)
547
+ {
548
+ rl_skiplist *skiplist;
549
+
550
+ int retval;
551
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, NULL, NULL, &skiplist, NULL, 0, 0);
552
+ RL_CALL(_rl_zrange, RL_OK, db, skiplist, - end - 1, - start - 1, -1, iterator);
553
+ cleanup:
554
+ return retval;
555
+ }
556
+
557
+ int rl_zrange(rlite *db, const unsigned char *key, long keylen, long start, long end, rl_zset_iterator **iterator)
558
+ {
559
+ rl_skiplist *skiplist;
560
+
561
+ int retval;
562
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, NULL, NULL, &skiplist, NULL, 0, 0);
563
+ RL_CALL(_rl_zrange, RL_OK, db, skiplist, start, end, 1, iterator);
564
+ cleanup:
565
+ return retval;
566
+ }
567
+
568
+ int rl_zset_iterator_next(rl_zset_iterator *iterator, double *score, unsigned char **member, long *memberlen)
569
+ {
570
+ if (member && !memberlen) {
571
+ fprintf(stderr, "If member is provided, memberlen is required\n");
572
+ return RL_UNEXPECTED;
573
+ }
574
+
575
+ rl_skiplist_node *node;
576
+ int retval;
577
+ RL_CALL(rl_skiplist_iterator_next, RL_OK, iterator, &node);
578
+
579
+ if (memberlen) {
580
+ retval = rl_multi_string_get(iterator->db, node->value, member, memberlen);
581
+ if (retval != RL_OK) {
582
+ rl_skiplist_iterator_destroy(iterator->db, iterator);
583
+ goto cleanup;
584
+ }
585
+ }
586
+
587
+ if (score) {
588
+ *score = node->score;
589
+ }
590
+ cleanup:
591
+ return retval;
592
+ }
593
+
594
+ int rl_zset_iterator_destroy(rl_zset_iterator *iterator)
595
+ {
596
+ return rl_skiplist_iterator_destroy(iterator->db, iterator);
597
+ }
598
+
599
+ int rl_zrem(rlite *db, const unsigned char *key, long keylen, long members_size, unsigned char **members, long *members_len, long *changed)
600
+ {
601
+ rl_btree *scores;
602
+ rl_skiplist *skiplist;
603
+ long scores_page, skiplist_page, levels_page_number;
604
+ int retval;
605
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, &levels_page_number, &scores, &scores_page, &skiplist, &skiplist_page, 1, 1);
606
+ long i;
607
+ long _changed = 0;
608
+ for (i = 0; i < members_size; i++) {
609
+ retval = remove_member(db, key, keylen, levels_page_number, scores, scores_page, skiplist, skiplist_page, members[i], members_len[i]);
610
+ if (retval != RL_OK && retval != RL_NOT_FOUND && retval != RL_DELETED) {
611
+ goto cleanup;
612
+ }
613
+ else if (retval == RL_OK || retval == RL_DELETED) {
614
+ _changed++;
615
+ if (retval == RL_DELETED) {
616
+ // there is no any other element in the zset, nothing else to delete
617
+ break;
618
+ }
619
+ }
620
+ }
621
+
622
+ *changed = _changed;
623
+ retval = RL_OK;
624
+ cleanup:
625
+ return retval;
626
+ }
627
+
628
+ static int _zremiterator(rlite *db, const unsigned char *key, long keylen, long levels_page_number, rl_zset_iterator *iterator, rl_btree *scores, long scores_page, rl_skiplist *skiplist, long skiplist_page, long *changed)
629
+ {
630
+ long _changed = 0;
631
+ double score;
632
+ unsigned char *member;
633
+ long memberlen;
634
+ int retval;
635
+ while ((retval = rl_zset_iterator_next(iterator, &score, &member, &memberlen)) == RL_OK) {
636
+ retval = remove_member_score(db, key, keylen, levels_page_number, scores, scores_page, skiplist, skiplist_page, member, memberlen, score);
637
+ rl_free(member);
638
+ if (retval != RL_OK && retval != RL_DELETED) {
639
+ rl_zset_iterator_destroy(iterator);
640
+ goto cleanup;
641
+ }
642
+ _changed++;
643
+ }
644
+
645
+ if (retval != RL_END) {
646
+ goto cleanup;
647
+ }
648
+
649
+ *changed = _changed;
650
+ retval = RL_OK;
651
+ cleanup:
652
+ return retval;
653
+ }
654
+
655
+ int rl_zremrangebyrank(rlite *db, const unsigned char *key, long keylen, long start, long end, long *changed)
656
+ {
657
+ rl_zset_iterator *iterator;
658
+ rl_btree *scores;
659
+ rl_skiplist *skiplist;
660
+ long scores_page, skiplist_page, levels_page_number;
661
+ int retval;
662
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, &levels_page_number, &scores, &scores_page, &skiplist, &skiplist_page, 1, 1);
663
+ RL_CALL(_rl_zrange, RL_OK, db, skiplist, start, end, 1, &iterator);
664
+ RL_CALL(_zremiterator, RL_OK, db, key, keylen, levels_page_number, iterator, scores, scores_page, skiplist, skiplist_page, changed);
665
+ retval = RL_OK;
666
+ cleanup:
667
+ if (retval != RL_OK && changed) {
668
+ *changed = 0;
669
+ }
670
+ return retval;
671
+ }
672
+
673
+ int rl_zremrangebyscore(rlite *db, const unsigned char *key, long keylen, rl_zrangespec *range, long *changed)
674
+ {
675
+ rl_zset_iterator *iterator;
676
+ rl_btree *scores;
677
+ rl_skiplist *skiplist;
678
+ long scores_page, skiplist_page, levels_page_number;
679
+ int retval;
680
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, &levels_page_number, &scores, &scores_page, &skiplist, &skiplist_page, 1, 1);
681
+
682
+ long start, end;
683
+ RL_CALL(_rl_zrangebyscore, RL_OK, db, skiplist, range, &start, &end);
684
+ RL_CALL(_rl_zrange, RL_OK, db, skiplist, start, end, 1, &iterator);
685
+ RL_CALL(_zremiterator, RL_OK, db, key, keylen, levels_page_number, iterator, scores, scores_page, skiplist, skiplist_page, changed);
686
+ retval = RL_OK;
687
+ cleanup:
688
+ if (retval != RL_OK && changed) {
689
+ *changed = 0;
690
+ }
691
+ return retval;
692
+ }
693
+
694
+ int rl_zremrangebylex(rlite *db, const unsigned char *key, long keylen, unsigned char *min, long minlen, unsigned char *max, long maxlen, long *changed)
695
+ {
696
+ rl_zset_iterator *iterator;
697
+ rl_btree *scores;
698
+ rl_skiplist *skiplist;
699
+ long scores_page, skiplist_page, start, end, levels_page_number;
700
+ int retval;
701
+ RL_CALL(validate_lex_range, RL_OK, min, minlen, max, maxlen);
702
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, &levels_page_number, &scores, &scores_page, &skiplist, &skiplist_page, 1, 1);
703
+ retval = lex_get_range(db, min, minlen, max, maxlen, skiplist, &start, &end);
704
+ if (retval == RL_NOT_FOUND) {
705
+ *changed = 0;
706
+ retval = RL_OK;
707
+ goto cleanup;
708
+ }
709
+ if (retval != RL_OK) {
710
+ goto cleanup;
711
+ }
712
+
713
+ RL_CALL(_rl_zrange, RL_OK, db, skiplist, start, end, 1, &iterator);
714
+ RL_CALL(_zremiterator, RL_OK, db, key, keylen, levels_page_number, iterator, scores, scores_page, skiplist, skiplist_page, changed);
715
+ retval = RL_OK;
716
+ cleanup:
717
+ if (retval != RL_OK && changed) {
718
+ *changed = 0;
719
+ }
720
+ return retval;
721
+ }
722
+
723
+
724
+ static int incrby(rlite *db, const unsigned char *key, long keylen, double score, unsigned char *member, long memberlen, double *newscore, int clearnan)
725
+ {
726
+ rl_btree *scores;
727
+ rl_skiplist *skiplist;
728
+ long scores_page, skiplist_page, levels_page_number;
729
+ double existing_score = 0.0;
730
+ int retval;
731
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, &levels_page_number, &scores, &scores_page, &skiplist, &skiplist_page, 1, 1);
732
+ retval = rl_get_zscore(db, scores, member, memberlen, &existing_score);
733
+ if (retval != RL_FOUND && retval != RL_NOT_FOUND) {
734
+ goto cleanup;
735
+ }
736
+ else if (retval == RL_FOUND) {
737
+ score += existing_score;
738
+ if (isnan(score)) {
739
+ if (clearnan) {
740
+ score = 0.0;
741
+ }
742
+ else {
743
+ retval = RL_NAN;
744
+ goto cleanup;
745
+ }
746
+ }
747
+ retval = remove_member(db, key, keylen, levels_page_number, scores, scores_page, skiplist, skiplist_page, member, memberlen);
748
+ if (retval == RL_DELETED) {
749
+ // it would be nice if we could update the score without destroying the btree, maybe remove_member should have an int destroy?
750
+ RL_CALL(rl_zset_get_objects, RL_OK, db, key, keylen, NULL, &scores, &scores_page, &skiplist, &skiplist_page, 0, 1);
751
+ }
752
+ else if (retval != RL_OK) {
753
+ goto cleanup;
754
+ }
755
+ }
756
+
757
+ RL_CALL(add_member, RL_OK, db, scores, scores_page, skiplist, skiplist_page, score, member, memberlen);
758
+ if (newscore) {
759
+ *newscore = score;
760
+ }
761
+ cleanup:
762
+ return retval;
763
+ }
764
+
765
+ int rl_zincrby(rlite *db, const unsigned char *key, long keylen, double score, unsigned char *member, long memberlen, double *newscore)
766
+ {
767
+ return incrby(db, key, keylen, score, member, memberlen, newscore, 0);
768
+ }
769
+
770
+ int rl_zinterstore(rlite *db, long keys_size, unsigned char **keys, long *keys_len, double *_weights, int aggregate)
771
+ {
772
+ unsigned char *member = NULL;
773
+ rl_btree **btrees = NULL;
774
+ rl_skiplist **skiplists = NULL;
775
+ double weight = 1.0, weight_tmp;
776
+ double *weights = NULL;
777
+ rl_skiplist_node *node;
778
+ rl_skiplist_iterator *skiplist_iterator = NULL;
779
+ rl_btree_iterator *btree_iterator = NULL;
780
+ int retval;
781
+ long target_btree_page, target_skiplist_page;
782
+ long multi_string_page;
783
+ rl_btree *target_btree;
784
+ rl_skiplist *target_skiplist;
785
+ int found;
786
+ void *tmp;
787
+ double skiplist_score, tmp_score;
788
+ long memberlen;
789
+ unsigned char digest[20];
790
+
791
+ if (keys_size > 1) {
792
+ RL_MALLOC(btrees, sizeof(rl_btree *) * (keys_size - 1));
793
+ RL_MALLOC(skiplists, sizeof(rl_skiplist *) * (keys_size - 1));
794
+ }
795
+ else {
796
+ retval = RL_UNEXPECTED;
797
+ goto cleanup;
798
+ }
799
+ retval = rl_key_delete_with_value(db, keys[0], keys_len[0]);
800
+ if (retval != RL_OK && retval != RL_NOT_FOUND) {
801
+ goto cleanup;
802
+ }
803
+ rl_btree *btree, *btree_tmp;
804
+ rl_skiplist *skiplist = NULL, *skiplist_tmp;
805
+ long i;
806
+ // key in position 0 is the target key
807
+ // we'll store a pivot skiplist in btree/skiplist and the others in btrees/skiplists
808
+ // TODO: qsort instead
809
+ RL_MALLOC(weights, sizeof(double) * (keys_size - 2));
810
+ for (i = 1; i < keys_size; i++) {
811
+ weight_tmp = _weights ? _weights[i - 1] : 1.0;
812
+ RL_CALL2(rl_zset_get_objects, RL_OK, RL_WRONG_TYPE, db, keys[i], keys_len[i], NULL, &btree_tmp, NULL, &skiplist_tmp, NULL, 0, 0);
813
+ if (retval == RL_WRONG_TYPE) {
814
+ skiplist_tmp = NULL;
815
+ RL_CALL(rl_set_get_objects, RL_OK, db, keys[i], keys_len[i], NULL, &btree_tmp, 0, 0);
816
+ }
817
+ if (i == 1) {
818
+ btree = btree_tmp;
819
+ skiplist = skiplist_tmp;
820
+ weight = weight_tmp;
821
+ }
822
+ else if (btree_tmp->number_of_elements < btree->number_of_elements) {
823
+ weights[i - 2] = weight;
824
+ weight = weight_tmp;
825
+ btrees[i - 2] = btree;
826
+ btree = btree_tmp;
827
+ skiplists[i - 2] = skiplist;
828
+ skiplist = skiplist_tmp;
829
+ }
830
+ else {
831
+ weights[i - 2] = weight_tmp;
832
+ btrees[i - 2] = btree_tmp;
833
+ skiplists[i - 2] = skiplist_tmp;
834
+ }
835
+ }
836
+
837
+ RL_CALL(rl_zset_get_objects, RL_OK, db, keys[0], keys_len[0], NULL, &target_btree, &target_btree_page, &target_skiplist, &target_skiplist_page, 1, 1);
838
+
839
+ if (skiplist) {
840
+ RL_CALL(rl_skiplist_iterator_create, RL_OK, db, &skiplist_iterator, skiplist, 0, 0, 0);
841
+ } else {
842
+ RL_CALL(rl_btree_iterator_create, RL_OK, db, btree, &btree_iterator);
843
+ }
844
+ while ((retval = skiplist ? rl_skiplist_iterator_next(skiplist_iterator, &node) : rl_btree_iterator_next(btree_iterator, NULL, &tmp)) == RL_OK) {
845
+ found = 1;
846
+ if (skiplist) {
847
+ skiplist_score = node->score * weight;
848
+ multi_string_page = node->value;
849
+ } else {
850
+ skiplist_score = weight;
851
+ multi_string_page = *(long *)tmp;
852
+ rl_free(tmp);
853
+ }
854
+ for (i = 1; i < keys_size - 1; i++) {
855
+ RL_CALL(rl_multi_string_sha1, RL_OK, db, digest, multi_string_page);
856
+
857
+ retval = rl_btree_find_score(db, btrees[i - 1], digest, &tmp, NULL, NULL);
858
+ if (retval == RL_NOT_FOUND) {
859
+ found = 0;
860
+ break;
861
+ }
862
+ else if (retval == RL_FOUND) {
863
+ tmp_score = skiplist ? *(double *)tmp : 1.0;
864
+ if (aggregate == RL_ZSET_AGGREGATE_SUM) {
865
+ skiplist_score += tmp_score * weights[i - 1];
866
+ }
867
+ else if (
868
+ (aggregate == RL_ZSET_AGGREGATE_MIN && tmp_score * weights[i - 1] < skiplist_score) ||
869
+ (aggregate == RL_ZSET_AGGREGATE_MAX && tmp_score * weights[i - 1] > skiplist_score)
870
+ ) {
871
+ skiplist_score = tmp_score * weights[i - 1];
872
+ }
873
+ }
874
+ else {
875
+ goto cleanup;
876
+ }
877
+ }
878
+ if (found) {
879
+ RL_CALL(rl_multi_string_get, RL_OK, db, multi_string_page, &member, &memberlen);
880
+ RL_CALL(add_member, RL_OK, db, target_btree, target_btree_page, target_skiplist, target_skiplist_page, isnan(skiplist_score) ? 0.0 : skiplist_score, member, memberlen);
881
+ rl_free(member);
882
+ member = NULL;
883
+ }
884
+ }
885
+ skiplist_iterator = NULL;
886
+ btree_iterator = NULL;
887
+
888
+ if (retval != RL_END) {
889
+ goto cleanup;
890
+ }
891
+
892
+ retval = RL_OK;
893
+ cleanup:
894
+ rl_free(member);
895
+ if (skiplist_iterator) {
896
+ rl_zset_iterator_destroy(skiplist_iterator);
897
+ }
898
+ if (btree_iterator) {
899
+ rl_btree_iterator_destroy(btree_iterator);
900
+ }
901
+ rl_free(weights);
902
+ rl_free(btrees);
903
+ rl_free(skiplists);
904
+ return retval;
905
+ }
906
+ static int zunionstore_minmax(rlite *db, long keys_size, unsigned char **keys, long *keys_len, double *weights, int aggregate)
907
+ {
908
+ rl_btree *target_scores;
909
+ long target_scores_page, target_skiplist_page;
910
+ rl_skiplist *target_skiplist;
911
+ int retval;
912
+ rl_skiplist_iterator **iterators = NULL;;
913
+ rl_skiplist *skiplist;
914
+ double *scores = NULL, score;
915
+ unsigned char **members = NULL;
916
+ long *memberslen = NULL, i;
917
+ long position;
918
+ RL_CALL(rl_zset_get_objects, RL_OK, db, keys[0], keys_len[0], NULL, &target_scores, &target_scores_page, &target_skiplist, &target_skiplist_page, 1, 1);
919
+ RL_MALLOC(scores, sizeof(double) * keys_size);
920
+ RL_MALLOC(members, sizeof(unsigned char *) * keys_size);
921
+ for (i = 0; i < keys_size; i++) {
922
+ members[i] = NULL;
923
+ }
924
+ RL_MALLOC(memberslen, sizeof(long) * keys_size);
925
+ RL_MALLOC(iterators, sizeof(rl_skiplist_iterator *) * keys_size);
926
+ for (i = 0; i < keys_size; i++) {
927
+ iterators[i] = NULL;
928
+ }
929
+
930
+ for (i = 0; i < keys_size; i++) {
931
+ retval = rl_zset_get_objects(db, keys[i], keys_len[i], NULL, NULL, NULL, &skiplist, NULL, 0, 0);
932
+ if (retval == RL_NOT_FOUND) {
933
+ iterators[i] = NULL;
934
+ continue;
935
+ }
936
+ if (retval != RL_OK) {
937
+ goto cleanup;
938
+ }
939
+ RL_CALL(rl_skiplist_iterator_create, RL_OK, db, &iterators[i], skiplist, 0, aggregate == RL_ZSET_AGGREGATE_MAX ? -1 : 1, 0);
940
+ retval = rl_zset_iterator_next(iterators[i], &scores[i], &members[i], &memberslen[i]);
941
+ if (retval != RL_OK) {
942
+ iterators[i] = NULL;
943
+ if (retval != RL_END) {
944
+ goto cleanup;
945
+ }
946
+ }
947
+ }
948
+
949
+ while (1) {
950
+ position = -1;
951
+ for (i = 0; i < keys_size; i++) {
952
+ if (!iterators[i]) {
953
+ continue;
954
+ }
955
+ if (position == -1) {
956
+ position = i;
957
+ continue;
958
+ }
959
+ score = weights ? weights[position - 1] * scores[position] : scores[position];
960
+ if (isnan(score)) {
961
+ score = 0.0;
962
+ }
963
+ if ((aggregate == RL_ZSET_AGGREGATE_MAX && scores[i] > score) ||
964
+ (aggregate == RL_ZSET_AGGREGATE_MIN && scores[i] < score)) {
965
+ position = i;
966
+ }
967
+ }
968
+ if (position == -1) {
969
+ break;
970
+ }
971
+
972
+ score = weights ? weights[position - 1] * scores[position] : scores[position];
973
+ if (isnan(score)) {
974
+ score = 0.0;
975
+ }
976
+ retval = add_member(db, target_scores, target_scores_page, target_skiplist, target_skiplist_page, score, members[position], memberslen[position]);
977
+ if (retval != RL_FOUND && retval != RL_OK) {
978
+ goto cleanup;
979
+ }
980
+ rl_free(members[position]);
981
+ members[position] = NULL;
982
+
983
+ retval = rl_zset_iterator_next(iterators[position], &scores[position], &members[position], &memberslen[position]);
984
+ if (retval != RL_OK) {
985
+ iterators[position] = NULL;
986
+ if (retval != RL_END) {
987
+ goto cleanup;
988
+ }
989
+ }
990
+ }
991
+ if (target_scores->number_of_elements == 0) {
992
+ RL_CALL(rl_key_delete_with_value, RL_OK, db, keys[0], keys_len[0]);
993
+ }
994
+
995
+ retval = RL_OK;
996
+ cleanup:
997
+ if (iterators) {
998
+ for (i = 0; i < keys_size; i++) {
999
+ if (iterators[i]) {
1000
+ rl_zset_iterator_destroy(iterators[i]);
1001
+ }
1002
+ rl_free(members[i]);
1003
+ }
1004
+ }
1005
+ rl_free(iterators);
1006
+ rl_free(memberslen);
1007
+ rl_free(members);
1008
+ rl_free(scores);
1009
+ return retval;
1010
+ }
1011
+
1012
+ static int zunionstore_sum(rlite *db, long keys_size, unsigned char **keys, long *keys_len, double *weights)
1013
+ {
1014
+ rl_skiplist_iterator *iterator = NULL;
1015
+ rl_skiplist *skiplist;
1016
+ double score;
1017
+ unsigned char *member;
1018
+ long memberlen;
1019
+ int retval;
1020
+ long i;
1021
+ for (i = 1; i < keys_size; i++) {
1022
+ retval = rl_zset_get_objects(db, keys[i], keys_len[i], NULL, NULL, NULL, &skiplist, NULL, 0, 0);
1023
+ if (retval == RL_NOT_FOUND) {
1024
+ continue;
1025
+ }
1026
+ if (retval != RL_OK) {
1027
+ goto cleanup;
1028
+ }
1029
+ RL_CALL(rl_skiplist_iterator_create, RL_OK, db, &iterator, skiplist, 0, 1, 0);
1030
+ while ((retval = rl_zset_iterator_next(iterator, &score, &member, &memberlen)) == RL_OK) {
1031
+ if (weights) {
1032
+ score *= weights[i - 1];
1033
+ }
1034
+ if (isnan(score)) {
1035
+ score = 0.0;
1036
+ }
1037
+ retval = incrby(db, keys[0], keys_len[0], score, member, memberlen, NULL, 1);
1038
+ rl_free(member);
1039
+ if (retval != RL_OK) {
1040
+ goto cleanup;
1041
+ }
1042
+ }
1043
+ iterator = NULL;
1044
+
1045
+ if (retval != RL_END) {
1046
+ goto cleanup;
1047
+ }
1048
+ }
1049
+
1050
+ retval = RL_OK;
1051
+ cleanup:
1052
+ if (iterator) {
1053
+ rl_zset_iterator_destroy(iterator);
1054
+ }
1055
+ return retval;
1056
+ }
1057
+
1058
+ int rl_zunionstore(rlite *db, long keys_size, unsigned char **keys, long *keys_len, double *weights, int aggregate)
1059
+ {
1060
+ int retval;
1061
+ retval = rl_key_delete_with_value(db, keys[0], keys_len[0]);
1062
+ if (retval != RL_OK && retval != RL_NOT_FOUND) {
1063
+ goto cleanup;
1064
+ }
1065
+ if (aggregate == RL_ZSET_AGGREGATE_SUM) {
1066
+ RL_CALL(zunionstore_sum, RL_OK, db, keys_size, keys, keys_len, weights);
1067
+ }
1068
+ else {
1069
+ RL_CALL(zunionstore_minmax, RL_OK, db, keys_size, keys, keys_len, weights, aggregate);
1070
+ }
1071
+
1072
+ cleanup:
1073
+ return retval;
1074
+ }
1075
+
1076
+ int rl_zset_pages(struct rlite *db, long page, short *pages)
1077
+ {
1078
+ rl_btree *scores;
1079
+ rl_skiplist *skiplist;
1080
+ rl_skiplist_iterator *iterator = NULL;
1081
+ rl_skiplist_node *node;
1082
+ long scores_page, skiplist_page;
1083
+ int retval;
1084
+ void *tmp;
1085
+ rl_list *levels;
1086
+
1087
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_list_long, page, &rl_list_type_long, &tmp, 1);
1088
+ levels = tmp;
1089
+ rl_list_pages(db, levels, pages);
1090
+
1091
+ RL_CALL(rl_zset_read, RL_OK, db, page, &scores, &scores_page, &skiplist, &skiplist_page);
1092
+ pages[scores_page] = 1;
1093
+ pages[skiplist_page] = 1;
1094
+
1095
+ RL_CALL(rl_btree_pages, RL_OK, db, scores, pages);
1096
+
1097
+ RL_CALL(rl_skiplist_pages, RL_OK, db, skiplist, pages);
1098
+
1099
+ RL_CALL(rl_skiplist_iterator_create, RL_OK, db, &iterator, skiplist, 0, 1, 0);
1100
+ while ((rl_skiplist_iterator_next(iterator, &node)) == RL_OK) {
1101
+ pages[node->value] = 1;
1102
+ RL_CALL(rl_multi_string_pages, RL_OK, iterator->db, node->value, pages);
1103
+ }
1104
+ iterator = NULL;
1105
+
1106
+ if (retval != RL_END) {
1107
+ goto cleanup;
1108
+ }
1109
+
1110
+ retval = RL_OK;
1111
+ cleanup:
1112
+ if (retval != RL_OK) {
1113
+ if (iterator) {
1114
+ rl_skiplist_iterator_destroy(db, iterator);
1115
+ }
1116
+ }
1117
+ return retval;
1118
+ }
1119
+
1120
+ int rl_zset_delete(rlite *db, long value_page)
1121
+ {
1122
+ long skiplist_page, scores_page;
1123
+ rl_skiplist *skiplist;
1124
+ rl_btree *scores;
1125
+ int retval;
1126
+ void *tmp;
1127
+ rl_list *levels;
1128
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_list_long, value_page, &rl_list_type_long, &tmp, 1);
1129
+ levels = tmp;
1130
+ RL_CALL(rl_list_get_element, RL_FOUND, db, levels, &tmp, 0);
1131
+ scores_page = *(long *)tmp;
1132
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_btree_hash_sha1_double, scores_page, &rl_btree_type_hash_sha1_double, &tmp, 1);
1133
+ scores = tmp;
1134
+ RL_CALL(rl_list_get_element, RL_FOUND, db, levels, &tmp, 1);
1135
+ skiplist_page = *(long *)tmp;
1136
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_skiplist, skiplist_page, NULL, &tmp, 1);
1137
+ skiplist = tmp;
1138
+ RL_CALL(rl_skiplist_delete_all, RL_OK, db, skiplist);
1139
+ RL_CALL(rl_delete, RL_OK, db, skiplist_page);
1140
+ RL_CALL(rl_btree_delete, RL_OK, db, scores);
1141
+ RL_CALL(rl_delete, RL_OK, db, scores_page);
1142
+ RL_CALL(rl_read, RL_FOUND, db, &rl_data_type_list_long, value_page, &rl_list_type_long, &tmp, 1);
1143
+ RL_CALL(rl_list_delete, RL_OK, db, tmp);
1144
+ RL_CALL(rl_delete, RL_OK, db, value_page);
1145
+ cleanup:
1146
+ return retval;
1147
+ }