1 : #include "redis.h"
2 : #include "lzf.h" /* LZF compression library */
3 : #include "zipmap.h"
4 :
5 : #include <math.h>
6 : #include <sys/types.h>
7 : #include <sys/time.h>
8 : #include <sys/resource.h>
9 : #include <sys/wait.h>
10 : #include <arpa/inet.h>
11 : #include <sys/stat.h>
12 :
13 8972133 : static int rdbWriteRaw(rio *rdb, void *p, size_t len) {
14 8972133 : if (rdb && rioWrite(rdb,p,len) == 0)
15 0 : return -1;
16 8972133 : return len;
17 : }
18 :
19 1728379 : int rdbSaveType(rio *rdb, unsigned char type) {
20 1728379 : return rdbWriteRaw(rdb,&type,1);
21 : }
22 :
23 1010173 : int rdbLoadType(rio *rdb) {
24 : unsigned char type;
25 1010173 : if (rioRead(rdb,&type,1) == 0) return -1;
26 1010173 : return type;
27 : }
28 :
29 0 : int rdbSaveTime(rio *rdb, time_t t) {
30 0 : int32_t t32 = (int32_t) t;
31 0 : return rdbWriteRaw(rdb,&t32,4);
32 : }
33 :
34 0 : time_t rdbLoadTime(rio *rdb) {
35 : int32_t t32;
36 0 : if (rioRead(rdb,&t32,4) == 0) return -1;
37 0 : return (time_t)t32;
38 : }
39 :
40 492 : int rdbSaveMillisecondTime(rio *rdb, long long t) {
41 492 : int64_t t64 = (int64_t) t;
42 492 : return rdbWriteRaw(rdb,&t64,8);
43 : }
44 :
45 1 : long long rdbLoadMillisecondTime(rio *rdb) {
46 : int64_t t64;
47 1 : if (rioRead(rdb,&t64,8) == 0) return -1;
48 1 : return (long long)t64;
49 : }
50 :
51 : /* Saves an encoded length. The first two bits in the first byte are used to
52 : * hold the encoding type. See the REDIS_RDB_* definitions for more information
53 : * on the types of encoding. */
54 3463406 : int rdbSaveLen(rio *rdb, uint32_t len) {
55 : unsigned char buf[2];
56 : size_t nwritten;
57 :
58 3463406 : if (len < (1<<6)) {
59 : /* Save a 6 bit len */
60 3419929 : buf[0] = (len&0xFF)|(REDIS_RDB_6BITLEN<<6);
61 3419929 : if (rdbWriteRaw(rdb,buf,1) == -1) return -1;
62 3419929 : nwritten = 1;
63 43477 : } else if (len < (1<<14)) {
64 : /* Save a 14 bit len */
65 43477 : buf[0] = ((len>>8)&0xFF)|(REDIS_RDB_14BITLEN<<6);
66 43477 : buf[1] = len&0xFF;
67 43477 : if (rdbWriteRaw(rdb,buf,2) == -1) return -1;
68 43477 : nwritten = 2;
69 : } else {
70 : /* Save a 32 bit len */
71 0 : buf[0] = (REDIS_RDB_32BITLEN<<6);
72 0 : if (rdbWriteRaw(rdb,buf,1) == -1) return -1;
73 0 : len = htonl(len);
74 0 : if (rdbWriteRaw(rdb,&len,4) == -4) return -1;
75 0 : nwritten = 1+4;
76 : }
77 3463406 : return nwritten;
78 : }
79 :
80 : /* Load an encoded length. The "isencoded" argument is set to 1 if the length
81 : * is not actually a length but an "encoding type". See the REDIS_RDB_ENC_*
82 : * definitions in rdb.h for more information. */
83 2027968 : uint32_t rdbLoadLen(rio *rdb, int *isencoded) {
84 : unsigned char buf[2];
85 : uint32_t len;
86 : int type;
87 :
88 2027968 : if (isencoded) *isencoded = 0;
89 2027968 : if (rioRead(rdb,buf,1) == 0) return REDIS_RDB_LENERR;
90 2027968 : type = (buf[0]&0xC0)>>6;
91 2027968 : if (type == REDIS_RDB_ENCVAL) {
92 : /* Read a 6 bit encoding type. */
93 7486 : if (isencoded) *isencoded = 1;
94 7486 : return buf[0]&0x3F;
95 2020482 : } else if (type == REDIS_RDB_6BITLEN) {
96 : /* Read a 6 bit len. */
97 2018416 : return buf[0]&0x3F;
98 2066 : } else if (type == REDIS_RDB_14BITLEN) {
99 : /* Read a 14 bit len. */
100 2066 : if (rioRead(rdb,buf+1,1) == 0) return REDIS_RDB_LENERR;
101 2066 : return ((buf[0]&0x3F)<<8)|buf[1];
102 : } else {
103 : /* Read a 32 bit len. */
104 0 : if (rioRead(rdb,&len,4) == 0) return REDIS_RDB_LENERR;
105 0 : return ntohl(len);
106 : }
107 : }
108 :
109 : /* Encodes the "value" argument as integer when it fits in the supported ranges
110 : * for encoded types. If the function successfully encodes the integer, the
111 : * representation is stored in the buffer pointer to by "enc" and the string
112 : * length is returned. Otherwise 0 is returned. */
113 204350 : int rdbEncodeInteger(long long value, unsigned char *enc) {
114 204350 : if (value >= -(1<<7) && value <= (1<<7)-1) {
115 132510 : enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT8;
116 132510 : enc[1] = value&0xFF;
117 132510 : return 2;
118 71840 : } else if (value >= -(1<<15) && value <= (1<<15)-1) {
119 42858 : enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT16;
120 42858 : enc[1] = value&0xFF;
121 42858 : enc[2] = (value>>8)&0xFF;
122 42858 : return 3;
123 28982 : } else if (value >= -((long long)1<<31) && value <= ((long long)1<<31)-1) {
124 17015 : enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT32;
125 17015 : enc[1] = value&0xFF;
126 17015 : enc[2] = (value>>8)&0xFF;
127 17015 : enc[3] = (value>>16)&0xFF;
128 17015 : enc[4] = (value>>24)&0xFF;
129 17015 : return 5;
130 : } else {
131 11967 : return 0;
132 : }
133 : }
134 :
135 : /* Loads an integer-encoded object with the specified encoding type "enctype".
136 : * If the "encode" argument is set the function may return an integer-encoded
137 : * string object, otherwise it always returns a raw string object. */
138 6904 : robj *rdbLoadIntegerObject(rio *rdb, int enctype, int encode) {
139 : unsigned char enc[4];
140 : long long val;
141 :
142 6904 : if (enctype == REDIS_RDB_ENC_INT8) {
143 1009 : if (rioRead(rdb,enc,1) == 0) return NULL;
144 1009 : val = (signed char)enc[0];
145 5895 : } else if (enctype == REDIS_RDB_ENC_INT16) {
146 : uint16_t v;
147 5064 : if (rioRead(rdb,enc,2) == 0) return NULL;
148 5064 : v = enc[0]|(enc[1]<<8);
149 5064 : val = (int16_t)v;
150 831 : } else if (enctype == REDIS_RDB_ENC_INT32) {
151 : uint32_t v;
152 831 : if (rioRead(rdb,enc,4) == 0) return NULL;
153 831 : v = enc[0]|(enc[1]<<8)|(enc[2]<<16)|(enc[3]<<24);
154 831 : val = (int32_t)v;
155 : } else {
156 0 : val = 0; /* anti-warning */
157 0 : redisPanic("Unknown RDB integer encoding type");
158 : }
159 6904 : if (encode)
160 5538 : return createStringObjectFromLongLong(val);
161 : else
162 1366 : return createObject(REDIS_STRING,sdsfromlonglong(val));
163 : }
164 :
165 : /* String objects in the form "2391" "-100" without any space and with a
166 : * range of values that can fit in an 8, 16 or 32 bit signed value can be
167 : * encoded as integers to save space */
168 38071 : int rdbTryIntegerEncoding(char *s, size_t len, unsigned char *enc) {
169 : long long value;
170 : char *endptr, buf[32];
171 :
172 : /* Check if it's possible to encode this value as a number */
173 38071 : value = strtoll(s, &endptr, 10);
174 38071 : if (endptr[0] != '\0') return 0;
175 25519 : ll2string(buf,32,value);
176 :
177 : /* If the number converted back into a string is not identical
178 : * then it's not possible to encode the string as integer */
179 25519 : if (strlen(buf) != len || memcmp(buf,s,len)) return 0;
180 :
181 25155 : return rdbEncodeInteger(value,enc);
182 : }
183 :
184 61673 : int rdbSaveLzfStringObject(rio *rdb, unsigned char *s, size_t len) {
185 : size_t comprlen, outlen;
186 : unsigned char byte;
187 61673 : int n, nwritten = 0;
188 : void *out;
189 :
190 : /* We require at least four bytes compression for this to be worth it */
191 61673 : if (len <= 4) return 0;
192 61673 : outlen = len-4;
193 61673 : if ((out = zmalloc(outlen+1)) == NULL) return 0;
194 61673 : comprlen = lzf_compress(s, len, out, outlen);
195 61673 : if (comprlen == 0) {
196 49732 : zfree(out);
197 49732 : return 0;
198 : }
199 : /* Data compressed! Let's save it on disk */
200 11941 : byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
201 11941 : if ((n = rdbWriteRaw(rdb,&byte,1)) == -1) goto writeerr;
202 11941 : nwritten += n;
203 :
204 11941 : if ((n = rdbSaveLen(rdb,comprlen)) == -1) goto writeerr;
205 11941 : nwritten += n;
206 :
207 11941 : if ((n = rdbSaveLen(rdb,len)) == -1) goto writeerr;
208 11941 : nwritten += n;
209 :
210 11941 : if ((n = rdbWriteRaw(rdb,out,comprlen)) == -1) goto writeerr;
211 11941 : nwritten += n;
212 :
213 11941 : zfree(out);
214 11941 : return nwritten;
215 :
216 : writeerr:
217 0 : zfree(out);
218 0 : return -1;
219 : }
220 :
221 582 : robj *rdbLoadLzfStringObject(rio *rdb) {
222 : unsigned int len, clen;
223 582 : unsigned char *c = NULL;
224 582 : sds val = NULL;
225 :
226 582 : if ((clen = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL;
227 582 : if ((len = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL;
228 582 : if ((c = zmalloc(clen)) == NULL) goto err;
229 582 : if ((val = sdsnewlen(NULL,len)) == NULL) goto err;
230 582 : if (rioRead(rdb,c,clen) == 0) goto err;
231 582 : if (lzf_decompress(c,clen,val,len) == 0) goto err;
232 582 : zfree(c);
233 582 : return createObject(REDIS_STRING,val);
234 : err:
235 0 : zfree(c);
236 0 : sdsfree(val);
237 0 : return NULL;
238 : }
239 :
240 : /* Save a string objet as [len][data] on disk. If the object is a string
241 : * representation of an integer value we try to save it in a special form */
242 3454506 : int rdbSaveRawString(rio *rdb, unsigned char *s, size_t len) {
243 : int enclen;
244 3454506 : int n, nwritten = 0;
245 :
246 : /* Try integer encoding */
247 3454506 : if (len <= 11) {
248 : unsigned char buf[5];
249 38071 : if ((enclen = rdbTryIntegerEncoding((char*)s,len,buf)) > 0) {
250 19987 : if (rdbWriteRaw(rdb,buf,enclen) == -1) return -1;
251 19987 : return enclen;
252 : }
253 : }
254 :
255 : /* Try LZF compression - under 20 bytes it's unable to compress even
256 : * aaaaaaaaaaaaaaaaaa so skip it */
257 3434519 : if (server.rdb_compression && len > 20) {
258 61673 : n = rdbSaveLzfStringObject(rdb,s,len);
259 61673 : if (n == -1) return -1;
260 61673 : if (n > 0) return n;
261 : /* Return value of 0 means data can't be compressed, save the old way */
262 : }
263 :
264 : /* Store verbatim */
265 3422578 : if ((n = rdbSaveLen(rdb,len)) == -1) return -1;
266 3422578 : nwritten += n;
267 3422578 : if (len > 0) {
268 3422290 : if (rdbWriteRaw(rdb,s,len) == -1) return -1;
269 3422290 : nwritten += len;
270 : }
271 3422578 : return nwritten;
272 : }
273 :
274 : /* Save a long long value as either an encoded string or a string. */
275 179195 : int rdbSaveLongLongAsStringObject(rio *rdb, long long value) {
276 : unsigned char buf[32];
277 179195 : int n, nwritten = 0;
278 179195 : int enclen = rdbEncodeInteger(value,buf);
279 179195 : if (enclen > 0) {
280 172396 : return rdbWriteRaw(rdb,buf,enclen);
281 : } else {
282 : /* Encode as string */
283 6799 : enclen = ll2string((char*)buf,32,value);
284 6799 : redisAssert(enclen < 32);
285 6799 : if ((n = rdbSaveLen(rdb,enclen)) == -1) return -1;
286 6799 : nwritten += n;
287 6799 : if ((n = rdbWriteRaw(rdb,buf,enclen)) == -1) return -1;
288 6799 : nwritten += n;
289 : }
290 6799 : return nwritten;
291 : }
292 :
293 : /* Like rdbSaveStringObjectRaw() but handle encoded objects */
294 3599943 : int rdbSaveStringObject(rio *rdb, robj *obj) {
295 : /* Avoid to decode the object, then encode it again, if the
296 : * object is alrady integer encoded. */
297 3599943 : if (obj->encoding == REDIS_ENCODING_INT) {
298 179195 : return rdbSaveLongLongAsStringObject(rdb,(long)obj->ptr);
299 : } else {
300 3420748 : redisAssertWithInfo(NULL,obj,obj->encoding == REDIS_ENCODING_RAW);
301 6841496 : return rdbSaveRawString(rdb,obj->ptr,sdslen(obj->ptr));
302 : }
303 : }
304 :
305 2026339 : robj *rdbGenericLoadStringObject(rio *rdb, int encode) {
306 : int isencoded;
307 : uint32_t len;
308 : sds val;
309 :
310 2026339 : len = rdbLoadLen(rdb,&isencoded);
311 2026339 : if (isencoded) {
312 7486 : switch(len) {
313 : case REDIS_RDB_ENC_INT8:
314 : case REDIS_RDB_ENC_INT16:
315 : case REDIS_RDB_ENC_INT32:
316 6904 : return rdbLoadIntegerObject(rdb,len,encode);
317 : case REDIS_RDB_ENC_LZF:
318 582 : return rdbLoadLzfStringObject(rdb);
319 : default:
320 0 : redisPanic("Unknown RDB encoding type");
321 : }
322 : }
323 :
324 2018853 : if (len == REDIS_RDB_LENERR) return NULL;
325 2018853 : val = sdsnewlen(NULL,len);
326 2018853 : if (len && rioRead(rdb,val,len) == 0) {
327 0 : sdsfree(val);
328 0 : return NULL;
329 : }
330 2018853 : return createObject(REDIS_STRING,val);
331 : }
332 :
333 1012085 : robj *rdbLoadStringObject(rio *rdb) {
334 1012085 : return rdbGenericLoadStringObject(rdb,0);
335 : }
336 :
337 1014254 : robj *rdbLoadEncodedStringObject(rio *rdb) {
338 1014254 : return rdbGenericLoadStringObject(rdb,1);
339 : }
340 :
341 : /* Save a double value. Doubles are saved as strings prefixed by an unsigned
342 : * 8 bit integer specifing the length of the representation.
343 : * This 8 bit integer has special values in order to specify the following
344 : * conditions:
345 : * 253: not a number
346 : * 254: + inf
347 : * 255: - inf
348 : */
349 134404 : int rdbSaveDoubleValue(rio *rdb, double val) {
350 : unsigned char buf[128];
351 : int len;
352 :
353 134404 : if (isnan(val)) {
354 0 : buf[0] = 253;
355 0 : len = 1;
356 134404 : } else if (!isfinite(val)) {
357 980 : len = 1;
358 980 : buf[0] = (val < 0) ? 255 : 254;
359 : } else {
360 : #if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
361 : /* Check if the float is in a safe range to be casted into a
362 : * long long. We are assuming that long long is 64 bit here.
363 : * Also we are assuming that there are no implementations around where
364 : * double has precision < 52 bit.
365 : *
366 : * Under this assumptions we test if a double is inside an interval
367 : * where casting to long long is safe. Then using two castings we
368 : * make sure the decimal part is zero. If all this is true we use
369 : * integer printing function that is much faster. */
370 : double min = -4503599627370495; /* (2^52)-1 */
371 : double max = 4503599627370496; /* -(2^52) */
372 : if (val > min && val < max && val == ((double)((long long)val)))
373 : ll2string((char*)buf+1,sizeof(buf),(long long)val);
374 : else
375 : #endif
376 133424 : snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);
377 133424 : buf[0] = strlen((char*)buf+1);
378 133424 : len = buf[0]+1;
379 : }
380 134404 : return rdbWriteRaw(rdb,buf,len);
381 : }
382 :
383 : /* For information about double serialization check rdbSaveDoubleValue() */
384 355 : int rdbLoadDoubleValue(rio *rdb, double *val) {
385 : char buf[128];
386 : unsigned char len;
387 :
388 355 : if (rioRead(rdb,&len,1) == 0) return -1;
389 355 : switch(len) {
390 18 : case 255: *val = R_NegInf; return 0;
391 14 : case 254: *val = R_PosInf; return 0;
392 0 : case 253: *val = R_Nan; return 0;
393 : default:
394 323 : if (rioRead(rdb,buf,len) == 0) return -1;
395 323 : buf[len] = '\0';
396 323 : sscanf(buf, "%lg", val);
397 323 : return 0;
398 : }
399 : }
400 :
401 : /* Save the object type of object "o". */
402 1727735 : int rdbSaveObjectType(rio *rdb, robj *o) {
403 1727735 : switch (o->type) {
404 : case REDIS_STRING:
405 1687274 : return rdbSaveType(rdb,REDIS_RDB_TYPE_STRING);
406 : case REDIS_LIST:
407 5963 : if (o->encoding == REDIS_ENCODING_ZIPLIST)
408 4767 : return rdbSaveType(rdb,REDIS_RDB_TYPE_LIST_ZIPLIST);
409 1196 : else if (o->encoding == REDIS_ENCODING_LINKEDLIST)
410 1196 : return rdbSaveType(rdb,REDIS_RDB_TYPE_LIST);
411 : else
412 0 : redisPanic("Unknown list encoding");
413 : case REDIS_SET:
414 13990 : if (o->encoding == REDIS_ENCODING_INTSET)
415 9808 : return rdbSaveType(rdb,REDIS_RDB_TYPE_SET_INTSET);
416 4182 : else if (o->encoding == REDIS_ENCODING_HT)
417 4182 : return rdbSaveType(rdb,REDIS_RDB_TYPE_SET);
418 : else
419 0 : redisPanic("Unknown set encoding");
420 : case REDIS_ZSET:
421 12846 : if (o->encoding == REDIS_ENCODING_ZIPLIST)
422 9843 : return rdbSaveType(rdb,REDIS_RDB_TYPE_ZSET_ZIPLIST);
423 3003 : else if (o->encoding == REDIS_ENCODING_SKIPLIST)
424 3003 : return rdbSaveType(rdb,REDIS_RDB_TYPE_ZSET);
425 : else
426 0 : redisPanic("Unknown sorted set encoding");
427 : case REDIS_HASH:
428 7662 : if (o->encoding == REDIS_ENCODING_ZIPLIST)
429 7658 : return rdbSaveType(rdb,REDIS_RDB_TYPE_HASH_ZIPLIST);
430 4 : else if (o->encoding == REDIS_ENCODING_HT)
431 4 : return rdbSaveType(rdb,REDIS_RDB_TYPE_HASH);
432 : else
433 0 : redisPanic("Unknown hash encoding");
434 : default:
435 0 : redisPanic("Unknown object type");
436 : }
437 : return -1; /* avoid warning */
438 : }
439 :
440 : /* Load object type. Return -1 when the byte doesn't contain an object type. */
441 3 : int rdbLoadObjectType(rio *rdb) {
442 : int type;
443 3 : if ((type = rdbLoadType(rdb)) == -1) return -1;
444 3 : if (!rdbIsObjectType(type)) return -1;
445 3 : return type;
446 : }
447 :
448 : /* Save a Redis object. Returns -1 on error, 0 on success. */
449 1731135 : int rdbSaveObject(rio *rdb, robj *o) {
450 1731135 : int n, nwritten = 0;
451 :
452 1731135 : if (o->type == REDIS_STRING) {
453 : /* Save a string value */
454 1687284 : if ((n = rdbSaveStringObject(rdb,o)) == -1) return -1;
455 1687284 : nwritten += n;
456 43851 : } else if (o->type == REDIS_LIST) {
457 : /* Save a list value */
458 6077 : if (o->encoding == REDIS_ENCODING_ZIPLIST) {
459 4827 : size_t l = ziplistBlobLen((unsigned char*)o->ptr);
460 :
461 4827 : if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1;
462 4827 : nwritten += n;
463 1250 : } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
464 1250 : list *list = o->ptr;
465 : listIter li;
466 : listNode *ln;
467 :
468 1250 : if ((n = rdbSaveLen(rdb,listLength(list))) == -1) return -1;
469 1250 : nwritten += n;
470 :
471 1250 : listRewind(list,&li);
472 20081 : while((ln = listNext(&li))) {
473 17581 : robj *eleobj = listNodeValue(ln);
474 17581 : if ((n = rdbSaveStringObject(rdb,eleobj)) == -1) return -1;
475 17581 : nwritten += n;
476 : }
477 : } else {
478 0 : redisPanic("Unknown list encoding");
479 : }
480 37774 : } else if (o->type == REDIS_SET) {
481 : /* Save a set value */
482 14046 : if (o->encoding == REDIS_ENCODING_HT) {
483 4212 : dict *set = o->ptr;
484 4212 : dictIterator *di = dictGetIterator(set);
485 : dictEntry *de;
486 :
487 4212 : if ((n = rdbSaveLen(rdb,dictSize(set))) == -1) return -1;
488 4212 : nwritten += n;
489 :
490 37217 : while((de = dictNext(di)) != NULL) {
491 28793 : robj *eleobj = dictGetKey(de);
492 28793 : if ((n = rdbSaveStringObject(rdb,eleobj)) == -1) return -1;
493 28793 : nwritten += n;
494 : }
495 4212 : dictReleaseIterator(di);
496 9834 : } else if (o->encoding == REDIS_ENCODING_INTSET) {
497 9834 : size_t l = intsetBlobLen((intset*)o->ptr);
498 :
499 9834 : if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1;
500 9834 : nwritten += n;
501 : } else {
502 0 : redisPanic("Unknown set encoding");
503 : }
504 23728 : } else if (o->type == REDIS_ZSET) {
505 : /* Save a sorted set value */
506 16060 : if (o->encoding == REDIS_ENCODING_ZIPLIST) {
507 11437 : size_t l = ziplistBlobLen((unsigned char*)o->ptr);
508 :
509 11437 : if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1;
510 11437 : nwritten += n;
511 4623 : } else if (o->encoding == REDIS_ENCODING_SKIPLIST) {
512 4623 : zset *zs = o->ptr;
513 4623 : dictIterator *di = dictGetIterator(zs->dict);
514 : dictEntry *de;
515 :
516 4623 : if ((n = rdbSaveLen(rdb,dictSize(zs->dict))) == -1) return -1;
517 4623 : nwritten += n;
518 :
519 143650 : while((de = dictNext(di)) != NULL) {
520 134404 : robj *eleobj = dictGetKey(de);
521 134404 : double *score = dictGetVal(de);
522 :
523 134404 : if ((n = rdbSaveStringObject(rdb,eleobj)) == -1) return -1;
524 134404 : nwritten += n;
525 134404 : if ((n = rdbSaveDoubleValue(rdb,*score)) == -1) return -1;
526 134404 : nwritten += n;
527 : }
528 4623 : dictReleaseIterator(di);
529 : } else {
530 0 : redisPanic("Unknown sorted set encoding");
531 : }
532 7668 : } else if (o->type == REDIS_HASH) {
533 : /* Save a hash value */
534 7668 : if (o->encoding == REDIS_ENCODING_ZIPLIST) {
535 7660 : size_t l = ziplistBlobLen((unsigned char*)o->ptr);
536 :
537 7660 : if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1;
538 7660 : nwritten += n;
539 :
540 8 : } else if (o->encoding == REDIS_ENCODING_HT) {
541 8 : dictIterator *di = dictGetIterator(o->ptr);
542 : dictEntry *de;
543 :
544 8 : if ((n = rdbSaveLen(rdb,dictSize((dict*)o->ptr))) == -1) return -1;
545 8 : nwritten += n;
546 :
547 2091 : while((de = dictNext(di)) != NULL) {
548 2075 : robj *key = dictGetKey(de);
549 2075 : robj *val = dictGetVal(de);
550 :
551 2075 : if ((n = rdbSaveStringObject(rdb,key)) == -1) return -1;
552 2075 : nwritten += n;
553 2075 : if ((n = rdbSaveStringObject(rdb,val)) == -1) return -1;
554 2075 : nwritten += n;
555 : }
556 8 : dictReleaseIterator(di);
557 :
558 : } else {
559 0 : redisPanic("Unknown hash encoding");
560 : }
561 :
562 : } else {
563 0 : redisPanic("Unknown object type");
564 : }
565 1731135 : return nwritten;
566 : }
567 :
568 : /* Return the length the object will have on disk if saved with
569 : * the rdbSaveObject() function. Currently we use a trick to get
570 : * this length with very little changes to the code. In the future
571 : * we could switch to a faster solution. */
572 3400 : off_t rdbSavedObjectLen(robj *o) {
573 3400 : int len = rdbSaveObject(NULL,o);
574 3400 : redisAssertWithInfo(NULL,o,len != -1);
575 3400 : return len;
576 : }
577 :
578 : /* Save a key-value pair, with expire time, type, key, value.
579 : * On error -1 is returned.
580 : * On success if the key was actaully saved 1 is returned, otherwise 0
581 : * is returned (the key was already expired). */
582 1727732 : int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val,
583 : long long expiretime, long long now)
584 : {
585 : /* Save the expire time */
586 1727732 : if (expiretime != -1) {
587 : /* If this key is already expired skip it */
588 493 : if (expiretime < now) return 0;
589 492 : if (rdbSaveType(rdb,REDIS_RDB_OPCODE_EXPIRETIME_MS) == -1) return -1;
590 492 : if (rdbSaveMillisecondTime(rdb,expiretime) == -1) return -1;
591 : }
592 :
593 : /* Save type, key, value */
594 1727731 : if (rdbSaveObjectType(rdb,val) == -1) return -1;
595 1727731 : if (rdbSaveStringObject(rdb,key) == -1) return -1;
596 1727731 : if (rdbSaveObject(rdb,val) == -1) return -1;
597 1727731 : return 1;
598 : }
599 :
600 : /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
601 98 : int rdbSave(char *filename) {
602 98 : dictIterator *di = NULL;
603 : dictEntry *de;
604 : char tmpfile[256];
605 : char magic[10];
606 : int j;
607 98 : long long now = mstime();
608 : FILE *fp;
609 : rio rdb;
610 :
611 98 : snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
612 98 : fp = fopen(tmpfile,"w");
613 98 : if (!fp) {
614 0 : redisLog(REDIS_WARNING, "Failed opening .rdb for saving: %s",
615 : strerror(errno));
616 0 : return REDIS_ERR;
617 : }
618 :
619 98 : rioInitWithFile(&rdb,fp);
620 98 : snprintf(magic,sizeof(magic),"REDIS%04d",REDIS_RDB_VERSION);
621 98 : if (rdbWriteRaw(&rdb,magic,9) == -1) goto werr;
622 :
623 1666 : for (j = 0; j < server.dbnum; j++) {
624 1568 : redisDb *db = server.db+j;
625 1568 : dict *d = db->dict;
626 1568 : if (dictSize(d) == 0) continue;
627 54 : di = dictGetSafeIterator(d);
628 54 : if (!di) {
629 0 : fclose(fp);
630 0 : return REDIS_ERR;
631 : }
632 :
633 : /* Write the SELECT DB opcode */
634 54 : if (rdbSaveType(&rdb,REDIS_RDB_OPCODE_SELECTDB) == -1) goto werr;
635 54 : if (rdbSaveLen(&rdb,j) == -1) goto werr;
636 :
637 : /* Iterate this DB writing every entry */
638 1727786 : while((de = dictNext(di)) != NULL) {
639 1727732 : sds keystr = dictGetKey(de);
640 1727732 : robj key, *o = dictGetVal(de);
641 : long long expire;
642 :
643 1727732 : initStaticStringObject(key,keystr);
644 1727732 : expire = getExpire(db,&key);
645 1727732 : if (rdbSaveKeyValuePair(&rdb,&key,o,expire,now) == -1) goto werr;
646 : }
647 54 : dictReleaseIterator(di);
648 : }
649 : /* EOF opcode */
650 98 : if (rdbSaveType(&rdb,REDIS_RDB_OPCODE_EOF) == -1) goto werr;
651 :
652 : /* Make sure data will not remain on the OS's output buffers */
653 98 : fflush(fp);
654 98 : fsync(fileno(fp));
655 98 : fclose(fp);
656 :
657 : /* Use RENAME to make sure the DB file is changed atomically only
658 : * if the generate DB file is ok. */
659 98 : if (rename(tmpfile,filename) == -1) {
660 0 : redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
661 0 : unlink(tmpfile);
662 0 : return REDIS_ERR;
663 : }
664 98 : redisLog(REDIS_NOTICE,"DB saved on disk");
665 98 : server.dirty = 0;
666 98 : server.lastsave = time(NULL);
667 98 : server.lastbgsave_status = REDIS_OK;
668 98 : return REDIS_OK;
669 :
670 : werr:
671 0 : fclose(fp);
672 0 : unlink(tmpfile);
673 0 : redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
674 0 : if (di) dictReleaseIterator(di);
675 0 : return REDIS_ERR;
676 : }
677 :
678 8 : int rdbSaveBackground(char *filename) {
679 : pid_t childpid;
680 : long long start;
681 :
682 8 : if (server.rdb_child_pid != -1) return REDIS_ERR;
683 :
684 8 : server.dirty_before_bgsave = server.dirty;
685 :
686 8 : start = ustime();
687 8 : if ((childpid = fork()) == 0) {
688 : int retval;
689 :
690 : /* Child */
691 0 : if (server.ipfd > 0) close(server.ipfd);
692 0 : if (server.sofd > 0) close(server.sofd);
693 0 : retval = rdbSave(filename);
694 0 : _exit((retval == REDIS_OK) ? 0 : 1);
695 : } else {
696 : /* Parent */
697 8 : server.stat_fork_time = ustime()-start;
698 8 : if (childpid == -1) {
699 0 : redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
700 : strerror(errno));
701 0 : return REDIS_ERR;
702 : }
703 8 : redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
704 8 : server.rdb_child_pid = childpid;
705 8 : updateDictResizePolicy();
706 8 : return REDIS_OK;
707 : }
708 : return REDIS_OK; /* unreached */
709 : }
710 :
711 0 : void rdbRemoveTempFile(pid_t childpid) {
712 : char tmpfile[256];
713 :
714 0 : snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid);
715 0 : unlink(tmpfile);
716 0 : }
717 :
718 : /* Load a Redis object of the specified type from the specified file.
719 : * On success a newly allocated object is returned, otherwise NULL. */
720 1010127 : robj *rdbLoadObject(int rdbtype, rio *rdb) {
721 : robj *o, *ele, *dec;
722 : size_t len;
723 : unsigned int i;
724 :
725 1010127 : redisLog(REDIS_DEBUG,"LOADING OBJECT %d (at %d)\n",rdbtype,rdb->tell(rdb));
726 1010127 : if (rdbtype == REDIS_RDB_TYPE_STRING) {
727 : /* Read string value */
728 1007745 : if ((o = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL;
729 1007745 : o = tryObjectEncoding(o);
730 2382 : } else if (rdbtype == REDIS_RDB_TYPE_LIST) {
731 : /* Read list value */
732 80 : if ((len = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL;
733 :
734 : /* Use a real list when there are too many entries */
735 80 : if (len > server.list_max_ziplist_entries) {
736 1 : o = createListObject();
737 : } else {
738 79 : o = createZiplistObject();
739 : }
740 :
741 : /* Load every single element of the list */
742 763 : while(len--) {
743 683 : if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL;
744 :
745 : /* If we are using a ziplist and the value is too big, convert
746 : * the object to a real list. */
747 880 : if (o->encoding == REDIS_ENCODING_ZIPLIST &&
748 106 : ele->encoding == REDIS_ENCODING_RAW &&
749 182 : sdslen(ele->ptr) > server.list_max_ziplist_value)
750 78 : listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
751 :
752 683 : if (o->encoding == REDIS_ENCODING_ZIPLIST) {
753 28 : dec = getDecodedObject(ele);
754 56 : o->ptr = ziplistPush(o->ptr,dec->ptr,sdslen(dec->ptr),REDIS_TAIL);
755 28 : decrRefCount(dec);
756 28 : decrRefCount(ele);
757 : } else {
758 655 : ele = tryObjectEncoding(ele);
759 655 : listAddNodeTail(o->ptr,ele);
760 : }
761 : }
762 2302 : } else if (rdbtype == REDIS_RDB_TYPE_SET) {
763 : /* Read list/set value */
764 203 : if ((len = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL;
765 :
766 : /* Use a regular set when there are too many entries. */
767 203 : if (len > server.set_max_intset_entries) {
768 3 : o = createSetObject();
769 : /* It's faster to expand the dict to the right size asap in order
770 : * to avoid rehashing */
771 3 : if (len > DICT_HT_INITIAL_SIZE)
772 3 : dictExpand(o->ptr,len);
773 : } else {
774 200 : o = createIntsetObject();
775 : }
776 :
777 : /* Load every single element of the list/set */
778 5674 : for (i = 0; i < len; i++) {
779 : long long llval;
780 5471 : if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL;
781 5471 : ele = tryObjectEncoding(ele);
782 :
783 5471 : if (o->encoding == REDIS_ENCODING_INTSET) {
784 : /* Fetch integer value from element */
785 335 : if (isObjectRepresentableAsLongLong(ele,&llval) == REDIS_OK) {
786 135 : o->ptr = intsetAdd(o->ptr,llval,NULL);
787 : } else {
788 200 : setTypeConvert(o,REDIS_ENCODING_HT);
789 200 : dictExpand(o->ptr,len);
790 : }
791 : }
792 :
793 : /* This will also be called when the set was just converted
794 : * to regular hashtable encoded set */
795 5471 : if (o->encoding == REDIS_ENCODING_HT) {
796 5336 : dictAdd((dict*)o->ptr,ele,NULL);
797 : } else {
798 135 : decrRefCount(ele);
799 : }
800 : }
801 2099 : } else if (rdbtype == REDIS_RDB_TYPE_ZSET) {
802 : /* Read list/set value */
803 : size_t zsetlen;
804 159 : size_t maxelelen = 0;
805 : zset *zs;
806 :
807 159 : if ((zsetlen = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL;
808 159 : o = createZsetObject();
809 159 : zs = o->ptr;
810 :
811 : /* Load every single element of the list/set */
812 673 : while(zsetlen--) {
813 : robj *ele;
814 : double score;
815 : zskiplistNode *znode;
816 :
817 355 : if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL;
818 355 : ele = tryObjectEncoding(ele);
819 355 : if (rdbLoadDoubleValue(rdb,&score) == -1) return NULL;
820 :
821 : /* Don't care about integer-encoded strings. */
822 548 : if (ele->encoding == REDIS_ENCODING_RAW &&
823 193 : sdslen(ele->ptr) > maxelelen)
824 334 : maxelelen = sdslen(ele->ptr);
825 :
826 355 : znode = zslInsert(zs->zsl,score,ele);
827 355 : dictAdd(zs->dict,ele,&znode->score);
828 355 : incrRefCount(ele); /* added to skiplist */
829 : }
830 :
831 : /* Convert *after* loading, since sorted sets are not stored ordered. */
832 317 : if (zsetLength(o) <= server.zset_max_ziplist_entries &&
833 158 : maxelelen <= server.zset_max_ziplist_value)
834 11 : zsetConvert(o,REDIS_ENCODING_ZIPLIST);
835 1940 : } else if (rdbtype == REDIS_RDB_TYPE_HASH) {
836 : size_t len;
837 : int ret;
838 :
839 1 : len = rdbLoadLen(rdb, NULL);
840 1 : if (len == REDIS_RDB_LENERR) return NULL;
841 :
842 1 : o = createHashObject();
843 :
844 : /* Too many entries? Use an hash table. */
845 1 : if (len > server.hash_max_ziplist_entries)
846 0 : hashTypeConvert(o, REDIS_ENCODING_HT);
847 :
848 : /* Load every field and value into the ziplist */
849 12 : while (o->encoding == REDIS_ENCODING_ZIPLIST && len > 0) {
850 : robj *field, *value;
851 :
852 11 : len--;
853 : /* Load raw strings */
854 11 : field = rdbLoadStringObject(rdb);
855 11 : if (field == NULL) return NULL;
856 11 : redisAssert(field->encoding == REDIS_ENCODING_RAW);
857 11 : value = rdbLoadStringObject(rdb);
858 11 : if (value == NULL) return NULL;
859 11 : redisAssert(field->encoding == REDIS_ENCODING_RAW);
860 :
861 : /* Add pair to ziplist */
862 22 : o->ptr = ziplistPush(o->ptr, field->ptr, sdslen(field->ptr), ZIPLIST_TAIL);
863 22 : o->ptr = ziplistPush(o->ptr, value->ptr, sdslen(value->ptr), ZIPLIST_TAIL);
864 : /* Convert to hash table if size threshold is exceeded */
865 33 : if (sdslen(field->ptr) > server.hash_max_ziplist_value ||
866 22 : sdslen(value->ptr) > server.hash_max_ziplist_value)
867 : {
868 0 : decrRefCount(field);
869 0 : decrRefCount(value);
870 0 : hashTypeConvert(o, REDIS_ENCODING_HT);
871 0 : break;
872 : }
873 11 : decrRefCount(field);
874 11 : decrRefCount(value);
875 : }
876 :
877 : /* Load remaining fields and values into the hash table */
878 1 : while (o->encoding == REDIS_ENCODING_HT && len > 0) {
879 : robj *field, *value;
880 :
881 0 : len--;
882 : /* Load encoded strings */
883 0 : field = rdbLoadEncodedStringObject(rdb);
884 0 : if (field == NULL) return NULL;
885 0 : value = rdbLoadEncodedStringObject(rdb);
886 0 : if (value == NULL) return NULL;
887 :
888 0 : field = tryObjectEncoding(field);
889 0 : value = tryObjectEncoding(value);
890 :
891 : /* Add pair to hash table */
892 0 : ret = dictAdd((dict*)o->ptr, field, value);
893 0 : redisAssert(ret == REDIS_OK);
894 : }
895 :
896 : /* All pairs should be read by now */
897 1 : redisAssert(len == 0);
898 :
899 1939 : } else if (rdbtype == REDIS_RDB_TYPE_HASH_ZIPMAP ||
900 : rdbtype == REDIS_RDB_TYPE_LIST_ZIPLIST ||
901 : rdbtype == REDIS_RDB_TYPE_SET_INTSET ||
902 : rdbtype == REDIS_RDB_TYPE_ZSET_ZIPLIST ||
903 : rdbtype == REDIS_RDB_TYPE_HASH_ZIPLIST)
904 : {
905 1939 : robj *aux = rdbLoadStringObject(rdb);
906 :
907 1939 : if (aux == NULL) return NULL;
908 1939 : o = createObject(REDIS_STRING,NULL); /* string is just placeholder */
909 3878 : o->ptr = zmalloc(sdslen(aux->ptr));
910 3878 : memcpy(o->ptr,aux->ptr,sdslen(aux->ptr));
911 1939 : decrRefCount(aux);
912 :
913 : /* Fix the object encoding, and make sure to convert the encoded
914 : * data type into the base type if accordingly to the current
915 : * configuration there are too many elements in the encoded data
916 : * type. Note that we only check the length and not max element
917 : * size as this is an O(N) scan. Eventually everything will get
918 : * converted. */
919 1939 : switch(rdbtype) {
920 : case REDIS_RDB_TYPE_HASH_ZIPMAP:
921 : /* Convert to ziplist encoded hash. This must be deprecated
922 : * when loading dumps created by Redis 2.4 gets deprecated. */
923 : {
924 3 : unsigned char *zl = ziplistNew();
925 3 : unsigned char *zi = zipmapRewind(o->ptr);
926 : unsigned char *fstr, *vstr;
927 : unsigned int flen, vlen;
928 3 : unsigned int maxlen = 0;
929 :
930 12 : while ((zi = zipmapNext(zi, &fstr, &flen, &vstr, &vlen)) != NULL) {
931 6 : if (flen > maxlen) maxlen = flen;
932 6 : if (vlen > maxlen) maxlen = vlen;
933 6 : zl = ziplistPush(zl, fstr, flen, ZIPLIST_TAIL);
934 6 : zl = ziplistPush(zl, vstr, vlen, ZIPLIST_TAIL);
935 : }
936 :
937 3 : zfree(o->ptr);
938 3 : o->ptr = zl;
939 3 : o->type = REDIS_HASH;
940 3 : o->encoding = REDIS_ENCODING_ZIPLIST;
941 :
942 5 : if (hashTypeLength(o) > server.hash_max_ziplist_entries ||
943 2 : maxlen > server.hash_max_ziplist_value)
944 : {
945 2 : hashTypeConvert(o, REDIS_ENCODING_HT);
946 : }
947 : }
948 : break;
949 : case REDIS_RDB_TYPE_LIST_ZIPLIST:
950 309 : o->type = REDIS_LIST;
951 309 : o->encoding = REDIS_ENCODING_ZIPLIST;
952 309 : if (ziplistLen(o->ptr) > server.list_max_ziplist_entries)
953 0 : listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
954 : break;
955 : case REDIS_RDB_TYPE_SET_INTSET:
956 559 : o->type = REDIS_SET;
957 559 : o->encoding = REDIS_ENCODING_INTSET;
958 559 : if (intsetLen(o->ptr) > server.set_max_intset_entries)
959 0 : setTypeConvert(o,REDIS_ENCODING_HT);
960 : break;
961 : case REDIS_RDB_TYPE_ZSET_ZIPLIST:
962 588 : o->type = REDIS_ZSET;
963 588 : o->encoding = REDIS_ENCODING_ZIPLIST;
964 588 : if (zsetLength(o) > server.zset_max_ziplist_entries)
965 12 : zsetConvert(o,REDIS_ENCODING_SKIPLIST);
966 : break;
967 : case REDIS_RDB_TYPE_HASH_ZIPLIST:
968 480 : o->type = REDIS_HASH;
969 480 : o->encoding = REDIS_ENCODING_ZIPLIST;
970 480 : if (hashTypeLength(o) > server.hash_max_ziplist_entries)
971 0 : hashTypeConvert(o, REDIS_ENCODING_HT);
972 : break;
973 : default:
974 0 : redisPanic("Unknown encoding");
975 : break;
976 : }
977 : } else {
978 0 : redisPanic("Unknown object type");
979 : }
980 1010127 : return o;
981 : }
982 :
983 : /* Mark that we are loading in the global state and setup the fields
984 : * needed to provide loading stats. */
985 47 : void startLoading(FILE *fp) {
986 : struct stat sb;
987 :
988 : /* Load the DB */
989 47 : server.loading = 1;
990 47 : server.loading_start_time = time(NULL);
991 94 : if (fstat(fileno(fp), &sb) == -1) {
992 0 : server.loading_total_bytes = 1; /* just to avoid division by zero */
993 : } else {
994 47 : server.loading_total_bytes = sb.st_size;
995 : }
996 47 : }
997 :
998 : /* Refresh the loading progress info */
999 24 : void loadingProgress(off_t pos) {
1000 1054 : server.loading_loaded_bytes = pos;
1001 24 : }
1002 :
1003 : /* Loading finished */
1004 22 : void stopLoading(void) {
1005 45 : server.loading = 0;
1006 22 : }
1007 :
1008 66 : int rdbLoad(char *filename) {
1009 : uint32_t dbid;
1010 : int type, rdbver;
1011 66 : redisDb *db = server.db+0;
1012 : char buf[1024];
1013 66 : long long expiretime, now = mstime();
1014 66 : long loops = 0;
1015 : FILE *fp;
1016 : rio rdb;
1017 :
1018 66 : fp = fopen(filename,"r");
1019 66 : if (!fp) {
1020 43 : errno = ENOENT;
1021 43 : return REDIS_ERR;
1022 : }
1023 23 : rioInitWithFile(&rdb,fp);
1024 23 : if (rioRead(&rdb,buf,9) == 0) goto eoferr;
1025 23 : buf[9] = '\0';
1026 23 : if (memcmp(buf,"REDIS",5) != 0) {
1027 0 : fclose(fp);
1028 0 : redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
1029 0 : errno = EINVAL;
1030 0 : return REDIS_ERR;
1031 : }
1032 : rdbver = atoi(buf+5);
1033 23 : if (rdbver < 1 || rdbver > 4) {
1034 0 : fclose(fp);
1035 0 : redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver);
1036 0 : errno = EINVAL;
1037 0 : return REDIS_ERR;
1038 : }
1039 :
1040 23 : startLoading(fp);
1041 : while(1) {
1042 : robj *key, *val;
1043 1010169 : expiretime = -1;
1044 :
1045 : /* Serve the clients from time to time */
1046 1010169 : if (!(loops++ % 1000)) {
1047 1030 : loadingProgress(rdb.tell(&rdb));
1048 1030 : aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT);
1049 : }
1050 :
1051 : /* Read type. */
1052 1010169 : if ((type = rdbLoadType(&rdb)) == -1) goto eoferr;
1053 1010169 : if (type == REDIS_RDB_OPCODE_EXPIRETIME) {
1054 0 : if ((expiretime = rdbLoadTime(&rdb)) == -1) goto eoferr;
1055 : /* We read the time so we need to read the object type again. */
1056 0 : if ((type = rdbLoadType(&rdb)) == -1) goto eoferr;
1057 : /* the EXPIRETIME opcode specifies time in seconds, so convert
1058 : * into milliesconds. */
1059 0 : expiretime *= 1000;
1060 1010169 : } else if (type == REDIS_RDB_OPCODE_EXPIRETIME_MS) {
1061 : /* Milliseconds precision expire times introduced with RDB
1062 : * version 3. */
1063 1 : if ((expiretime = rdbLoadMillisecondTime(&rdb)) == -1) goto eoferr;
1064 : /* We read the time so we need to read the object type again. */
1065 1 : if ((type = rdbLoadType(&rdb)) == -1) goto eoferr;
1066 : }
1067 :
1068 1010169 : if (type == REDIS_RDB_OPCODE_EOF)
1069 : break;
1070 :
1071 : /* Handle SELECT DB opcode as a special case */
1072 1010146 : if (type == REDIS_RDB_OPCODE_SELECTDB) {
1073 22 : if ((dbid = rdbLoadLen(&rdb,NULL)) == REDIS_RDB_LENERR)
1074 : goto eoferr;
1075 22 : if (dbid >= (unsigned)server.dbnum) {
1076 0 : redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
1077 0 : exit(1);
1078 : }
1079 22 : db = server.db+dbid;
1080 22 : continue;
1081 : }
1082 : /* Read key */
1083 1010124 : if ((key = rdbLoadStringObject(&rdb)) == NULL) goto eoferr;
1084 : /* Read value */
1085 1010124 : if ((val = rdbLoadObject(type,&rdb)) == NULL) goto eoferr;
1086 : /* Check if the key already expired. This function is used when loading
1087 : * an RDB file from disk, either at startup, or when an RDB was
1088 : * received from the master. In the latter case, the master is
1089 : * responsible for key expiry. If we would expire keys here, the
1090 : * snapshot taken by the master may not be reflected on the slave. */
1091 1010124 : if (server.masterhost == NULL && expiretime != -1 && expiretime < now) {
1092 0 : decrRefCount(key);
1093 0 : decrRefCount(val);
1094 0 : continue;
1095 : }
1096 : /* Add the new object in the hash table */
1097 1010124 : dbAdd(db,key,val);
1098 :
1099 : /* Set the expire time if needed */
1100 1010124 : if (expiretime != -1) setExpire(db,key,expiretime);
1101 :
1102 1010124 : decrRefCount(key);
1103 : }
1104 23 : fclose(fp);
1105 : stopLoading();
1106 23 : return REDIS_OK;
1107 :
1108 : eoferr: /* unexpected end of file is handled here with a fatal exit */
1109 0 : redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
1110 0 : exit(1);
1111 : return REDIS_ERR; /* Just to avoid warning */
1112 : }
1113 :
1114 : /* A background saving child (BGSAVE) terminated its work. Handle this. */
1115 8 : void backgroundSaveDoneHandler(int exitcode, int bysignal) {
1116 8 : if (!bysignal && exitcode == 0) {
1117 8 : redisLog(REDIS_NOTICE,
1118 : "Background saving terminated with success");
1119 8 : server.dirty = server.dirty - server.dirty_before_bgsave;
1120 8 : server.lastsave = time(NULL);
1121 8 : server.lastbgsave_status = REDIS_OK;
1122 0 : } else if (!bysignal && exitcode != 0) {
1123 0 : redisLog(REDIS_WARNING, "Background saving error");
1124 0 : server.lastbgsave_status = REDIS_ERR;
1125 : } else {
1126 0 : redisLog(REDIS_WARNING,
1127 : "Background saving terminated by signal %d", bysignal);
1128 0 : rdbRemoveTempFile(server.rdb_child_pid);
1129 0 : server.lastbgsave_status = REDIS_ERR;
1130 : }
1131 8 : server.rdb_child_pid = -1;
1132 : /* Possibly there are slaves waiting for a BGSAVE in order to be served
1133 : * (the first stage of SYNC is a bulk transfer of dump.rdb) */
1134 8 : updateSlavesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
1135 8 : }
1136 :
1137 4 : void saveCommand(redisClient *c) {
1138 4 : if (server.rdb_child_pid != -1) {
1139 0 : addReplyError(c,"Background save already in progress");
1140 0 : return;
1141 : }
1142 4 : if (rdbSave(server.rdb_filename) == REDIS_OK) {
1143 4 : addReply(c,shared.ok);
1144 : } else {
1145 0 : addReply(c,shared.err);
1146 : }
1147 : }
1148 :
1149 1 : void bgsaveCommand(redisClient *c) {
1150 1 : if (server.rdb_child_pid != -1) {
1151 0 : addReplyError(c,"Background save already in progress");
1152 1 : } else if (server.aof_child_pid != -1) {
1153 0 : addReplyError(c,"Can't BGSAVE while AOF log rewriting is in progress");
1154 1 : } else if (rdbSaveBackground(server.rdb_filename) == REDIS_OK) {
1155 1 : addReplyStatus(c,"Background saving started");
1156 : } else {
1157 0 : addReply(c,shared.err);
1158 : }
1159 1 : }
|