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,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
+ }