X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/b33ef40105391502d9e44443fd4e337c06396468..bdbf3acff5ffc5d114f18c1383b103fe6f45829e:/src/ziplist.c diff --git a/src/ziplist.c b/src/ziplist.c index 98ad3113..f5f9e9a6 100644 --- a/src/ziplist.c +++ b/src/ziplist.c @@ -67,9 +67,9 @@ #include #include #include "zmalloc.h" +#include "util.h" #include "ziplist.h" - -int ll2string(char *s, size_t len, long long value); +#include "endian.h" #define ZIP_END 255 #define ZIP_BIGLEN 254 @@ -119,6 +119,7 @@ static unsigned int zipEntryEncoding(unsigned char *p) { return p[0] & 0xf0; } assert(NULL); + return 0; } /* Return bytes needed to store integer encoded by 'encoding' */ @@ -129,13 +130,14 @@ static unsigned int zipIntSize(unsigned char encoding) { case ZIP_INT_64B: return sizeof(int64_t); } assert(NULL); + return 0; } /* Decode the encoded length pointed by 'p'. If a pointer to 'lensize' is * provided, it is set to the number of bytes required to encode the length. */ static unsigned int zipDecodeLength(unsigned char *p, unsigned int *lensize) { unsigned char encoding = zipEntryEncoding(p); - unsigned int len; + unsigned int len = 0; if (ZIP_IS_STR(encoding)) { switch(encoding) { @@ -205,6 +207,7 @@ static unsigned int zipPrevDecodeLength(unsigned char *p, unsigned int *lensize) } else { if (lensize) *lensize = 1+sizeof(len); memcpy(&len,p+1,sizeof(len)); + memrev32ifbe(&len); } return len; } @@ -221,6 +224,7 @@ static unsigned int zipPrevEncodeLength(unsigned char *p, unsigned int len) { } else { p[0] = ZIP_BIGLEN; memcpy(p+1,&len,sizeof(len)); + memrev32ifbe(p+1); return 1+sizeof(len); } } @@ -232,6 +236,7 @@ static void zipPrevEncodeLengthForceLarge(unsigned char *p, unsigned int len) { if (p == NULL) return; p[0] = ZIP_BIGLEN; memcpy(p+1,&len,sizeof(len)); + memrev32ifbe(p+1); } /* Return the difference in number of bytes needed to store the new length @@ -246,22 +251,9 @@ static int zipPrevLenByteDiff(unsigned char *p, unsigned int len) { * Stores the integer value in 'v' and its encoding in 'encoding'. */ static int zipTryEncoding(unsigned char *entry, unsigned int entrylen, long long *v, unsigned char *encoding) { long long value; - char *eptr; - char buf[32]; if (entrylen >= 32 || entrylen == 0) return 0; - if (entry[0] == '-' || (entry[0] >= '0' && entry[0] <= '9')) { - int slen; - - /* Perform a back-and-forth conversion to make sure that - * the string turned into an integer is not losing any info. */ - memcpy(buf,entry,entrylen); - buf[entrylen] = '\0'; - value = strtoll(buf,&eptr,10); - if (eptr[0] != '\0') return 0; - slen = ll2string(buf,32,value); - if (entrylen != (unsigned)slen || memcmp(buf,entry,slen)) return 0; - + if (string2ll((char*)entry,entrylen,&value)) { /* Great, the string can be encoded. Check what's the smallest * of our encoding types that can hold this value. */ if (value >= INT16_MIN && value <= INT16_MAX) { @@ -285,12 +277,15 @@ static void zipSaveInteger(unsigned char *p, int64_t value, unsigned char encodi if (encoding == ZIP_INT_16B) { i16 = value; memcpy(p,&i16,sizeof(i16)); + memrev16ifbe(p); } else if (encoding == ZIP_INT_32B) { i32 = value; memcpy(p,&i32,sizeof(i32)); + memrev32ifbe(p); } else if (encoding == ZIP_INT_64B) { i64 = value; memcpy(p,&i64,sizeof(i64)); + memrev64ifbe(p); } else { assert(NULL); } @@ -300,15 +295,18 @@ static void zipSaveInteger(unsigned char *p, int64_t value, unsigned char encodi static int64_t zipLoadInteger(unsigned char *p, unsigned char encoding) { int16_t i16; int32_t i32; - int64_t i64, ret; + int64_t i64, ret = 0; if (encoding == ZIP_INT_16B) { memcpy(&i16,p,sizeof(i16)); + memrev16ifbe(&i16); ret = i16; } else if (encoding == ZIP_INT_32B) { memcpy(&i32,p,sizeof(i32)); + memrev16ifbe(&i32); ret = i32; } else if (encoding == ZIP_INT_64B) { memcpy(&i64,p,sizeof(i64)); + memrev16ifbe(&i64); ret = i64; } else { assert(NULL); @@ -373,8 +371,8 @@ static unsigned char *ziplistResize(unsigned char *zl, unsigned int len) { * The pointer "p" points to the first entry that does NOT need to be * updated, i.e. consecutive fields MAY need an update. */ static unsigned char *__ziplistCascadeUpdate(unsigned char *zl, unsigned char *p) { - unsigned int curlen = ZIPLIST_BYTES(zl), rawlen, rawlensize; - unsigned int offset, noffset, extra; + size_t curlen = ZIPLIST_BYTES(zl), rawlen, rawlensize; + size_t offset, noffset, extra; unsigned char *np; zlentry cur, next; @@ -396,12 +394,17 @@ static unsigned char *__ziplistCascadeUpdate(unsigned char *zl, unsigned char *p offset = p-zl; extra = rawlensize-next.prevrawlensize; zl = ziplistResize(zl,curlen+extra); - ZIPLIST_TAIL_OFFSET(zl) += extra; p = zl+offset; - /* Move the tail to the back. */ + /* Current pointer and offset for next element. */ np = p+rawlen; noffset = np-zl; + + /* Update tail offset when next element is not the tail element. */ + if ((zl+ZIPLIST_TAIL_OFFSET(zl)) != np) + ZIPLIST_TAIL_OFFSET(zl) += extra; + + /* Move the tail to the back. */ memmove(np+rawlensize, np+next.prevrawlensize, curlen-noffset-next.prevrawlensize-1); @@ -429,7 +432,8 @@ static unsigned char *__ziplistCascadeUpdate(unsigned char *zl, unsigned char *p /* Delete "num" entries, starting at "p". Returns pointer to the ziplist. */ static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsigned int num) { unsigned int i, totlen, deleted = 0; - int offset, nextdiff = 0; + size_t offset; + int nextdiff = 0; zlentry first, tail; first = zipEntry(p); @@ -481,8 +485,9 @@ static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsig /* Insert item at "p". */ static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen) { - unsigned int curlen = ZIPLIST_BYTES(zl), reqlen, prevlen = 0; - unsigned int offset, nextdiff = 0; + size_t curlen = ZIPLIST_BYTES(zl), reqlen, prevlen = 0; + size_t offset; + int nextdiff = 0; unsigned char encoding = 0; long long value; zlentry entry, tail; @@ -595,7 +600,12 @@ unsigned char *ziplistIndex(unsigned char *zl, int index) { return (p[0] == ZIP_END || index > 0) ? NULL : p; } -/* Return pointer to next entry in ziplist. */ +/* Return pointer to next entry in ziplist. + * + * zl is the pointer to the ziplist + * p is the pointer to the current element + * + * The element after 'p' is returned, otherwise NULL if we are at the end. */ unsigned char *ziplistNext(unsigned char *zl, unsigned char *p) { ((void) zl); @@ -661,7 +671,7 @@ unsigned char *ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char * Also update *p in place, to be able to iterate over the * ziplist, while deleting entries. */ unsigned char *ziplistDelete(unsigned char *zl, unsigned char **p) { - unsigned int offset = *p-zl; + size_t offset = *p-zl; zl = __ziplistDelete(zl,*p,1); /* Store pointer to current element in p, because ziplistDelete will @@ -723,8 +733,8 @@ unsigned int ziplistLen(unsigned char *zl) { return len; } -/* Return size in bytes of ziplist. */ -unsigned int ziplistSize(unsigned char *zl) { +/* Return ziplist blob size in bytes. */ +size_t ziplistBlobLen(unsigned char *zl) { return ZIPLIST_BYTES(zl); } @@ -754,9 +764,9 @@ void ziplistRepr(unsigned char *zl) { "pls: %2u, " "payload %5u" "} ", - (long unsigned int)p, + (long unsigned)p, index, - p-zl, + (unsigned long) (p-zl), entry.headersize+entry.len, entry.headersize, entry.prevrawlen, @@ -765,10 +775,11 @@ void ziplistRepr(unsigned char *zl) { p += entry.headersize; if (ZIP_IS_STR(entry.encoding)) { if (entry.len > 40) { - fwrite(p,40,1,stdout); + if (fwrite(p,40,1,stdout) == 0) perror("fwrite"); printf("..."); } else { - fwrite(p,entry.len,1,stdout); + if (entry.len && + fwrite(p,entry.len,1,stdout) == 0) perror("fwrite"); } } else { printf("%lld", (long long) zipLoadInteger(p,entry.encoding)); @@ -857,7 +868,7 @@ void pop(unsigned char *zl, int where) { printf("Pop tail: "); if (vstr) - fwrite(vstr,vlen,1,stdout); + if (vlen && fwrite(vstr,vlen,1,stdout) == 0) perror("fwrite"); else printf("%lld", vlong); @@ -869,7 +880,7 @@ void pop(unsigned char *zl, int where) { } } -void randstring(char *target, unsigned int min, unsigned int max) { +int randstring(char *target, unsigned int min, unsigned int max) { int p, len = min+rand()%(max-min+1); int minval, maxval; switch(rand() % 3) { @@ -891,10 +902,9 @@ void randstring(char *target, unsigned int min, unsigned int max) { while(p < len) target[p++] = minval+rand()%(maxval-minval+1); - return; + return len; } - int main(int argc, char **argv) { unsigned char *zl, *p; unsigned char *entry; @@ -932,7 +942,7 @@ int main(int argc, char **argv) { return 1; } if (entry) { - fwrite(entry,elen,1,stdout); + if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); printf("\n"); } else { printf("%lld\n", value); @@ -962,7 +972,7 @@ int main(int argc, char **argv) { return 1; } if (entry) { - fwrite(entry,elen,1,stdout); + if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); printf("\n"); } else { printf("%lld\n", value); @@ -979,7 +989,7 @@ int main(int argc, char **argv) { return 1; } if (entry) { - fwrite(entry,elen,1,stdout); + if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); printf("\n"); } else { printf("%lld\n", value); @@ -1007,7 +1017,7 @@ int main(int argc, char **argv) { while (ziplistGet(p, &entry, &elen, &value)) { printf("Entry: "); if (entry) { - fwrite(entry,elen,1,stdout); + if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld", value); } @@ -1024,7 +1034,7 @@ int main(int argc, char **argv) { while (ziplistGet(p, &entry, &elen, &value)) { printf("Entry: "); if (entry) { - fwrite(entry,elen,1,stdout); + if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld", value); } @@ -1041,7 +1051,7 @@ int main(int argc, char **argv) { while (ziplistGet(p, &entry, &elen, &value)) { printf("Entry: "); if (entry) { - fwrite(entry,elen,1,stdout); + if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld", value); } @@ -1070,7 +1080,7 @@ int main(int argc, char **argv) { while (ziplistGet(p, &entry, &elen, &value)) { printf("Entry: "); if (entry) { - fwrite(entry,elen,1,stdout); + if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld", value); } @@ -1087,7 +1097,7 @@ int main(int argc, char **argv) { while (ziplistGet(p, &entry, &elen, &value)) { printf("Entry: "); if (entry) { - fwrite(entry,elen,1,stdout); + if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld", value); } @@ -1144,7 +1154,8 @@ int main(int argc, char **argv) { } else { printf("Entry: "); if (entry) { - fwrite(entry,elen,1,stdout); + if (elen && fwrite(entry,elen,1,stdout) == 0) + perror("fwrite"); } else { printf("%lld",value); } @@ -1226,6 +1237,7 @@ int main(int argc, char **argv) { int i,j,len,where; unsigned char *p; char buf[1024]; + int buflen; list *ref; listNode *refnode; @@ -1234,10 +1246,6 @@ int main(int argc, char **argv) { unsigned int slen; long long sval; - /* In the regression for the cascade bug, it was triggered - * with a random seed of 2. */ - srand(2); - for (i = 0; i < 20000; i++) { zl = ziplistNew(); ref = listCreate(); @@ -1247,31 +1255,32 @@ int main(int argc, char **argv) { /* Create lists */ for (j = 0; j < len; j++) { where = (rand() & 1) ? ZIPLIST_HEAD : ZIPLIST_TAIL; - switch(rand() % 4) { - case 0: - sprintf(buf,"%lld",(0LL + rand()) >> 20); - break; - case 1: - sprintf(buf,"%lld",(0LL + rand())); - break; - case 2: - sprintf(buf,"%lld",(0LL + rand()) << 20); - break; - case 3: - randstring(buf,0,256); - break; - default: - assert(NULL); + if (rand() % 2) { + buflen = randstring(buf,1,sizeof(buf)-1); + } else { + switch(rand() % 3) { + case 0: + buflen = sprintf(buf,"%lld",(0LL + rand()) >> 20); + break; + case 1: + buflen = sprintf(buf,"%lld",(0LL + rand())); + break; + case 2: + buflen = sprintf(buf,"%lld",(0LL + rand()) << 20); + break; + default: + assert(NULL); + } } /* Add to ziplist */ - zl = ziplistPush(zl, (unsigned char*)buf, strlen(buf), where); + zl = ziplistPush(zl, (unsigned char*)buf, buflen, where); /* Add to reference list */ if (where == ZIPLIST_HEAD) { - listAddNodeHead(ref,sdsnew(buf)); + listAddNodeHead(ref,sdsnewlen(buf, buflen)); } else if (where == ZIPLIST_TAIL) { - listAddNodeTail(ref,sdsnew(buf)); + listAddNodeTail(ref,sdsnewlen(buf, buflen)); } else { assert(NULL); } @@ -1286,12 +1295,13 @@ int main(int argc, char **argv) { assert(ziplistGet(p,&sstr,&slen,&sval)); if (sstr == NULL) { - sprintf(buf,"%lld",sval); + buflen = sprintf(buf,"%lld",sval); } else { - memcpy(buf,sstr,slen); - buf[slen] = '\0'; + buflen = slen; + memcpy(buf,sstr,buflen); + buf[buflen] = '\0'; } - assert(strcmp(buf,listNodeValue(refnode)) == 0); + assert(memcmp(buf,listNodeValue(refnode),buflen) == 0); } zfree(zl); listRelease(ref);