void zipmapRepr(unsigned char *p) { unsigned int l; printf("{status %u}",*p++); while(1) { if (p[0] == ZIPMAP_END) { printf("{end}"); break; } else { unsigned char e; l = zipmapDecodeLength(p); printf("{key %u}",l); p += zipmapEncodeLength(NULL,l); if (l != 0 && fwrite(p,l,1,stdout) == 0) perror("fwrite"); p += l; l = zipmapDecodeLength(p); printf("{value %u}",l); p += zipmapEncodeLength(NULL,l); e = *p++; if (l != 0 && fwrite(p,l,1,stdout) == 0) perror("fwrite"); p += l+e; if (e) { printf("["); while(e--) printf("."); printf("]"); } } } printf("\n"); }
/* Search for a matching key, returning a pointer to the entry inside the * zipmap. Returns NULL if the key is not found. * * If NULL is returned, and totlen is not NULL, it is set to the entire * size of the zimap, so that the calling function will be able to * reallocate the original zipmap to make room for more entries. */ static unsigned char *zipmapLookupRaw(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned int *totlen) { unsigned char *p = zm+1, *k = NULL; unsigned int l,llen; // 遍历zipmap while(*p != ZIPMAP_END) { unsigned char free; // 返回len表示的长度 /* Match or skip the key */ l = zipmapDecodeLength(p); // 返回要编码l表示的长度需要的字节数,1还是5字节 llen = zipmapEncodeLength(NULL,l); // 看看Key是不是相等 if (key != NULL && k == NULL && l == klen && !memcmp(p+llen,key,l)) { // 如果外部不想知道总长度的时候,直接返回 /* Only return when the user doesn't care * for the total length of the zipmap. */ if (totlen != NULL) { k = p; } else { return p; } } // p到达下一个元素的位置 p += llen+l; /* Skip the value as well */ l = zipmapDecodeLength(p); p += zipmapEncodeLength(NULL,l); free = p[0]; p += l+1+free; /* +1 to skip the free byte */ } // 返回zm的总字节长度 if (totlen != NULL) *totlen = (unsigned int)(p-zm)+1; return k; }
/* This function is used to iterate through all the zipmap elements. * * 这个函数用于遍历 zipmap 的所有元素。 * * In the first call the first argument is the pointer to the zipmap + 1. * * 在第一次调用这个函数时, zm 参数的值为 zipmap + 1 * (也即是,指向 zipmap 的第一个节点) * * In the next calls what zipmapNext returns is used as first argument. * * 而在之后的调用中, zm 参数的值为之前调用 zipmapNext 时所返回的值。 * * Example: * * 示例: * * unsigned char *i = zipmapRewind(my_zipmap); * while((i = zipmapNext(i,&key,&klen,&value,&vlen)) != NULL) { * printf("%d bytes key at $p\n", klen, key); * printf("%d bytes value at $p\n", vlen, value); * } * * T = O(1) */ unsigned char *zipmapNext(unsigned char *zm, unsigned char **key, unsigned int *klen, unsigned char **value, unsigned int *vlen) { // 已到达列表末尾,停止迭代 if (zm[0] == ZIPMAP_END) return NULL; // 取出键,并保存到 key 参数中 if (key) { *key = zm; *klen = zipmapDecodeLength(zm); *key += ZIPMAP_LEN_BYTES(*klen); } // 越过键 zm += zipmapRawKeyLength(zm); // 取出值,并保存到 value 参数中 if (value) { *value = zm+1; *vlen = zipmapDecodeLength(zm); *value += ZIPMAP_LEN_BYTES(*vlen); } // 越过值 zm += zipmapRawValueLength(zm); // 返回指向下一节点的指针 return zm; }
/* Search for a matching key, returning a pointer to the entry inside the * zipmap. Returns NULL if the key is not found. * * If NULL is returned, and totlen is not NULL, it is set to the entire * size of the zimap, so that the calling function will be able to * reallocate the original zipmap to make room for more entries. */ static unsigned char *zipmapLookupRaw(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned int *totlen) { unsigned char *p = zm+1, *k = NULL; unsigned int l,llen; while(*p != ZIPMAP_END) { unsigned char free; /* Match or skip the key */ l = zipmapDecodeLength(p); llen = zipmapEncodeLength(NULL,l); if (key != NULL && k == NULL && l == klen && !memcmp(p+llen,key,l)) { /* Only return when the user doesn't care * for the total length of the zipmap. */ if (totlen != NULL) { k = p; } else { return p; } } p += llen+l; /* Skip the value as well */ l = zipmapDecodeLength(p); p += zipmapEncodeLength(NULL,l); free = p[0]; p += l+1+free; /* +1 to skip the free byte */ } if (totlen != NULL) *totlen = (unsigned int)(p-zm)+1; return k; }
/* Search for a matching key, returning a pointer to the entry inside the * zipmap. Returns NULL if the key is not found. * * 在 zipmap 中查找和给定 key 匹配的节点: * * 1)找到的话就返回节点的指针。 * * 2)没找到则返回 NULL 。 * * If NULL is returned, and totlen is not NULL, it is set to the entire * size of the zimap, so that the calling function will be able to * reallocate the original zipmap to make room for more entries. * * 如果没有找到相应的节点(函数返回 NULL),并且 totlen 不为 NULL , * 那么 *totlen 的值将被设为整个 zipmap 的大小, * 这样调用者就可以根据 *totlen 的值,对 zipmap 进行内存重分配, * 从而让 zipmap 容纳更多节点。 * * T = O(N^2) */ static unsigned char *zipmapLookupRaw(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned int *totlen) { // zm+1 略过 <zmlen> 属性,将 p 指向 zipmap 的首个节点 unsigned char *p = zm+1, *k = NULL; unsigned int l,llen; // 遍历整个 zipmap 来寻找 // T = O(N^2) while(*p != ZIPMAP_END) { unsigned char free; /* Match or skip the key */ // 计算键的长度 l = zipmapDecodeLength(p); // 计算编码键的长度所需的字节数 llen = zipmapEncodeLength(NULL,l); // 对比 key // T = O(N) if (key != NULL && k == NULL && l == klen && !memcmp(p+llen,key,l)) { /* Only return when the user doesn't care * for the total length of the zipmap. */ if (totlen != NULL) { // 如果调用者需要知道整个 zipmap 的长度,那么记录找到的指针到变量 k // 之后遍历时,程序只计算 zipmap 剩余节点的长度,不再用 memcmp 进行对比 // 因为 k 已经不为 NULL 了 k = p; } else { // 如果调用者不需要知道整个 zipmap 的长度,那么直接返回 p return p; } } // 越过键节点,指向值节点 p += llen+l; /* Skip the value as well */ // 计算值的长度 l = zipmapDecodeLength(p); // 计算编码值的长度所需的字节数, // 并移动指针 p ,越过该 <len> 属性,指向 <free> 属性 p += zipmapEncodeLength(NULL,l); // 取出 <free> 属性的值 free = p[0]; // 略过值节点,指向下一节点 p += l+1+free; /* +1 to skip the free byte */ } // 计算并记录 zipmap 的空间长度 // + 1 是将 ZIPMAP_END 也计算在内 if (totlen != NULL) *totlen = (unsigned int)(p-zm)+1; // 返回找到 key 的指针 return k; }
/* This function is used to iterate through all the zipmap elements. * In the first call the first argument is the pointer to the zipmap + 1. * In the next calls what zipmapNext returns is used as first argument. * Example: * * unsigned char *i = zipmapRewind(my_zipmap); * while((i = zipmapNext(i,&key,&klen,&value,&vlen)) != NULL) { * printf("%d bytes key at $p\n", klen, key); * printf("%d bytes value at $p\n", vlen, value); * } */ unsigned char *zipmapNext(unsigned char *zm, unsigned char **key, unsigned int *klen, unsigned char **value, unsigned int *vlen) { if (zm[0] == ZIPMAP_END) return NULL; if (key) { *key = zm; *klen = zipmapDecodeLength(zm); *key += ZIPMAP_LEN_BYTES(*klen); } zm += zipmapRawKeyLength(zm); if (value) { *value = zm+1; *vlen = zipmapDecodeLength(zm); *value += ZIPMAP_LEN_BYTES(*vlen); } zm += zipmapRawValueLength(zm); return zm; }
/* Return the total amount used by a value * (encoded length + single byte free count + payload) */ static unsigned int zipmapRawValueLength(unsigned char *p) { unsigned int l = zipmapDecodeLength(p); unsigned int used; used = zipmapEncodeLength(NULL,l); used += p[used] + 1 + l; return used; }
/* Search a key and retrieve the pointer and len of the associated value. * If the key is found the function returns 1, otherwise 0. */ int zipmapGet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char **value, unsigned int *vlen) { unsigned char *p; if ((p = zipmapLookupRaw(zm,key,klen,NULL)) == NULL) return 0; p += zipmapRawKeyLength(p); *vlen = zipmapDecodeLength(p); *value = p + ZIPMAP_LEN_BYTES(*vlen) + 1; return 1; }
/* 获取value节点占用的字节数,即len字段 + 1个字节free字段 + value字符串长度 + 空闲空间大小 */ static unsigned int zipmapRawValueLength(unsigned char *p) { // 获取value字符串的长度 unsigned int l = zipmapDecodeLength(p); unsigned int used; // 获取保存value字符串长度所需要的字节数 used = zipmapEncodeLength(NULL,l); // p[used]里面存储着空闲空间的大小 used += p[used] + 1 + l; return used; }
/* 按关键字key查找zipmap,如果totlen不为NULL,函数返回后存放zipmap占用的字节数 */ static unsigned char *zipmapLookupRaw(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned int *totlen) { // zipmap中第1个字节是zmlen字段,zm+1跳过第1个字节 unsigned char *p = zm+1, *k = NULL; unsigned int l,llen; // 从前往后查找 while(*p != ZIPMAP_END) { unsigned char free; /* Match or skip the key */ // 确定key字符串的长度 l = zipmapDecodeLength(p); // 确定保存key字符串长度所需要的字节数,也就是len字段所需要的字节数 llen = zipmapEncodeLength(NULL,l); // 比较当前key与给定key是否匹配 if (key != NULL && k == NULL && l == klen && !memcmp(p+llen,key,l)) { /* Only return when the user doesn't care * for the total length of the zipmap. */ // 如果totlen为NULL,表示函数调用者不关心zipmap占用的字节数,此时直接返回p,否则先记录下p指针然后继续遍历 if (totlen != NULL) { k = p; } else { return p; } } // p加上llen和l,到了value节点处 p += llen+l; /* Skip the value as well */ // 确定value字符串的长度 l = zipmapDecodeLength(p); // 确定保存value字符串长度所需要的字节数,也就是len字段所需要的字节数 p += zipmapEncodeLength(NULL,l); // 读出free字段的值(前面我们讲过:free只占用一个字节) free = p[0]; // 跳到下一个key节点的 p += l+1+free; /* +1 to skip the free byte */ } // 到这里遍历完整个zipmap,得到其占用的字节数 if (totlen != NULL) *totlen = (unsigned int)(p-zm)+1; return k; }
/* zipmap的迭代器式遍历函数,典型用法如下: * * unsigned char *i = zipmapRewind(my_zipmap); * while((i = zipmapNext(i,&key,&klen,&value,&vlen)) != NULL) { * printf("%d bytes key at $p\n", klen, key); * printf("%d bytes value at $p\n", vlen, value); * } */ unsigned char *zipmapNext(unsigned char *zm, unsigned char **key, unsigned int *klen, unsigned char **value, unsigned int *vlen) { // 如果达到尾部,直接返回NULL if (zm[0] == ZIPMAP_END) return NULL; // 获取key if (key) { *key = zm; *klen = zipmapDecodeLength(zm); *key += ZIPMAP_LEN_BYTES(*klen); } zm += zipmapRawKeyLength(zm); // 获取value if (value) { // +1是为了跳过free字段,该字段占用一个字节 *value = zm+1; *vlen = zipmapDecodeLength(zm); *value += ZIPMAP_LEN_BYTES(*vlen); } // 此时zm指向下一个键值对的首地址 zm += zipmapRawValueLength(zm); return zm; }
/* Return the total amount used by a value * (encoded length + single byte free count + payload) * * 返回值所占用的字节总数 * * 包括编码长度值所需的字节数,单个字节的 <free> 属性,以及值的长度本身 * * T = O(1) */ static unsigned int zipmapRawValueLength(unsigned char *p) { // 取出值的长度 unsigned int l = zipmapDecodeLength(p); unsigned int used; // 编码长度所需的字节数 used = zipmapEncodeLength(NULL,l); // 计算总和 used += p[used] + 1 + l; return used; }
/* Search for a matching key, returning a pointer to the entry inside the * zipmap. Returns NULL if the key is not found. * * If NULL is returned, and totlen is not NULL, it is set to the entire * size of the zimap, so that the calling function will be able to * reallocate the original zipmap to make room for more entries. * * If NULL is returned, and freeoff and freelen are not NULL, they are set * to the offset of the first empty space that can hold '*freelen' bytes * (freelen is an integer pointer used both to signal the required length * and to get the reply from the function). If there is not a suitable * free space block to hold the requested bytes, *freelen is set to 0. */ static unsigned char *zipmapLookupRaw(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned int *totlen, unsigned int *freeoff, unsigned int *freelen) { unsigned char *p = zm+1; unsigned int l; unsigned int reqfreelen = 0; /* initialized just to prevent warning */ if (freelen) { reqfreelen = *freelen; *freelen = 0; assert(reqfreelen != 0); } while(*p != ZIPMAP_END) { if (*p == ZIPMAP_EMPTY) { l = zipmapDecodeLength(p+1); /* if the user want a free space report, and this space is * enough, and we did't already found a suitable space... */ if (freelen && l >= reqfreelen && *freelen == 0) { *freelen = l; *freeoff = p-zm; } p += l; zm[0] |= ZIPMAP_STATUS_FRAGMENTED; } else { unsigned char free; /* Match or skip the key */ l = zipmapDecodeLength(p); if (l == klen && !memcmp(p+1,key,l)) return p; p += zipmapEncodeLength(NULL,l) + l; /* Skip the value as well */ l = zipmapDecodeLength(p); p += zipmapEncodeLength(NULL,l); free = p[0]; p += l+1+free; /* +1 to skip the free byte */ } } if (totlen != NULL) *totlen = (unsigned int)(p-zm)+1; return NULL; }
void zipmapRepr(unsigned char *p) { unsigned int l; printf("{status %u}",*p++); while(1) { if (p[0] == ZIPMAP_END) { printf("{end}"); break; } else if (p[0] == ZIPMAP_EMPTY) { l = zipmapDecodeLength(p+1); printf("{%u empty block}", l); p += l; } else { unsigned char e; l = zipmapDecodeLength(p); printf("{key %u}",l); p += zipmapEncodeLength(NULL,l); fwrite(p,l,1,stdout); p += l; l = zipmapDecodeLength(p); printf("{value %u}",l); p += zipmapEncodeLength(NULL,l); e = *p++; fwrite(p,l,1,stdout); p += l+e; if (e) { printf("["); while(e--) printf("."); printf("]"); } } } printf("\n"); }
/* Search a key and retrieve the pointer and len of the associated value. * If the key is found the function returns 1, otherwise 0. */ int zipmapXGet(unsigned char **zm, unsigned char *key, unsigned int klen, unsigned char **value, unsigned int *vlen, unsigned int timestamp) { unsigned char *p; if ((p = zipmapXLookupRaw(*zm,key,klen,NULL,NULL)) == NULL) return 0; p += zipmapRawKeyLength(p); unsigned int ts = *(unsigned int*)p; p += sizeof(unsigned int); *vlen = zipmapDecodeLength(p); *value = p + ZIPMAP_LEN_BYTES(*vlen) + 1; if (ts < timestamp) { *vlen = 0; *value = NULL; return 0; } return 1; }
/* Search a key and retrieve the pointer and len of the associated value. * If the key is found the function returns 1, otherwise 0. * * 在 zipmap 中按 key 进行查找, * 将值的指针保存到 *value 中,并将值的长度保存到 *vlen 中。 * * 成功找到值时函数返回 1 ,没找到则返回 0 。 * * T = O(N^2) */ int zipmapGet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char **value, unsigned int *vlen) { unsigned char *p; // 在 zipmap 中按 key 查找 // 没找到直接返回 0 // T = O(N^2) if ((p = zipmapLookupRaw(zm,key,klen,NULL)) == NULL) return 0; // 越过键,指向值 p += zipmapRawKeyLength(p); // 取出值的长度 *vlen = zipmapDecodeLength(p); // 将 *value 指向值, +1 为越过 <free> 属性 *value = p + ZIPMAP_LEN_BYTES(*vlen) + 1; // 找到,返回 1 return 1; }
/* 获取key节点占用的字节数,即len字段 + key字符串长度 */ static unsigned int zipmapRawKeyLength(unsigned char *p) { // 获取key字符串的长度 unsigned int l = zipmapDecodeLength(p); // 加上保存key字符串长度所需要的字节数 return zipmapEncodeLength(NULL,l) + l; }
/* Return the total amount used by a key (encoded length + payload) */ static unsigned int zipmapRawKeyLength(unsigned char *p) { unsigned int l = zipmapDecodeLength(p); return zipmapEncodeLength(NULL,l) + l; }