/* Set key to value, creating the key if it does not already exist. * If 'update' is not NULL, *update is set to 1 if the key was * already preset, otherwise to 0. */ unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update) { unsigned int zmlen, offset; unsigned int freelen, reqlen = zipmapRequiredLength(klen,vlen); unsigned int empty, vempty; unsigned char *p; freelen = reqlen; if (update) *update = 0; p = zipmapLookupRaw(zm,key,klen,&zmlen); if (p == NULL) { /* Key not found: enlarge */ zm = zipmapResize(zm, zmlen+reqlen); p = zm+zmlen-1; zmlen = zmlen+reqlen; /* Increase zipmap length (this is an insert) */ if (zm[0] < ZIPMAP_BIGLEN) zm[0]++; } else { /* Key found. Is there enough space for the new value? */ /* Compute the total length: */ if (update) *update = 1; freelen = zipmapRawEntryLength(p); if (freelen < reqlen) { /* Store the offset of this key within the current zipmap, so * it can be resized. Then, move the tail backwards so this * pair fits at the current position. */ offset = p-zm; zm = zipmapResize(zm, zmlen-freelen+reqlen); p = zm+offset; /* The +1 in the number of bytes to be moved is caused by the * end-of-zipmap byte. Note: the *original* zmlen is used. */ memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1)); zmlen = zmlen-freelen+reqlen; freelen = reqlen; } } /* We now have a suitable block where the key/value entry can * be written. If there is too much free space, move the tail * of the zipmap a few bytes to the front and shrink the zipmap, * as we want zipmaps to be very space efficient. */ empty = freelen-reqlen; if (empty >= ZIPMAP_VALUE_MAX_FREE) { /* First, move the tail <empty> bytes to the front, then resize * the zipmap to be <empty> bytes smaller. */ offset = p-zm; memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1)); zmlen -= empty; zm = zipmapResize(zm, zmlen); p = zm+offset; vempty = 0; } 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; }
/* 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; }
/* 根据key设置value,如果key不存在则创建相应的键值对,参数update用来辨别更新操作和添加操作。 */ unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update) { unsigned int zmlen, offset; // 计算存储key和value所需要的字节数 unsigned int freelen, reqlen = zipmapRequiredLength(klen,vlen); unsigned int empty, vempty; unsigned char *p; /************************************************************************ * 下面这段代码用于在zipmap留出足够的空间来容纳新插入的键值对或新的value值,尚未写入 ************************************************************************/ freelen = reqlen; if (update) *update = 0; // 在zipmap中查找key,函数返回后zmlen中保存了zipmap所占用的字节数。 p = zipmapLookupRaw(zm,key,klen,&zmlen); if (p == NULL) { /* Key not found: enlarge */ // 如果key指定的键值对不存在,则对zipmap扩容,为容纳新的键值对准备内存空间 // zipmapResize执行的是realloc操作 zm = zipmapResize(zm, zmlen+reqlen); // 此时p指向扩容前zipmap的结尾符,将从这里添加新的键值对 p = zm+zmlen-1; // 更新zipmap所占用的内存空间大小 zmlen = zmlen+reqlen; /* Increase zipmap length (this is an insert) */ // 更新zipmap中保存的键值对数量,即zmlen字段 if (zm[0] < ZIPMAP_BIGLEN) zm[0]++; } else { /* Key found. Is there enough space for the new value? */ /* 找到可对应的键值对,执行更新操作。这里需要考虑value节点的空间大小是否能够容纳新值 */ /* Compute the total length: */ if (update) *update = 1; // 求出旧value节点的空间大小 freelen = zipmapRawEntryLength(p); if (freelen < reqlen) { /* Store the offset of this key within the current zipmap, so * it can be resized. Then, move the tail backwards so this * pair fits at the current position. */ // 旧节点的空间太小,需要扩容操作,zipmapResize函数会重新分配空间,所以需要记录p指针的偏移量 offset = p-zm; zm = zipmapResize(zm, zmlen-freelen+reqlen); p = zm+offset; /* The +1 in the number of bytes to be moved is caused by the * end-of-zipmap byte. Note: the *original* zmlen is used. */ // 移动旧value节点以后的元素以确保有足够的空间容纳新值( +1是将尾部结尾符一起移动) memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1)); zmlen = zmlen-freelen+reqlen; freelen = reqlen; } } /* We now have a suitable block where the key/value entry can * be written. If there is too much free space, move the tail * of the zipmap a few bytes to the front and shrink the zipmap, * as we want zipmaps to be very space efficient. */ // freelen表示经上步骤后流出来的空余空间大小,reqlen表示插入或更新键值对所需要的空间,两者的差就是free字段的 // 的值,如果该值过大zipmap会自动调整。下面这段代码就是完成调整功能。 empty = freelen-reqlen; if (empty >= ZIPMAP_VALUE_MAX_FREE) { /* First, move the tail <empty> bytes to the front, then resize * the zipmap to be <empty> bytes smaller. */ offset = p-zm; memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1)); zmlen -= empty; zm = zipmapResize(zm, zmlen); p = zm+offset; vempty = 0; } else { vempty = empty; } /****************************************** * 下面的操作是讲key和value写入zipmap指定位置 *******************************************/ /* Just write the key + value and we are done. */ /* Key: */ // 对key的长度编码并写入zipmap中 p += zipmapEncodeLength(p,klen); // 写入key字符串 memcpy(p,key,klen); // 移动指针到value写入位置 p += klen; /* Value: */ // 对value的长度编码并写入zipmap中 p += zipmapEncodeLength(p,vlen); // 写入free字段 *p++ = vempty; // 写入value memcpy(p,val,vlen); return zm; }
/* Set key to value, creating the key if it does not already exist. * * 将 key 的值设置为 value ,如果 key 不存在于 zipmap 中,那么新创建一个。 * * If 'update' is not NULL, *update is set to 1 if the key was * already preset, otherwise to 0. * * 如果 update 不为 NULL : * * 1) 那么在 key 已经存在时,将 *update 设为 1 。 * * 2) 如果 key 未存在,将 *update 设为 0 。 * * T = O(N^2) */ unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update) { unsigned int zmlen, offset; // 计算节点所需的长度 unsigned int freelen, reqlen = zipmapRequiredLength(klen,vlen); unsigned int empty, vempty; unsigned char *p; freelen = reqlen; if (update) *update = 0; // 按 key 在 zipmap 中查找节点 // T = O(N^2) p = zipmapLookupRaw(zm,key,klen,&zmlen); if (p == NULL) { /* Key not found: enlarge */ // key 不存在,扩展 zipmap // T = O(N) zm = zipmapResize(zm, zmlen+reqlen); p = zm+zmlen-1; zmlen = zmlen+reqlen; /* Increase zipmap length (this is an insert) */ if (zm[0] < ZIPMAP_BIGLEN) zm[0]++; } else { /* Key found. Is there enough space for the new value? */ /* Compute the total length: */ // 键已经存在,检查旧的值空间大小能否满足新值 // 如果不满足的话,扩展 zipmap 并移动数据 if (update) *update = 1; // T = O(1) freelen = zipmapRawEntryLength(p); if (freelen < reqlen) { /* Store the offset of this key within the current zipmap, so * it can be resized. Then, move the tail backwards so this * pair fits at the current position. */ // 如果已有空间不满足新值所需空间,那么对 zipmap 进行扩展 // T = O(N) offset = p-zm; zm = zipmapResize(zm, zmlen-freelen+reqlen); p = zm+offset; /* The +1 in the number of bytes to be moved is caused by the * end-of-zipmap byte. Note: the *original* zmlen is used. */ // 向后移动数据,为节点空出足以存放新值的空间 // T = O(N) memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1)); zmlen = zmlen-freelen+reqlen; freelen = reqlen; } } /* We now have a suitable block where the key/value entry can * be written. If there is too much free space, move the tail * of the zipmap a few bytes to the front and shrink the zipmap, * as we want zipmaps to be very space efficient. */ // 计算节点空余空间的长度,如果空余空间太大了,就进行缩短 empty = freelen-reqlen; if (empty >= ZIPMAP_VALUE_MAX_FREE) { /* First, move the tail <empty> bytes to the front, then resize * the zipmap to be <empty> bytes smaller. */ offset = p-zm; // 前移数据,覆盖空余空间 // T = O(N) memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1)); zmlen -= empty; // 缩小 zipmap ,移除多余的空间 // T = O(N) zm = zipmapResize(zm, zmlen); p = zm+offset; vempty = 0; } else { vempty = empty; } /* Just write the key + value and we are done. */ /* Key: */ // 写入键 // T = O(N) p += zipmapEncodeLength(p,klen); memcpy(p,key,klen); p += klen; /* Value: */ // 写入值 // T = O(N) p += zipmapEncodeLength(p,vlen); *p++ = vempty; memcpy(p,val,vlen); return zm; }