hirlite 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/LICENSE +28 -0
- data/Rakefile +51 -0
- data/ext/hirlite_ext/extconf.rb +33 -0
- data/ext/hirlite_ext/hirlite_ext.c +14 -0
- data/ext/hirlite_ext/hirlite_ext.h +38 -0
- data/ext/hirlite_ext/rlite.c +351 -0
- data/lib/hirlite/rlite.rb +1 -0
- data/lib/hirlite/version.rb +3 -0
- data/lib/hirlite.rb +2 -0
- data/vendor/rlite/Makefile +6 -0
- data/vendor/rlite/deps/crc64.c +191 -0
- data/vendor/rlite/deps/crc64.h +3 -0
- data/vendor/rlite/deps/endianconv.h +73 -0
- data/vendor/rlite/deps/hyperloglog.c +1547 -0
- data/vendor/rlite/deps/hyperloglog.h +14 -0
- data/vendor/rlite/deps/lzf.h +100 -0
- data/vendor/rlite/deps/lzfP.h +159 -0
- data/vendor/rlite/deps/lzf_c.c +295 -0
- data/vendor/rlite/deps/lzf_d.c +150 -0
- data/vendor/rlite/deps/sha1.c +227 -0
- data/vendor/rlite/deps/sha1.h +19 -0
- data/vendor/rlite/deps/utilfromredis.c +397 -0
- data/vendor/rlite/deps/utilfromredis.h +11 -0
- data/vendor/rlite/src/Makefile +79 -0
- data/vendor/rlite/src/constants.h +15 -0
- data/vendor/rlite/src/dump.c +191 -0
- data/vendor/rlite/src/dump.h +3 -0
- data/vendor/rlite/src/hirlite.c +3985 -0
- data/vendor/rlite/src/hirlite.h +186 -0
- data/vendor/rlite/src/page_btree.c +1556 -0
- data/vendor/rlite/src/page_btree.h +133 -0
- data/vendor/rlite/src/page_key.c +283 -0
- data/vendor/rlite/src/page_key.h +25 -0
- data/vendor/rlite/src/page_list.c +718 -0
- data/vendor/rlite/src/page_list.h +70 -0
- data/vendor/rlite/src/page_long.c +61 -0
- data/vendor/rlite/src/page_long.h +14 -0
- data/vendor/rlite/src/page_multi_string.c +538 -0
- data/vendor/rlite/src/page_multi_string.h +18 -0
- data/vendor/rlite/src/page_skiplist.c +689 -0
- data/vendor/rlite/src/page_skiplist.h +70 -0
- data/vendor/rlite/src/page_string.c +55 -0
- data/vendor/rlite/src/page_string.h +12 -0
- data/vendor/rlite/src/pqsort.c +185 -0
- data/vendor/rlite/src/pqsort.h +40 -0
- data/vendor/rlite/src/restore.c +401 -0
- data/vendor/rlite/src/restore.h +3 -0
- data/vendor/rlite/src/rlite.c +1309 -0
- data/vendor/rlite/src/rlite.h +159 -0
- data/vendor/rlite/src/sort.c +530 -0
- data/vendor/rlite/src/sort.h +18 -0
- data/vendor/rlite/src/status.h +19 -0
- data/vendor/rlite/src/type_hash.c +607 -0
- data/vendor/rlite/src/type_hash.h +29 -0
- data/vendor/rlite/src/type_list.c +477 -0
- data/vendor/rlite/src/type_list.h +23 -0
- data/vendor/rlite/src/type_set.c +796 -0
- data/vendor/rlite/src/type_set.h +34 -0
- data/vendor/rlite/src/type_string.c +613 -0
- data/vendor/rlite/src/type_string.h +34 -0
- data/vendor/rlite/src/type_zset.c +1147 -0
- data/vendor/rlite/src/type_zset.h +50 -0
- data/vendor/rlite/src/util.c +334 -0
- data/vendor/rlite/src/util.h +71 -0
- metadata +151 -0
@@ -0,0 +1,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
|
+
}
|