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,397 @@
1
+ /*
2
+ * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * * Redistributions of source code must retain the above copyright notice,
9
+ * this list of conditions and the following disclaimer.
10
+ * * Redistributions in binary form must reproduce the above copyright
11
+ * notice, this list of conditions and the following disclaimer in the
12
+ * documentation and/or other materials provided with the distribution.
13
+ * * Neither the name of Redis nor the names of its contributors may be used
14
+ * to endorse or promote products derived from this software without
15
+ * specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ * POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+ #include "utilfromredis.h"
30
+ #include <ctype.h>
31
+ #include <limits.h>
32
+ #include <string.h>
33
+ #include <stdint.h>
34
+
35
+ // https://github.com/antirez/redis/blob/unstable/src/util.c#L45
36
+ //
37
+ /* Glob-style pattern matching. */
38
+ int rl_stringmatchlen(const char *pattern, int patternLen,
39
+ const char *string, int stringLen, int nocase)
40
+ {
41
+ while(patternLen) {
42
+ switch(pattern[0]) {
43
+ case '*':
44
+ while (pattern[1] == '*') {
45
+ pattern++;
46
+ patternLen--;
47
+ }
48
+ if (patternLen == 1)
49
+ return 1; /* match */
50
+ while(stringLen) {
51
+ if (rl_stringmatchlen(pattern+1, patternLen-1,
52
+ string, stringLen, nocase))
53
+ return 1; /* match */
54
+ string++;
55
+ stringLen--;
56
+ }
57
+ return 0; /* no match */
58
+ break;
59
+ case '?':
60
+ if (stringLen == 0)
61
+ return 0; /* no match */
62
+ string++;
63
+ stringLen--;
64
+ break;
65
+ case '[':
66
+ {
67
+ int not, match;
68
+
69
+ pattern++;
70
+ patternLen--;
71
+ not = pattern[0] == '^';
72
+ if (not) {
73
+ pattern++;
74
+ patternLen--;
75
+ }
76
+ match = 0;
77
+ while(1) {
78
+ if (pattern[0] == '\\') {
79
+ pattern++;
80
+ patternLen--;
81
+ if (pattern[0] == string[0])
82
+ match = 1;
83
+ } else if (pattern[0] == ']') {
84
+ break;
85
+ } else if (patternLen == 0) {
86
+ pattern--;
87
+ patternLen++;
88
+ break;
89
+ } else if (pattern[1] == '-' && patternLen >= 3) {
90
+ int start = pattern[0];
91
+ int end = pattern[2];
92
+ int c = string[0];
93
+ if (start > end) {
94
+ int t = start;
95
+ start = end;
96
+ end = t;
97
+ }
98
+ if (nocase) {
99
+ start = tolower(start);
100
+ end = tolower(end);
101
+ c = tolower(c);
102
+ }
103
+ pattern += 2;
104
+ patternLen -= 2;
105
+ if (c >= start && c <= end)
106
+ match = 1;
107
+ } else {
108
+ if (!nocase) {
109
+ if (pattern[0] == string[0])
110
+ match = 1;
111
+ } else {
112
+ if (tolower((int)pattern[0]) == tolower((int)string[0]))
113
+ match = 1;
114
+ }
115
+ }
116
+ pattern++;
117
+ patternLen--;
118
+ }
119
+ if (not)
120
+ match = !match;
121
+ if (!match)
122
+ return 0; /* no match */
123
+ string++;
124
+ stringLen--;
125
+ break;
126
+ }
127
+ case '\\':
128
+ if (patternLen >= 2) {
129
+ pattern++;
130
+ patternLen--;
131
+ }
132
+ /* fall through */
133
+ default:
134
+ if (!nocase) {
135
+ if (pattern[0] != string[0])
136
+ return 0; /* no match */
137
+ } else {
138
+ if (tolower((int)pattern[0]) != tolower((int)string[0]))
139
+ return 0; /* no match */
140
+ }
141
+ string++;
142
+ stringLen--;
143
+ break;
144
+ }
145
+ pattern++;
146
+ patternLen--;
147
+ if (stringLen == 0) {
148
+ while(*pattern == '*') {
149
+ pattern++;
150
+ patternLen--;
151
+ }
152
+ break;
153
+ }
154
+ }
155
+ if (patternLen == 0 && stringLen == 0)
156
+ return 1;
157
+ return 0;
158
+ }
159
+
160
+ // Adapted from https://github.com/antirez/redis/blob/unstable/src/bitops.c#L287
161
+ /* BITOP op_name target_key src_key1 src_key2 src_key3 ... src_keyN */
162
+ void rl_internal_bitop(int op, unsigned long numkeys, unsigned char **objects, unsigned long *objectslen, unsigned char **result, long *resultlen)
163
+ {
164
+ unsigned long j;
165
+ unsigned long maxlen = 0; /* Array of length of src strings, and max len. */
166
+ unsigned long minlen = 0; /* Min len among the input keys. */
167
+ unsigned char *res = NULL; /* Resulting string. */
168
+
169
+
170
+ /* Lookup keys, and store pointers to the string objects into an array. */
171
+ for (j = 0; j < numkeys; j++) {
172
+ if (objectslen[j] > maxlen) maxlen = objectslen[j];
173
+ if (j == 0 || objectslen[j] < minlen) minlen = objectslen[j];
174
+ }
175
+
176
+ /* Compute the bit operation, if at least one string is not empty. */
177
+ if (maxlen) {
178
+ res = (unsigned char *)malloc(sizeof(unsigned char) * maxlen);
179
+ unsigned char output, byte;
180
+ unsigned long i;
181
+
182
+ /* Fast path: as far as we have data for all the input bitmaps we
183
+ * can take a fast path that performs much better than the
184
+ * vanilla algorithm. */
185
+ j = 0;
186
+ if (minlen && numkeys <= 16) {
187
+ unsigned long *lp[16];
188
+ unsigned long *lres = (unsigned long*) res;
189
+
190
+ memcpy(lp, objects, sizeof(unsigned long*) * numkeys);
191
+ memcpy(res, objects[0], minlen);
192
+
193
+ /* Different branches per different operations for speed (sorry). */
194
+ if (op == BITOP_AND) {
195
+ while(minlen >= sizeof(unsigned long)*4) {
196
+ for (i = 1; i < numkeys; i++) {
197
+ lres[0] &= lp[i][0];
198
+ lres[1] &= lp[i][1];
199
+ lres[2] &= lp[i][2];
200
+ lres[3] &= lp[i][3];
201
+ lp[i]+=4;
202
+ }
203
+ lres+=4;
204
+ j += sizeof(unsigned long)*4;
205
+ minlen -= sizeof(unsigned long)*4;
206
+ }
207
+ } else if (op == BITOP_OR) {
208
+ while(minlen >= sizeof(unsigned long)*4) {
209
+ for (i = 1; i < numkeys; i++) {
210
+ lres[0] |= lp[i][0];
211
+ lres[1] |= lp[i][1];
212
+ lres[2] |= lp[i][2];
213
+ lres[3] |= lp[i][3];
214
+ lp[i]+=4;
215
+ }
216
+ lres+=4;
217
+ j += sizeof(unsigned long)*4;
218
+ minlen -= sizeof(unsigned long)*4;
219
+ }
220
+ } else if (op == BITOP_XOR) {
221
+ while(minlen >= sizeof(unsigned long)*4) {
222
+ for (i = 1; i < numkeys; i++) {
223
+ lres[0] ^= lp[i][0];
224
+ lres[1] ^= lp[i][1];
225
+ lres[2] ^= lp[i][2];
226
+ lres[3] ^= lp[i][3];
227
+ lp[i]+=4;
228
+ }
229
+ lres+=4;
230
+ j += sizeof(unsigned long)*4;
231
+ minlen -= sizeof(unsigned long)*4;
232
+ }
233
+ } else if (op == BITOP_NOT) {
234
+ while(minlen >= sizeof(unsigned long)*4) {
235
+ lres[0] = ~lres[0];
236
+ lres[1] = ~lres[1];
237
+ lres[2] = ~lres[2];
238
+ lres[3] = ~lres[3];
239
+ lres+=4;
240
+ j += sizeof(unsigned long)*4;
241
+ minlen -= sizeof(unsigned long)*4;
242
+ }
243
+ }
244
+ }
245
+
246
+ /* j is set to the next byte to process by the previous loop. */
247
+ for (; j < maxlen; j++) {
248
+ output = (objectslen[0] <= j) ? 0 : objects[0][j];
249
+ if (op == BITOP_NOT) output = ~output;
250
+ for (i = 1; i < numkeys; i++) {
251
+ byte = (objectslen[i] <= j) ? 0 : objects[i][j];
252
+ switch(op) {
253
+ case BITOP_AND: output &= byte; break;
254
+ case BITOP_OR: output |= byte; break;
255
+ case BITOP_XOR: output ^= byte; break;
256
+ }
257
+ }
258
+ res[j] = output;
259
+ }
260
+ }
261
+
262
+ *result = res;
263
+ *resultlen = maxlen;
264
+ }
265
+
266
+ // https://github.com/antirez/redis/blob/unstable/src/bitops.c#L61
267
+ /* Count number of bits set in the binary array pointed by 's' and long
268
+ * 'count' bytes. The implementation of this function is required to
269
+ * work with a input string length up to 512 MB. */
270
+ size_t rl_redisPopcount(void *s, long count) {
271
+ size_t bits = 0;
272
+ unsigned char *p = s;
273
+ uint32_t *p4;
274
+ static const unsigned char bitsinbyte[256] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
275
+
276
+ /* Count initial bytes not aligned to 32 bit. */
277
+ while((unsigned long)p & 3 && count) {
278
+ bits += bitsinbyte[*p++];
279
+ count--;
280
+ }
281
+
282
+ /* Count bits 16 bytes at a time */
283
+ p4 = (uint32_t*)p;
284
+ while(count>=16) {
285
+ uint32_t aux1, aux2, aux3, aux4;
286
+
287
+ aux1 = *p4++;
288
+ aux2 = *p4++;
289
+ aux3 = *p4++;
290
+ aux4 = *p4++;
291
+ count -= 16;
292
+
293
+ aux1 = aux1 - ((aux1 >> 1) & 0x55555555);
294
+ aux1 = (aux1 & 0x33333333) + ((aux1 >> 2) & 0x33333333);
295
+ aux2 = aux2 - ((aux2 >> 1) & 0x55555555);
296
+ aux2 = (aux2 & 0x33333333) + ((aux2 >> 2) & 0x33333333);
297
+ aux3 = aux3 - ((aux3 >> 1) & 0x55555555);
298
+ aux3 = (aux3 & 0x33333333) + ((aux3 >> 2) & 0x33333333);
299
+ aux4 = aux4 - ((aux4 >> 1) & 0x55555555);
300
+ aux4 = (aux4 & 0x33333333) + ((aux4 >> 2) & 0x33333333);
301
+ bits += ((((aux1 + (aux1 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
302
+ ((((aux2 + (aux2 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
303
+ ((((aux3 + (aux3 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
304
+ ((((aux4 + (aux4 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24);
305
+ }
306
+ /* Count the remaining bytes. */
307
+ p = (unsigned char*)p4;
308
+ while(count--) bits += bitsinbyte[*p++];
309
+ return bits;
310
+ }
311
+
312
+ // https://github.com/antirez/redis/blob/unstable/src/bitops.c#L110
313
+ /* Return the position of the first bit set to one (if 'bit' is 1) or
314
+ * zero (if 'bit' is 0) in the bitmap starting at 's' and long 'count' bytes.
315
+ *
316
+ * The function is guaranteed to return a value >= 0 if 'bit' is 0 since if
317
+ * no zero bit is found, it returns count*8 assuming the string is zero
318
+ * padded on the right. However if 'bit' is 1 it is possible that there is
319
+ * not a single set bit in the bitmap. In this special case -1 is returned. */
320
+ long rl_internal_bitpos(void *s, unsigned long count, int bit) {
321
+ unsigned long *l;
322
+ unsigned char *c;
323
+ unsigned long skipval, word = 0, one;
324
+ long pos = 0; /* Position of bit, to return to the caller. */
325
+ unsigned long j;
326
+
327
+ /* Process whole words first, seeking for first word that is not
328
+ * all ones or all zeros respectively if we are lookig for zeros
329
+ * or ones. This is much faster with large strings having contiguous
330
+ * blocks of 1 or 0 bits compared to the vanilla bit per bit processing.
331
+ *
332
+ * Note that if we start from an address that is not aligned
333
+ * to sizeof(unsigned long) we consume it byte by byte until it is
334
+ * aligned. */
335
+
336
+ /* Skip initial bits not aligned to sizeof(unsigned long) byte by byte. */
337
+ skipval = bit ? 0 : UCHAR_MAX;
338
+ c = (unsigned char*) s;
339
+ while((unsigned long)c & (sizeof(*l)-1) && count) {
340
+ if (*c != skipval) break;
341
+ c++;
342
+ count--;
343
+ pos += 8;
344
+ }
345
+
346
+ /* Skip bits with full word step. */
347
+ skipval = bit ? 0 : ULONG_MAX;
348
+ l = (unsigned long*) c;
349
+ while (count >= sizeof(*l)) {
350
+ if (*l != skipval) break;
351
+ l++;
352
+ count -= sizeof(*l);
353
+ pos += sizeof(*l)*8;
354
+ }
355
+
356
+ /* Load bytes into "word" considering the first byte as the most significant
357
+ * (we basically consider it as written in big endian, since we consider the
358
+ * string as a set of bits from left to right, with the first bit at position
359
+ * zero.
360
+ *
361
+ * Note that the loading is designed to work even when the bytes left
362
+ * (count) are less than a full word. We pad it with zero on the right. */
363
+ c = (unsigned char*)l;
364
+ for (j = 0; j < sizeof(*l); j++) {
365
+ word <<= 8;
366
+ if (count) {
367
+ word |= *c;
368
+ c++;
369
+ count--;
370
+ }
371
+ }
372
+
373
+ /* Special case:
374
+ * If bits in the string are all zero and we are looking for one,
375
+ * return -1 to signal that there is not a single "1" in the whole
376
+ * string. This can't happen when we are looking for "0" as we assume
377
+ * that the right of the string is zero padded. */
378
+ if (bit == 1 && word == 0) return -1;
379
+
380
+ /* Last word left, scan bit by bit. The first thing we need is to
381
+ * have a single "1" set in the most significant position in an
382
+ * unsigned long. We don't know the size of the long so we use a
383
+ * simple trick. */
384
+ one = ULONG_MAX; /* All bits set to 1.*/
385
+ one >>= 1; /* All bits set to 1 but the MSB. */
386
+ one = ~one; /* All bits set to 0 but the MSB. */
387
+
388
+ while(one) {
389
+ if (((one & word) != 0) == bit) return pos;
390
+ pos++;
391
+ one >>= 1;
392
+ }
393
+
394
+ /* If we reached this point, there is a bug in the algorithm, since
395
+ * the case of no match is handled as a special case before. */
396
+ return -2;
397
+ }
@@ -0,0 +1,11 @@
1
+ #include <stdlib.h>
2
+
3
+ #define BITOP_AND 0
4
+ #define BITOP_OR 1
5
+ #define BITOP_XOR 2
6
+ #define BITOP_NOT 3
7
+
8
+ int rl_stringmatchlen(const char *pattern, int patternLen, const char *string, int stringLen, int nocase);
9
+ void rl_internal_bitop(int op, unsigned long numkeys, unsigned char **objects, unsigned long *objectslen, unsigned char **result, long *resultlen);
10
+ size_t rl_redisPopcount(void *s, long count);
11
+ long rl_internal_bitpos(void *s, unsigned long count, int bit);
@@ -0,0 +1,79 @@
1
+ OPTIMIZATION?=-O2
2
+
3
+ ifeq ($(uname_S),SunOS)
4
+ # make isinf() available
5
+ CFLAGS?= -pedantic $(OPTIMIZATION) -Wall -W -D__EXTENSIONS__ -D_XPG6
6
+ DEBUG?=-g -ggdb
7
+ else
8
+ CFLAGS?= -pedantic $(OPTIMIZATION) -Wall -W $(ARCH) $(PROF)
9
+ DEBUG?=-g -ggdb
10
+ endif
11
+
12
+ DEBUG.gcc += -rdynamic
13
+ CFLAGS.gcc += -std=c99 -I./
14
+
15
+ ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
16
+ DEBUG += ${DEBUG.clang}
17
+ CFLAGS += ${CFLAGS.clang}
18
+ else
19
+ DEBUG += ${DEBUG.gcc}
20
+ CFLAGS += ${CFLAGS.gcc}
21
+ endif
22
+
23
+ LIBS=-lm
24
+
25
+ all: buildtest buildhirlitetest
26
+
27
+ gcov: CFLAGS += -fprofile-arcs -ftest-coverage
28
+ gcov: clean test
29
+
30
+ builddebug: CFLAGS += -DDEBUG=1
31
+ builddebug: clean buildtest
32
+
33
+ debug: builddebug vtest
34
+
35
+ lcov: gcov
36
+ mkdir -p lcov
37
+ lcov --directory . --capture --output-file lcov/app.info
38
+ genhtml lcov/app.info -o lcov/html
39
+
40
+ full-lcov: CFLAGS += -fprofile-arcs -ftest-coverage -DDEBUG=1
41
+ full-lcov: clean buildtest buildhirlitetest
42
+
43
+ clang-analyzer:
44
+ rm -rf analyzer
45
+ scan-build -o analyzer make
46
+
47
+ .c.o:
48
+ $(CC) $(ARCH) $(DEBUG) $(CFLAGS) -c $<
49
+
50
+ libhirlite.a: hirlite.o librlite.a
51
+ ar -cq libhirlite.a rlite.o page_skiplist.o page_string.o page_list.o page_btree.o page_key.o type_string.o type_list.o type_set.o type_zset.o type_hash.o page_long.o page_multi_string.o util.o utilfromredis.o hyperloglog.o sha1.o crc64.o restore.o dump.o lzf_c.o lzf_d.o sort.o pqsort.o hirlite.o
52
+
53
+ librlite.a: rlite.o page_skiplist.o page_string.o page_list.o page_btree.o page_key.o page_multi_string.o page_long.o type_string.o type_list.o type_set.o type_zset.o type_hash.o util.o restore.o dump.o sort.o pqsort.o ../deps/utilfromredis.o ../deps/hyperloglog.o ../deps/sha1.o ../deps/crc64.o ../deps/lzf_c.o ../deps/lzf_d.o
54
+ ar -cq librlite.a rlite.o page_skiplist.o page_string.o page_list.o page_btree.o page_key.o type_string.o type_list.o type_set.o type_zset.o type_hash.o page_long.o page_multi_string.o util.o utilfromredis.o hyperloglog.o sha1.o crc64.o lzf_c.o lzf_d.o restore.o dump.o sort.o pqsort.o
55
+
56
+ buildtest: librlite.a test/rlite-test.o test/btree-test.o test/list-test.o test/string-test.o test/multi_string-test.o test/multi-test.o test/key-test.o test/type_string-test.o test/type_list-test.o test/type_set-test.o test/type_zset-test.o test/type_hash-test.o test/skiplist-test.o test/long-test.o test/restore-test.o test/hyperloglog-test.o test/dump-test.o test/sort-test.o test/test_util.o test/test.o
57
+ $(CC) $(DEBUG) $(CFLAGS) -o rlite-test test.o rlite-test.o btree-test.o list-test.o string-test.o multi_string-test.o multi-test.o key-test.o type_string-test.o type_list-test.o type_set-test.o type_zset-test.o type_hash-test.o skiplist-test.o long-test.o restore-test.o hyperloglog-test.o dump-test.o sort-test.o test_util.o librlite.a $(LIBS)
58
+
59
+ buildhirlitetest: libhirlite.a test/echo.o test/hash.o test/list.o test/parser.o test/set.o test/string.o test/test_hirlite.o test/zset.o test/db.o test/multi.o test/sort.o
60
+ $(CC) $(DEBUG) $(CFLAGS) -o hirlite-test echo.o hash.o list.o parser.o set.o string.o test_hirlite.o zset.o db.o multi.o sort.o libhirlite.a $(LIBS)
61
+
62
+ rlitetest: buildtest
63
+ ./rlite-test
64
+
65
+ hirlitetest: buildhirlitetest
66
+ ./hirlite-test
67
+
68
+ test: rlitetest hirlitetest
69
+
70
+ vrlitetest: buildtest
71
+ valgrind --track-origins=yes --leak-check=full --show-reachable=yes ./rlite-test
72
+
73
+ vhirlitetest: buildhirlitetest
74
+ valgrind --track-origins=yes --leak-check=full --show-reachable=yes ./hirlite-test
75
+
76
+ vtest: vrlitetest vhirlitetest
77
+
78
+ clean:
79
+ rm -rf *-test *.o *.a *.dSYM *.gcda *.gcno lcov
@@ -0,0 +1,15 @@
1
+ #define _POSIX_C_SOURCE 199309L
2
+
3
+ #define RLITE_CRLF "\r\n"
4
+ #define RLITE_STR_OK "OK"
5
+ #define RLITE_STR_ERR "ERR"
6
+ #define RLITE_PONG "PONG"
7
+ #define RLITE_QUEUED "QUEUED"
8
+ #define RLITE_WRONGTYPEERR "WRONGTYPE Operation against a key holding the wrong kind of value"
9
+ #define RLITE_WRONGNUMBEROFARGUMENTS "ERR wrong number of arguments for %s"
10
+ #define RLITE_NOKEYERR "ERR No such key"
11
+ #define RLITE_SYNTAXERR "ERR syntax error"
12
+ #define RLITE_SAMEOBJECTERR "ERR source and destination objects are the same"
13
+ #define RLITE_OUTOFRANGEERR "ERR index out of range"
14
+ #define RLITE_INVALIDMINMAXERR "ERR min or max not valid string range item"
15
+ #define RLITE_NOSCRIPTERR "NOSCRIPT No matching script. Please use EVAL."
@@ -0,0 +1,191 @@
1
+ #include <arpa/inet.h>
2
+ #include "rlite.h"
3
+ #include "util.h"
4
+ #include "../deps/crc64.h"
5
+ #include "../deps/endianconv.h"
6
+
7
+ int rl_dump(struct rlite *db, const unsigned char *key, long keylen, unsigned char **data, long *datalen)
8
+ {
9
+ int retval;
10
+ uint64_t crc;
11
+ unsigned char type;
12
+ unsigned char *value = NULL, *value2 = NULL;
13
+ unsigned char *buf = NULL;
14
+ long buflen;
15
+ long valuelen, value2len;
16
+ unsigned char **values = NULL;
17
+ long i = -1, *valueslen = NULL;
18
+ uint32_t length;
19
+ double score;
20
+ char f[40];
21
+
22
+ RL_CALL(rl_key_get, RL_FOUND, db, key, keylen, &type, NULL, NULL, NULL, NULL);
23
+ if (type == RL_TYPE_STRING) {
24
+ RL_CALL(rl_get, RL_OK, db, key, keylen, &value, &valuelen);
25
+ RL_MALLOC(buf, sizeof(unsigned char) * (16 + valuelen));
26
+ buf[0] = REDIS_RDB_TYPE_STRING;
27
+ buf[1] = (REDIS_RDB_32BITLEN << 6);
28
+ length = htonl(valuelen);
29
+ memcpy(&buf[2], &length, 4);
30
+ memcpy(&buf[6], value, valuelen);
31
+ buflen = valuelen + 6;
32
+ } else if (type == RL_TYPE_LIST) {
33
+ RL_CALL(rl_lrange, RL_OK, db, key, keylen, 0, -1, &valuelen, &values, &valueslen);
34
+ buflen = 16;
35
+ for (i = 0; i < valuelen; i++) {
36
+ buflen += 5 + valueslen[i];
37
+ }
38
+ RL_MALLOC(buf, sizeof(unsigned char) * buflen);
39
+ buf[0] = REDIS_RDB_TYPE_LIST;
40
+ buf[1] = (REDIS_RDB_32BITLEN << 6);
41
+ length = htonl(valuelen);
42
+ memcpy(&buf[2], &length, 4);
43
+ buflen = 6;
44
+ for (i = 0; i < valuelen; i++) {
45
+ buf[buflen++] = (REDIS_RDB_32BITLEN << 6);
46
+ length = htonl(valueslen[i]);
47
+ memcpy(&buf[buflen], &length, 4);
48
+ buflen += 4;
49
+ memcpy(&buf[buflen], values[i], valueslen[i]);
50
+ buflen += valueslen[i];
51
+ }
52
+ } else if (type == RL_TYPE_SET) {
53
+ rl_set_iterator *iterator;
54
+ RL_CALL(rl_smembers, RL_OK, db, &iterator, key, keylen);
55
+ buflen = 16;
56
+ length = 0;
57
+ while ((retval = rl_set_iterator_next(iterator, NULL, &valuelen)) == RL_OK) {
58
+ buflen += 5 + valuelen;
59
+ length++;
60
+ }
61
+ if (retval != RL_END) {
62
+ goto cleanup;
63
+ }
64
+
65
+ RL_MALLOC(buf, sizeof(unsigned char) * buflen);
66
+ buf[0] = REDIS_RDB_TYPE_SET;
67
+ buf[1] = (REDIS_RDB_32BITLEN << 6);
68
+ length = htonl(length);
69
+ memcpy(&buf[2], &length, 4);
70
+ buflen = 6;
71
+
72
+ RL_CALL(rl_smembers, RL_OK, db, &iterator, key, keylen);
73
+ while ((retval = rl_set_iterator_next(iterator, &value, &valuelen)) == RL_OK) {
74
+ buf[buflen++] = (REDIS_RDB_32BITLEN << 6);
75
+ length = htonl(valuelen);
76
+ memcpy(&buf[buflen], &length, 4);
77
+ buflen += 4;
78
+ memcpy(&buf[buflen], value, valuelen);
79
+ buflen += valuelen;
80
+ rl_free(value);
81
+ value = NULL;
82
+ }
83
+ if (retval != RL_END) {
84
+ goto cleanup;
85
+ }
86
+ } else if (type == RL_TYPE_ZSET) {
87
+ rl_zset_iterator *iterator;
88
+ RL_CALL(rl_zrange, RL_OK, db, key, keylen, 0, -1, &iterator);
89
+ buflen = 16;
90
+ length = 0;
91
+ while ((retval = rl_zset_iterator_next(iterator, &score, NULL, &valuelen)) == RL_OK) {
92
+ buflen += 6 + valuelen + snprintf(f, 40, "%lf", score);
93
+ length++;
94
+ }
95
+ if (retval != RL_END) {
96
+ goto cleanup;
97
+ }
98
+
99
+ RL_MALLOC(buf, sizeof(unsigned char) * buflen);
100
+ buf[0] = REDIS_RDB_TYPE_ZSET;
101
+ buf[1] = (REDIS_RDB_32BITLEN << 6);
102
+ length = htonl(length);
103
+ memcpy(&buf[2], &length, 4);
104
+ buflen = 6;
105
+
106
+ RL_CALL(rl_zrange, RL_OK, db, key, keylen, 0, -1, &iterator);
107
+ while ((retval = rl_zset_iterator_next(iterator, &score, &value, &valuelen)) == RL_OK) {
108
+ buf[buflen++] = (REDIS_RDB_32BITLEN << 6);
109
+ length = htonl(valuelen);
110
+ memcpy(&buf[buflen], &length, 4);
111
+ buflen += 4;
112
+ memcpy(&buf[buflen], value, valuelen);
113
+ buflen += valuelen;
114
+ rl_free(value);
115
+ value = NULL;
116
+
117
+ valuelen = snprintf(f, 40, "%lf", score);
118
+ buf[buflen++] = valuelen;
119
+ memcpy(&buf[buflen], f, valuelen);
120
+ buflen += valuelen;
121
+ }
122
+ if (retval != RL_END) {
123
+ goto cleanup;
124
+ }
125
+ } else if (type == RL_TYPE_HASH) {
126
+ rl_hash_iterator *iterator;
127
+ RL_CALL(rl_hgetall, RL_OK, db, &iterator, key, keylen);
128
+ buflen = 16;
129
+ length = 0;
130
+ while ((retval = rl_hash_iterator_next(iterator, NULL, &value2len, NULL, &valuelen)) == RL_OK) {
131
+ buflen += 10 + valuelen + value2len;
132
+ length++;
133
+ }
134
+ if (retval != RL_END) {
135
+ goto cleanup;
136
+ }
137
+
138
+ RL_MALLOC(buf, sizeof(unsigned char) * buflen);
139
+ buf[0] = REDIS_RDB_TYPE_HASH;
140
+ buf[1] = (REDIS_RDB_32BITLEN << 6);
141
+ length = htonl(length);
142
+ memcpy(&buf[2], &length, 4);
143
+ buflen = 6;
144
+
145
+ RL_CALL(rl_hgetall, RL_OK, db, &iterator, key, keylen);
146
+ while ((retval = rl_hash_iterator_next(iterator, &value, &valuelen, &value2, &value2len)) == RL_OK) {
147
+ buf[buflen++] = (REDIS_RDB_32BITLEN << 6);
148
+ length = htonl(valuelen);
149
+ memcpy(&buf[buflen], &length, 4);
150
+ buflen += 4;
151
+ memcpy(&buf[buflen], value, valuelen);
152
+ buflen += valuelen;
153
+ rl_free(value);
154
+ value = NULL;
155
+
156
+ buf[buflen++] = (REDIS_RDB_32BITLEN << 6);
157
+ length = htonl(value2len);
158
+ memcpy(&buf[buflen], &length, 4);
159
+ buflen += 4;
160
+ memcpy(&buf[buflen], value2, value2len);
161
+ buflen += value2len;
162
+ rl_free(value2);
163
+ value2 = NULL;
164
+ }
165
+ } else {
166
+ retval = RL_UNEXPECTED;
167
+ goto cleanup;
168
+ }
169
+ buf[buflen++] = REDIS_RDB_VERSION;
170
+ buf[buflen++] = REDIS_RDB_VERSION >> 8;
171
+
172
+ crc = rl_crc64(0, buf, buflen);
173
+ memrev64ifbe(&crc);
174
+ memcpy(&buf[buflen], &crc, 8);
175
+ buflen += 8;
176
+
177
+ *data = buf;
178
+ *datalen = buflen;
179
+ retval = RL_OK;
180
+ cleanup:
181
+ if (values) {
182
+ for (i = 0; i < valuelen; i++) {
183
+ rl_free(values[i]);
184
+ }
185
+ rl_free(values);
186
+ }
187
+ rl_free(valueslen);
188
+ rl_free(value);
189
+ rl_free(value2);
190
+ return retval;
191
+ }
@@ -0,0 +1,3 @@
1
+ #include "rlite.h"
2
+
3
+ int rl_dump(struct rlite *db, const unsigned char *key, long keylen, unsigned char **data, long *datalen);