|
57 | 57 | #include <sys/time.h>
|
58 | 58 | #include <sys/resource.h>
|
59 | 59 | #include <limits.h>
|
| 60 | +#include <math.h> |
60 | 61 |
|
61 | 62 | #include "redis.h"
|
62 | 63 | #include "ae.h" /* Event driven programming library */
|
@@ -338,6 +339,12 @@ struct sharedObjectsStruct {
|
338 | 339 | *select5, *select6, *select7, *select8, *select9;
|
339 | 340 | } shared;
|
340 | 341 |
|
| 342 | +/* Global vars that are actally used as constants. The following double |
| 343 | + * values are used for double on-disk serialization, and are initialized |
| 344 | + * at runtime to avoid strange compiler optimizations. */ |
| 345 | + |
| 346 | +static double R_Zero, R_PosInf, R_NegInf, R_Nan; |
| 347 | + |
341 | 348 | /*================================ Prototypes =============================== */
|
342 | 349 |
|
343 | 350 | static void freeStringObject(robj *o);
|
@@ -1021,6 +1028,12 @@ static void initServerConfig() {
|
1021 | 1028 | server.masterport = 6379;
|
1022 | 1029 | server.master = NULL;
|
1023 | 1030 | server.replstate = REDIS_REPL_NONE;
|
| 1031 | + |
| 1032 | + /* Double constants initialization */ |
| 1033 | + R_Zero = 0.0; |
| 1034 | + R_PosInf = 1.0/R_Zero; |
| 1035 | + R_NegInf = -1.0/R_Zero; |
| 1036 | + R_Nan = R_Zero/R_Zero; |
1024 | 1037 | }
|
1025 | 1038 |
|
1026 | 1039 | static void initServer() {
|
@@ -2238,6 +2251,33 @@ static int rdbSaveStringObject(FILE *fp, robj *obj) {
|
2238 | 2251 | }
|
2239 | 2252 | }
|
2240 | 2253 |
|
| 2254 | +/* Save a double value. Doubles are saved as strings prefixed by an unsigned |
| 2255 | + * 8 bit integer specifing the length of the representation. |
| 2256 | + * This 8 bit integer has special values in order to specify the following |
| 2257 | + * conditions: |
| 2258 | + * 253: not a number |
| 2259 | + * 254: + inf |
| 2260 | + * 255: - inf |
| 2261 | + */ |
| 2262 | +static int rdbSaveDoubleValue(FILE *fp, double val) { |
| 2263 | + unsigned char buf[128]; |
| 2264 | + int len; |
| 2265 | + |
| 2266 | + if (isnan(val)) { |
| 2267 | + buf[0] = 253; |
| 2268 | + len = 1; |
| 2269 | + } else if (!isfinite(val)) { |
| 2270 | + len = 1; |
| 2271 | + buf[0] = (val < 0) ? 255 : 254; |
| 2272 | + } else { |
| 2273 | + snprintf((char*)buf+1,sizeof(buf)-1,"%.16g",val); |
| 2274 | + buf[0] = strlen((char*)buf); |
| 2275 | + len = buf[0]+1; |
| 2276 | + } |
| 2277 | + if (fwrite(buf,len,1,fp) == 0) return -1; |
| 2278 | + return 0; |
| 2279 | +} |
| 2280 | + |
2241 | 2281 | /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
|
2242 | 2282 | static int rdbSave(char *filename) {
|
2243 | 2283 | dictIterator *di = NULL;
|
@@ -2500,6 +2540,23 @@ static robj *rdbLoadStringObject(FILE*fp, int rdbver) {
|
2500 | 2540 | return tryObjectSharing(createObject(REDIS_STRING,val));
|
2501 | 2541 | }
|
2502 | 2542 |
|
| 2543 | +/* For information about double serialization check rdbSaveDoubleValue() */ |
| 2544 | +static int rdbLoadDoubleValue(FILE *fp, double *val) { |
| 2545 | + char buf[128]; |
| 2546 | + unsigned char len; |
| 2547 | + |
| 2548 | + if (fread(&len,1,1,fp) == 0) return -1; |
| 2549 | + switch(len) { |
| 2550 | + case 255: *val = R_NegInf; return 0; |
| 2551 | + case 254: *val = R_PosInf; return 0; |
| 2552 | + case 253: *val = R_Nan; return 0; |
| 2553 | + default: |
| 2554 | + if (fread(buf,len,1,fp) == 0) return -1; |
| 2555 | + sscanf(buf, "%lg", val); |
| 2556 | + return 0; |
| 2557 | + } |
| 2558 | +} |
| 2559 | + |
2503 | 2560 | static int rdbLoad(char *filename) {
|
2504 | 2561 | FILE *fp;
|
2505 | 2562 | robj *keyobj = NULL;
|
|
0 commit comments