/* 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 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* If 'p' points to a key, this function returns the total amount of * bytes used to store this entry (entry = key + associated value + trailing * free space if any). */ static unsigned int zipmapRawEntryLength(unsigned char *p) { unsigned int l = zipmapRawKeyLength(p); return l + zipmapRawValueLength(p+l); }
/* Set key to value, creating the key if it does not already exist. */ unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen) { unsigned int oldlen = 0, freeoff = 0, freelen; unsigned int reqlen = zipmapRequiredLength(klen,vlen); unsigned int empty, vempty; unsigned char *p; freelen = reqlen; p = zipmapLookupRaw(zm,key,klen,&oldlen,&freeoff,&freelen); if (p == NULL && freelen == 0) { printf("HERE oldlen:%u required:%u\n",oldlen,reqlen); /* Key not found, and not space for the new key. Enlarge */ zm = zrealloc(zm,oldlen+reqlen); p = zm+oldlen-1; zm[oldlen+reqlen-1] = ZIPMAP_END; freelen = reqlen; printf("New total length is: %u\n", oldlen+reqlen); } else if (p == NULL) { /* Key not found, but there is enough free space. */ p = zm+freeoff; /* note: freelen is already set in this case */ } else { unsigned char *b = p; /* Key found. Is there enough space for the new value? */ /* Compute the total length: */ freelen = zipmapRawKeyLength(b); b += freelen; freelen += zipmapRawValueLength(b); if (freelen < reqlen) { /* Mark this entry as free and recurse */ p[0] = ZIPMAP_EMPTY; zipmapEncodeLength(p+1,freelen); zm[0] |= ZIPMAP_STATUS_FRAGMENTED; return zipmapSet(zm,key,klen,val,vlen); } } /* Ok we have a suitable block where to write the new key/value * entry. */ empty = freelen-reqlen; /* If there is too much free space mark it as a free block instead * of adding it as trailing empty space for the value, as we want * zipmaps to be very space efficient. */ if (empty > ZIPMAP_VALUE_MAX_FREE) { unsigned char *e; e = p+reqlen; e[0] = ZIPMAP_EMPTY; zipmapEncodeLength(e+1,empty); vempty = 0; zm[0] |= ZIPMAP_STATUS_FRAGMENTED; } else { vempty = empty; } /* Just write the key + value and we are done. */ /* Key: */ p += zipmapEncodeLength(p,klen); memcpy(p,key,klen); p += klen; /* Value: */ p += zipmapEncodeLength(p,vlen); *p++ = vempty; memcpy(p,val,vlen); return zm; }
/* If 'p' points to a key, this function returns the total amount of * bytes used to store this entry (entry = key + associated value + trailing * free space if any). */ static unsigned int zipmapXRawEntryLength(unsigned char *p) { unsigned int l = zipmapRawKeyLength(p); return l + sizeof(unsigned int) + zipmapRawValueLength(p+l+sizeof(unsigned int)); }