Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
7fb16bac
Commit
7fb16bac
authored
Apr 14, 2010
by
Pieter Noordhuis
Browse files
refactor of hash commands to use specialized api that abstracts zipmap and dict apis
parent
a71f072f
Changes
1
Hide whitespace changes
Inline
Side-by-side
redis.c
View file @
7fb16bac
...
@@ -6042,325 +6042,315 @@ static void zrevrankCommand(redisClient *c) {
...
@@ -6042,325 +6042,315 @@ static void zrevrankCommand(redisClient *c) {
zrankGenericCommand(c, 1);
zrankGenericCommand(c, 1);
}
}
/* =================================== Hashes =============================== */
/* ========================= Hashes utility functions ======================= */
static
void
hsetCommand
(
redisClient
*
c
)
{
#define REDIS_HASH_KEY 1
int
update
=
0
;
#define REDIS_HASH_VALUE 2
robj
*
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
/* Check the length of a number of objects to see if we need to convert a
* zipmap to a real hash. Note that we only check string encoded objects
* as their string length can be queried in constant time. */
static void hashTryConversion(robj *subject, robj **argv, int start, int end) {
int i;
if (subject->encoding != REDIS_ENCODING_ZIPMAP) return;
if
(
o
==
NULL
)
{
for (i = start; i <= end; i++) {
o
=
createHashObject
();
if (argv[i]->encoding == REDIS_ENCODING_RAW &&
dictAdd
(
c
->
db
->
dict
,
c
->
argv
[
1
],
o
);
sdslen(argv[i]->ptr) > server.hash_max_zipmap_value)
incrRefCount
(
c
->
argv
[
1
]);
{
}
else
{
convertToRealHash(subject);
if
(
o
->
type
!=
REDIS_HASH
)
{
addReply
(
c
,
shared
.
wrongtypeerr
);
return;
return;
}
}
}
}
/* We want to convert the zipmap into an hash table right now if the
}
* entry to be added is too big. Note that we check if the object
* is integer encoded before to try fetching the length in the test below.
/* Get the value from a hash identified by key. Returns either a string
* This is because integers are small, but currently stringObjectLen()
* object or NULL if the value cannot be found. The refcount of the object
* performs a slow conversion: not worth it. */
* is always increased by 1 when the value was found. */
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
&&
static robj *hashGet(robj *o, robj *key) {
((
c
->
argv
[
2
]
->
encoding
==
REDIS_ENCODING_RAW
&&
robj *value = NULL;
sdslen
(
c
->
argv
[
2
]
->
ptr
)
>
server
.
hash_max_zipmap_value
)
||
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
(
c
->
argv
[
3
]
->
encoding
==
REDIS_ENCODING_RAW
&&
unsigned char *v;
sdslen
(
c
->
argv
[
3
]
->
ptr
)
>
server
.
hash_max_zipmap_value
)))
unsigned int vlen;
{
key = getDecodedObject(key);
convertToRealHash
(
o
);
if (zipmapGet(o->ptr,key->ptr,sdslen(key->ptr),&v,&vlen)) {
value = createStringObject((char*)v,vlen);
}
decrRefCount(key);
} else {
dictEntry *de = dictFind(o->ptr,key);
if (de != NULL) {
value = dictGetEntryVal(de);
incrRefCount(value);
}
}
}
return value;
}
/* Test if the key exists in the given hash. Returns 1 if the key
* exists and 0 when it doesn't. */
static int hashExists(robj *o, robj *key) {
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
unsigned
char
*
zm
=
o
->
ptr
;
key = getDecodedObject(key);
robj
*
valobj
=
getDecodedObject
(
c
->
argv
[
3
]);
if (zipmapExists(o->ptr,key->ptr,sdslen(key->ptr))) {
decrRefCount(key);
return 1;
}
decrRefCount(key);
} else {
if (dictFind(o->ptr,key) != NULL) {
return 1;
}
}
return 0;
}
zm
=
zipmapSet
(
zm
,
c
->
argv
[
2
]
->
ptr
,
sdslen
(
c
->
argv
[
2
]
->
ptr
),
/* Add an element, discard the old if the key already exists.
valobj
->
ptr
,
sdslen
(
valobj
->
ptr
),
&
update
);
* Return 0 on insert and 1 on update. */
decrRefCount
(
valobj
);
static int hashReplace(robj *o, robj *key, robj *value) {
o
->
ptr
=
zm
;
int update = 0;
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
key = getDecodedObject(key);
value = getDecodedObject(value);
o->ptr = zipmapSet(o->ptr,
key->ptr,sdslen(key->ptr),
value->ptr,sdslen(value->ptr), &update);
decrRefCount(key);
decrRefCount(value);
/*
And here there is the second check for hash conversion.
*/
/*
Check if the zipmap needs to be upgraded to a real hash table
*/
if
(
zipmapLen
(
zm
)
>
server
.
hash_max_zipmap_entries
)
if (zipmapLen(
o->ptr
) > server.hash_max_zipmap_entries)
convertToRealHash(o);
convertToRealHash(o);
} else {
} else {
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
value = tryObjectEncoding(value);
/* note that c->argv[3] is already encoded, as the latest arg
if (dictReplace(o->ptr,key,value)) {
* of a bulk command is always integer encoded if possible. */
/* Insert */
if
(
dictReplace
(
o
->
ptr
,
c
->
argv
[
2
],
c
->
argv
[
3
]))
{
incrRefCount(key);
incrRefCount
(
c
->
argv
[
2
]);
} else {
} else {
/* Update */
update = 1;
update = 1;
}
}
incrRefCount
(
c
->
argv
[
3
]
);
incrRefCount(
value
);
}
}
server
.
dirty
++
;
return update;
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
":%d
\r\n
"
,
update
==
0
));
}
}
static
void
hmsetCommand
(
redisClient
*
c
)
{
/* Delete an element from a hash.
int
i
;
* Return 1 on deleted and 0 on not found. */
robj
*
o
,
*
key
,
*
val
;
static int hashDelete(robj *o, robj *key) {
int deleted = 0;
if
((
c
->
argc
%
2
)
==
1
)
{
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
addReplySds
(
c
,
sdsnew
(
"-ERR wrong number of arguments for HMSET
\r\n
"
));
key = getDecodedObject(key);
return
;
o->ptr = zipmapDel(o->ptr,key->ptr,sdslen(key->ptr), &deleted);
decrRefCount(key);
} else {
deleted = dictDelete((dict*)o->ptr,key) == DICT_OK;
/* Always check if the dictionary needs a resize after a delete. */
if (deleted && htNeedsResize(o->ptr)) dictResize(o->ptr);
}
}
return deleted;
}
if
((
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]))
==
NULL
)
{
/* Return the number of elements in a hash. */
o
=
createHashObject
();
static inline unsigned long hashLength(robj *o) {
dictAdd
(
c
->
db
->
dict
,
c
->
argv
[
1
],
o
);
return (o->encoding == REDIS_ENCODING_ZIPMAP) ?
incrRefCount
(
c
->
argv
[
1
]);
zipmapLen((unsigned char*)o->ptr) : dictSize((dict*)o->ptr);
}
/* Structure to hold hash iteration abstration. Note that iteration over
* hashes involves both fields and values. Because it is possible that
* not both are required, store pointers in the iterator to avoid
* unnecessary memory allocation for fields/values. */
typedef struct {
int encoding;
unsigned char *zi;
unsigned char *zk, *zv;
unsigned int zklen, zvlen;
dictIterator *di;
dictEntry *de;
} hashIterator;
static void hashInitIterator(robj *subject, hashIterator *hi) {
hi->encoding = subject->encoding;
if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
hi->zi = zipmapRewind(subject->ptr);
} else if (hi->encoding == REDIS_ENCODING_HT) {
hi->di = dictGetIterator(subject->ptr);
} else {
} else {
if
(
o
->
type
!=
REDIS_HASH
)
{
redisAssert(NULL);
addReply
(
c
,
shared
.
wrongtypeerr
);
return
;
}
}
}
}
/* We want to convert the zipmap into an hash table right now if the
static void hashReleaseIterator(hashIterator *hi) {
* entry to be added is too big. */
if (hi->encoding == REDIS_ENCODING_HT) {
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
dictReleaseIterator(hi->di);
for
(
i
=
2
;
i
<
c
->
argc
;
i
+=
2
)
{
if
((
c
->
argv
[
i
]
->
encoding
==
REDIS_ENCODING_RAW
&&
sdslen
(
c
->
argv
[
i
]
->
ptr
)
>
server
.
hash_max_zipmap_value
)
||
(
c
->
argv
[
i
+
1
]
->
encoding
==
REDIS_ENCODING_RAW
&&
sdslen
(
c
->
argv
[
i
+
1
]
->
ptr
)
>
server
.
hash_max_zipmap_value
))
{
convertToRealHash
(
o
);
break
;
}
}
}
}
}
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
/* Move to the next entry in the hash. Return REDIS_OK when the next entry
unsigned
char
*
zm
=
o
->
ptr
;
* could be found and REDIS_ERR when the iterator reaches the end. */
static inline int hashNext(hashIterator *hi) {
if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
if ((hi->zi = zipmapNext(hi->zi, &hi->zk, &hi->zklen,
&hi->zv, &hi->zvlen)) == NULL) return REDIS_ERR;
} else {
if ((hi->de = dictNext(hi->di)) == NULL) return REDIS_ERR;
}
return REDIS_OK;
}
for
(
i
=
2
;
i
<
c
->
argc
;
i
+=
2
)
{
/* Get key or value object at current iteration position. This always
key
=
getDecodedObject
(
c
->
argv
[
i
]);
* increases the refcount of the field object by 1. */
val
=
getDecodedObject
(
c
->
argv
[
i
+
1
]);
static inline robj *hashCurrent(hashIterator *hi, int what) {
zm
=
zipmapSet
(
zm
,
key
->
ptr
,
sdslen
(
key
->
ptr
),
robj *o;
val
->
ptr
,
sdslen
(
val
->
ptr
),
NULL
);
if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
decrRefCount
(
key
);
if (what & REDIS_HASH_KEY) {
decrRefCount
(
val
);
o = createStringObject((char*)hi->zk,hi->zklen);
o
->
ptr
=
zm
;
} else {
o = createStringObject((char*)hi->zv,hi->zvlen);
}
}
/* And here there is the second check for hash conversion. */
if
(
zipmapLen
(
zm
)
>
server
.
hash_max_zipmap_entries
)
convertToRealHash
(
o
);
} else {
} else {
for
(
i
=
2
;
i
<
c
->
argc
;
i
+=
2
)
{
if (what & REDIS_HASH_KEY) {
key
=
tryObjectEncoding
(
c
->
argv
[
i
]);
o = dictGetEntryKey(hi->de);
val
=
tryObjectEncoding
(
c
->
argv
[
i
+
1
]);
} else {
if
(
dictReplace
(
o
->
ptr
,
key
,
val
))
{
o = dictGetEntryVal(hi->de);
incrRefCount
(
key
);
}
incrRefCount
(
val
);
}
}
incrRefCount(o);
}
}
return o;
addReply
(
c
,
shared
.
ok
);
}
}
static
void
hincrbyCommand
(
redisClient
*
c
)
{
static robj *hashLookupWriteOrCreate(redisClient *c, robj *key) {
long
long
value
=
0
,
incr
=
0
;
robj *o = lookupKeyWrite(c->db,key);
robj
*
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
if
(
getLongLongFromObject
(
c
,
c
->
argv
[
3
],
&
incr
)
!=
REDIS_OK
)
return
;
if (o == NULL) {
if (o == NULL) {
o = createHashObject();
o = createHashObject();
dictAdd
(
c
->
db
->
dict
,
c
->
argv
[
1
]
,
o
);
dictAdd(c->db->dict,
key
,o);
incrRefCount
(
c
->
argv
[
1
]
);
incrRefCount(
key
);
} else {
} else {
if (o->type != REDIS_HASH) {
if (o->type != REDIS_HASH) {
addReply(c,shared.wrongtypeerr);
addReply(c,shared.wrongtypeerr);
return
;
return
NULL
;
}
}
}
}
return o;
}
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
/* ============================= Hash commands ============================== */
unsigned
char
*
zm
=
o
->
ptr
;
static void hsetCommand(redisClient *c) {
unsigned
char
*
zval
;
int update = 0;
unsigned
int
zvlen
;
robj *o;
/* Find value if already present in hash */
if
(
zipmapGet
(
zm
,
c
->
argv
[
2
]
->
ptr
,
sdslen
(
c
->
argv
[
2
]
->
ptr
),
&
zval
,
&
zvlen
))
{
/* strtoll needs the char* to have a trailing \0, but
* the zipmap doesn't include them. */
sds
szval
=
sdsnewlen
(
zval
,
zvlen
);
value
=
strtoll
(
szval
,
NULL
,
10
);
sdsfree
(
szval
);
}
value
+=
incr
;
sds
svalue
=
sdscatprintf
(
sdsempty
(),
"%lld"
,
value
);
zm
=
zipmapSet
(
zm
,
c
->
argv
[
2
]
->
ptr
,
sdslen
(
c
->
argv
[
2
]
->
ptr
),
(
unsigned
char
*
)
svalue
,
sdslen
(
svalue
),
NULL
);
sdsfree
(
svalue
);
o
->
ptr
=
zm
;
/* Check if the zipmap needs to be converted. */
if
(
zipmapLen
(
zm
)
>
server
.
hash_max_zipmap_entries
)
convertToRealHash
(
o
);
}
else
{
robj
*
hval
;
dictEntry
*
de
;
/* Find value if already present in hash */
if ((o = hashLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
de
=
dictFind
(
o
->
ptr
,
c
->
argv
[
2
]);
hashTryConversion(o,c->argv,2,3);
if
(
de
!=
NULL
)
{
update = hashReplace(o,c->argv[2],c->argv[3]);
hval
=
dictGetEntryVal
(
de
);
addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",update == 0));
if
(
hval
->
encoding
==
REDIS_ENCODING_RAW
)
server.dirty++;
value
=
strtoll
(
hval
->
ptr
,
NULL
,
10
);
}
else
if
(
hval
->
encoding
==
REDIS_ENCODING_INT
)
value
=
(
long
)
hval
->
ptr
;
else
redisAssert
(
1
!=
1
);
}
value
+=
incr
;
static void hmsetCommand(redisClient *c) {
hval
=
createObject
(
REDIS_STRING
,
sdscatprintf
(
sdsempty
(),
"%lld"
,
value
));
int i;
hval
=
tryObjectEncoding
(
hval
);
robj *o;
if
(
dictReplace
(
o
->
ptr
,
c
->
argv
[
2
],
hval
))
{
incrRefCount
(
c
->
argv
[
2
]);
if ((c->argc % 2) == 1) {
}
addReplySds(c,sdsnew("-ERR wrong number of arguments for HMSET\r\n"));
return;
}
if ((o = hashLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
hashTryConversion(o,c->argv,2,c->argc-1);
for (i = 2; i < c->argc; i += 2) {
hashReplace(o,c->argv[i],c->argv[i+1]);
}
addReply(c, shared.ok);
}
static void hincrbyCommand(redisClient *c) {
long long value, incr;
robj *o, *current, *new;
if (getLongLongFromObject(c,c->argv[3],&incr) != REDIS_OK) return;
if ((o = hashLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
if ((current = hashGet(o,c->argv[2])) != NULL) {
if (current->encoding == REDIS_ENCODING_RAW)
value = strtoll(current->ptr,NULL,10);
else if (current->encoding == REDIS_ENCODING_INT)
value = (long)current->ptr;
else
redisAssert(1 != 1);
decrRefCount(current);
} else {
value = 0;
}
}
value += incr;
new = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
hashReplace(o,c->argv[2],new);
decrRefCount(new);
addReplyLongLong(c,value);
server.dirty++;
server.dirty++;
addReplyLongLong
(
c
,
value
);
}
}
static void hgetCommand(redisClient *c) {
static void hgetCommand(redisClient *c) {
robj
*
o
;
robj *o, *value;
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
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
if ((value = hashGet(o,c->argv[2])) != NULL) {
unsigned
char
*
zm
=
o
->
ptr
;
addReplyBulk(c,value);
unsigned
char
*
val
;
decrRefCount(value);
unsigned
int
vlen
;
robj
*
field
;
field
=
getDecodedObject
(
c
->
argv
[
2
]);
if
(
zipmapGet
(
zm
,
field
->
ptr
,
sdslen
(
field
->
ptr
),
&
val
,
&
vlen
))
{
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
"$%u
\r\n
"
,
vlen
));
addReplySds
(
c
,
sdsnewlen
(
val
,
vlen
));
addReply
(
c
,
shared
.
crlf
);
decrRefCount
(
field
);
return
;
}
else
{
addReply
(
c
,
shared
.
nullbulk
);
decrRefCount
(
field
);
return
;
}
} else {
} else {
struct
dictEntry
*
de
;
addReply(c,shared.nullbulk);
de
=
dictFind
(
o
->
ptr
,
c
->
argv
[
2
]);
if
(
de
==
NULL
)
{
addReply
(
c
,
shared
.
nullbulk
);
}
else
{
robj
*
e
=
dictGetEntryVal
(
de
);
addReplyBulk
(
c
,
e
);
}
}
}
}
}
static void hmgetCommand(redisClient *c) {
static void hmgetCommand(redisClient *c) {
int i;
int i;
robj *o, *value;
robj
*
o
=
lookupKeyRead
(
c
->
db
,
c
->
argv
[
1
]);
o = lookupKeyRead(c->db,c->argv[1]);
if
(
o
==
NULL
)
{
if (o != NULL && o->type != REDIS_HASH) {
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
"*%d
\r\n
"
,
c
->
argc
-
2
));
addReply(c,shared.wrongtypeerr);
for
(
i
=
2
;
i
<
c
->
argc
;
i
++
)
{
addReply
(
c
,
shared
.
nullbulk
);
}
return
;
}
else
{
if
(
o
->
type
!=
REDIS_HASH
)
{
addReply
(
c
,
shared
.
wrongtypeerr
);
return
;
}
}
}
/* Note the check for o != NULL happens inside the loop. This is
* done because objects that cannot be found are considered to be
* an empty hash. The reply should then be a series of NULLs. */
addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-2));
addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-2));
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
for (i = 2; i < c->argc; i++) {
unsigned
char
*
zm
=
o
->
ptr
;
if (o != NULL && (value = hashGet(o,c->argv[i])) != NULL) {
unsigned
char
*
v
;
addReplyBulk(c,value);
unsigned
int
vlen
;
decrRefCount(value);
robj
*
field
;
} else {
addReply(c,shared.nullbulk);
for
(
i
=
2
;
i
<
c
->
argc
;
i
++
)
{
field
=
getDecodedObject
(
c
->
argv
[
i
]);
if
(
zipmapGet
(
zm
,
field
->
ptr
,
sdslen
(
field
->
ptr
),
&
v
,
&
vlen
))
{
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
"$%u
\r\n
"
,
vlen
));
addReplySds
(
c
,
sdsnewlen
(
v
,
vlen
));
addReply
(
c
,
shared
.
crlf
);
}
else
{
addReply
(
c
,
shared
.
nullbulk
);
}
decrRefCount
(
field
);
}
}
else
{
dictEntry
*
de
;
for
(
i
=
2
;
i
<
c
->
argc
;
i
++
)
{
de
=
dictFind
(
o
->
ptr
,
c
->
argv
[
i
]);
if
(
de
!=
NULL
)
{
addReplyBulk
(
c
,(
robj
*
)
dictGetEntryVal
(
de
));
}
else
{
addReply
(
c
,
shared
.
nullbulk
);
}
}
}
}
}
}
}
static void hdelCommand(redisClient *c) {
static void hdelCommand(redisClient *c) {
robj *o;
robj *o;
int
deleted
=
0
;
if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,o,REDIS_HASH)) return;
checkType(c,o,REDIS_HASH)) return;
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
if (hashDelete(o,c->argv[2])) {
robj
*
field
=
getDecodedObject
(
c
->
argv
[
2
]);
if (hashLength(o) == 0) deleteKey(c->db,c->argv[1]);
addReply(c,shared.cone);
o
->
ptr
=
zipmapDel
((
unsigned
char
*
)
o
->
ptr
,
server.dirty++;
(
unsigned
char
*
)
field
->
ptr
,
sdslen
(
field
->
ptr
),
&
deleted
);
decrRefCount
(
field
);
if
(
zipmapLen
((
unsigned
char
*
)
o
->
ptr
)
==
0
)
deleteKey
(
c
->
db
,
c
->
argv
[
1
]);
} else {
} else {
deleted
=
dictDelete
((
dict
*
)
o
->
ptr
,
c
->
argv
[
2
])
==
DICT_OK
;
addReply(c,shared.czero);
if
(
htNeedsResize
(
o
->
ptr
))
dictResize
(
o
->
ptr
);
if
(
dictSize
((
dict
*
)
o
->
ptr
)
==
0
)
deleteKey
(
c
->
db
,
c
->
argv
[
1
]);
}
}
if
(
deleted
)
server
.
dirty
++
;
addReply
(
c
,
deleted
?
shared
.
cone
:
shared
.
czero
);
}
}
static void hlenCommand(redisClient *c) {
static void hlenCommand(redisClient *c) {
robj *o;
robj *o;
unsigned
long
len
;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,o,REDIS_HASH)) return;
checkType(c,o,REDIS_HASH)) return;
len
=
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
?
addReplyUlong(c,hashLength(o));
zipmapLen
((
unsigned
char
*
)
o
->
ptr
)
:
dictSize
((
dict
*
)
o
->
ptr
);
addReplyUlong
(
c
,
len
);
}
}
#define REDIS_GETALL_KEYS 1
#define REDIS_GETALL_VALS 2
static void genericHgetallCommand(redisClient *c, int flags) {
static void genericHgetallCommand(redisClient *c, int flags) {
robj
*
o
,
*
lenobj
;
robj *o, *lenobj
, *obj
;
unsigned long count = 0;
unsigned long count = 0;
hashIterator hi;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
|| checkType(c,o,REDIS_HASH)) return;
|| checkType(c,o,REDIS_HASH)) return;
...
@@ -6369,79 +6359,44 @@ static void genericHgetallCommand(redisClient *c, int flags) {
...
@@ -6369,79 +6359,44 @@ static void genericHgetallCommand(redisClient *c, int flags) {
addReply(c,lenobj);
addReply(c,lenobj);
decrRefCount(lenobj);
decrRefCount(lenobj);
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
hashInitIterator(o, &hi);
unsigned
char
*
p
=
zipmapRewind
(
o
->
ptr
);
while (hashNext(&hi) != REDIS_ERR) {
unsigned
char
*
field
,
*
val
;
if (flags & REDIS_HASH_KEY) {
unsigned
int
flen
,
vlen
;
obj = hashCurrent(&hi,REDIS_HASH_KEY);
addReplyBulk(c,obj);
while
((
p
=
zipmapNext
(
p
,
&
field
,
&
flen
,
&
val
,
&
vlen
))
!=
NULL
)
{
decrRefCount(obj);
robj
*
aux
;
count++;
if
(
flags
&
REDIS_GETALL_KEYS
)
{
aux
=
createStringObject
((
char
*
)
field
,
flen
);
addReplyBulk
(
c
,
aux
);
decrRefCount
(
aux
);
count
++
;
}
if
(
flags
&
REDIS_GETALL_VALS
)
{
aux
=
createStringObject
((
char
*
)
val
,
vlen
);
addReplyBulk
(
c
,
aux
);
decrRefCount
(
aux
);
count
++
;
}
}
}
}
else
{
if (flags & REDIS_HASH_VALUE) {
dictIterator
*
di
=
dictGetIterator
(
o
->
ptr
);
obj = hashCurrent(&hi,REDIS_HASH_VALUE);
dictEntry
*
de
;
addReplyBulk(c,obj);
decrRefCount(obj);
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
count++;
robj
*
fieldobj
=
dictGetEntryKey
(
de
);
robj
*
valobj
=
dictGetEntryVal
(
de
);
if
(
flags
&
REDIS_GETALL_KEYS
)
{
addReplyBulk
(
c
,
fieldobj
);
count
++
;
}
if
(
flags
&
REDIS_GETALL_VALS
)
{
addReplyBulk
(
c
,
valobj
);
count
++
;
}
}
}
dictReleaseIterator
(
di
);
}
}
hashReleaseIterator(&hi);
lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",count);
lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",count);
}
}
static void hkeysCommand(redisClient *c) {
static void hkeysCommand(redisClient *c) {
genericHgetallCommand
(
c
,
REDIS_
GETALL
_KEY
S
);
genericHgetallCommand(c,REDIS_
HASH
_KEY);
}
}
static void hvalsCommand(redisClient *c) {
static void hvalsCommand(redisClient *c) {
genericHgetallCommand
(
c
,
REDIS_
GETALL
_VAL
S
);
genericHgetallCommand(c,REDIS_
HASH
_VAL
UE
);
}
}
static void hgetallCommand(redisClient *c) {
static void hgetallCommand(redisClient *c) {
genericHgetallCommand
(
c
,
REDIS_
GETALL
_KEY
S
|
REDIS_
GETALL
_VAL
S
);
genericHgetallCommand(c,REDIS_
HASH
_KEY|REDIS_
HASH
_VAL
UE
);
}
}
static void hexistsCommand(redisClient *c) {
static void hexistsCommand(redisClient *c) {
robj *o;
robj *o;
int
exists
=
0
;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,o,REDIS_HASH)) return;
checkType(c,o,REDIS_HASH)) return;
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
addReply(c, hashExists(o,c->argv[2]) ? shared.cone : shared.czero);
robj
*
field
;
unsigned
char
*
zm
=
o
->
ptr
;
field
=
getDecodedObject
(
c
->
argv
[
2
]);
exists
=
zipmapExists
(
zm
,
field
->
ptr
,
sdslen
(
field
->
ptr
));
decrRefCount
(
field
);
}
else
{
exists
=
dictFind
(
o
->
ptr
,
c
->
argv
[
2
])
!=
NULL
;
}
addReply
(
c
,
exists
?
shared
.
cone
:
shared
.
czero
);
}
}
static void convertToRealHash(robj *o) {
static void convertToRealHash(robj *o) {
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment