t_string.c中定义了字符串键的实现过程。

#include "server.h"
#include <math.h> /* isnan(), isinf() */
//检查客户端的字符串长度
static int checkStringLength(client *c, long long size) {if (size > 512*1024*1024) {addReplyError(c,"string exceeds maximum allowed size (512MB)");//这里说明了一个字符串的的大小不能超过512Mreturn C_ERR;}return C_OK;
}
/* The setGenericCommand() function implements the SET operation with different options and variants. This function is called in order to implement the following commands: SET, SETEX, PSETEX, SETNX. 'flags' changes the behavior of the command (NX or XX, see belove). 'expire' represents an expire to set in form of a Redis object as passed by the user. It is interpreted according to the specified 'unit'. 'ok_reply' and 'abort_reply' is what the function will reply to the client if the operation is performed, or when it is not because of NX or XX flags.If ok_reply is NULL "+OK" is used. If abort_reply is NULL, "$-1" is used.这个函数实现的是Set的不同变体和相关的操作 */
#define OBJ_SET_NO_FLAGS 0
#define OBJ_SET_NX (1<<0)     /* Set if key not exists. */
#define OBJ_SET_XX (1<<1)     /* Set if key exists. */
#define OBJ_SET_EX (1<<2)     /* Set if time in seconds is given */
#define OBJ_SET_PX (1<<3)     /* Set if time in ms in given */
void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire, int unit, robj *ok_reply, robj *abort_reply) {long long milliseconds = 0; /* initialized to avoid any harmness warning */if (expire) {if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != C_OK)return;if (milliseconds <= 0) {addReplyErrorFormat(c,"invalid expire time in %s",c->cmd->name);return;}if (unit == UNIT_SECONDS) milliseconds *= 1000;}if ((flags & OBJ_SET_NX && lookupKeyWrite(c->db,key) != NULL) ||(flags & OBJ_SET_XX && lookupKeyWrite(c->db,key) == NULL)){addReply(c, abort_reply ? abort_reply : shared.nullbulk);return;}setKey(c->db,key,val);server.dirty++;if (expire) setExpire(c->db,key,mstime()+milliseconds);notifyKeyspaceEvent(NOTIFY_STRING,"set",key,c->db->id);if (expire) notifyKeyspaceEvent(NOTIFY_GENERIC,"expire",key,c->db->id);addReply(c, ok_reply ? ok_reply : shared.ok);
}/* SET key value [NX] [XX] [EX <seconds>] [PX <milliseconds>] 根据不同的参数设置不同的参数执行setGenericCommand*/
void setCommand(client *c) {int j;robj *expire = NULL;int unit = UNIT_SECONDS;int flags = OBJ_SET_NO_FLAGS;for (j = 3; j < c->argc; j++) {char *a = c->argv[j]->ptr;robj *next = (j == c->argc-1) ? NULL : c->argv[j+1];if ((a[0] == 'n' || a[0] == 'N') &&(a[1] == 'x' || a[1] == 'X') && a[2] == '\0' &&!(flags & OBJ_SET_XX)){flags |= OBJ_SET_NX;} else if ((a[0] == 'x' || a[0] == 'X') &&(a[1] == 'x' || a[1] == 'X') && a[2] == '\0' &&!(flags & OBJ_SET_NX)){flags |= OBJ_SET_XX;} else if ((a[0] == 'e' || a[0] == 'E') &&(a[1] == 'x' || a[1] == 'X') && a[2] == '\0' &&!(flags & OBJ_SET_PX) && next){flags |= OBJ_SET_EX;unit = UNIT_SECONDS;expire = next;j++;} else if ((a[0] == 'p' || a[0] == 'P') &&(a[1] == 'x' || a[1] == 'X') && a[2] == '\0' &&!(flags & OBJ_SET_EX) && next){flags |= OBJ_SET_PX;unit = UNIT_MILLISECONDS;expire = next;j++;} else {addReply(c,shared.syntaxerr);return;}}c->argv[2] = tryObjectEncoding(c->argv[2]);setGenericCommand(c,flags,c->argv[1],c->argv[2],expire,unit,NULL,NULL);
}
//下面是一些针对set特定命令的执行函数,都会调用到setGenericCommand
void setnxCommand(client *c) {c->argv[2] = tryObjectEncoding(c->argv[2]);setGenericCommand(c,OBJ_SET_NX,c->argv[1],c->argv[2],NULL,0,shared.cone,shared.czero);
}
void setexCommand(client *c) {c->argv[3] = tryObjectEncoding(c->argv[3]);setGenericCommand(c,OBJ_SET_NO_FLAGS,c->argv[1],c->argv[3],c->argv[2],UNIT_SECONDS,NULL,NULL);
}
void psetexCommand(client *c) {c->argv[3] = tryObjectEncoding(c->argv[3]);setGenericCommand(c,OBJ_SET_NO_FLAGS,c->argv[1],c->argv[3],c->argv[2],UNIT_MILLISECONDS,NULL,NULL);
}
int getGenericCommand(client *c) {robj *o;if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)return C_OK;if (o->type != OBJ_STRING) {addReply(c,shared.wrongtypeerr);return C_ERR;} else {addReplyBulk(c,o);return C_OK;}
}
//获取客户端的命令
void getCommand(client *c) {getGenericCommand(c);
}void getsetCommand(client *c) {if (getGenericCommand(c) == C_ERR) return;c->argv[2] = tryObjectEncoding(c->argv[2]);setKey(c->db,c->argv[1],c->argv[2]);notifyKeyspaceEvent(NOTIFY_STRING,"set",c->argv[1],c->db->id);//通知事件,定义在Notify.c中server.dirty++;
}
//
void setrangeCommand(client *c) {robj *o;long offset;sds value = c->argv[3]->ptr;if (getLongFromObjectOrReply(c,c->argv[2],&offset,NULL) != C_OK)return;if (offset < 0) {addReplyError(c,"offset is out of range");return;}o = lookupKeyWrite(c->db,c->argv[1]);//查看key是否过期,然后查询set返回结果,定义在Db.c中if (o == NULL) {/* Return 0 when setting nothing on a non-existing string 如果设置的值长度为0,那么直接返回*/if (sdslen(value) == 0) {addReply(c,shared.czero);return;}/* Return when the resulting string exceeds allowed size 如果超过最大字节数,直接返回*/if (checkStringLength(c,offset+sdslen(value)) != C_OK)return;o = createObject(OBJ_STRING,sdsnewlen(NULL, offset+sdslen(value)));//创建对象dbAdd(c->db,c->argv[1],o);//给这个客户端使用的db增加一个对象} else {size_t olen;/* Key exists, check type */if (checkType(c,o,OBJ_STRING))return;/* Return existing string length when setting nothing */olen = stringObjectLen(o);if (sdslen(value) == 0) {addReplyLongLong(c,olen);return;}/* Return when the resulting string exceeds allowed size */if (checkStringLength(c,offset+sdslen(value)) != C_OK)return;/* Create a copy when the object is shared or encoded. */o = dbUnshareStringValue(c->db,c->argv[1],o);}if (sdslen(value) > 0) {o->ptr = sdsgrowzero(o->ptr,offset+sdslen(value));memcpy((char*)o->ptr+offset,value,sdslen(value));signalModifiedKey(c->db,c->argv[1]);notifyKeyspaceEvent(NOTIFY_STRING,"setrange",c->argv[1],c->db->id);server.dirty++;}addReplyLongLong(c,sdslen(o->ptr));//返回客户端长度
}void getrangeCommand(client *c) {robj *o;long long start, end;char *str, llbuf[32];size_t strlen;
//检查第3和第4个参数是否是数字if (getLongLongFromObjectOrReply(c,c->argv[2],&start,NULL) != C_OK)return;if (getLongLongFromObjectOrReply(c,c->argv[3],&end,NULL) != C_OK)return;if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptybulk)) == NULL ||checkType(c,o,OBJ_STRING)) return;//判断类型是否符合要求,返回if (o->encoding == OBJ_ENCODING_INT) {str = llbuf;strlen = ll2string(llbuf,sizeof(llbuf),(long)o->ptr);} else {str = o->ptr;strlen = sdslen(str);}/* Convert negative indexes 转化负数的操作*/if (start < 0 && end < 0 && start > end) {addReply(c,shared.emptybulk);return;}if (start < 0) start = strlen+start;if (end < 0) end = strlen+end;if (start < 0) start = 0;if (end < 0) end = 0;if ((unsigned long long)end >= strlen) end = strlen-1;/* Precondition: end >= 0 && end < strlen, so the only condition where nothing can be returned is: start > end. 判断长度满足条件*/if (start > end || strlen == 0) {addReply(c,shared.emptybulk);} else {addReplyBulkCBuffer(c,(char*)str+start,end-start+1);}
}
//获取指定的key的value
void mgetCommand(client *c) {int j;addReplyMultiBulkLen(c,c->argc-1);for (j = 1; j < c->argc; j++) {robj *o = lookupKeyRead(c->db,c->argv[j]);if (o == NULL) {addReply(c,shared.nullbulk);} else {if (o->type != OBJ_STRING) {addReply(c,shared.nullbulk);} else {addReplyBulk(c,o);}}}
}
//mset通用命令
void msetGenericCommand(client *c, int nx) {int j, busykeys = 0;if ((c->argc % 2) == 0) {addReplyError(c,"wrong number of arguments for MSET");return;}/* Handle the NX flag. The MSETNX semantic is to return zero and don't set nothing at all if at least one already key exists. 处理NX标志,如果至少存在一个key,那么返回0,且不设置任何内容*/if (nx) {for (j = 1; j < c->argc; j += 2) {if (lookupKeyWrite(c->db,c->argv[j]) != NULL) {busykeys++;}}if (busykeys) {addReply(c, shared.czero);return;}}for (j = 1; j < c->argc; j += 2) {c->argv[j+1] = tryObjectEncoding(c->argv[j+1]);setKey(c->db,c->argv[j],c->argv[j+1]);notifyKeyspaceEvent(NOTIFY_STRING,"set",c->argv[j],c->db->id);}server.dirty += (c->argc-1)/2;addReply(c, nx ? shared.cone : shared.ok);
}void msetCommand(client *c) {msetGenericCommand(c,0);
}void msetnxCommand(client *c) {msetGenericCommand(c,1);
}
//是一个value增加incr
void incrDecrCommand(client *c, long long incr) {long long value, oldvalue;robj *o, *new;o = lookupKeyWrite(c->db,c->argv[1]);if (o != NULL && checkType(c,o,OBJ_STRING)) return;if (getLongLongFromObjectOrReply(c,o,&value,NULL) != C_OK) return;oldvalue = value;if ((incr < 0 && oldvalue < 0 && incr < (LLONG_MIN-oldvalue)) ||(incr > 0 && oldvalue > 0 && incr > (LLONG_MAX-oldvalue))) {addReplyError(c,"increment or decrement would overflow");return;}value += incr;if (o && o->refcount == 1 && o->encoding == OBJ_ENCODING_INT &&(value < 0 || value >= OBJ_SHARED_INTEGERS) &&value >= LONG_MIN && value <= LONG_MAX){new = o;o->ptr = (void*)((long)value);} else {new = createStringObjectFromLongLong(value);if (o) {dbOverwrite(c->db,c->argv[1],new);} else {dbAdd(c->db,c->argv[1],new);}}signalModifiedKey(c->db,c->argv[1]);notifyKeyspaceEvent(NOTIFY_STRING,"incrby",c->argv[1],c->db->id);server.dirty++;addReply(c,shared.colon);addReply(c,new);addReply(c,shared.crlf);
}
//+1
void incrCommand(client *c) {incrDecrCommand(c,1);
}
//-1
void decrCommand(client *c) {incrDecrCommand(c,-1);
}//增加命令
void incrbyCommand(client *c) {long long incr;if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != C_OK) return;incrDecrCommand(c,incr);
}
//减少命令
void decrbyCommand(client *c) {long long incr;if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != C_OK) return;incrDecrCommand(c,-incr);
}
//增加浮点数命令
void incrbyfloatCommand(client *c) {long double incr, value;robj *o, *new, *aux;o = lookupKeyWrite(c->db,c->argv[1]);if (o != NULL && checkType(c,o,OBJ_STRING)) return;if (getLongDoubleFromObjectOrReply(c,o,&value,NULL) != C_OK ||getLongDoubleFromObjectOrReply(c,c->argv[2],&incr,NULL) != C_OK)return;value += incr;if (isnan(value) || isinf(value)) {addReplyError(c,"increment would produce NaN or Infinity");return;}new = createStringObjectFromLongDouble(value,1);if (o)dbOverwrite(c->db,c->argv[1],new);elsedbAdd(c->db,c->argv[1],new);signalModifiedKey(c->db,c->argv[1]);notifyKeyspaceEvent(NOTIFY_STRING,"incrbyfloat",c->argv[1],c->db->id);server.dirty++;addReplyBulk(c,new);/* Always replicate INCRBYFLOAT as a SET command with the final value in order to make sure that differences in float precision or formatting will not create differences in replicas or after an AOF restart. */aux = createStringObject("SET",3);rewriteClientCommandArgument(c,0,aux);decrRefCount(aux);rewriteClientCommandArgument(c,2,new);
}
//追加命令,不存在创建,是字符类型追加
void appendCommand(client *c) {size_t totlen;robj *o, *append;o = lookupKeyWrite(c->db,c->argv[1]);if (o == NULL) {/* Create the key */c->argv[2] = tryObjectEncoding(c->argv[2]);dbAdd(c->db,c->argv[1],c->argv[2]);incrRefCount(c->argv[2]);totlen = stringObjectLen(c->argv[2]);} else {/* Key exists, check type */if (checkType(c,o,OBJ_STRING))return;/* "append" is an argument, so always an sds */append = c->argv[2];totlen = stringObjectLen(o)+sdslen(append->ptr);if (checkStringLength(c,totlen) != C_OK)return;/* Append the value */o = dbUnshareStringValue(c->db,c->argv[1],o);o->ptr = sdscatlen(o->ptr,append->ptr,sdslen(append->ptr));totlen = sdslen(o->ptr);}signalModifiedKey(c->db,c->argv[1]);notifyKeyspaceEvent(NOTIFY_STRING,"append",c->argv[1],c->db->id);server.dirty++;addReplyLongLong(c,totlen);
}
//返回对象长度
void strlenCommand(client *c) {robj *o;if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||checkType(c,o,OBJ_STRING)) return;addReplyLongLong(c,stringObjectLen(o));
}

