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 30 #include "redis.h" 31 #include "lzf.h" /* LZF compression library */ 32 #include "zipmap.h" 33 #include "endianconv.h" 34 35 #include <math.h> 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> 41 #include <sys/stat.h> 42 43 static int rdbWriteRaw(rio *rdb, void *p, size_t len) { 44 if (rdb && rioWrite(rdb,p,len) == 0) 45 return -1; 46 return len; 47 } 48 49 int rdbSaveType(rio *rdb, unsigned char type) { 50 return rdbWriteRaw(rdb,&type,1); 51 } 52 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. */ 56 int rdbLoadType(rio *rdb) { 57 unsigned char type; 58 if (rioRead(rdb,&type,1) == 0) return -1; 59 return type; 60 } 61 62 time_t rdbLoadTime(rio *rdb) { 63 int32_t t32; 64 if (rioRead(rdb,&t32,4) == 0) return -1; 65 return (time_t)t32; 66 } 67 68 int rdbSaveMillisecondTime(rio *rdb, long long t) { 69 int64_t t64 = (int64_t) t; 70 return rdbWriteRaw(rdb,&t64,8); 71 } 72 73 long long rdbLoadMillisecondTime(rio *rdb) { 74 int64_t t64; 75 if (rioRead(rdb,&t64,8) == 0) return -1; 76 return (long long)t64; 77 } 78 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. */ 82 int rdbSaveLen(rio *rdb, uint32_t len) { 83 unsigned char buf[2]; 84 size_t nwritten; 85 86 if (len < (1<<6)) { 87 /* Save a 6 bit len */ 88 buf[0] = (len&0xFF)|(REDIS_RDB_6BITLEN<<6); 89 if (rdbWriteRaw(rdb,buf,1) == -1) return -1; 90 nwritten = 1; 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; 95 if (rdbWriteRaw(rdb,buf,2) == -1) return -1; 96 nwritten = 2; 97 } else { 98 /* Save a 32 bit len */ 99 buf[0] = (REDIS_RDB_32BITLEN<<6); 100 if (rdbWriteRaw(rdb,buf,1) == -1) return -1; 101 len = htonl(len); 102 if (rdbWriteRaw(rdb,&len,4) == -1) return -1; 103 nwritten = 1+4; 104 } 105 return nwritten; 106 } 107 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. */ 111 uint32_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. */ 141 int rdbEncodeInteger(long long value, unsigned char *enc) { 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 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. */ 166 robj *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 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 */ 196 int 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 212 int rdbSaveLzfStringObject(rio *rdb, unsigned char *s, size_t len) { 213 size_t comprlen, outlen; 214 unsigned char byte; 215 int n, nwritten = 0; 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; 229 if ((n = rdbWriteRaw(rdb,&byte,1)) == -1) goto writeerr; 230 nwritten += n; 231 232 if ((n = rdbSaveLen(rdb,comprlen)) == -1) goto writeerr; 233 nwritten += n; 234 235 if ((n = rdbSaveLen(rdb,len)) == -1) goto writeerr; 236 nwritten += n; 237 238 if ((n = rdbWriteRaw(rdb,out,comprlen)) == -1) goto writeerr; 239 nwritten += n; 240 241 zfree(out); 242 return nwritten; 243 244 writeerr: 245 zfree(out); 246 return -1; 247 } 248 249 robj *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); 262 err: 263 zfree(c); 264 sdsfree(val); 265 return NULL; 266 } 267 268 /* Save a string object as [len][data] on disk. If the object is a string 269 * representation of an integer value we try to save it in a special form */ 270 int rdbSaveRawString(rio *rdb, unsigned char *s, size_t len) { 271 int enclen; 272 int n, nwritten = 0; 273 274 /* Try integer encoding */ 275 if (len <= 11) { 276 unsigned char buf[5]; 277 if ((enclen = rdbTryIntegerEncoding((char*)s,len,buf)) > 0) { 278 if (rdbWriteRaw(rdb,buf,enclen) == -1) return -1; 279 return enclen; 280 } 281 } 282 283 /* Try LZF compression - under 20 bytes it's unable to compress even 284 * aaaaaaaaaaaaaaaaaa so skip it */ 285 if (server.rdb_compression && len > 20) { 286 n = rdbSaveLzfStringObject(rdb,s,len); 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 */ 290 } 291 292 /* Store verbatim */ 293 if ((n = rdbSaveLen(rdb,len)) == -1) return -1; 294 nwritten += n; 295 if (len > 0) { 296 if (rdbWriteRaw(rdb,s,len) == -1) return -1; 297 nwritten += len; 298 } 299 return nwritten; 300 } 301 302 /* Save a long long value as either an encoded string or a string. */ 303 int rdbSaveLongLongAsStringObject(rio *rdb, long long value) { 304 unsigned char buf[32]; 305 int n, nwritten = 0; 306 int enclen = rdbEncodeInteger(value,buf); 307 if (enclen > 0) { 308 return rdbWriteRaw(rdb,buf,enclen); 309 } else { 310 /* Encode as string */ 311 enclen = ll2string((char*)buf,32,value); 312 redisAssert(enclen < 32); 313 if ((n = rdbSaveLen(rdb,enclen)) == -1) return -1; 314 nwritten += n; 315 if ((n = rdbWriteRaw(rdb,buf,enclen)) == -1) return -1; 316 nwritten += n; 317 } 318 return nwritten; 319 } 320 321 /* Like rdbSaveStringObjectRaw() but handle encoded objects */ 322 int rdbSaveStringObject(rio *rdb, robj *obj) { 323 /* Avoid to decode the object, then encode it again, if the 324 * object is already integer encoded. */ 325 if (obj->encoding == REDIS_ENCODING_INT) { 326 return rdbSaveLongLongAsStringObject(rdb,(long)obj->ptr); 327 } else { 328 redisAssertWithInfo(NULL,obj,sdsEncodedObject(obj)); 329 return rdbSaveRawString(rdb,obj->ptr,sdslen(obj->ptr)); 330 } 331 } 332 333 robj *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 361 robj *rdbLoadStringObject(rio *rdb) { 362 return rdbGenericLoadStringObject(rdb,0); 363 } 364 365 robj *rdbLoadEncodedStringObject(rio *rdb) { 366 return rdbGenericLoadStringObject(rdb,1); 367 } 368 369 /* Save a double value. Doubles are saved as strings prefixed by an unsigned 370 * 8 bit integer specifying 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 */ 377 int rdbSaveDoubleValue(rio *rdb, double val) { 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 } 408 return rdbWriteRaw(rdb,buf,len); 409 } 410 411 /* For information about double serialization check rdbSaveDoubleValue() */ 412 int 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". */ 430 int 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: 456 if (o->encoding == REDIS_ENCODING_ZIPLIST) 457 return rdbSaveType(rdb,REDIS_RDB_TYPE_HASH_ZIPLIST); 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 468 /* Use rdbLoadType() to load a TYPE in RDB format, but returns -1 if the 469 * type is not specifically a valid Object Type. */ 470 int rdbLoadObjectType(rio *rdb) { 471 int type; 472 if ((type = rdbLoadType(rdb)) == -1) return -1; 473 if (!rdbIsObjectType(type)) return -1; 474 return type; 475 } 476 477 /* Save a Redis object. Returns -1 on error, 0 on success. */ 478 int rdbSaveObject(rio *rdb, robj *o) { 479 int n, nwritten = 0; 480 481 if (o->type == REDIS_STRING) { 482 /* Save a string value */ 483 if ((n = rdbSaveStringObject(rdb,o)) == -1) return -1; 484 nwritten += n; 485 } else if (o->type == REDIS_LIST) { 486 /* Save a list value */ 487 if (o->encoding == REDIS_ENCODING_ZIPLIST) { 488 size_t l = ziplistBlobLen((unsigned char*)o->ptr); 489 490 if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1; 491 nwritten += n; 492 } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) { 493 list *list = o->ptr; 494 listIter li; 495 listNode *ln; 496 497 if ((n = rdbSaveLen(rdb,listLength(list))) == -1) return -1; 498 nwritten += n; 499 500 listRewind(list,&li); 501 while((ln = listNext(&li))) { 502 robj *eleobj = listNodeValue(ln); 503 if ((n = rdbSaveStringObject(rdb,eleobj)) == -1) return -1; 504 nwritten += n; 505 } 506 } else { 507 redisPanic("Unknown list encoding"); 508 } 509 } else if (o->type == REDIS_SET) { 510 /* Save a set value */ 511 if (o->encoding == REDIS_ENCODING_HT) { 512 dict *set = o->ptr; 513 dictIterator *di = dictGetIterator(set); 514 dictEntry *de; 515 516 if ((n = rdbSaveLen(rdb,dictSize(set))) == -1) return -1; 517 nwritten += n; 518 519 while((de = dictNext(di)) != NULL) { 520 robj *eleobj = dictGetKey(de); 521 if ((n = rdbSaveStringObject(rdb,eleobj)) == -1) return -1; 522 nwritten += n; 523 } 524 dictReleaseIterator(di); 525 } else if (o->encoding == REDIS_ENCODING_INTSET) { 526 size_t l = intsetBlobLen((intset*)o->ptr); 527 528 if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1; 529 nwritten += n; 530 } else { 531 redisPanic("Unknown set encoding"); 532 } 533 } else if (o->type == REDIS_ZSET) { 534 /* Save a sorted set value */ 535 if (o->encoding == REDIS_ENCODING_ZIPLIST) { 536 size_t l = ziplistBlobLen((unsigned char*)o->ptr); 537 538 if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1; 539 nwritten += n; 540 } else if (o->encoding == REDIS_ENCODING_SKIPLIST) { 541 zset *zs = o->ptr; 542 dictIterator *di = dictGetIterator(zs->dict); 543 dictEntry *de; 544 545 if ((n = rdbSaveLen(rdb,dictSize(zs->dict))) == -1) return -1; 546 nwritten += n; 547 548 while((de = dictNext(di)) != NULL) { 549 robj *eleobj = dictGetKey(de); 550 double *score = dictGetVal(de); 551 552 if ((n = rdbSaveStringObject(rdb,eleobj)) == -1) return -1; 553 nwritten += n; 554 if ((n = rdbSaveDoubleValue(rdb,*score)) == -1) return -1; 555 nwritten += n; 556 } 557 dictReleaseIterator(di); 558 } else { 559 redisPanic("Unknown sorted set encoding"); 560 } 561 } else if (o->type == REDIS_HASH) { 562 /* Save a hash value */ 563 if (o->encoding == REDIS_ENCODING_ZIPLIST) { 564 size_t l = ziplistBlobLen((unsigned char*)o->ptr); 565 566 if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1; 567 nwritten += n; 568 569 } else if (o->encoding == REDIS_ENCODING_HT) { 570 dictIterator *di = dictGetIterator(o->ptr); 571 dictEntry *de; 572 573 if ((n = rdbSaveLen(rdb,dictSize((dict*)o->ptr))) == -1) return -1; 574 nwritten += n; 575 576 while((de = dictNext(di)) != NULL) { 577 robj *key = dictGetKey(de); 578 robj *val = dictGetVal(de); 579 580 if ((n = rdbSaveStringObject(rdb,key)) == -1) return -1; 581 nwritten += n; 582 if ((n = rdbSaveStringObject(rdb,val)) == -1) return -1; 583 nwritten += n; 584 } 585 dictReleaseIterator(di); 586 587 } else { 588 redisPanic("Unknown hash encoding"); 589 } 590 591 } else { 592 redisPanic("Unknown object type"); 593 } 594 return nwritten; 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. */ 601 off_t rdbSavedObjectLen(robj *o) { 602 int len = rdbSaveObject(NULL,o); 603 redisAssertWithInfo(NULL,o,len != -1); 604 return len; 605 } 606 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 actually saved 1 is returned, otherwise 0 610 * is returned (the key was already expired). */ 611 int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val, 612 long long expiretime, long long now) 613 { 614 /* Save the expire time */ 615 if (expiretime != -1) { 616 /* If this key is already expired skip it */ 617 if (expiretime < now) return 0; 618 if (rdbSaveType(rdb,REDIS_RDB_OPCODE_EXPIRETIME_MS) == -1) return -1; 619 if (rdbSaveMillisecondTime(rdb,expiretime) == -1) return -1; 620 } 621 622 /* Save type, key, value */ 623 if (rdbSaveObjectType(rdb,val) == -1) return -1; 624 if (rdbSaveStringObject(rdb,key) == -1) return -1; 625 if (rdbSaveObject(rdb,val) == -1) return -1; 626 return 1; 627 } 628 629 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */ 630 int rdbSave(char *filename) { 631 dictIterator *di = NULL; 632 dictEntry *de; 633 char tmpfile[256]; 634 char magic[10]; 635 int j; 636 long long now = mstime(); 637 FILE *fp; 638 rio rdb; 639 uint64_t cksum; 640 641 snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid()); 642 fp = fopen(tmpfile,"w"); 643 if (!fp) { 644 redisLog(REDIS_WARNING, "Failed opening .rdb for saving: %s", 645 strerror(errno)); 646 return REDIS_ERR; 647 } 648 649 rioInitWithFile(&rdb,fp); 650 if (server.rdb_checksum) 651 rdb.update_cksum = rioGenericUpdateChecksum; 652 snprintf(magic,sizeof(magic),"REDIS%04d",REDIS_RDB_VERSION); 653 if (rdbWriteRaw(&rdb,magic,9) == -1) goto werr; 654 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; 659 di = dictGetSafeIterator(d); 660 if (!di) { 661 fclose(fp); 662 return REDIS_ERR; 663 } 664 665 /* Write the SELECT DB opcode */ 666 if (rdbSaveType(&rdb,REDIS_RDB_OPCODE_SELECTDB) == -1) goto werr; 667 if (rdbSaveLen(&rdb,j) == -1) goto werr; 668 669 /* Iterate this DB writing every entry */ 670 while((de = dictNext(di)) != NULL) { 671 sds keystr = dictGetKey(de); 672 robj key, *o = dictGetVal(de); 673 long long expire; 674 675 initStaticStringObject(key,keystr); 676 expire = getExpire(db,&key); 677 if (rdbSaveKeyValuePair(&rdb,&key,o,expire,now) == -1) goto werr; 678 } 679 dictReleaseIterator(di); 680 } 681 di = NULL; /* So that we don't release it again on error. */ 682 683 /* EOF opcode */ 684 if (rdbSaveType(&rdb,REDIS_RDB_OPCODE_EOF) == -1) goto werr; 685 686 /* CRC64 checksum. It will be zero if checksum computation is disabled, the 687 * loading code skips the check in this case. */ 688 cksum = rdb.cksum; 689 memrev64ifbe(&cksum); 690 rioWrite(&rdb,&cksum,8); 691 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); 707 server.lastbgsave_status = REDIS_OK; 708 return REDIS_OK; 709 710 werr: 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 718 int rdbSaveBackground(char *filename) { 719 pid_t childpid; 720 long long start; 721 722 if (server.rdb_child_pid != -1) return REDIS_ERR; 723 724 server.dirty_before_bgsave = server.dirty; 725 server.lastbgsave_try = time(NULL); 726 727 start = ustime(); 728 if ((childpid = fork()) == 0) { 729 int retval; 730 731 /* Child */ 732 closeListeningSockets(0); 733 redisSetProcTitle("redis-rdb-bgsave"); 734 retval = rdbSave(filename); 735 if (retval == REDIS_OK) { 736 size_t private_dirty = zmalloc_get_private_dirty(); 737 738 if (private_dirty) { 739 redisLog(REDIS_NOTICE, 740 "RDB: %zu MB of memory used by copy-on-write", 741 private_dirty/(1024*1024)); 742 } 743 } 744 exitFromChild((retval == REDIS_OK) ? 0 : 1); 745 } else { 746 /* Parent */ 747 server.stat_fork_time = ustime()-start; 748 if (childpid == -1) { 749 server.lastbgsave_status = REDIS_ERR; 750 redisLog(REDIS_WARNING,"Can't save in background: fork: %s", 751 strerror(errno)); 752 return REDIS_ERR; 753 } 754 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid); 755 server.rdb_save_time_start = time(NULL); 756 server.rdb_child_pid = childpid; 757 updateDictResizePolicy(); 758 return REDIS_OK; 759 } 760 return REDIS_OK; /* unreached */ 761 } 762 763 void rdbRemoveTempFile(pid_t childpid) { 764 char tmpfile[256]; 765 766 snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid); 767 unlink(tmpfile); 768 } 769 770 /* Load a Redis object of the specified type from the specified file. 771 * On success a newly allocated object is returned, otherwise NULL. */ 772 robj *rdbLoadObject(int rdbtype, rio *rdb) { 773 robj *o, *ele, *dec; 774 size_t len; 775 unsigned int i; 776 777 if (rdbtype == REDIS_RDB_TYPE_STRING) { 778 /* Read string value */ 779 if ((o = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL; 780 o = tryObjectEncoding(o); 781 } else if (rdbtype == REDIS_RDB_TYPE_LIST) { 782 /* Read list value */ 783 if ((len = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL; 784 785 /* Use a real list when there are too many entries */ 786 if (len > server.list_max_ziplist_entries) { 787 o = createListObject(); 788 } else { 789 o = createZiplistObject(); 790 } 791 792 /* Load every single element of the list */ 793 while(len--) { 794 if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL; 795 796 /* If we are using a ziplist and the value is too big, convert 797 * the object to a real list. */ 798 if (o->encoding == REDIS_ENCODING_ZIPLIST && 799 sdsEncodedObject(ele) && 800 sdslen(ele->ptr) > server.list_max_ziplist_value) 801 listTypeConvert(o,REDIS_ENCODING_LINKEDLIST); 802 803 if (o->encoding == REDIS_ENCODING_ZIPLIST) { 804 dec = getDecodedObject(ele); 805 o->ptr = ziplistPush(o->ptr,dec->ptr,sdslen(dec->ptr),REDIS_TAIL); 806 decrRefCount(dec); 807 decrRefCount(ele); 808 } else { 809 ele = tryObjectEncoding(ele); 810 listAddNodeTail(o->ptr,ele); 811 } 812 } 813 } else if (rdbtype == REDIS_RDB_TYPE_SET) { 814 /* Read list/set value */ 815 if ((len = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL; 816 817 /* Use a regular set when there are too many entries. */ 818 if (len > server.set_max_intset_entries) { 819 o = createSetObject(); 820 /* It's faster to expand the dict to the right size asap in order 821 * to avoid rehashing */ 822 if (len > DICT_HT_INITIAL_SIZE) 823 dictExpand(o->ptr,len); 824 } else { 825 o = createIntsetObject(); 826 } 827 828 /* Load every single element of the list/set */ 829 for (i = 0; i < len; i++) { 830 long long llval; 831 if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL; 832 ele = tryObjectEncoding(ele); 833 834 if (o->encoding == REDIS_ENCODING_INTSET) { 835 /* Fetch integer value from element */ 836 if (isObjectRepresentableAsLongLong(ele,&llval) == REDIS_OK) { 837 o->ptr = intsetAdd(o->ptr,llval,NULL); 838 } else { 839 setTypeConvert(o,REDIS_ENCODING_HT); 840 dictExpand(o->ptr,len); 841 } 842 } 843 844 /* This will also be called when the set was just converted 845 * to a regular hash table encoded set */ 846 if (o->encoding == REDIS_ENCODING_HT) { 847 dictAdd((dict*)o->ptr,ele,NULL); 848 } else { 849 decrRefCount(ele); 850 } 851 } 852 } else if (rdbtype == REDIS_RDB_TYPE_ZSET) { 853 /* Read list/set value */ 854 size_t zsetlen; 855 size_t maxelelen = 0; 856 zset *zs; 857 858 if ((zsetlen = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL; 859 o = createZsetObject(); 860 zs = o->ptr; 861 862 /* Load every single element of the list/set */ 863 while(zsetlen--) { 864 robj *ele; 865 double score; 866 zskiplistNode *znode; 867 868 if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL; 869 ele = tryObjectEncoding(ele); 870 if (rdbLoadDoubleValue(rdb,&score) == -1) return NULL; 871 872 /* Don't care about integer-encoded strings. */ 873 if (sdsEncodedObject(ele) && sdslen(ele->ptr) > maxelelen) 874 maxelelen = sdslen(ele->ptr); 875 876 znode = zslInsert(zs->zsl,score,ele); 877 dictAdd(zs->dict,ele,&znode->score); 878 incrRefCount(ele); /* added to skiplist */ 879 } 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); 885 } else if (rdbtype == REDIS_RDB_TYPE_HASH) { 886 size_t len; 887 int ret; 888 889 len = rdbLoadLen(rdb, NULL); 890 if (len == REDIS_RDB_LENERR) return NULL; 891 892 o = createHashObject(); 893 894 /* Too many entries? Use a hash table. */ 895 if (len > server.hash_max_ziplist_entries) 896 hashTypeConvert(o, REDIS_ENCODING_HT); 897 898 /* Load every field and value into the ziplist */ 899 while (o->encoding == REDIS_ENCODING_ZIPLIST && len > 0) { 900 robj *field, *value; 901 902 len--; 903 /* Load raw strings */ 904 field = rdbLoadStringObject(rdb); 905 if (field == NULL) return NULL; 906 redisAssert(sdsEncodedObject(field)); 907 value = rdbLoadStringObject(rdb); 908 if (value == NULL) return NULL; 909 redisAssert(sdsEncodedObject(value)); 910 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); 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) 917 { 918 decrRefCount(field); 919 decrRefCount(value); 920 hashTypeConvert(o, REDIS_ENCODING_HT); 921 break; 922 } 923 decrRefCount(field); 924 decrRefCount(value); 925 } 926 927 /* Load remaining fields and values into the hash table */ 928 while (o->encoding == REDIS_ENCODING_HT && len > 0) { 929 robj *field, *value; 930 931 len--; 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 949 } else if (rdbtype == REDIS_RDB_TYPE_HASH_ZIPMAP || 950 rdbtype == REDIS_RDB_TYPE_LIST_ZIPLIST || 951 rdbtype == REDIS_RDB_TYPE_SET_INTSET || 952 rdbtype == REDIS_RDB_TYPE_ZSET_ZIPLIST || 953 rdbtype == REDIS_RDB_TYPE_HASH_ZIPLIST) 954 { 955 robj *aux = rdbLoadStringObject(rdb); 956 957 if (aux == NULL) return NULL; 958 o = createObject(REDIS_STRING,NULL); /* string is just placeholder */ 959 o->ptr = zmalloc(sdslen(aux->ptr)); 960 memcpy(o->ptr,aux->ptr,sdslen(aux->ptr)); 961 decrRefCount(aux); 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. */ 969 switch(rdbtype) { 970 case REDIS_RDB_TYPE_HASH_ZIPMAP: 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); 976 unsigned char *fstr, *vstr; 977 unsigned int flen, vlen; 978 unsigned int maxlen = 0; 979 980 while ((zi = zipmapNext(zi, &fstr, &flen, &vstr, &vlen)) != NULL) { 981 if (flen > maxlen) maxlen = flen; 982 if (vlen > maxlen) maxlen = vlen; 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 992 if (hashTypeLength(o) > server.hash_max_ziplist_entries || 993 maxlen > server.hash_max_ziplist_value) 994 { 995 hashTypeConvert(o, REDIS_ENCODING_HT); 996 } 997 } 998 break; 999 case REDIS_RDB_TYPE_LIST_ZIPLIST: 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; 1005 case REDIS_RDB_TYPE_SET_INTSET: 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; 1011 case REDIS_RDB_TYPE_ZSET_ZIPLIST: 1012 o->type = REDIS_ZSET; 1013 o->encoding = REDIS_ENCODING_ZIPLIST; 1014 if (zsetLength(o) > server.zset_max_ziplist_entries) 1015 zsetConvert(o,REDIS_ENCODING_SKIPLIST); 1016 break; 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; 1023 default: 1024 redisPanic("Unknown encoding"); 1025 break; 1026 } 1027 } else { 1028 redisPanic("Unknown object type"); 1029 } 1030 return o; 1031 } 1032 1033 /* Mark that we are loading in the global state and setup the fields 1034 * needed to provide loading stats. */ 1035 void 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 */ 1049 void loadingProgress(off_t pos) { 1050 server.loading_loaded_bytes = pos; 1051 if (server.stat_peak_memory < zmalloc_used_memory()) 1052 server.stat_peak_memory = zmalloc_used_memory(); 1053 } 1054 1055 /* Loading finished */ 1056 void stopLoading(void) { 1057 server.loading = 0; 1058 } 1059 1060 /* Track loading progress in order to serve client's from time to time 1061 and if needed calculate rdb checksum */ 1062 void rdbLoadProgressCallback(rio *r, const void *buf, size_t len) { 1063 if (server.rdb_checksum) 1064 rioGenericUpdateChecksum(r, buf, len); 1065 if (server.loading_process_events_interval_bytes && 1066 (r->processed_bytes + len)/server.loading_process_events_interval_bytes > r->processed_bytes/server.loading_process_events_interval_bytes) 1067 { 1068 /* The DB can take some non trivial amount of time to load. Update 1069 * our cached time since it is used to create and update the last 1070 * interaction time with clients and for other important things. */ 1071 updateCachedTime(); 1072 if (server.masterhost && server.repl_state == REDIS_REPL_TRANSFER) 1073 replicationSendNewlineToMaster(); 1074 loadingProgress(r->processed_bytes); 1075 aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT); 1076 } 1077 } 1078 1079 int rdbLoad(char *filename) { 1080 uint32_t dbid; 1081 int type, rdbver; 1082 redisDb *db = server.db+0; 1083 char buf[1024]; 1084 long long expiretime, now = mstime(); 1085 FILE *fp; 1086 rio rdb; 1087 1088 if ((fp = fopen(filename,"r")) == NULL) return REDIS_ERR; 1089 1090 rioInitWithFile(&rdb,fp); 1091 rdb.update_cksum = rdbLoadProgressCallback; 1092 rdb.max_processing_chunk = server.loading_process_events_interval_bytes; 1093 if (rioRead(&rdb,buf,9) == 0) goto eoferr; 1094 buf[9] = '\0'; 1095 if (memcmp(buf,"REDIS",5) != 0) { 1096 fclose(fp); 1097 redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file"); 1098 errno = EINVAL; 1099 return REDIS_ERR; 1100 } 1101 rdbver = atoi(buf+5); 1102 if (rdbver < 1 || rdbver > REDIS_RDB_VERSION) { 1103 fclose(fp); 1104 redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver); 1105 errno = EINVAL; 1106 return REDIS_ERR; 1107 } 1108 1109 startLoading(fp); 1110 while(1) { 1111 robj *key, *val; 1112 expiretime = -1; 1113 1114 /* Read type. */ 1115 if ((type = rdbLoadType(&rdb)) == -1) goto eoferr; 1116 if (type == REDIS_RDB_OPCODE_EXPIRETIME) { 1117 if ((expiretime = rdbLoadTime(&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; 1120 /* the EXPIRETIME opcode specifies time in seconds, so convert 1121 * into milliseconds. */ 1122 expiretime *= 1000; 1123 } else if (type == REDIS_RDB_OPCODE_EXPIRETIME_MS) { 1124 /* Milliseconds precision expire times introduced with RDB 1125 * version 3. */ 1126 if ((expiretime = rdbLoadMillisecondTime(&rdb)) == -1) goto eoferr; 1127 /* We read the time so we need to read the object type again. */ 1128 if ((type = rdbLoadType(&rdb)) == -1) goto eoferr; 1129 } 1130 1131 if (type == REDIS_RDB_OPCODE_EOF) 1132 break; 1133 1134 /* Handle SELECT DB opcode as a special case */ 1135 if (type == REDIS_RDB_OPCODE_SELECTDB) { 1136 if ((dbid = rdbLoadLen(&rdb,NULL)) == REDIS_RDB_LENERR) 1137 goto eoferr; 1138 if (dbid >= (unsigned)server.dbnum) { 1139 redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum); 1140 exit(1); 1141 } 1142 db = server.db+dbid; 1143 continue; 1144 } 1145 /* Read key */ 1146 if ((key = rdbLoadStringObject(&rdb)) == NULL) goto eoferr; 1147 /* Read value */ 1148 if ((val = rdbLoadObject(type,&rdb)) == NULL) goto eoferr; 1149 /* Check if the key already expired. This function is used when loading 1150 * an RDB file from disk, either at startup, or when an RDB was 1151 * received from the master. In the latter case, the master is 1152 * responsible for key expiry. If we would expire keys here, the 1153 * snapshot taken by the master may not be reflected on the slave. */ 1154 if (server.masterhost == NULL && expiretime != -1 && expiretime < now) { 1155 decrRefCount(key); 1156 decrRefCount(val); 1157 continue; 1158 } 1159 /* Add the new object in the hash table */ 1160 dbAdd(db,key,val); 1161 1162 /* Set the expire time if needed */ 1163 if (expiretime != -1) setExpire(db,key,expiretime); 1164 1165 decrRefCount(key); 1166 } 1167 /* Verify the checksum if RDB version is >= 5 */ 1168 if (rdbver >= 5 && server.rdb_checksum) { 1169 uint64_t cksum, expected = rdb.cksum; 1170 1171 if (rioRead(&rdb,&cksum,8) == 0) goto eoferr; 1172 memrev64ifbe(&cksum); 1173 if (cksum == 0) { 1174 redisLog(REDIS_WARNING,"RDB file was saved with checksum disabled: no check performed."); 1175 } else if (cksum != expected) { 1176 redisLog(REDIS_WARNING,"Wrong RDB checksum. Aborting now."); 1177 exit(1); 1178 } 1179 } 1180 1181 fclose(fp); 1182 stopLoading(); 1183 return REDIS_OK; 1184 1185 eoferr: /* unexpected end of file is handled here with a fatal exit */ 1186 redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, aborting now."); 1187 exit(1); 1188 return REDIS_ERR; /* Just to avoid warning */ 1189 } 1190 1191 /* A background saving child (BGSAVE) terminated its work. Handle this. */ 1192 void backgroundSaveDoneHandler(int exitcode, int bysignal) { 1193 if (!bysignal && exitcode == 0) { 1194 redisLog(REDIS_NOTICE, 1195 "Background saving terminated with success"); 1196 server.dirty = server.dirty - server.dirty_before_bgsave; 1197 server.lastsave = time(NULL); 1198 server.lastbgsave_status = REDIS_OK; 1199 } else if (!bysignal && exitcode != 0) { 1200 redisLog(REDIS_WARNING, "Background saving error"); 1201 server.lastbgsave_status = REDIS_ERR; 1202 } else { 1203 redisLog(REDIS_WARNING, 1204 "Background saving terminated by signal %d", bysignal); 1205 rdbRemoveTempFile(server.rdb_child_pid); 1206 /* SIGUSR1 is whitelisted, so we have a way to kill a child without 1207 * tirggering an error conditon. */ 1208 if (bysignal != SIGUSR1) 1209 server.lastbgsave_status = REDIS_ERR; 1210 } 1211 server.rdb_child_pid = -1; 1212 server.rdb_save_time_last = time(NULL)-server.rdb_save_time_start; 1213 server.rdb_save_time_start = -1; 1214 /* Possibly there are slaves waiting for a BGSAVE in order to be served 1215 * (the first stage of SYNC is a bulk transfer of dump.rdb) */ 1216 updateSlavesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR); 1217 } 1218 1219 void saveCommand(redisClient *c) { 1220 if (server.rdb_child_pid != -1) { 1221 addReplyError(c,"Background save already in progress"); 1222 return; 1223 } 1224 if (rdbSave(server.rdb_filename) == REDIS_OK) { 1225 addReply(c,shared.ok); 1226 } else { 1227 addReply(c,shared.err); 1228 } 1229 } 1230 1231 void bgsaveCommand(redisClient *c) { 1232 if (server.rdb_child_pid != -1) { 1233 addReplyError(c,"Background save already in progress"); 1234 } else if (server.aof_child_pid != -1) { 1235 addReplyError(c,"Can't BGSAVE while AOF log rewriting is in progress"); 1236 } else if (rdbSaveBackground(server.rdb_filename) == REDIS_OK) { 1237 addReplyStatus(c,"Background saving started"); 1238 } else { 1239 addReply(c,shared.err); 1240 } 1241 } 1242