]> git.saurik.com Git - redis.git/blame - src/t_string.c
README more specific about tcmalloc space benefits
[redis.git] / src / t_string.c
CommitLineData
e2641e09 1#include "redis.h"
2
3/*-----------------------------------------------------------------------------
4 * String Commands
5 *----------------------------------------------------------------------------*/
6
7void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire) {
8 int retval;
9 long seconds = 0; /* initialized to avoid an harmness warning */
10
11 if (expire) {
12 if (getLongFromObjectOrReply(c, expire, &seconds, NULL) != REDIS_OK)
13 return;
14 if (seconds <= 0) {
3ab20376 15 addReplyError(c,"invalid expire time in SETEX");
e2641e09 16 return;
17 }
18 }
19
e2641e09 20 retval = dbAdd(c->db,key,val);
21 if (retval == REDIS_ERR) {
22 if (!nx) {
23 dbReplace(c->db,key,val);
24 incrRefCount(val);
25 } else {
26 addReply(c,shared.czero);
27 return;
28 }
29 } else {
30 incrRefCount(val);
31 }
5b4bff9c 32 touchWatchedKey(c->db,key);
e2641e09 33 server.dirty++;
34 removeExpire(c->db,key);
35 if (expire) setExpire(c->db,key,time(NULL)+seconds);
36 addReply(c, nx ? shared.cone : shared.ok);
37}
38
39void setCommand(redisClient *c) {
40 setGenericCommand(c,0,c->argv[1],c->argv[2],NULL);
41}
42
43void setnxCommand(redisClient *c) {
44 setGenericCommand(c,1,c->argv[1],c->argv[2],NULL);
45}
46
47void setexCommand(redisClient *c) {
48 setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2]);
49}
50
51int getGenericCommand(redisClient *c) {
52 robj *o;
53
54 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
55 return REDIS_OK;
56
57 if (o->type != REDIS_STRING) {
58 addReply(c,shared.wrongtypeerr);
59 return REDIS_ERR;
60 } else {
61 addReplyBulk(c,o);
62 return REDIS_OK;
63 }
64}
65
66void getCommand(redisClient *c) {
67 getGenericCommand(c);
68}
69
70void getsetCommand(redisClient *c) {
71 if (getGenericCommand(c) == REDIS_ERR) return;
72 dbReplace(c->db,c->argv[1],c->argv[2]);
73 incrRefCount(c->argv[2]);
5b4bff9c 74 touchWatchedKey(c->db,c->argv[1]);
e2641e09 75 server.dirty++;
76 removeExpire(c->db,c->argv[1]);
77}
78
79void mgetCommand(redisClient *c) {
80 int j;
81
0537e7bf 82 addReplyMultiBulkLen(c,c->argc-1);
e2641e09 83 for (j = 1; j < c->argc; j++) {
84 robj *o = lookupKeyRead(c->db,c->argv[j]);
85 if (o == NULL) {
86 addReply(c,shared.nullbulk);
87 } else {
88 if (o->type != REDIS_STRING) {
89 addReply(c,shared.nullbulk);
90 } else {
91 addReplyBulk(c,o);
92 }
93 }
94 }
95}
96
97void msetGenericCommand(redisClient *c, int nx) {
98 int j, busykeys = 0;
99
100 if ((c->argc % 2) == 0) {
3ab20376 101 addReplyError(c,"wrong number of arguments for MSET");
e2641e09 102 return;
103 }
104 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
105 * set nothing at all if at least one already key exists. */
106 if (nx) {
107 for (j = 1; j < c->argc; j += 2) {
108 if (lookupKeyWrite(c->db,c->argv[j]) != NULL) {
109 busykeys++;
110 }
111 }
112 }
113 if (busykeys) {
114 addReply(c, shared.czero);
115 return;
116 }
117
118 for (j = 1; j < c->argc; j += 2) {
119 c->argv[j+1] = tryObjectEncoding(c->argv[j+1]);
120 dbReplace(c->db,c->argv[j],c->argv[j+1]);
121 incrRefCount(c->argv[j+1]);
122 removeExpire(c->db,c->argv[j]);
5b4bff9c 123 touchWatchedKey(c->db,c->argv[j]);
e2641e09 124 }
125 server.dirty += (c->argc-1)/2;
126 addReply(c, nx ? shared.cone : shared.ok);
127}
128
129void msetCommand(redisClient *c) {
130 msetGenericCommand(c,0);
131}
132
133void msetnxCommand(redisClient *c) {
134 msetGenericCommand(c,1);
135}
136
137void incrDecrCommand(redisClient *c, long long incr) {
138 long long value;
139 robj *o;
140
141 o = lookupKeyWrite(c->db,c->argv[1]);
142 if (o != NULL && checkType(c,o,REDIS_STRING)) return;
143 if (getLongLongFromObjectOrReply(c,o,&value,NULL) != REDIS_OK) return;
144
145 value += incr;
146 o = createStringObjectFromLongLong(value);
147 dbReplace(c->db,c->argv[1],o);
5b4bff9c 148 touchWatchedKey(c->db,c->argv[1]);
e2641e09 149 server.dirty++;
150 addReply(c,shared.colon);
151 addReply(c,o);
152 addReply(c,shared.crlf);
153}
154
155void incrCommand(redisClient *c) {
156 incrDecrCommand(c,1);
157}
158
159void decrCommand(redisClient *c) {
160 incrDecrCommand(c,-1);
161}
162
163void incrbyCommand(redisClient *c) {
164 long long incr;
165
166 if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != REDIS_OK) return;
167 incrDecrCommand(c,incr);
168}
169
170void decrbyCommand(redisClient *c) {
171 long long incr;
172
173 if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != REDIS_OK) return;
174 incrDecrCommand(c,-incr);
175}
176
177void appendCommand(redisClient *c) {
178 int retval;
179 size_t totlen;
180 robj *o;
181
182 o = lookupKeyWrite(c->db,c->argv[1]);
183 if (o == NULL) {
184 /* Create the key */
185 retval = dbAdd(c->db,c->argv[1],c->argv[2]);
186 incrRefCount(c->argv[2]);
187 totlen = stringObjectLen(c->argv[2]);
188 } else {
189 if (o->type != REDIS_STRING) {
190 addReply(c,shared.wrongtypeerr);
191 return;
192 }
193 /* If the object is specially encoded or shared we have to make
194 * a copy */
195 if (o->refcount != 1 || o->encoding != REDIS_ENCODING_RAW) {
196 robj *decoded = getDecodedObject(o);
197
198 o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
199 decrRefCount(decoded);
200 dbReplace(c->db,c->argv[1],o);
201 }
202 /* APPEND! */
203 if (c->argv[2]->encoding == REDIS_ENCODING_RAW) {
204 o->ptr = sdscatlen(o->ptr,
205 c->argv[2]->ptr, sdslen(c->argv[2]->ptr));
206 } else {
207 o->ptr = sdscatprintf(o->ptr, "%ld",
208 (unsigned long) c->argv[2]->ptr);
209 }
210 totlen = sdslen(o->ptr);
211 }
5b4bff9c 212 touchWatchedKey(c->db,c->argv[1]);
e2641e09 213 server.dirty++;
b70d3555 214 addReplyLongLong(c,totlen);
e2641e09 215}
216
217void substrCommand(redisClient *c) {
218 robj *o;
219 long start = atoi(c->argv[2]->ptr);
220 long end = atoi(c->argv[3]->ptr);
221 size_t rangelen, strlen;
222 sds range;
223
224 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
225 checkType(c,o,REDIS_STRING)) return;
226
227 o = getDecodedObject(o);
228 strlen = sdslen(o->ptr);
229
230 /* convert negative indexes */
231 if (start < 0) start = strlen+start;
232 if (end < 0) end = strlen+end;
233 if (start < 0) start = 0;
234 if (end < 0) end = 0;
235
236 /* indexes sanity checks */
237 if (start > end || (size_t)start >= strlen) {
238 /* Out of range start or start > end result in null reply */
239 addReply(c,shared.nullbulk);
240 decrRefCount(o);
241 return;
242 }
243 if ((size_t)end >= strlen) end = strlen-1;
244 rangelen = (end-start)+1;
245
246 /* Return the result */
247 addReplySds(c,sdscatprintf(sdsempty(),"$%zu\r\n",rangelen));
248 range = sdsnewlen((char*)o->ptr+start,rangelen);
249 addReplySds(c,range);
250 addReply(c,shared.crlf);
251 decrRefCount(o);
252}
253
80091bba 254void strlenCommand(redisClient *c) {
255 robj *o;
256
257 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
258 checkType(c,o,REDIS_STRING)) return;
e2641e09 259
80091bba 260 o = getDecodedObject(o);
261 addReplyLongLong(c,sdslen(o->ptr));
262 decrRefCount(o);
263}