Commit 3d24304f authored by antirez's avatar antirez
Browse files

HGET HMGET are now COW friendly, plus API refactoring and changes needed for...

HGET HMGET are now COW friendly, plus API refactoring and changes needed for the new implementation.
parent 1b508da7
...@@ -823,7 +823,8 @@ void setTypeConvert(robj *subject, int enc); ...@@ -823,7 +823,8 @@ void setTypeConvert(robj *subject, int enc);
void convertToRealHash(robj *o); void convertToRealHash(robj *o);
void hashTypeTryConversion(robj *subject, robj **argv, int start, int end); void hashTypeTryConversion(robj *subject, robj **argv, int start, int end);
void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2); void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2);
robj *hashTypeGet(robj *o, robj *key); int hashTypeGet(robj *o, robj *key, robj **objval, unsigned char **v, unsigned int *vlen);
robj *hashTypeGetObject(robj *o, robj *key);
int hashTypeExists(robj *o, robj *key); int hashTypeExists(robj *o, robj *key);
int hashTypeSet(robj *o, robj *key, robj *value); int hashTypeSet(robj *o, robj *key, robj *value);
int hashTypeDelete(robj *o, robj *key); int hashTypeDelete(robj *o, robj *key);
......
...@@ -76,7 +76,7 @@ robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) { ...@@ -76,7 +76,7 @@ robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
/* Retrieve value from hash by the field name. This operation /* Retrieve value from hash by the field name. This operation
* already increases the refcount of the returned object. */ * already increases the refcount of the returned object. */
initStaticStringObject(fieldobj,((char*)&fieldname)+(sizeof(struct sdshdr))); initStaticStringObject(fieldobj,((char*)&fieldname)+(sizeof(struct sdshdr)));
o = hashTypeGet(o, &fieldobj); o = hashTypeGetObject(o, &fieldobj);
} else { } else {
if (o->type != REDIS_STRING) return NULL; if (o->type != REDIS_STRING) return NULL;
......
...@@ -31,27 +31,56 @@ void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2) { ...@@ -31,27 +31,56 @@ void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2) {
} }
} }
/* Get the value from a hash identified by key. Returns either a string /* Get the value from a hash identified by key.
* object or NULL if the value cannot be found. The refcount of the object *
* is always increased by 1 when the value was found. */ * If the string is found either REDIS_ENCODING_HT or REDIS_ENCODING_ZIPMAP
robj *hashTypeGet(robj *o, robj *key) { * is returned, and either **objval or **v and *vlen are set accordingly,
robj *value = NULL; * so that objects in hash tables are returend as objects and pointers
* inside a zipmap are returned as such.
*
* If the object was not found -1 is returned.
*
* This function is copy on write friendly as there is no incr/decr
* of refcount needed if objects are accessed just for reading operations. */
int hashTypeGet(robj *o, robj *key, robj **objval, unsigned char **v,
unsigned int *vlen)
{
if (o->encoding == REDIS_ENCODING_ZIPMAP) { if (o->encoding == REDIS_ENCODING_ZIPMAP) {
unsigned char *v; int found;
unsigned int vlen;
key = getDecodedObject(key); key = getDecodedObject(key);
if (zipmapGet(o->ptr,key->ptr,sdslen(key->ptr),&v,&vlen)) { found = zipmapGet(o->ptr,key->ptr,sdslen(key->ptr),v,vlen);
value = createStringObject((char*)v,vlen);
}
decrRefCount(key); decrRefCount(key);
if (!found) return -1;
} else { } else {
dictEntry *de = dictFind(o->ptr,key); dictEntry *de = dictFind(o->ptr,key);
if (de != NULL) { if (de == NULL) return -1;
value = dictGetEntryVal(de); *objval = dictGetEntryVal(de);
incrRefCount(value); }
} return o->encoding;
}
/* Higher level function of hashTypeGet() that always returns a Redis
* object (either new or with refcount incremented), so that the caller
* can retain a reference or call decrRefCount after the usage.
*
* The lower level function can prevent copy on write so it is
* the preferred way of doing read operations. */
robj *hashTypeGetObject(robj *o, robj *key) {
robj *objval;
unsigned char *v;
unsigned int vlen;
int encoding = hashTypeGet(o,key,&objval,&v,&vlen);
switch(encoding) {
case REDIS_ENCODING_HT:
incrRefCount(objval);
return objval;
case REDIS_ENCODING_ZIPMAP:
objval = createStringObject((char*)v,vlen);
return objval;
default: return NULL;
} }
return value;
} }
/* Test if the key exists in the given hash. Returns 1 if the key /* Test if the key exists in the given hash. Returns 1 if the key
...@@ -270,7 +299,7 @@ void hincrbyCommand(redisClient *c) { ...@@ -270,7 +299,7 @@ void hincrbyCommand(redisClient *c) {
if (getLongLongFromObjectOrReply(c,c->argv[3],&incr,NULL) != REDIS_OK) return; if (getLongLongFromObjectOrReply(c,c->argv[3],&incr,NULL) != REDIS_OK) return;
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return; if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
if ((current = hashTypeGet(o,c->argv[2])) != NULL) { if ((current = hashTypeGetObject(o,c->argv[2])) != NULL) {
if (getLongLongFromObjectOrReply(c,current,&value, if (getLongLongFromObjectOrReply(c,current,&value,
"hash value is not an integer") != REDIS_OK) { "hash value is not an integer") != REDIS_OK) {
decrRefCount(current); decrRefCount(current);
...@@ -293,20 +322,29 @@ void hincrbyCommand(redisClient *c) { ...@@ -293,20 +322,29 @@ void hincrbyCommand(redisClient *c) {
void hgetCommand(redisClient *c) { void hgetCommand(redisClient *c) {
robj *o, *value; robj *o, *value;
unsigned char *v;
unsigned int vlen;
int encoding;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL || if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
checkType(c,o,REDIS_HASH)) return; checkType(c,o,REDIS_HASH)) return;
if ((value = hashTypeGet(o,c->argv[2])) != NULL) { if ((encoding = hashTypeGet(o,c->argv[2],&value,&v,&vlen)) != -1) {
addReplyBulk(c,value); if (encoding == REDIS_ENCODING_HT)
decrRefCount(value); addReplyBulk(c,value);
else
addReplyBulkCBuffer(c,v,vlen);
} else { } else {
addReply(c,shared.nullbulk); addReply(c,shared.nullbulk);
} }
} }
void hmgetCommand(redisClient *c) { void hmgetCommand(redisClient *c) {
int i; int i, encoding;
robj *o, *value; robj *o, *value;
unsigned char *v;
unsigned int vlen;
o = lookupKeyRead(c->db,c->argv[1]); o = lookupKeyRead(c->db,c->argv[1]);
if (o != NULL && o->type != REDIS_HASH) { if (o != NULL && o->type != REDIS_HASH) {
addReply(c,shared.wrongtypeerr); addReply(c,shared.wrongtypeerr);
...@@ -318,9 +356,12 @@ void hmgetCommand(redisClient *c) { ...@@ -318,9 +356,12 @@ void hmgetCommand(redisClient *c) {
* an empty hash. The reply should then be a series of NULLs. */ * an empty hash. The reply should then be a series of NULLs. */
addReplyMultiBulkLen(c,c->argc-2); addReplyMultiBulkLen(c,c->argc-2);
for (i = 2; i < c->argc; i++) { for (i = 2; i < c->argc; i++) {
if (o != NULL && (value = hashTypeGet(o,c->argv[i])) != NULL) { if (o != NULL &&
addReplyBulk(c,value); (encoding = hashTypeGet(o,c->argv[i],&value,&v,&vlen)) != -1) {
decrRefCount(value); if (encoding == REDIS_ENCODING_HT)
addReplyBulk(c,value);
else
addReplyBulkCBuffer(c,v,vlen);
} else { } else {
addReply(c,shared.nullbulk); addReply(c,shared.nullbulk);
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment