Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xindoo
redis
提交
7fb16bac
R
redis
项目概览
xindoo
/
redis
通知
2
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
redis
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
7fb16bac
编写于
4月 14, 2010
作者:
P
Pieter Noordhuis
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor of hash commands to use specialized api that abstracts zipmap and dict apis
上级
a71f072f
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
246 addition
and
291 deletion
+246
-291
redis.c
redis.c
+246
-291
未找到文件。
redis.c
浏览文件 @
7fb16bac
...
...
@@ -6042,325 +6042,315 @@ static void zrevrankCommand(redisClient *c) {
zrankGenericCommand
(
c
,
1
);
}
/* =================================== Hashes =============================== */
static
void
hsetCommand
(
redisClient
*
c
)
{
int
update
=
0
;
robj
*
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
/* ========================= Hashes utility functions ======================= */
#define REDIS_HASH_KEY 1
#define REDIS_HASH_VALUE 2
/* 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
)
{
o
=
createHashObject
();
dictAdd
(
c
->
db
->
dict
,
c
->
argv
[
1
],
o
);
incrRefCount
(
c
->
argv
[
1
]);
}
else
{
if
(
o
->
type
!=
REDIS_HASH
)
{
addReply
(
c
,
shared
.
wrongtypeerr
);
for
(
i
=
start
;
i
<=
end
;
i
++
)
{
if
(
argv
[
i
]
->
encoding
==
REDIS_ENCODING_RAW
&&
sdslen
(
argv
[
i
]
->
ptr
)
>
server
.
hash_max_zipmap_value
)
{
convertToRealHash
(
subject
);
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
)
{
unsigned
char
*
v
;
unsigned
int
vlen
;
key
=
getDecodedObject
(
key
);
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
)
{
unsigned
char
*
zm
=
o
->
ptr
;
robj
*
valobj
=
getDecodedObject
(
c
->
argv
[
3
]);
key
=
getDecodedObject
(
key
);
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
),
valobj
->
ptr
,
sdslen
(
valobj
->
ptr
),
&
update
);
decrRefCount
(
valobj
);
o
->
ptr
=
zm
;
/* Add an element, discard the old if the key already exists.
* 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
)
{
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.
*/
if
(
zipmapLen
(
zm
)
>
server
.
hash_max_zipmap_entries
)
/*
Check if the zipmap needs to be upgraded to a real hash table
*/
if
(
zipmapLen
(
o
->
ptr
)
>
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
]);
value
=
tryObjectEncoding
(
value
);
if
(
dictReplace
(
o
->
ptr
,
key
,
value
))
{
/* Insert */
incrRefCount
(
key
);
}
else
{
/* Update */
update
=
1
;
}
incrRefCount
(
c
->
argv
[
3
]
);
incrRefCount
(
value
);
}
server
.
dirty
++
;
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
":%d
\r\n
"
,
update
==
0
));
return
update
;
}
static
void
hmsetCommand
(
redisClient
*
c
)
{
int
i
;
robj
*
o
,
*
key
,
*
val
;
if
((
c
->
argc
%
2
)
==
1
)
{
addReplySds
(
c
,
sdsnew
(
"-ERR wrong number of arguments for HMSET
\r\n
"
));
return
;
/* 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
)
{
key
=
getDecodedObject
(
key
);
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
)
{
o
=
createHashObject
();
dictAdd
(
c
->
db
->
dict
,
c
->
argv
[
1
],
o
);
incrRefCount
(
c
->
argv
[
1
]);
/* Return the number of elements in a hash. */
static
inline
unsigned
long
hashLength
(
robj
*
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
{
if
(
o
->
type
!=
REDIS_HASH
)
{
addReply
(
c
,
shared
.
wrongtypeerr
);
return
;
}
redisAssert
(
NULL
);
}
}
/* We want to convert the zipmap into an hash table right now if the
* entry to be added is too big. */
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
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
;
}
}
static
void
hashReleaseIterator
(
hashIterator
*
hi
)
{
if
(
hi
->
encoding
==
REDIS_ENCODING_HT
)
{
dictReleaseIterator
(
hi
->
di
);
}
}
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
unsigned
char
*
zm
=
o
->
ptr
;
/* Move to the next entry in the hash. Return REDIS_OK when the next entry
* 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
)
{
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
(
val
);
o
->
ptr
=
zm
;
/* 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
);
}
/* And here there is the second check for hash conversion. */
if
(
zipmapLen
(
zm
)
>
server
.
hash_max_zipmap_entries
)
convertToRealHash
(
o
);
}
else
{
for
(
i
=
2
;
i
<
c
->
argc
;
i
+=
2
)
{
key
=
tryObjectEncoding
(
c
->
argv
[
i
]);
val
=
tryObjectEncoding
(
c
->
argv
[
i
+
1
]);
if
(
dictReplace
(
o
->
ptr
,
key
,
val
))
{
incrRefCount
(
key
);
}
incrRefCount
(
val
);
if
(
what
&
REDIS_HASH_KEY
)
{
o
=
dictGetEntryKey
(
hi
->
de
);
}
else
{
o
=
dictGetEntryVal
(
hi
->
de
);
}
incrRefCount
(
o
);
}
addReply
(
c
,
shared
.
ok
);
return
o
;
}
static
void
hincrbyCommand
(
redisClient
*
c
)
{
long
long
value
=
0
,
incr
=
0
;
robj
*
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
if
(
getLongLongFromObject
(
c
,
c
->
argv
[
3
],
&
incr
)
!=
REDIS_OK
)
return
;
static
robj
*
hashLookupWriteOrCreate
(
redisClient
*
c
,
robj
*
key
)
{
robj
*
o
=
lookupKeyWrite
(
c
->
db
,
key
);
if
(
o
==
NULL
)
{
o
=
createHashObject
();
dictAdd
(
c
->
db
->
dict
,
c
->
argv
[
1
]
,
o
);
incrRefCount
(
c
->
argv
[
1
]
);
dictAdd
(
c
->
db
->
dict
,
key
,
o
);
incrRefCount
(
key
);
}
else
{
if
(
o
->
type
!=
REDIS_HASH
)
{
addReply
(
c
,
shared
.
wrongtypeerr
);
return
;
return
NULL
;
}
}
return
o
;
}
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
unsigned
char
*
zm
=
o
->
ptr
;
unsigned
char
*
zval
;
unsigned
int
zvlen
;
/* 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
;
/* ============================= Hash commands ============================== */
static
void
hsetCommand
(
redisClient
*
c
)
{
int
update
=
0
;
robj
*
o
;
/* Find value if already present in hash */
de
=
dictFind
(
o
->
ptr
,
c
->
argv
[
2
]);
if
(
de
!=
NULL
)
{
hval
=
dictGetEntryVal
(
de
);
if
(
hval
->
encoding
==
REDIS_ENCODING_RAW
)
value
=
strtoll
(
hval
->
ptr
,
NULL
,
10
);
else
if
(
hval
->
encoding
==
REDIS_ENCODING_INT
)
value
=
(
long
)
hval
->
ptr
;
else
redisAssert
(
1
!=
1
);
}
if
((
o
=
hashLookupWriteOrCreate
(
c
,
c
->
argv
[
1
]))
==
NULL
)
return
;
hashTryConversion
(
o
,
c
->
argv
,
2
,
3
);
update
=
hashReplace
(
o
,
c
->
argv
[
2
],
c
->
argv
[
3
]);
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
":%d
\r\n
"
,
update
==
0
));
server
.
dirty
++
;
}
value
+=
incr
;
hval
=
createObject
(
REDIS_STRING
,
sdscatprintf
(
sdsempty
(),
"%lld"
,
value
));
hval
=
tryObjectEncoding
(
hval
);
if
(
dictReplace
(
o
->
ptr
,
c
->
argv
[
2
],
hval
))
{
incrRefCount
(
c
->
argv
[
2
]);
}
static
void
hmsetCommand
(
redisClient
*
c
)
{
int
i
;
robj
*
o
;
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
++
;
addReplyLongLong
(
c
,
value
);
}
static
void
hgetCommand
(
redisClient
*
c
)
{
robj
*
o
;
robj
*
o
,
*
value
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
nullbulk
))
==
NULL
||
checkType
(
c
,
o
,
REDIS_HASH
))
return
;
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
unsigned
char
*
zm
=
o
->
ptr
;
unsigned
char
*
val
;
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
;
}
if
((
value
=
hashGet
(
o
,
c
->
argv
[
2
]))
!=
NULL
)
{
addReplyBulk
(
c
,
value
);
decrRefCount
(
value
);
}
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
);
}
addReply
(
c
,
shared
.
nullbulk
);
}
}
static
void
hmgetCommand
(
redisClient
*
c
)
{
int
i
;
robj
*
o
=
lookupKeyRead
(
c
->
db
,
c
->
argv
[
1
]);
if
(
o
==
NULL
)
{
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
);
return
;
}
robj
*
o
,
*
value
;
o
=
lookupKeyRead
(
c
->
db
,
c
->
argv
[
1
]);
if
(
o
!=
NULL
&&
o
->
type
!=
REDIS_HASH
)
{
addReply
(
c
,
shared
.
wrongtypeerr
);
}
/* 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
));
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
++
)
{
de
=
dictFind
(
o
->
ptr
,
c
->
argv
[
i
]);
if
(
de
!=
NULL
)
{
addReplyBulk
(
c
,(
robj
*
)
dictGetEntryVal
(
de
));
}
else
{
addReply
(
c
,
shared
.
nullbulk
);
}
for
(
i
=
2
;
i
<
c
->
argc
;
i
++
)
{
if
(
o
!=
NULL
&&
(
value
=
hashGet
(
o
,
c
->
argv
[
i
]))
!=
NULL
)
{
addReplyBulk
(
c
,
value
);
decrRefCount
(
value
);
}
else
{
addReply
(
c
,
shared
.
nullbulk
);
}
}
}
static
void
hdelCommand
(
redisClient
*
c
)
{
robj
*
o
;
int
deleted
=
0
;
if
((
o
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
o
,
REDIS_HASH
))
return
;
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
robj
*
field
=
getDecodedObject
(
c
->
argv
[
2
]);
o
->
ptr
=
zipmapDel
((
unsigned
char
*
)
o
->
ptr
,
(
unsigned
char
*
)
field
->
ptr
,
sdslen
(
field
->
ptr
),
&
deleted
);
decrRefCount
(
field
);
if
(
zipmapLen
((
unsigned
char
*
)
o
->
ptr
)
==
0
)
deleteKey
(
c
->
db
,
c
->
argv
[
1
]);
if
(
hashDelete
(
o
,
c
->
argv
[
2
]))
{
if
(
hashLength
(
o
)
==
0
)
deleteKey
(
c
->
db
,
c
->
argv
[
1
]);
addReply
(
c
,
shared
.
cone
);
server
.
dirty
++
;
}
else
{
deleted
=
dictDelete
((
dict
*
)
o
->
ptr
,
c
->
argv
[
2
])
==
DICT_OK
;
if
(
htNeedsResize
(
o
->
ptr
))
dictResize
(
o
->
ptr
);
if
(
dictSize
((
dict
*
)
o
->
ptr
)
==
0
)
deleteKey
(
c
->
db
,
c
->
argv
[
1
]);
addReply
(
c
,
shared
.
czero
);
}
if
(
deleted
)
server
.
dirty
++
;
addReply
(
c
,
deleted
?
shared
.
cone
:
shared
.
czero
);
}
static
void
hlenCommand
(
redisClient
*
c
)
{
robj
*
o
;
unsigned
long
len
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
o
,
REDIS_HASH
))
return
;
len
=
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
?
zipmapLen
((
unsigned
char
*
)
o
->
ptr
)
:
dictSize
((
dict
*
)
o
->
ptr
);
addReplyUlong
(
c
,
len
);
addReplyUlong
(
c
,
hashLength
(
o
));
}
#define REDIS_GETALL_KEYS 1
#define REDIS_GETALL_VALS 2
static
void
genericHgetallCommand
(
redisClient
*
c
,
int
flags
)
{
robj
*
o
,
*
lenobj
;
robj
*
o
,
*
lenobj
,
*
obj
;
unsigned
long
count
=
0
;
hashIterator
hi
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
emptymultibulk
))
==
NULL
||
checkType
(
c
,
o
,
REDIS_HASH
))
return
;
...
...
@@ -6369,79 +6359,44 @@ static void genericHgetallCommand(redisClient *c, int flags) {
addReply
(
c
,
lenobj
);
decrRefCount
(
lenobj
);
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
unsigned
char
*
p
=
zipmapRewind
(
o
->
ptr
);
unsigned
char
*
field
,
*
val
;
unsigned
int
flen
,
vlen
;
while
((
p
=
zipmapNext
(
p
,
&
field
,
&
flen
,
&
val
,
&
vlen
))
!=
NULL
)
{
robj
*
aux
;
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
++
;
}
hashInitIterator
(
o
,
&
hi
);
while
(
hashNext
(
&
hi
)
!=
REDIS_ERR
)
{
if
(
flags
&
REDIS_HASH_KEY
)
{
obj
=
hashCurrent
(
&
hi
,
REDIS_HASH_KEY
);
addReplyBulk
(
c
,
obj
);
decrRefCount
(
obj
);
count
++
;
}
}
else
{
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
++
;
}
if
(
flags
&
REDIS_HASH_VALUE
)
{
obj
=
hashCurrent
(
&
hi
,
REDIS_HASH_VALUE
);
addReplyBulk
(
c
,
obj
);
decrRefCount
(
obj
);
count
++
;
}
dictReleaseIterator
(
di
);
}
hashReleaseIterator
(
&
hi
);
lenobj
->
ptr
=
sdscatprintf
(
sdsempty
(),
"*%lu
\r\n
"
,
count
);
}
static
void
hkeysCommand
(
redisClient
*
c
)
{
genericHgetallCommand
(
c
,
REDIS_
GETALL_KEYS
);
genericHgetallCommand
(
c
,
REDIS_
HASH_KEY
);
}
static
void
hvalsCommand
(
redisClient
*
c
)
{
genericHgetallCommand
(
c
,
REDIS_
GETALL_VALS
);
genericHgetallCommand
(
c
,
REDIS_
HASH_VALUE
);
}
static
void
hgetallCommand
(
redisClient
*
c
)
{
genericHgetallCommand
(
c
,
REDIS_
GETALL_KEYS
|
REDIS_GETALL_VALS
);
genericHgetallCommand
(
c
,
REDIS_
HASH_KEY
|
REDIS_HASH_VALUE
);
}
static
void
hexistsCommand
(
redisClient
*
c
)
{
robj
*
o
;
int
exists
=
0
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
o
,
REDIS_HASH
))
return
;
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
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
);
addReply
(
c
,
hashExists
(
o
,
c
->
argv
[
2
])
?
shared
.
cone
:
shared
.
czero
);
}
static
void
convertToRealHash
(
robj
*
o
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录