From 574069edf5a2188ddff853aa77e13284ba5ab18d Mon Sep 17 00:00:00 2001 From: Nick Apperson Date: Thu, 2 Mar 2017 01:28:38 -0600 Subject: [PATCH 1/2] Add prepend command --- src/redis.c | 1 + src/redis.h | 1 + src/sds.c | 23 +++++++++++++++++++++++ src/sds.h | 1 + src/t_string.c | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 59 insertions(+) diff --git a/src/redis.c b/src/redis.c index 5ca5c8ef96e..ac0d348d8c1 100644 --- a/src/redis.c +++ b/src/redis.c @@ -124,6 +124,7 @@ struct redisCommand redisCommandTable[] = { {"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0}, {"psetex",psetexCommand,4,"wm",0,NULL,1,1,1,0,0}, {"append",appendCommand,3,"wm",0,NULL,1,1,1,0,0}, + {"prepend",prependCommand,3,"wm",0,NULL,1,1,1,0,0}, {"strlen",strlenCommand,2,"rF",0,NULL,1,1,1,0,0}, {"del",delCommand,-2,"w",0,NULL,1,-1,1,0,0}, {"exists",existsCommand,2,"rF",0,NULL,1,1,1,0,0}, diff --git a/src/redis.h b/src/redis.h index f04dd12d595..27b87467be2 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1394,6 +1394,7 @@ void blpopCommand(redisClient *c); void brpopCommand(redisClient *c); void brpoplpushCommand(redisClient *c); void appendCommand(redisClient *c); +void prependCommand(redisClient *c); void strlenCommand(redisClient *c); void zrankCommand(redisClient *c); void zrevrankCommand(redisClient *c); diff --git a/src/sds.c b/src/sds.c index 7c24318075f..b168eb9692f 100644 --- a/src/sds.c +++ b/src/sds.c @@ -250,6 +250,29 @@ sds sdscatlen(sds s, const void *t, size_t len) { return s; } +/* Prepend the specified binary-safe string pointed by 't' of 'len' bytes to the + * beginning of the specified sds string 's'. + * + * After the call, the passed sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdsprecatlen(sds s, const void *t, size_t len) { + struct sdshdr *sh; + size_t curlen = sdslen(s); + + s = sdsMakeRoomFor(s,len); + if (s == NULL) return NULL; + sh = (void*) (s-(sizeof(struct sdshdr))); + + memmove(s+len, s, curlen); + memcpy(s, t, len); +// memcpy(s+curlen, t, len); + + sh->len = curlen+len; + sh->free = sh->free-len; + s[curlen+len] = '\0'; + return s; +} + /* Append the specified null termianted C string to the sds string 's'. * * After the call, the passed sds string is no longer valid and all the diff --git a/src/sds.h b/src/sds.h index 37aaf7a28a4..f5a2b65a529 100644 --- a/src/sds.h +++ b/src/sds.h @@ -63,6 +63,7 @@ void sdsfree(sds s); size_t sdsavail(const sds s); sds sdsgrowzero(sds s, size_t len); sds sdscatlen(sds s, const void *t, size_t len); +sds sdsprecatlen(sds s, const void *t, size_t len); sds sdscat(sds s, const char *t); sds sdscatsds(sds s, const sds t); sds sdscpylen(sds s, const char *t, size_t len); diff --git a/src/t_string.c b/src/t_string.c index 96c978add8a..36f6d5cbda3 100644 --- a/src/t_string.c +++ b/src/t_string.c @@ -439,6 +439,39 @@ void appendCommand(redisClient *c) { addReplyLongLong(c,totlen); } +void prependCommand(redisClient *c) { + size_t totlen; + robj *o, *prepend; + + 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,REDIS_STRING)) + return; + + /* "prepend" is an argument, so always an sds */ + prepend = c->argv[2]; + totlen = stringObjectLen(o)+sdslen(prepend->ptr); + if (checkStringLength(c,totlen) != REDIS_OK) + return; + + /* Append the value */ + o = dbUnshareStringValue(c->db,c->argv[1],o); + o->ptr = sdsprecatlen(o->ptr,prepend->ptr,sdslen(prepend->ptr)); + totlen = sdslen(o->ptr); + } + signalModifiedKey(c->db,c->argv[1]); + notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"prepend",c->argv[1],c->db->id); + server.dirty++; + addReplyLongLong(c,totlen); +} + void strlenCommand(redisClient *c) { robj *o; if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL || From 5108576ab42f9c8caac9ff1faef221fd34b99cad Mon Sep 17 00:00:00 2001 From: Nick Apperson Date: Thu, 2 Mar 2017 02:10:38 -0600 Subject: [PATCH 2/2] Conditional Prepend --- src/redis.c | 1 + src/redis.h | 1 + src/sds.c | 3 --- src/t_string.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/redis.c b/src/redis.c index ac0d348d8c1..456d27bac2a 100644 --- a/src/redis.c +++ b/src/redis.c @@ -125,6 +125,7 @@ struct redisCommand redisCommandTable[] = { {"psetex",psetexCommand,4,"wm",0,NULL,1,1,1,0,0}, {"append",appendCommand,3,"wm",0,NULL,1,1,1,0,0}, {"prepend",prependCommand,3,"wm",0,NULL,1,1,1,0,0}, + {"prependfe",prependfeCommand,3,"wm",0,NULL,1,1,1,0,0}, {"strlen",strlenCommand,2,"rF",0,NULL,1,1,1,0,0}, {"del",delCommand,-2,"w",0,NULL,1,-1,1,0,0}, {"exists",existsCommand,2,"rF",0,NULL,1,1,1,0,0}, diff --git a/src/redis.h b/src/redis.h index 27b87467be2..f200550c42a 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1395,6 +1395,7 @@ void brpopCommand(redisClient *c); void brpoplpushCommand(redisClient *c); void appendCommand(redisClient *c); void prependCommand(redisClient *c); +void prependfeCommand(redisClient *c); void strlenCommand(redisClient *c); void zrankCommand(redisClient *c); void zrevrankCommand(redisClient *c); diff --git a/src/sds.c b/src/sds.c index b168eb9692f..e3502feede6 100644 --- a/src/sds.c +++ b/src/sds.c @@ -262,11 +262,8 @@ sds sdsprecatlen(sds s, const void *t, size_t len) { s = sdsMakeRoomFor(s,len); if (s == NULL) return NULL; sh = (void*) (s-(sizeof(struct sdshdr))); - memmove(s+len, s, curlen); memcpy(s, t, len); -// memcpy(s+curlen, t, len); - sh->len = curlen+len; sh->free = sh->free-len; s[curlen+len] = '\0'; diff --git a/src/t_string.c b/src/t_string.c index 36f6d5cbda3..23c02c32aa0 100644 --- a/src/t_string.c +++ b/src/t_string.c @@ -461,7 +461,7 @@ void prependCommand(redisClient *c) { if (checkStringLength(c,totlen) != REDIS_OK) return; - /* Append the value */ + /* Prepend the value */ o = dbUnshareStringValue(c->db,c->argv[1],o); o->ptr = sdsprecatlen(o->ptr,prepend->ptr,sdslen(prepend->ptr)); totlen = sdslen(o->ptr); @@ -472,6 +472,48 @@ void prependCommand(redisClient *c) { addReplyLongLong(c,totlen); } +void prependfeCommand(redisClient *c) { + size_t totlen; + robj *o, *prepend; + + 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,REDIS_STRING)) + return; + + /* "prepend" is an argument, so always an sds */ + prepend = c->argv[2]; + totlen = stringObjectLen(o)+sdslen(prepend->ptr); + if (checkStringLength(c,totlen) != REDIS_OK) + return; + + /* Check to see if the first bytes match */ + /* if they do, no change is needed */ + if(((char*)o->ptr)[0] == ((char*)prepend->ptr)[0]){ + addReplyLongLong(c,stringObjectLen(o)); + return; + } + + /* Prepend the value */ + else { + o = dbUnshareStringValue(c->db,c->argv[1],o); + o->ptr = sdsprecatlen(o->ptr,prepend->ptr,sdslen(prepend->ptr)); + totlen = sdslen(o->ptr); + } + } + signalModifiedKey(c->db,c->argv[1]); + notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"prepend",c->argv[1],c->db->id); + server.dirty++; + addReplyLongLong(c,totlen); +} + void strlenCommand(redisClient *c) { robj *o; if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||