结合redis设计与实现的redis源码学习-8.2-t_string(字符串键)相关推荐

  1. redis源码学习笔记目录

    Redis源码分析(零)学习路径笔记 Redis源码分析(一)redis.c //redis-server.c Redis源码分析(二)redis-cli.c Redis源码剖析(三)--基础数据结构 ...

  2. 使用 Redis 实现语音社交聊天室源码中的排行榜功能

    在语音社交聊天室源码中,排行榜功能是一个很普遍的需求.使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择. 一般语音社交聊天室源码的排行榜都是有实效性的,比如"用户积分榜&quo ...

  3. 单机redis工具类的使用附源码

    单机redis工具类的使用附源码 问题背景 项目搭建 代码测试 总结 Lyric: 怎么隐藏我的悲伤 问题背景 redis常用的工具类 注意事项: 默认已安装redis,可以使用安装包安装看这篇文章, ...

  4. java ee 员工管理系统,fb3492 javaEE_原生Servlet_MySql企业员工信息管理系统的设计与实现,java源码含论文与答辩PPT...

    fb3492 javaEE_原生Servlet_MySql企业员工信息管理系统的设计与实现,java源码含论文与答辩PPT 存储:百度网盘 --/资源热下载站/VIP源码/Java源码/fb3492 ...

  5. java毕业生设计运动会成绩管理系统计算机源码+系统+mysql+调试部署+lw

    java毕业生设计运动会成绩管理系统计算机源码+系统+mysql+调试部署+lw java毕业生设计运动会成绩管理系统计算机源码+系统+mysql+调试部署+lw 本源码技术栈: 项目架构:B/S架构 ...

  6. 基于JAVA图书借阅系统的设计与实现计算机毕业设计源码+系统+lw文档+部署

    基于JAVA图书借阅系统的设计与实现计算机毕业设计源码+系统+lw文档+部署 基于JAVA图书借阅系统的设计与实现计算机毕业设计源码+系统+lw文档+部署 本源码技术栈: 项目架构:B/S架构 开发语 ...

  7. java毕业生设计在线直播平台计算机源码+系统+mysql+调试部署+lw

    java毕业生设计在线直播平台计算机源码+系统+mysql+调试部署+lw java毕业生设计在线直播平台计算机源码+系统+mysql+调试部署+lw 本源码技术栈: 项目架构:B/S架构 开发语言: ...

  8. java毕业生设计大学生兼职平台计算机源码+系统+mysql+调试部署+lw

    java毕业生设计大学生兼职平台计算机源码+系统+mysql+调试部署+lw java毕业生设计大学生兼职平台计算机源码+系统+mysql+调试部署+lw 本源码技术栈: 项目架构:B/S架构 开发语 ...

  9. 【毕业设计】8-基于STM32的水质_浊度检测仪设计与实现(原理图+源码+实物照片+答辩论文)

    [毕业设计]8-基于STM32的水质/浊度检测仪设计与实现(原理图+源码+实物照片+答辩论文) 文章目录 [毕业设计]8-基于STM32的水质/浊度检测仪设计与实现(原理图+源码+实物照片+答辩论文) ...

