LCOV - code coverage report
Current view: directory - redis/src - rdb.c (source / functions) Found Hit Coverage
Test: redis.info Lines: 617 508 82.3 %
Date: 2012-04-04 Functions: 38 35 92.1 %
Colors: not hit hit

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

Generated by: LCOV version 1.7