【Redis源碼】setrange命令

簡(jiǎn)介
setrange命令主要用于設置value的部分子串,設置時(shí)將值從偏移量offset開(kāi)始覆蓋成value值。如果偏移值大于原值的長(cháng)度,則偏移量之前的字符串由“\x00”填充。
命令格式:
setrange key offset value
setrange 命令
由于要指定值的偏移量,所以setrange在執行時(shí)會(huì )首先判斷offset參數必須為long類(lèi)型且必須大于等于0,否則設置失敗。
與append命令一樣,原key在Redis中不存在時(shí),Redis會(huì )創(chuàng )建一個(gè)robj對象,并將robj先設置到數據庫;當key在Redis中存在時(shí),會(huì )要求原值必須為string類(lèi)型,并且由于Redis的限制,value的長(cháng)度加offset值必須小于512 MB。
if (checkStringLength(c,offset+sdslen(value)) != C_OK)
return;
setrange命令會(huì )修改原value值,如果原值是共享類(lèi)型的,則需解除共享,新創(chuàng )建一個(gè)新robj對象,對新對象進(jìn)行操作。代碼實(shí)現:
/* Create a copy when the object is shared or encoded. */
o = dbUnshareStringValue(c->db,c->argv[1],o);
考慮到當value的長(cháng)度加offset會(huì )大于原值長(cháng)度時(shí),需要額外分配空間用于存儲新值并返回。此時(shí)調用了sdsgrowzero函數。sdsgrowzero函數會(huì )進(jìn)行識別,只有當offset+sdslen(value)大于原值長(cháng)度時(shí)才會(huì )擴充空間,否則直接返回原字符串。
o->ptr = sdsgrowzero(o->ptr,offset+sdslen(value));
memcpy((char*)o->ptr+offset,value,sdslen(value));
當有了robj的地址之后,從offset位置開(kāi)始將value覆蓋掉原值,通過(guò)memcpy函數來(lái)實(shí)現。
通過(guò)以上步驟,實(shí)現了字符串的setrange操作。
評論