最新文章

  1. mysql 要使用最新版吗,如何安装最新版MySQL数据库?
  2. python安装工具命令pip安装慢切换为国内阿里云镜像方法及前后对比
  3. Cow Toll Paths(floyd变形)
  4. Halcon算子学习:图像阈值分割-threshold、binary_threshold、dyn_threshold算子
  5. 情人节福利,撩妹神器恋爱话术库它来了~
  6. github上传文件
  7. android service 样例(电话录音和获取系统当前时间)
  8. -函数-MATLAB提供的函数/主子函数/匿名-嵌套函数
  9. Synchronized原理(轻量级锁篇)
  10. 恭喜猛龙获得NBA总冠军
  11. 妮妮lisp_140种Python标准库、第三方库和外部工具都有!
  12. keil5 c语言函数库,C语言中KeilC51库函数大全.doc
  13. python人工智能方向面试准备_人工智能入门学习路线及就业面试
  14. C++ 求最大公因数
  15. SwiftUI 界面大全之个人简历界面支持自定义字体(教程含源码)
  16. 什么是好代码?怎么写好代码?
  17. [转载]informix onbar规复饬令用法
  18. python编的俄罗斯方块游戏下载_用python写一个俄罗斯方块小游戏
  19. Linux OTG当串口、网口、U盘
  20. oracle模糊查询导致cpu高,oracle模糊查询效率提高

热门文章

  1. 人脸识别-人工智能领域的介绍有哪些
  2. 开心一刻:我朋友去就医,问道:医生,我追不上那些狗咋办
  3. 逐步实现 猜数字小游戏/关机小程序
  4. c语言一个图片是幼儿园的,【资源学习】c语言程序代码,登录幼儿园200个小朋友的数据...
  5. 【HackTheBox】dancing(SMB)
  6. 【科创人独家】SmartX张凯:技术专家型CTO的修行之路
  7. mongodb(可以当查询手册使用)
  8. 一加5Android 手机,小米、一加这五款手机值了!配置不错还能抢先体验Android12
  9. 服务器数据恢复-Windows服务器RAID5数据恢复案例
  10. HR看过来:捕捉“大师球”程序员的错误做法