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