]> git.saurik.com Git - redis.git/blame - src/rdb.c
TODO modified
[redis.git] / src / rdb.c
CommitLineData
e2641e09 1#include "redis.h"
2#include "lzf.h" /* LZF compression library */
3
4#include <math.h>
3688d7f3 5#include <sys/types.h>
6#include <sys/time.h>
7#include <sys/resource.h>
8#include <sys/wait.h>
9#include <arpa/inet.h>
97e7f8ae 10#include <sys/stat.h>
e2641e09 11
9a68cf91
PN
12/* Convenience wrapper around fwrite, that returns the number of bytes written
13 * to the file instead of the number of objects (see fwrite(3)) and -1 in the
14 * case of an error. It also supports a NULL *fp to skip writing altogether
15 * instead of writing to /dev/null. */
16static int rdbWriteRaw(FILE *fp, void *p, size_t len) {
17 if (fp != NULL && fwrite(p,len,1,fp) == 0) return -1;
18 return len;
19}
20
e2641e09 21int rdbSaveType(FILE *fp, unsigned char type) {
9a68cf91 22 return rdbWriteRaw(fp,&type,1);
e2641e09 23}
24
25int rdbSaveTime(FILE *fp, time_t t) {
26 int32_t t32 = (int32_t) t;
9a68cf91 27 return rdbWriteRaw(fp,&t32,4);
e2641e09 28}
29
30/* check rdbLoadLen() comments for more info */
31int rdbSaveLen(FILE *fp, uint32_t len) {
32 unsigned char buf[2];
8a623a98 33 int nwritten;
e2641e09 34
35 if (len < (1<<6)) {
36 /* Save a 6 bit len */
37 buf[0] = (len&0xFF)|(REDIS_RDB_6BITLEN<<6);
9a68cf91 38 if (rdbWriteRaw(fp,buf,1) == -1) return -1;
8a623a98 39 nwritten = 1;
e2641e09 40 } else if (len < (1<<14)) {
41 /* Save a 14 bit len */
42 buf[0] = ((len>>8)&0xFF)|(REDIS_RDB_14BITLEN<<6);
43 buf[1] = len&0xFF;
9a68cf91 44 if (rdbWriteRaw(fp,buf,2) == -1) return -1;
8a623a98 45 nwritten = 2;
e2641e09 46 } else {
47 /* Save a 32 bit len */
48 buf[0] = (REDIS_RDB_32BITLEN<<6);
9a68cf91 49 if (rdbWriteRaw(fp,buf,1) == -1) return -1;
e2641e09 50 len = htonl(len);
9a68cf91 51 if (rdbWriteRaw(fp,&len,4) == -1) return -1;
8a623a98 52 nwritten = 1+4;
e2641e09 53 }
8a623a98 54 return nwritten;
e2641e09 55}
56
57/* Encode 'value' as an integer if possible (if integer will fit the
58 * supported range). If the function sucessful encoded the integer
59 * then the (up to 5 bytes) encoded representation is written in the
60 * string pointed by 'enc' and the length is returned. Otherwise
61 * 0 is returned. */
62int rdbEncodeInteger(long long value, unsigned char *enc) {
63 /* Finally check if it fits in our ranges */
64 if (value >= -(1<<7) && value <= (1<<7)-1) {
65 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT8;
66 enc[1] = value&0xFF;
67 return 2;
68 } else if (value >= -(1<<15) && value <= (1<<15)-1) {
69 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT16;
70 enc[1] = value&0xFF;
71 enc[2] = (value>>8)&0xFF;
72 return 3;
73 } else if (value >= -((long long)1<<31) && value <= ((long long)1<<31)-1) {
74 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT32;
75 enc[1] = value&0xFF;
76 enc[2] = (value>>8)&0xFF;
77 enc[3] = (value>>16)&0xFF;
78 enc[4] = (value>>24)&0xFF;
79 return 5;
80 } else {
81 return 0;
82 }
83}
84
85/* String objects in the form "2391" "-100" without any space and with a
86 * range of values that can fit in an 8, 16 or 32 bit signed value can be
87 * encoded as integers to save space */
88int rdbTryIntegerEncoding(char *s, size_t len, unsigned char *enc) {
89 long long value;
90 char *endptr, buf[32];
91
92 /* Check if it's possible to encode this value as a number */
93 value = strtoll(s, &endptr, 10);
94 if (endptr[0] != '\0') return 0;
95 ll2string(buf,32,value);
96
97 /* If the number converted back into a string is not identical
98 * then it's not possible to encode the string as integer */
99 if (strlen(buf) != len || memcmp(buf,s,len)) return 0;
100
101 return rdbEncodeInteger(value,enc);
102}
103
104int rdbSaveLzfStringObject(FILE *fp, unsigned char *s, size_t len) {
105 size_t comprlen, outlen;
106 unsigned char byte;
8a623a98 107 int n, nwritten = 0;
e2641e09 108 void *out;
109
110 /* We require at least four bytes compression for this to be worth it */
111 if (len <= 4) return 0;
112 outlen = len-4;
113 if ((out = zmalloc(outlen+1)) == NULL) return 0;
114 comprlen = lzf_compress(s, len, out, outlen);
115 if (comprlen == 0) {
116 zfree(out);
117 return 0;
118 }
119 /* Data compressed! Let's save it on disk */
120 byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
9a68cf91
PN
121 if ((n = rdbWriteRaw(fp,&byte,1)) == -1) goto writeerr;
122 nwritten += n;
8a623a98
PN
123
124 if ((n = rdbSaveLen(fp,comprlen)) == -1) goto writeerr;
125 nwritten += n;
126
127 if ((n = rdbSaveLen(fp,len)) == -1) goto writeerr;
128 nwritten += n;
129
9a68cf91
PN
130 if ((n = rdbWriteRaw(fp,out,comprlen)) == -1) goto writeerr;
131 nwritten += n;
8a623a98 132
e2641e09 133 zfree(out);
8a623a98 134 return nwritten;
e2641e09 135
136writeerr:
137 zfree(out);
138 return -1;
139}
140
141/* Save a string objet as [len][data] on disk. If the object is a string
2cc99365 142 * representation of an integer value we try to save it in a special form */
e2641e09 143int rdbSaveRawString(FILE *fp, unsigned char *s, size_t len) {
144 int enclen;
8a623a98 145 int n, nwritten = 0;
e2641e09 146
147 /* Try integer encoding */
148 if (len <= 11) {
149 unsigned char buf[5];
150 if ((enclen = rdbTryIntegerEncoding((char*)s,len,buf)) > 0) {
9a68cf91 151 if (rdbWriteRaw(fp,buf,enclen) == -1) return -1;
8a623a98 152 return enclen;
e2641e09 153 }
154 }
155
156 /* Try LZF compression - under 20 bytes it's unable to compress even
157 * aaaaaaaaaaaaaaaaaa so skip it */
158 if (server.rdbcompression && len > 20) {
8a623a98
PN
159 n = rdbSaveLzfStringObject(fp,s,len);
160 if (n == -1) return -1;
161 if (n > 0) return n;
162 /* Return value of 0 means data can't be compressed, save the old way */
e2641e09 163 }
164
165 /* Store verbatim */
8a623a98
PN
166 if ((n = rdbSaveLen(fp,len)) == -1) return -1;
167 nwritten += n;
168 if (len > 0) {
9a68cf91 169 if (rdbWriteRaw(fp,s,len) == -1) return -1;
8a623a98
PN
170 nwritten += len;
171 }
172 return nwritten;
e2641e09 173}
174
175/* Save a long long value as either an encoded string or a string. */
176int rdbSaveLongLongAsStringObject(FILE *fp, long long value) {
177 unsigned char buf[32];
8a623a98 178 int n, nwritten = 0;
e2641e09 179 int enclen = rdbEncodeInteger(value,buf);
180 if (enclen > 0) {
9a68cf91 181 return rdbWriteRaw(fp,buf,enclen);
e2641e09 182 } else {
183 /* Encode as string */
184 enclen = ll2string((char*)buf,32,value);
185 redisAssert(enclen < 32);
8a623a98
PN
186 if ((n = rdbSaveLen(fp,enclen)) == -1) return -1;
187 nwritten += n;
9a68cf91
PN
188 if ((n = rdbWriteRaw(fp,buf,enclen)) == -1) return -1;
189 nwritten += n;
e2641e09 190 }
8a623a98 191 return nwritten;
e2641e09 192}
193
194/* Like rdbSaveStringObjectRaw() but handle encoded objects */
195int rdbSaveStringObject(FILE *fp, robj *obj) {
196 /* Avoid to decode the object, then encode it again, if the
197 * object is alrady integer encoded. */
198 if (obj->encoding == REDIS_ENCODING_INT) {
199 return rdbSaveLongLongAsStringObject(fp,(long)obj->ptr);
200 } else {
201 redisAssert(obj->encoding == REDIS_ENCODING_RAW);
202 return rdbSaveRawString(fp,obj->ptr,sdslen(obj->ptr));
203 }
204}
205
206/* Save a double value. Doubles are saved as strings prefixed by an unsigned
207 * 8 bit integer specifing the length of the representation.
208 * This 8 bit integer has special values in order to specify the following
209 * conditions:
210 * 253: not a number
211 * 254: + inf
212 * 255: - inf
213 */
214int rdbSaveDoubleValue(FILE *fp, double val) {
215 unsigned char buf[128];
216 int len;
217
218 if (isnan(val)) {
219 buf[0] = 253;
220 len = 1;
221 } else if (!isfinite(val)) {
222 len = 1;
223 buf[0] = (val < 0) ? 255 : 254;
224 } else {
225#if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
226 /* Check if the float is in a safe range to be casted into a
227 * long long. We are assuming that long long is 64 bit here.
228 * Also we are assuming that there are no implementations around where
229 * double has precision < 52 bit.
230 *
231 * Under this assumptions we test if a double is inside an interval
232 * where casting to long long is safe. Then using two castings we
233 * make sure the decimal part is zero. If all this is true we use
234 * integer printing function that is much faster. */
235 double min = -4503599627370495; /* (2^52)-1 */
236 double max = 4503599627370496; /* -(2^52) */
237 if (val > min && val < max && val == ((double)((long long)val)))
238 ll2string((char*)buf+1,sizeof(buf),(long long)val);
239 else
240#endif
241 snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);
242 buf[0] = strlen((char*)buf+1);
243 len = buf[0]+1;
244 }
9a68cf91 245 return rdbWriteRaw(fp,buf,len);
e2641e09 246}
247
248/* Save a Redis object. */
249int rdbSaveObject(FILE *fp, robj *o) {
8a623a98
PN
250 int n, nwritten = 0;
251
e2641e09 252 if (o->type == REDIS_STRING) {
253 /* Save a string value */
8a623a98
PN
254 if ((n = rdbSaveStringObject(fp,o)) == -1) return -1;
255 nwritten += n;
e2641e09 256 } else if (o->type == REDIS_LIST) {
257 /* Save a list value */
258 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
26117e84 259 size_t l = ziplistBlobLen((unsigned char*)o->ptr);
e2641e09 260
26117e84 261 if ((n = rdbSaveRawString(fp,o->ptr,l)) == -1) return -1;
8a623a98 262 nwritten += n;
e2641e09 263 } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
264 list *list = o->ptr;
265 listIter li;
266 listNode *ln;
267
8a623a98
PN
268 if ((n = rdbSaveLen(fp,listLength(list))) == -1) return -1;
269 nwritten += n;
270
e2641e09 271 listRewind(list,&li);
272 while((ln = listNext(&li))) {
273 robj *eleobj = listNodeValue(ln);
8a623a98
PN
274 if ((n = rdbSaveStringObject(fp,eleobj)) == -1) return -1;
275 nwritten += n;
e2641e09 276 }
277 } else {
278 redisPanic("Unknown list encoding");
279 }
280 } else if (o->type == REDIS_SET) {
281 /* Save a set value */
96ffb2fe
PN
282 if (o->encoding == REDIS_ENCODING_HT) {
283 dict *set = o->ptr;
284 dictIterator *di = dictGetIterator(set);
285 dictEntry *de;
e2641e09 286
8a623a98
PN
287 if ((n = rdbSaveLen(fp,dictSize(set))) == -1) return -1;
288 nwritten += n;
289
96ffb2fe
PN
290 while((de = dictNext(di)) != NULL) {
291 robj *eleobj = dictGetEntryKey(de);
8a623a98
PN
292 if ((n = rdbSaveStringObject(fp,eleobj)) == -1) return -1;
293 nwritten += n;
96ffb2fe
PN
294 }
295 dictReleaseIterator(di);
296 } else if (o->encoding == REDIS_ENCODING_INTSET) {
26117e84 297 size_t l = intsetBlobLen((intset*)o->ptr);
96ffb2fe 298
26117e84 299 if ((n = rdbSaveRawString(fp,o->ptr,l)) == -1) return -1;
8a623a98 300 nwritten += n;
96ffb2fe
PN
301 } else {
302 redisPanic("Unknown set encoding");
e2641e09 303 }
e2641e09 304 } else if (o->type == REDIS_ZSET) {
305 /* Save a set value */
306 zset *zs = o->ptr;
307 dictIterator *di = dictGetIterator(zs->dict);
308 dictEntry *de;
309
8a623a98
PN
310 if ((n = rdbSaveLen(fp,dictSize(zs->dict))) == -1) return -1;
311 nwritten += n;
312
e2641e09 313 while((de = dictNext(di)) != NULL) {
314 robj *eleobj = dictGetEntryKey(de);
315 double *score = dictGetEntryVal(de);
316
8a623a98
PN
317 if ((n = rdbSaveStringObject(fp,eleobj)) == -1) return -1;
318 nwritten += n;
319 if ((n = rdbSaveDoubleValue(fp,*score)) == -1) return -1;
320 nwritten += n;
e2641e09 321 }
322 dictReleaseIterator(di);
323 } else if (o->type == REDIS_HASH) {
324 /* Save a hash value */
325 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
2cc99365 326 size_t l = zipmapBlobLen((unsigned char*)o->ptr);
e2641e09 327
2cc99365 328 if ((n = rdbSaveRawString(fp,o->ptr,l)) == -1) return -1;
8a623a98 329 nwritten += n;
e2641e09 330 } else {
331 dictIterator *di = dictGetIterator(o->ptr);
332 dictEntry *de;
333
8a623a98
PN
334 if ((n = rdbSaveLen(fp,dictSize((dict*)o->ptr))) == -1) return -1;
335 nwritten += n;
336
e2641e09 337 while((de = dictNext(di)) != NULL) {
338 robj *key = dictGetEntryKey(de);
339 robj *val = dictGetEntryVal(de);
340
8a623a98
PN
341 if ((n = rdbSaveStringObject(fp,key)) == -1) return -1;
342 nwritten += n;
343 if ((n = rdbSaveStringObject(fp,val)) == -1) return -1;
344 nwritten += n;
e2641e09 345 }
346 dictReleaseIterator(di);
347 }
348 } else {
349 redisPanic("Unknown object type");
350 }
8a623a98 351 return nwritten;
e2641e09 352}
353
354/* Return the length the object will have on disk if saved with
355 * the rdbSaveObject() function. Currently we use a trick to get
356 * this length with very little changes to the code. In the future
357 * we could switch to a faster solution. */
bd70a5f5
PN
358off_t rdbSavedObjectLen(robj *o) {
359 int len = rdbSaveObject(NULL,o);
360 redisAssert(len != -1);
361 return len;
e2641e09 362}
363
4ab98823 364/* Save a key-value pair, with expire time, type, key, value.
365 * On error -1 is returned.
366 * On success if the key was actaully saved 1 is returned, otherwise 0
367 * is returned (the key was already expired). */
05600eb8 368int rdbSaveKeyValuePair(FILE *fp, robj *key, robj *val,
369 time_t expiretime, time_t now)
4ab98823 370{
2cc99365 371 int vtype;
372
4ab98823 373 /* Save the expire time */
374 if (expiretime != -1) {
375 /* If this key is already expired skip it */
376 if (expiretime < now) return 0;
377 if (rdbSaveType(fp,REDIS_EXPIRETIME) == -1) return -1;
378 if (rdbSaveTime(fp,expiretime) == -1) return -1;
379 }
2cc99365 380 /* Fix the object type if needed, to support saving zipmaps, ziplists,
381 * and intsets, directly as blobs of bytes: they are already serialized. */
382 vtype = val->type;
383 if (vtype == REDIS_HASH && val->encoding == REDIS_ENCODING_ZIPMAP)
384 vtype = REDIS_HASH_ZIPMAP;
9fa7beb5 385 else if (vtype == REDIS_LIST && val->encoding == REDIS_ENCODING_ZIPLIST)
0a04b5f5 386 vtype = REDIS_LIST_ZIPLIST;
1213abe4 387 else if (vtype == REDIS_SET && val->encoding == REDIS_ENCODING_INTSET)
388 vtype = REDIS_SET_INTSET;
4ab98823 389 /* Save type, key, value */
1187b0a5 390 if (rdbSaveType(fp,vtype) == -1) return -1;
1fce3201 391 if (rdbSaveStringObject(fp,key) == -1) return -1;
4ab98823 392 if (rdbSaveObject(fp,val) == -1) return -1;
393 return 1;
394}
395
e2641e09 396/* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
397int rdbSave(char *filename) {
398 dictIterator *di = NULL;
399 dictEntry *de;
400 FILE *fp;
401 char tmpfile[256];
402 int j;
403 time_t now = time(NULL);
404
249ad25f 405 if (server.ds_enabled) {
406 cacheForcePointInTime();
407 return dsRdbSave(filename);
408 }
e2641e09 409
410 snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
411 fp = fopen(tmpfile,"w");
412 if (!fp) {
5b8ce853 413 redisLog(REDIS_WARNING, "Failed opening .rdb for saving: %s",
414 strerror(errno));
e2641e09 415 return REDIS_ERR;
416 }
417 if (fwrite("REDIS0001",9,1,fp) == 0) goto werr;
418 for (j = 0; j < server.dbnum; j++) {
419 redisDb *db = server.db+j;
420 dict *d = db->dict;
421 if (dictSize(d) == 0) continue;
422 di = dictGetIterator(d);
423 if (!di) {
424 fclose(fp);
425 return REDIS_ERR;
426 }
427
428 /* Write the SELECT DB opcode */
429 if (rdbSaveType(fp,REDIS_SELECTDB) == -1) goto werr;
430 if (rdbSaveLen(fp,j) == -1) goto werr;
431
432 /* Iterate this DB writing every entry */
433 while((de = dictNext(di)) != NULL) {
434 sds keystr = dictGetEntryKey(de);
435 robj key, *o = dictGetEntryVal(de);
05600eb8 436 time_t expire;
e2641e09 437
438 initStaticStringObject(key,keystr);
05600eb8 439 expire = getExpire(db,&key);
440 if (rdbSaveKeyValuePair(fp,&key,o,expire,now) == -1) goto werr;
e2641e09 441 }
442 dictReleaseIterator(di);
443 }
444 /* EOF opcode */
445 if (rdbSaveType(fp,REDIS_EOF) == -1) goto werr;
446
447 /* Make sure data will not remain on the OS's output buffers */
448 fflush(fp);
449 fsync(fileno(fp));
450 fclose(fp);
451
452 /* Use RENAME to make sure the DB file is changed atomically only
453 * if the generate DB file is ok. */
454 if (rename(tmpfile,filename) == -1) {
455 redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
456 unlink(tmpfile);
457 return REDIS_ERR;
458 }
459 redisLog(REDIS_NOTICE,"DB saved on disk");
460 server.dirty = 0;
461 server.lastsave = time(NULL);
462 return REDIS_OK;
463
464werr:
465 fclose(fp);
466 unlink(tmpfile);
467 redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
468 if (di) dictReleaseIterator(di);
469 return REDIS_ERR;
470}
471
472int rdbSaveBackground(char *filename) {
473 pid_t childpid;
474
36c17a53 475 if (server.bgsavechildpid != -1 ||
476 server.bgsavethread != (pthread_t) -1) return REDIS_ERR;
249ad25f 477
2f6b31c3 478 server.dirty_before_bgsave = server.dirty;
249ad25f 479
36c17a53 480 if (server.ds_enabled) {
481 cacheForcePointInTime();
cc275067 482 return dsRdbSaveBackground(filename);
36c17a53 483 }
484
e2641e09 485 if ((childpid = fork()) == 0) {
249ad25f 486 int retval;
487
e2641e09 488 /* Child */
a5639e7d
PN
489 if (server.ipfd > 0) close(server.ipfd);
490 if (server.sofd > 0) close(server.sofd);
36c17a53 491 retval = rdbSave(filename);
249ad25f 492 _exit((retval == REDIS_OK) ? 0 : 1);
e2641e09 493 } else {
494 /* Parent */
495 if (childpid == -1) {
496 redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
497 strerror(errno));
498 return REDIS_ERR;
499 }
500 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
501 server.bgsavechildpid = childpid;
502 updateDictResizePolicy();
503 return REDIS_OK;
504 }
505 return REDIS_OK; /* unreached */
506}
507
508void rdbRemoveTempFile(pid_t childpid) {
509 char tmpfile[256];
510
511 snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid);
512 unlink(tmpfile);
513}
514
515int rdbLoadType(FILE *fp) {
516 unsigned char type;
517 if (fread(&type,1,1,fp) == 0) return -1;
518 return type;
519}
520
521time_t rdbLoadTime(FILE *fp) {
522 int32_t t32;
523 if (fread(&t32,4,1,fp) == 0) return -1;
524 return (time_t) t32;
525}
526
527/* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
528 * of this file for a description of how this are stored on disk.
529 *
530 * isencoded is set to 1 if the readed length is not actually a length but
531 * an "encoding type", check the above comments for more info */
532uint32_t rdbLoadLen(FILE *fp, int *isencoded) {
533 unsigned char buf[2];
534 uint32_t len;
535 int type;
536
537 if (isencoded) *isencoded = 0;
538 if (fread(buf,1,1,fp) == 0) return REDIS_RDB_LENERR;
539 type = (buf[0]&0xC0)>>6;
540 if (type == REDIS_RDB_6BITLEN) {
541 /* Read a 6 bit len */
542 return buf[0]&0x3F;
543 } else if (type == REDIS_RDB_ENCVAL) {
544 /* Read a 6 bit len encoding type */
545 if (isencoded) *isencoded = 1;
546 return buf[0]&0x3F;
547 } else if (type == REDIS_RDB_14BITLEN) {
548 /* Read a 14 bit len */
549 if (fread(buf+1,1,1,fp) == 0) return REDIS_RDB_LENERR;
550 return ((buf[0]&0x3F)<<8)|buf[1];
551 } else {
552 /* Read a 32 bit len */
553 if (fread(&len,4,1,fp) == 0) return REDIS_RDB_LENERR;
554 return ntohl(len);
555 }
556}
557
558/* Load an integer-encoded object from file 'fp', with the specified
559 * encoding type 'enctype'. If encode is true the function may return
560 * an integer-encoded object as reply, otherwise the returned object
561 * will always be encoded as a raw string. */
562robj *rdbLoadIntegerObject(FILE *fp, int enctype, int encode) {
563 unsigned char enc[4];
564 long long val;
565
566 if (enctype == REDIS_RDB_ENC_INT8) {
567 if (fread(enc,1,1,fp) == 0) return NULL;
568 val = (signed char)enc[0];
569 } else if (enctype == REDIS_RDB_ENC_INT16) {
570 uint16_t v;
571 if (fread(enc,2,1,fp) == 0) return NULL;
572 v = enc[0]|(enc[1]<<8);
573 val = (int16_t)v;
574 } else if (enctype == REDIS_RDB_ENC_INT32) {
575 uint32_t v;
576 if (fread(enc,4,1,fp) == 0) return NULL;
577 v = enc[0]|(enc[1]<<8)|(enc[2]<<16)|(enc[3]<<24);
578 val = (int32_t)v;
579 } else {
580 val = 0; /* anti-warning */
581 redisPanic("Unknown RDB integer encoding type");
582 }
583 if (encode)
584 return createStringObjectFromLongLong(val);
585 else
586 return createObject(REDIS_STRING,sdsfromlonglong(val));
587}
588
589robj *rdbLoadLzfStringObject(FILE*fp) {
590 unsigned int len, clen;
591 unsigned char *c = NULL;
592 sds val = NULL;
593
594 if ((clen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
595 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
596 if ((c = zmalloc(clen)) == NULL) goto err;
597 if ((val = sdsnewlen(NULL,len)) == NULL) goto err;
598 if (fread(c,clen,1,fp) == 0) goto err;
599 if (lzf_decompress(c,clen,val,len) == 0) goto err;
600 zfree(c);
601 return createObject(REDIS_STRING,val);
602err:
603 zfree(c);
604 sdsfree(val);
605 return NULL;
606}
607
608robj *rdbGenericLoadStringObject(FILE*fp, int encode) {
609 int isencoded;
610 uint32_t len;
611 sds val;
612
613 len = rdbLoadLen(fp,&isencoded);
614 if (isencoded) {
615 switch(len) {
616 case REDIS_RDB_ENC_INT8:
617 case REDIS_RDB_ENC_INT16:
618 case REDIS_RDB_ENC_INT32:
619 return rdbLoadIntegerObject(fp,len,encode);
620 case REDIS_RDB_ENC_LZF:
621 return rdbLoadLzfStringObject(fp);
622 default:
623 redisPanic("Unknown RDB encoding type");
624 }
625 }
626
627 if (len == REDIS_RDB_LENERR) return NULL;
628 val = sdsnewlen(NULL,len);
629 if (len && fread(val,len,1,fp) == 0) {
630 sdsfree(val);
631 return NULL;
632 }
633 return createObject(REDIS_STRING,val);
634}
635
636robj *rdbLoadStringObject(FILE *fp) {
637 return rdbGenericLoadStringObject(fp,0);
638}
639
640robj *rdbLoadEncodedStringObject(FILE *fp) {
641 return rdbGenericLoadStringObject(fp,1);
642}
643
644/* For information about double serialization check rdbSaveDoubleValue() */
645int rdbLoadDoubleValue(FILE *fp, double *val) {
646 char buf[128];
647 unsigned char len;
648
649 if (fread(&len,1,1,fp) == 0) return -1;
650 switch(len) {
651 case 255: *val = R_NegInf; return 0;
652 case 254: *val = R_PosInf; return 0;
653 case 253: *val = R_Nan; return 0;
654 default:
655 if (fread(buf,len,1,fp) == 0) return -1;
656 buf[len] = '\0';
657 sscanf(buf, "%lg", val);
658 return 0;
659 }
660}
661
662/* Load a Redis object of the specified type from the specified file.
663 * On success a newly allocated object is returned, otherwise NULL. */
664robj *rdbLoadObject(int type, FILE *fp) {
665 robj *o, *ele, *dec;
666 size_t len;
96ffb2fe 667 unsigned int i;
e2641e09 668
669 redisLog(REDIS_DEBUG,"LOADING OBJECT %d (at %d)\n",type,ftell(fp));
670 if (type == REDIS_STRING) {
671 /* Read string value */
672 if ((o = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
673 o = tryObjectEncoding(o);
674 } else if (type == REDIS_LIST) {
675 /* Read list value */
676 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
677
678 /* Use a real list when there are too many entries */
679 if (len > server.list_max_ziplist_entries) {
680 o = createListObject();
681 } else {
682 o = createZiplistObject();
683 }
684
685 /* Load every single element of the list */
686 while(len--) {
687 if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
688
689 /* If we are using a ziplist and the value is too big, convert
690 * the object to a real list. */
691 if (o->encoding == REDIS_ENCODING_ZIPLIST &&
692 ele->encoding == REDIS_ENCODING_RAW &&
693 sdslen(ele->ptr) > server.list_max_ziplist_value)
694 listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
695
696 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
697 dec = getDecodedObject(ele);
698 o->ptr = ziplistPush(o->ptr,dec->ptr,sdslen(dec->ptr),REDIS_TAIL);
699 decrRefCount(dec);
700 decrRefCount(ele);
701 } else {
702 ele = tryObjectEncoding(ele);
703 listAddNodeTail(o->ptr,ele);
704 }
705 }
706 } else if (type == REDIS_SET) {
707 /* Read list/set value */
708 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
96ffb2fe
PN
709
710 /* Use a regular set when there are too many entries. */
711 if (len > server.set_max_intset_entries) {
712 o = createSetObject();
713 /* It's faster to expand the dict to the right size asap in order
714 * to avoid rehashing */
715 if (len > DICT_HT_INITIAL_SIZE)
716 dictExpand(o->ptr,len);
717 } else {
718 o = createIntsetObject();
719 }
720
e2641e09 721 /* Load every single element of the list/set */
96ffb2fe
PN
722 for (i = 0; i < len; i++) {
723 long long llval;
e2641e09 724 if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
725 ele = tryObjectEncoding(ele);
96ffb2fe
PN
726
727 if (o->encoding == REDIS_ENCODING_INTSET) {
728 /* Fetch integer value from element */
2df84b72 729 if (isObjectRepresentableAsLongLong(ele,&llval) == REDIS_OK) {
96ffb2fe
PN
730 o->ptr = intsetAdd(o->ptr,llval,NULL);
731 } else {
732 setTypeConvert(o,REDIS_ENCODING_HT);
733 dictExpand(o->ptr,len);
734 }
735 }
736
737 /* This will also be called when the set was just converted
738 * to regular hashtable encoded set */
739 if (o->encoding == REDIS_ENCODING_HT) {
740 dictAdd((dict*)o->ptr,ele,NULL);
bad7d097 741 } else {
742 decrRefCount(ele);
96ffb2fe 743 }
e2641e09 744 }
745 } else if (type == REDIS_ZSET) {
746 /* Read list/set value */
747 size_t zsetlen;
748 zset *zs;
749
750 if ((zsetlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
751 o = createZsetObject();
752 zs = o->ptr;
753 /* Load every single element of the list/set */
754 while(zsetlen--) {
755 robj *ele;
56e52b69
PN
756 double score;
757 zskiplistNode *znode;
e2641e09 758
759 if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
760 ele = tryObjectEncoding(ele);
56e52b69
PN
761 if (rdbLoadDoubleValue(fp,&score) == -1) return NULL;
762 znode = zslInsert(zs->zsl,score,ele);
763 dictAdd(zs->dict,ele,&znode->score);
e2641e09 764 incrRefCount(ele); /* added to skiplist */
765 }
766 } else if (type == REDIS_HASH) {
767 size_t hashlen;
768
769 if ((hashlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
770 o = createHashObject();
771 /* Too many entries? Use an hash table. */
772 if (hashlen > server.hash_max_zipmap_entries)
773 convertToRealHash(o);
774 /* Load every key/value, then set it into the zipmap or hash
775 * table, as needed. */
776 while(hashlen--) {
777 robj *key, *val;
778
779 if ((key = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
780 if ((val = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
781 /* If we are using a zipmap and there are too big values
782 * the object is converted to real hash table encoding. */
783 if (o->encoding != REDIS_ENCODING_HT &&
784 ((key->encoding == REDIS_ENCODING_RAW &&
785 sdslen(key->ptr) > server.hash_max_zipmap_value) ||
786 (val->encoding == REDIS_ENCODING_RAW &&
787 sdslen(val->ptr) > server.hash_max_zipmap_value)))
788 {
789 convertToRealHash(o);
790 }
791
792 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
793 unsigned char *zm = o->ptr;
794 robj *deckey, *decval;
795
796 /* We need raw string objects to add them to the zipmap */
797 deckey = getDecodedObject(key);
798 decval = getDecodedObject(val);
799 zm = zipmapSet(zm,deckey->ptr,sdslen(deckey->ptr),
800 decval->ptr,sdslen(decval->ptr),NULL);
801 o->ptr = zm;
802 decrRefCount(deckey);
803 decrRefCount(decval);
804 decrRefCount(key);
805 decrRefCount(val);
806 } else {
807 key = tryObjectEncoding(key);
808 val = tryObjectEncoding(val);
809 dictAdd((dict*)o->ptr,key,val);
810 }
811 }
26117e84 812 } else if (type == REDIS_HASH_ZIPMAP ||
813 type == REDIS_LIST_ZIPLIST ||
814 type == REDIS_SET_INTSET)
815 {
2cc99365 816 robj *aux = rdbLoadStringObject(fp);
817
818 if (aux == NULL) return NULL;
26117e84 819 o = createObject(REDIS_STRING,NULL); /* string is just placeholder */
2cc99365 820 o->ptr = zmalloc(sdslen(aux->ptr));
821 memcpy(o->ptr,aux->ptr,sdslen(aux->ptr));
822 decrRefCount(aux);
26117e84 823
824 /* Fix the object encoding, and make sure to convert the encoded
825 * data type into the base type if accordingly to the current
826 * configuration there are too many elements in the encoded data
827 * type. Note that we only check the length and not max element
828 * size as this is an O(N) scan. Eventually everything will get
829 * converted. */
830 switch(type) {
831 case REDIS_HASH_ZIPMAP:
832 o->type = REDIS_HASH;
833 o->encoding = REDIS_ENCODING_ZIPMAP;
834 if (zipmapLen(o->ptr) > server.hash_max_zipmap_entries)
835 convertToRealHash(o);
836 break;
837 case REDIS_LIST_ZIPLIST:
838 o->type = REDIS_LIST;
839 o->encoding = REDIS_ENCODING_ZIPLIST;
840 if (ziplistLen(o->ptr) > server.list_max_ziplist_entries)
841 listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
842 break;
843 case REDIS_SET_INTSET:
844 o->type = REDIS_SET;
845 o->encoding = REDIS_ENCODING_INTSET;
846 if (intsetLen(o->ptr) > server.set_max_intset_entries)
847 setTypeConvert(o,REDIS_ENCODING_HT);
848 break;
849 default:
850 redisPanic("Unknown enoding");
851 break;
f8956ed6 852 }
e2641e09 853 } else {
854 redisPanic("Unknown object type");
855 }
856 return o;
857}
858
97e7f8ae 859/* Mark that we are loading in the global state and setup the fields
860 * needed to provide loading stats. */
861void startLoading(FILE *fp) {
862 struct stat sb;
863
864 /* Load the DB */
865 server.loading = 1;
866 server.loading_start_time = time(NULL);
867 if (fstat(fileno(fp), &sb) == -1) {
868 server.loading_total_bytes = 1; /* just to avoid division by zero */
869 } else {
870 server.loading_total_bytes = sb.st_size;
871 }
872}
873
874/* Refresh the loading progress info */
875void loadingProgress(off_t pos) {
876 server.loading_loaded_bytes = pos;
877}
878
879/* Loading finished */
880void stopLoading(void) {
881 server.loading = 0;
882}
883
e2641e09 884int rdbLoad(char *filename) {
885 FILE *fp;
886 uint32_t dbid;
887 int type, retval, rdbver;
e2641e09 888 redisDb *db = server.db+0;
889 char buf[1024];
890 time_t expiretime, now = time(NULL);
97e7f8ae 891 long loops = 0;
e2641e09 892
893 fp = fopen(filename,"r");
894 if (!fp) return REDIS_ERR;
895 if (fread(buf,9,1,fp) == 0) goto eoferr;
896 buf[9] = '\0';
897 if (memcmp(buf,"REDIS",5) != 0) {
898 fclose(fp);
899 redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
900 return REDIS_ERR;
901 }
902 rdbver = atoi(buf+5);
903 if (rdbver != 1) {
904 fclose(fp);
905 redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver);
906 return REDIS_ERR;
907 }
97e7f8ae 908
909 startLoading(fp);
e2641e09 910 while(1) {
911 robj *key, *val;
e2641e09 912 expiretime = -1;
97e7f8ae 913
914 /* Serve the clients from time to time */
915 if (!(loops++ % 1000)) {
916 loadingProgress(ftello(fp));
917 aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT);
918 }
919
e2641e09 920 /* Read type. */
921 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
922 if (type == REDIS_EXPIRETIME) {
923 if ((expiretime = rdbLoadTime(fp)) == -1) goto eoferr;
924 /* We read the time so we need to read the object type again */
925 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
926 }
927 if (type == REDIS_EOF) break;
928 /* Handle SELECT DB opcode as a special case */
929 if (type == REDIS_SELECTDB) {
930 if ((dbid = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR)
931 goto eoferr;
932 if (dbid >= (unsigned)server.dbnum) {
933 redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
934 exit(1);
935 }
936 db = server.db+dbid;
937 continue;
938 }
939 /* Read key */
940 if ((key = rdbLoadStringObject(fp)) == NULL) goto eoferr;
941 /* Read value */
942 if ((val = rdbLoadObject(type,fp)) == NULL) goto eoferr;
943 /* Check if the key already expired */
944 if (expiretime != -1 && expiretime < now) {
945 decrRefCount(key);
946 decrRefCount(val);
947 continue;
948 }
949 /* Add the new object in the hash table */
950 retval = dbAdd(db,key,val);
951 if (retval == REDIS_ERR) {
952 redisLog(REDIS_WARNING,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", key->ptr);
953 exit(1);
954 }
955 /* Set the expire time if needed */
956 if (expiretime != -1) setExpire(db,key,expiretime);
957
e2641e09 958 decrRefCount(key);
e2641e09 959 }
960 fclose(fp);
97e7f8ae 961 stopLoading();
e2641e09 962 return REDIS_OK;
963
964eoferr: /* unexpected end of file is handled here with a fatal exit */
965 redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
966 exit(1);
967 return REDIS_ERR; /* Just to avoid warning */
968}
969
970/* A background saving child (BGSAVE) terminated its work. Handle this. */
36c17a53 971void backgroundSaveDoneHandler(int exitcode, int bysignal) {
e2641e09 972 if (!bysignal && exitcode == 0) {
973 redisLog(REDIS_NOTICE,
974 "Background saving terminated with success");
2f6b31c3 975 server.dirty = server.dirty - server.dirty_before_bgsave;
e2641e09 976 server.lastsave = time(NULL);
977 } else if (!bysignal && exitcode != 0) {
978 redisLog(REDIS_WARNING, "Background saving error");
979 } else {
980 redisLog(REDIS_WARNING,
36c17a53 981 "Background saving terminated by signal %d", bysignal);
e2641e09 982 rdbRemoveTempFile(server.bgsavechildpid);
983 }
984 server.bgsavechildpid = -1;
36c17a53 985 server.bgsavethread = (pthread_t) -1;
986 server.bgsavethread_state = REDIS_BGSAVE_THREAD_UNACTIVE;
e2641e09 987 /* Possibly there are slaves waiting for a BGSAVE in order to be served
988 * (the first stage of SYNC is a bulk transfer of dump.rdb) */
989 updateSlavesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
990}
36c17a53 991
992void saveCommand(redisClient *c) {
5b8ce853 993 if (server.bgsavechildpid != -1 || server.bgsavethread != (pthread_t)-1) {
36c17a53 994 addReplyError(c,"Background save already in progress");
995 return;
996 }
997 if (rdbSave(server.dbfilename) == REDIS_OK) {
998 addReply(c,shared.ok);
999 } else {
1000 addReply(c,shared.err);
1001 }
1002}
1003
1004void bgsaveCommand(redisClient *c) {
5b8ce853 1005 if (server.bgsavechildpid != -1 || server.bgsavethread != (pthread_t)-1) {
36c17a53 1006 addReplyError(c,"Background save already in progress");
1007 return;
1008 }
1009 if (rdbSaveBackground(server.dbfilename) == REDIS_OK) {
1010 addReplyStatus(c,"Background saving started");
1011 } else {
1012 addReply(c,shared.err);
1013 }
1014}