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
Show 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.
* This is because integers are small, but currently stringObjectLen()
* performs a slow conversion: not worth it. */
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
&&
((
c
->
argv
[
2
]
->
encoding
==
REDIS_ENCODING_RAW
&&
sdslen
(
c
->
argv
[
2
]
->
ptr
)
>
server
.
hash_max_zipmap_value
)
||
(
c
->
argv
[
3
]
->
encoding
==
REDIS_ENCODING_RAW
&&
sdslen
(
c
->
argv
[
3
]
->
ptr
)
>
server
.
hash_max_zipmap_value
)))
{
convertToRealHash
(
o
);
}
/* Get the value from a hash identified by key. Returns either a string
* object or NULL if the value cannot be found. The refcount of the object
* is always increased by 1 when the value was found. */
static
robj
*
hashGet
(
robj
*
o
,
robj
*
key
)
{
robj
*
value
=
NULL
;
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
unsigned
char
*
zm
=
o
->
ptr
;
unsigned
char
*
v
;
robj
*
valobj
=
getDecodedObject
(
c
->
argv
[
3
]);
unsigned
int
vlen
;
key
=
getDecodedObject
(
key
);
zm
=
zipmapSet
(
zm
,
c
->
argv
[
2
]
->
ptr
,
sdslen
(
c
->
argv
[
2
]
->
ptr
),
if
(
zipmapGet
(
o
->
ptr
,
key
->
ptr
,
sdslen
(
key
->
ptr
),
&
v
,
&
vlen
))
{
valobj
->
ptr
,
sdslen
(
valobj
->
ptr
),
&
update
);
value
=
createStringObject
((
char
*
)
v
,
vlen
);
decrRefCount
(
valobj
);
}
o
->
ptr
=
zm
;
decrRefCount
(
key
);
/* And here there is the second check for hash conversion. */
if
(
zipmapLen
(
zm
)
>
server
.
hash_max_zipmap_entries
)
convertToRealHash
(
o
);
}
else
{
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
/* note that c->argv[3] is already encoded, as the latest arg
* of a bulk command is always integer encoded if possible. */
if
(
dictReplace
(
o
->
ptr
,
c
->
argv
[
2
],
c
->
argv
[
3
]))
{
incrRefCount
(
c
->
argv
[
2
]);
}
else
{
}
else
{
update
=
1
;
dictEntry
*
de
=
dictFind
(
o
->
ptr
,
key
);
if
(
de
!=
NULL
)
{
value
=
dictGetEntryVal
(
de
);
incrRefCount
(
value
);
}
}
incrRefCount
(
c
->
argv
[
3
]);
}
}
server
.
dirty
++
;
return
value
;
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
":%d
\r\n
"
,
update
==
0
));
}
}
static
void
hmsetCommand
(
redisClient
*
c
)
{
/* Test if the key exists in the given hash. Returns 1 if the key
int
i
;
* exists and 0 when it doesn't. */
robj
*
o
,
*
key
,
*
val
;
static
int
hashExists
(
robj
*
o
,
robj
*
key
)
{
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
if
((
c
->
argc
%
2
)
==
1
)
{
key
=
getDecodedObject
(
key
);
addReplySds
(
c
,
sdsnew
(
"-ERR wrong number of arguments for HMSET
\r\n
"
));
if
(
zipmapExists
(
o
->
ptr
,
key
->
ptr
,
sdslen
(
key
->
ptr
)))
{
return
;
decrRefCount
(
key
);
return
1
;
}
}
decrRefCount
(
key
);
if
((
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]))
==
NULL
)
{
o
=
createHashObject
();
dictAdd
(
c
->
db
->
dict
,
c
->
argv
[
1
],
o
);
incrRefCount
(
c
->
argv
[
1
]);
}
else
{
}
else
{
if
(
o
->
type
!=
REDIS_HASH
)
{
if
(
dictFind
(
o
->
ptr
,
key
)
!=
NULL
)
{
addReply
(
c
,
shared
.
wrongtypeerr
);
return
1
;
return
;
}
}
}
}
return
0
;
}
/* We want to convert the zipmap into an hash table right now if the
/* Add an element, discard the old if the key already exists.
* entry to be added is too big. */
* Return 0 on insert and 1 on update. */
static
int
hashReplace
(
robj
*
o
,
robj
*
key
,
robj
*
value
)
{
int
update
=
0
;
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
for
(
i
=
2
;
i
<
c
->
argc
;
i
+=
2
)
{
key
=
getDecodedObject
(
key
);
if
((
c
->
argv
[
i
]
->
encoding
==
REDIS_ENCODING_RAW
&&
value
=
getDecodedObject
(
value
);
sdslen
(
c
->
argv
[
i
]
->
ptr
)
>
server
.
hash_max_zipmap_value
)
||
o
->
ptr
=
zipmapSet
(
o
->
ptr
,
(
c
->
argv
[
i
+
1
]
->
encoding
==
REDIS_ENCODING_RAW
&&
key
->
ptr
,
sdslen
(
key
->
ptr
),
sdslen
(
c
->
argv
[
i
+
1
]
->
ptr
)
>
server
.
hash_max_zipmap_value
))
{
value
->
ptr
,
sdslen
(
value
->
ptr
),
&
update
);
decrRefCount
(
key
);
decrRefCount
(
value
);
/* Check if the zipmap needs to be upgraded to a real hash table */
if
(
zipmapLen
(
o
->
ptr
)
>
server
.
hash_max_zipmap_entries
)
convertToRealHash
(
o
);
convertToRealHash
(
o
);
break
;
}
else
{
}
value
=
tryObjectEncoding
(
value
);
if
(
dictReplace
(
o
->
ptr
,
key
,
value
))
{
/* Insert */
incrRefCount
(
key
);
}
else
{
/* Update */
update
=
1
;
}
}
incrRefCount
(
value
);
}
}
return
update
;
}
/* Delete an element from a hash.
* Return 1 on deleted and 0 on not found. */
static
int
hashDelete
(
robj
*
o
,
robj
*
key
)
{
int
deleted
=
0
;
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
unsigned
char
*
zm
=
o
->
ptr
;
key
=
getDecodedObject
(
key
);
o
->
ptr
=
zipmapDel
(
o
->
ptr
,
key
->
ptr
,
sdslen
(
key
->
ptr
),
&
deleted
);
for
(
i
=
2
;
i
<
c
->
argc
;
i
+=
2
)
{
key
=
getDecodedObject
(
c
->
argv
[
i
]);
val
=
getDecodedObject
(
c
->
argv
[
i
+
1
]);
zm
=
zipmapSet
(
zm
,
key
->
ptr
,
sdslen
(
key
->
ptr
),
val
->
ptr
,
sdslen
(
val
->
ptr
),
NULL
);
decrRefCount
(
key
);
decrRefCount
(
key
);
decrRefCount
(
val
);
}
else
{
o
->
ptr
=
zm
;
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
;
}
/* And here there is the second check for hash conversion. */
/* Return the number of elements in a hash. */
if
(
zipmapLen
(
zm
)
>
server
.
hash_max_zipmap_entries
)
static
inline
unsigned
long
hashLength
(
robj
*
o
)
{
convertToRealHash
(
o
);
return
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
?
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
{
for
(
i
=
2
;
i
<
c
->
argc
;
i
+=
2
)
{
redisAssert
(
NULL
);
key
=
tryObjectEncoding
(
c
->
argv
[
i
]);
val
=
tryObjectEncoding
(
c
->
argv
[
i
+
1
]);
if
(
dictReplace
(
o
->
ptr
,
key
,
val
))
{
incrRefCount
(
key
);
}
incrRefCount
(
val
);
}
}
}
}
addReply
(
c
,
shared
.
ok
);
static
void
hashReleaseIterator
(
hashIterator
*
hi
)
{
if
(
hi
->
encoding
==
REDIS_ENCODING_HT
)
{
dictReleaseIterator
(
hi
->
di
);
}
}
}
static
void
hincrbyCommand
(
redisClient
*
c
)
{
/* Move to the next entry in the hash. Return REDIS_OK when the next entry
long
long
value
=
0
,
incr
=
0
;
* could be found and REDIS_ERR when the iterator reaches the end. */
robj
*
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
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
;
}
if
(
getLongLongFromObject
(
c
,
c
->
argv
[
3
],
&
incr
)
!=
REDIS_OK
)
return
;
/* Get key or value object at current iteration position. This always
* increases the refcount of the field object by 1. */
static
inline
robj
*
hashCurrent
(
hashIterator
*
hi
,
int
what
)
{
robj
*
o
;
if
(
hi
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
if
(
what
&
REDIS_HASH_KEY
)
{
o
=
createStringObject
((
char
*
)
hi
->
zk
,
hi
->
zklen
);
}
else
{
o
=
createStringObject
((
char
*
)
hi
->
zv
,
hi
->
zvlen
);
}
}
else
{
if
(
what
&
REDIS_HASH_KEY
)
{
o
=
dictGetEntryKey
(
hi
->
de
);
}
else
{
o
=
dictGetEntryVal
(
hi
->
de
);
}
incrRefCount
(
o
);
}
return
o
;
}
static
robj
*
hashLookupWriteOrCreate
(
redisClient
*
c
,
robj
*
key
)
{
robj
*
o
=
lookupKeyWrite
(
c
->
db
,
key
);
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
((
o
=
hashLookupWriteOrCreate
(
c
,
c
->
argv
[
1
]))
==
NULL
)
return
;
if
(
zipmapGet
(
zm
,
c
->
argv
[
2
]
->
ptr
,
sdslen
(
c
->
argv
[
2
]
->
ptr
),
hashTryConversion
(
o
,
c
->
argv
,
2
,
3
);
&
zval
,
&
zvlen
))
{
update
=
hashReplace
(
o
,
c
->
argv
[
2
],
c
->
argv
[
3
]);
/* strtoll needs the char* to have a trailing \0, but
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
":%d
\r\n
"
,
update
==
0
));
* the zipmap doesn't include them. */
server
.
dirty
++
;
sds
szval
=
sdsnewlen
(
zval
,
zvlen
);
}
value
=
strtoll
(
szval
,
NULL
,
10
);
sdsfree
(
szval
);
}
value
+=
incr
;
static
void
hmsetCommand
(
redisClient
*
c
)
{
sds
svalue
=
sdscatprintf
(
sdsempty
(),
"%lld"
,
value
);
int
i
;
zm
=
zipmapSet
(
zm
,
c
->
argv
[
2
]
->
ptr
,
sdslen
(
c
->
argv
[
2
]
->
ptr
),
robj
*
o
;
(
unsigned
char
*
)
svalue
,
sdslen
(
svalue
),
NULL
);
sdsfree
(
svalue
);
o
->
ptr
=
zm
;
/* Check if the zipmap needs to be converted. */
if
((
c
->
argc
%
2
)
==
1
)
{
if
(
zipmapLen
(
zm
)
>
server
.
hash_max_zipmap_entries
)
addReplySds
(
c
,
sdsnew
(
"-ERR wrong number of arguments for HMSET
\r\n
"
));
convertToRealHash
(
o
);
return
;
}
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
,
c
->
argc
-
1
);
if
(
de
!=
NULL
)
{
for
(
i
=
2
;
i
<
c
->
argc
;
i
+=
2
)
{
hval
=
dictGetEntryVal
(
de
);
hashReplace
(
o
,
c
->
argv
[
i
],
c
->
argv
[
i
+
1
]);
if
(
hval
->
encoding
==
REDIS_ENCODING_RAW
)
}
value
=
strtoll
(
hval
->
ptr
,
NULL
,
10
);
addReply
(
c
,
shared
.
ok
);
else
if
(
hval
->
encoding
==
REDIS_ENCODING_INT
)
}
value
=
(
long
)
hval
->
ptr
;
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
else
redisAssert
(
1
!=
1
);
redisAssert
(
1
!=
1
);
decrRefCount
(
current
);
}
else
{
value
=
0
;
}
}
value
+=
incr
;
value
+=
incr
;
hval
=
createObject
(
REDIS_STRING
,
sdscatprintf
(
sdsempty
(),
"%lld"
,
value
));
new
=
createObject
(
REDIS_STRING
,
sdscatprintf
(
sdsempty
(),
"%lld"
,
value
));
hval
=
tryObjectEncoding
(
hval
);
hashReplace
(
o
,
c
->
argv
[
2
],
new
);
if
(
dictReplace
(
o
->
ptr
,
c
->
argv
[
2
],
hval
))
{
decrRefCount
(
new
);
incrRefCount
(
c
->
argv
[
2
]);
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
{
}
else
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
(
c
,
shared
.
nullbulk
);
decrRefCount
(
field
);
return
;
}
}
else
{
struct
dictEntry
*
de
;
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
));
for
(
i
=
2
;
i
<
c
->
argc
;
i
++
)
{
addReply
(
c
,
shared
.
nullbulk
);
}
return
;
}
else
{
if
(
o
->
type
!=
REDIS_HASH
)
{
addReply
(
c
,
shared
.
wrongtypeerr
);
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
)
{
unsigned
char
*
zm
=
o
->
ptr
;
unsigned
char
*
v
;
unsigned
int
vlen
;
robj
*
field
;
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
++
)
{
for
(
i
=
2
;
i
<
c
->
argc
;
i
++
)
{
de
=
dictFind
(
o
->
ptr
,
c
->
argv
[
i
]);
if
(
o
!=
NULL
&&
(
value
=
hashGet
(
o
,
c
->
argv
[
i
]))
!=
NULL
)
{
if
(
de
!=
NULL
)
{
addReplyBulk
(
c
,
value
);
addReplyBulk
(
c
,(
robj
*
)
dictGetEntryVal
(
de
)
);
decrRefCount
(
value
);
}
else
{
}
else
{
addReply
(
c
,
shared
.
nullbulk
);
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
;
if
(
flags
&
REDIS_GETALL_KEYS
)
{
aux
=
createStringObject
((
char
*
)
field
,
flen
);
addReplyBulk
(
c
,
aux
);
decrRefCount
(
aux
);
count
++
;
count
++
;
}
}
if
(
flags
&
REDIS_
GETALL
_VAL
S
)
{
if
(
flags
&
REDIS_
HASH
_VAL
UE
)
{
aux
=
createStringObject
((
char
*
)
val
,
vlen
);
obj
=
hashCurrent
(
&
hi
,
REDIS_HASH_VALUE
);
addReplyBulk
(
c
,
aux
);
addReplyBulk
(
c
,
obj
);
decrRefCount
(
aux
);
decrRefCount
(
obj
);
count
++
;
count
++
;
}
}
}
}
}
else
{
hashReleaseIterator
(
&
hi
);
dictIterator
*
di
=
dictGetIterator
(
o
->
ptr
);
dictEntry
*
de
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
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
);
}
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