Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e951386265 | ||
|
|
715de15c3a | ||
|
|
7ef9c18b72 | ||
|
|
309dcdfd55 | ||
|
|
cac378a1e6 | ||
|
|
a69b4e79db | ||
|
|
740fc6c2b8 | ||
|
|
42202c868d | ||
|
|
8c133b605c | ||
|
|
b50acd7238 | ||
|
|
54db278695 | ||
|
|
011948bcef | ||
|
|
9f95d8b38f | ||
|
|
3d394a6fa2 | ||
|
|
68d2b648e0 | ||
|
|
283998404f | ||
|
|
a7b4d0fea6 | ||
|
|
59051dd59d | ||
|
|
cd836a37e7 | ||
|
|
4326d22380 | ||
|
|
161d3a35ff | ||
|
|
20a9d21dfb | ||
|
|
e902789aa7 | ||
|
|
3745bbd95b | ||
|
|
e63b2880b0 | ||
|
|
a9b70e1ef7 | ||
|
|
e300f753c5 | ||
|
|
efaeca5887 | ||
|
|
4d67305661 | ||
|
|
853bb6ca3e | ||
|
|
b16f23ae8e | ||
|
|
91e6368de0 | ||
|
|
e4451b9628 | ||
|
|
770bb8ef5f | ||
|
|
87b958a210 | ||
|
|
314ac90ba9 | ||
|
|
9f33822083 | ||
|
|
10a4b35bc5 | ||
|
|
7b1dd0b60d | ||
|
|
7a650741f7 | ||
|
|
2ce5f1b944 | ||
|
|
063a14372d | ||
|
|
dd70e1b571 | ||
|
|
d7112df465 | ||
|
|
ed021c88b9 | ||
|
|
1840b893c2 | ||
|
|
8bcde757ce | ||
|
|
1dff223c71 | ||
|
|
a7aa2b0740 | ||
|
|
5e8caca036 | ||
|
|
fcac342955 | ||
|
|
122f42844a | ||
|
|
fb45fefbca | ||
|
|
7b914c2531 | ||
|
|
75d517a27f | ||
|
|
4c98bc690e | ||
|
|
550b3a3a99 | ||
|
|
ef7e89352d | ||
|
|
9322d604ee | ||
|
|
5d92110630 | ||
|
|
4056037cc2 | ||
|
|
677ae5487f | ||
|
|
19956b3807 | ||
|
|
ab9122f2cb | ||
|
|
e62c6b0ed0 | ||
|
|
27a420fbc2 | ||
|
|
040e52c77f | ||
|
|
29b0a57695 | ||
|
|
6c0a5fde3d | ||
|
|
4ea3ed896b | ||
|
|
b3408e9a9b | ||
|
|
9588fd52ac | ||
|
|
544373ea66 | ||
|
|
e2626f69ec | ||
|
|
d75c36ee48 | ||
|
|
9dabbd1ab0 | ||
|
|
5c47e2e964 | ||
|
|
5c21eca66e | ||
|
|
ce518cea79 | ||
|
|
684b140a13 | ||
|
|
bc269c85e1 | ||
|
|
4a0ee5c6ac | ||
|
|
99c2fe0bcf | ||
|
|
b2e03f8329 | ||
|
|
c9e2900efc | ||
|
|
747174388f | ||
|
|
385f6190a3 | ||
|
|
b775ebb382 | ||
|
|
ac80a5c6a6 | ||
|
|
c74100a552 | ||
|
|
03379106d6 | ||
|
|
9ad229f663 | ||
|
|
0900edf776 | ||
|
|
ea520027b9 | ||
|
|
04679b3b3b | ||
|
|
2bf5c1324a | ||
|
|
3d93ca1bf6 | ||
|
|
c548431611 | ||
|
|
0ab29f7394 | ||
|
|
30dab7ad14 | ||
|
|
0c5fa59221 | ||
|
|
267e84f97d | ||
|
|
344cca75c6 | ||
|
|
0dd8e682f4 | ||
|
|
da7e54819a | ||
|
|
4e70215307 | ||
|
|
6aa162f6ff | ||
|
|
dd8b4be46b | ||
|
|
8620a434a0 | ||
|
|
a9a6a894e8 | ||
|
|
325fc1cb2e | ||
|
|
2a5aeef79f | ||
|
|
9095e4dc9b | ||
|
|
6711132083 | ||
|
|
c3e187190b | ||
|
|
a88264d934 | ||
|
|
17c5f17686 | ||
|
|
5def65008f |
No files matched your search
+28
@@ -0,0 +1,28 @@
|
||||
language: generic
|
||||
os: osx
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
script: make
|
||||
env: COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-5
|
||||
- nasm
|
||||
- uuid-dev
|
||||
sources: &sources
|
||||
- llvm-toolchain-precise-3.8
|
||||
- ubuntu-toolchain-r-test
|
||||
- os: linux
|
||||
script: make MALLOC=libc
|
||||
env: COMPILER_NAME=clang CXX=clang++-3.8 CC=clang-3.8 CXXFLAGS="-stdlib=libc++" LDFLAGS="-stdlib=libc++"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.8
|
||||
- libc++-dev
|
||||
- libc++abi-dev
|
||||
- nasm
|
||||
- uuid-dev
|
||||
sources: *sources
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
FROM ubuntu:18.04
|
||||
|
||||
|
||||
|
||||
RUN apt-get update \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -qqy \
|
||||
build-essential nasm autotools-dev autoconf libjemalloc-dev tcl tcl-dev uuid-dev \
|
||||
&& apt-get clean
|
||||
|
||||
CMD make
|
||||
@@ -1,7 +1,10 @@
|
||||

|
||||
[](https://travis-ci.org/JohnSully/KeyDB) [](https://gitter.im/KeyDB/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
What is KeyDB?
|
||||
--------------
|
||||
|
||||
KeyDB is a high performance fork of Redis focusing on multithreading, memory efficiency, and high throughput. In addition to multithreading KeyDB also has features only available in Redis Enterprise such as FLASH storage support, and some not available at all such as direct backup to AWS S3.
|
||||
KeyDB is a high performance fork of Redis focusing on multithreading, memory efficiency, and high throughput. In addition to multithreading KeyDB also has features only available in Redis Enterprise such as [Active Replication](https://github.com/JohnSully/KeyDB/wiki/KeyDB-(Redis-Fork):-Active-Replica-Support), [FLASH storage](https://github.com/JohnSully/KeyDB/wiki/FLASH-Storage) support, and some not available at all such as direct backup to AWS S3.
|
||||
|
||||
On the same hardware KeyDB can perform twice as many queries per second as Redis, with 60% lower latency.
|
||||
|
||||
@@ -9,6 +12,15 @@ KeyDB has full compatibility with the Redis protocol, modules, and scripts. Thi
|
||||
|
||||
Try our docker container: https://hub.docker.com/r/eqalpha/keydb
|
||||
|
||||
Talk on Gitter: https://gitter.im/KeyDB
|
||||
|
||||
Management GUI: We recommend [FastoNoSQL](https://fastonosql.com/) which has official KeyDB support.
|
||||
|
||||
New: Active Replica Support
|
||||
---------------------------
|
||||
|
||||
New! KeyDB now has support for Active Replicas. This feature greatly simplifies hot-spare failover and allows you to distribute writes over replicas instead of just a single master. For more information [see the wiki page](https://github.com/JohnSully/KeyDB/wiki/KeyDB-(Redis-Fork):-Active-Replica-Support).
|
||||
|
||||
Why fork Redis?
|
||||
---------------
|
||||
|
||||
@@ -37,7 +49,7 @@ The number of threads used to serve requests. This should be related to the num
|
||||
|
||||
scratch-file-path /path
|
||||
|
||||
If you would like to use the FLASH backed storage this option configures the directory for KeyDB's temporary files. This feature relies on snapshotting to work so must be used on a BTRFS filesystem. ZFS may also work but is untested. With this feature KeyDB will use RAM as a cache and page to disk as necessary. NOTE: This requires special compilation options, see Building KeyDB below.
|
||||
If you would like to use the [FLASH backed](https://github.com/JohnSully/KeyDB/wiki/FLASH-Storage) storage this option configures the directory for KeyDB's temporary files. This feature relies on snapshotting to work so must be used on a BTRFS filesystem. ZFS may also work but is untested. With this feature KeyDB will use RAM as a cache and page to disk as necessary. NOTE: This requires special compilation options, see Building KeyDB below.
|
||||
|
||||
db-s3-object /path/to/bucket
|
||||
|
||||
@@ -50,6 +62,10 @@ Building KeyDB
|
||||
|
||||
KeyDB can be compiled and is tested for use on Linux. KeyDB currently relies on SO_REUSEADDR's load balancing behavior which is available only in Linux. When we support marshalling connections across threads we plan to support other operating systems such as FreeBSD.
|
||||
|
||||
Install dependencies:
|
||||
|
||||
% sudo apt install build-essential nasm autotools-dev autoconf libjemalloc-dev tcl tcl-dev uuid-dev
|
||||
|
||||
Compiling is as simple as:
|
||||
|
||||
% make
|
||||
@@ -201,6 +217,26 @@ Future work:
|
||||
- Allow rebalancing of connections to different threads after the connection
|
||||
- Allow multiple readers access to the hashtable concurrently
|
||||
|
||||
Docker Build
|
||||
------------
|
||||
|
||||
Run the following commands for a full source download and build:
|
||||
|
||||
```
|
||||
git clone git@github.com:JohnSully/KeyDB.git
|
||||
docker run -it --rm -v `pwd`/KeyDB:/build -w /build devopsdood/keydb-builder make
|
||||
```
|
||||
|
||||
Then you have fresh binaries built, you can also pass any other options to the make command above after the word make. E.g.
|
||||
|
||||
```docker run -it --rm -v `pwd`/KeyDB:/build -w /build devopsdood/keydb-builder make MAllOC=memkind```
|
||||
|
||||
The above commands will build you binaries in the src directory. Standard `make install` without Docker command will work after if you wish to install
|
||||
|
||||
If you'd prefer you can build the Dockerfile in the repo instead of pulling the above container for use:
|
||||
|
||||
`docker build -t KeyDB .`
|
||||
|
||||
Code contributions
|
||||
-----------------
|
||||
|
||||
|
||||
Vendored
+11
-1
@@ -45,31 +45,41 @@ typedef char *sds;
|
||||
* However is here to document the layout of type 5 SDS strings. */
|
||||
struct __attribute__ ((__packed__)) sdshdr5 {
|
||||
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
|
||||
#ifndef __cplusplus
|
||||
char buf[];
|
||||
#endif
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr8 {
|
||||
uint8_t len; /* used */
|
||||
uint8_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
#ifndef __cplusplus
|
||||
char buf[];
|
||||
#endif
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr16 {
|
||||
uint16_t len; /* used */
|
||||
uint16_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
#ifndef __cplusplus
|
||||
char buf[];
|
||||
#endif
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr32 {
|
||||
uint32_t len; /* used */
|
||||
uint32_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
#ifndef __cplusplus
|
||||
char buf[];
|
||||
#endif
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
uint64_t len; /* used */
|
||||
uint64_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
#ifndef __cplusplus
|
||||
char buf[];
|
||||
#endif
|
||||
};
|
||||
|
||||
#define SDS_TYPE_5 0
|
||||
@@ -83,7 +93,7 @@ struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
||||
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||
|
||||
inline size_t sdslen(const sds s) {
|
||||
static inline size_t sdslen(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
|
||||
switch(__builtin_expect((flags&SDS_TYPE_MASK), SDS_TYPE_5)) {
|
||||
|
||||
@@ -1562,3 +1562,8 @@ server-threads 2
|
||||
# Should KeyDB pin threads to CPUs? By default this is disabled, and KeyDB will not bind threads.
|
||||
# When enabled threads are bount to cores sequentially starting at core 0.
|
||||
# server-thread-affinity true
|
||||
|
||||
# Uncomment the option below to enable Active Active support. Note that
|
||||
# replicas will still sync in the normal way and incorrect ordering when
|
||||
# bringing up replicas can result in data loss (the first master will win).
|
||||
# active-replica yes
|
||||
+18
-12
@@ -45,8 +45,9 @@ endif
|
||||
endif
|
||||
|
||||
USEASM?=true
|
||||
# Do we use our assembly spinlock?
|
||||
# Do we use our assembly spinlock? X64 only
|
||||
ifeq ($(uname_S),Linux)
|
||||
ifeq ($(uname_M),x86_64)
|
||||
ifneq ($(@@),32bit)
|
||||
ifeq ($(USEASM),true)
|
||||
ASM_OBJ+= fastlock_x64.o
|
||||
@@ -55,6 +56,11 @@ ifeq ($(USEASM),true)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(COMPILER_NAME),clang)
|
||||
CXXFLAGS+= -stdlib=libc++
|
||||
endif
|
||||
|
||||
# To get ARM stack traces if Redis crashes we need a special C flag.
|
||||
ifneq (,$(filter aarch64 armv,$(uname_M)))
|
||||
@@ -86,7 +92,7 @@ endif
|
||||
-include .make-settings
|
||||
|
||||
FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
|
||||
FINAL_CXXFLAGS=$(CXX_STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
|
||||
FINAL_CXXFLAGS=$(CXX_STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(CXXFLAGS) $(REDIS_CFLAGS)
|
||||
FINAL_LDFLAGS=$(LDFLAGS) $(REDIS_LDFLAGS) $(DEBUG)
|
||||
FINAL_LIBS=-lm
|
||||
DEBUG=-g -ggdb
|
||||
@@ -133,7 +139,7 @@ ifeq ($(uname_S),DragonFly)
|
||||
else
|
||||
# All the other OSes (notably Linux)
|
||||
FINAL_LDFLAGS+= -rdynamic
|
||||
FINAL_LIBS+=-ldl -pthread -lrt
|
||||
FINAL_LIBS+=-ldl -pthread -lrt -luuid
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@@ -191,9 +197,9 @@ endif
|
||||
|
||||
REDIS_SERVER_NAME=keydb-server
|
||||
REDIS_SENTINEL_NAME=keydb-sentinel
|
||||
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o acl.o storage.o rdb-s3.o fastlock.o gopher.o $(ASM_OBJ)
|
||||
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o acl.o storage.o rdb-s3.o fastlock.o $(ASM_OBJ)
|
||||
REDIS_CLI_NAME=keydb-cli
|
||||
REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o siphash.o crc16.o storage-lite.o fastlock.o $(ASM_OBJ)
|
||||
REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o redis-cli-cpphelper.o zmalloc.o release.o anet.o ae.o crc64.o siphash.o crc16.o storage-lite.o fastlock.o $(ASM_OBJ)
|
||||
REDIS_BENCHMARK_NAME=keydb-benchmark
|
||||
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o siphash.o redis-benchmark.o storage-lite.o fastlock.o $(ASM_OBJ)
|
||||
REDIS_CHECK_RDB_NAME=keydb-check-rdb
|
||||
@@ -224,22 +230,21 @@ persist-settings: distclean
|
||||
echo REDIS_LDFLAGS=$(REDIS_LDFLAGS) >> .make-settings
|
||||
echo PREV_FINAL_CFLAGS=$(FINAL_CFLAGS) >> .make-settings
|
||||
echo PREV_FINAL_LDFLAGS=$(FINAL_LDFLAGS) >> .make-settings
|
||||
-(cd modules && $(MAKE))
|
||||
-(cd ../deps && $(MAKE) $(DEPENDENCY_TARGETS))
|
||||
|
||||
.PHONY: persist-settings
|
||||
|
||||
# Prerequisites target
|
||||
.make-prerequisites:
|
||||
@touch $@
|
||||
|
||||
# Clean everything, persist settings and build dependencies if anything changed
|
||||
ifneq ($(strip $(PREV_FINAL_CFLAGS)), $(strip $(FINAL_CFLAGS)))
|
||||
.make-prerequisites: persist-settings
|
||||
endif
|
||||
|
||||
ifneq ($(strip $(PREV_FINAL_LDFLAGS)), $(strip $(FINAL_LDFLAGS)))
|
||||
else ifneq ($(strip $(PREV_FINAL_LDFLAGS)), $(strip $(FINAL_LDFLAGS)))
|
||||
.make-prerequisites: persist-settings
|
||||
else
|
||||
.make-prerequisites:
|
||||
endif
|
||||
@touch $@
|
||||
|
||||
# keydb-server
|
||||
$(REDIS_SERVER_NAME): $(REDIS_SERVER_OBJ)
|
||||
@@ -265,7 +270,7 @@ $(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
|
||||
$(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)
|
||||
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a $(FINAL_LIBS)
|
||||
|
||||
dict-benchmark: dict.c zmalloc.c sds.c siphash.c
|
||||
dict-benchmark: dict.cpp zmalloc.c sds.c siphash.c
|
||||
$(REDIS_CC) $(FINAL_CFLAGS) $^ -D DICT_BENCHMARK_MAIN -o $@ $(FINAL_LIBS)
|
||||
|
||||
# Because the jemalloc.h header is generated as a part of the jemalloc build,
|
||||
@@ -287,6 +292,7 @@ clean:
|
||||
|
||||
distclean: clean
|
||||
-(cd ../deps && $(MAKE) distclean)
|
||||
-(cd modules && $(MAKE) clean)
|
||||
-(rm -f .make-*)
|
||||
|
||||
.PHONY: distclean
|
||||
|
||||
+45
-45
@@ -157,17 +157,17 @@ uint64_t ACLGetCommandCategoryFlagByName(const char *name) {
|
||||
/* Method for passwords/pattern comparison used for the user->passwords list
|
||||
* so that we can search for items with listSearchKey(). */
|
||||
int ACLListMatchSds(void *a, void *b) {
|
||||
return sdscmp(a,b) == 0;
|
||||
return sdscmp((sds)a,(sds)b) == 0;
|
||||
}
|
||||
|
||||
/* Method to free list elements from ACL users password/ptterns lists. */
|
||||
void ACLListFreeSds(void *item) {
|
||||
sdsfree(item);
|
||||
sdsfree((sds)item);
|
||||
}
|
||||
|
||||
/* Method to duplicate list elements from ACL users password/ptterns lists. */
|
||||
void *ACLListDupSds(void *item) {
|
||||
return sdsdup(item);
|
||||
return sdsdup((sds)item);
|
||||
}
|
||||
|
||||
/* Create a new user with the specified name, store it in the list
|
||||
@@ -177,7 +177,7 @@ void *ACLListDupSds(void *item) {
|
||||
* If the user with such name already exists NULL is returned. */
|
||||
user *ACLCreateUser(const char *name, size_t namelen) {
|
||||
if (raxFind(Users,(unsigned char*)name,namelen) != raxNotFound) return NULL;
|
||||
user *u = zmalloc(sizeof(*u), MALLOC_LOCAL);
|
||||
user *u = (user*)zmalloc(sizeof(*u), MALLOC_LOCAL);
|
||||
u->name = sdsnewlen(name,namelen);
|
||||
u->flags = USER_FLAG_DISABLED;
|
||||
u->allowed_subcommands = NULL;
|
||||
@@ -229,7 +229,7 @@ void ACLFreeUserAndKillClients(user *u) {
|
||||
listNode *ln;
|
||||
listRewind(server.clients,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
client *c = listNodeValue(ln);
|
||||
client *c = (client*)listNodeValue(ln);
|
||||
if (c->puser == u) {
|
||||
/* We'll free the conenction asynchronously, so
|
||||
* in theory to set a different user is not needed.
|
||||
@@ -337,7 +337,7 @@ int ACLSetUserCommandBitsForCategory(user *u, const char *category, int value) {
|
||||
dictIterator *di = dictGetIterator(server.orig_commands);
|
||||
dictEntry *de;
|
||||
while ((de = dictNext(di)) != NULL) {
|
||||
struct redisCommand *cmd = dictGetVal(de);
|
||||
struct redisCommand *cmd = (redisCommand*)dictGetVal(de);
|
||||
if (cmd->flags & CMD_MODULE) continue; /* Ignore modules commands. */
|
||||
if (cmd->flags & cflag) {
|
||||
ACLSetUserCommandBit(u,cmd->id,value);
|
||||
@@ -362,7 +362,7 @@ int ACLCountCategoryBitsForUser(user *u, unsigned long *on, unsigned long *off,
|
||||
dictIterator *di = dictGetIterator(server.orig_commands);
|
||||
dictEntry *de;
|
||||
while ((de = dictNext(di)) != NULL) {
|
||||
struct redisCommand *cmd = dictGetVal(de);
|
||||
struct redisCommand *cmd = (redisCommand*)dictGetVal(de);
|
||||
if (cmd->flags & cflag) {
|
||||
if (ACLGetUserCommandBit(u,cmd->id))
|
||||
(*on)++;
|
||||
@@ -431,7 +431,7 @@ sds ACLDescribeUserCommandRules(user *u) {
|
||||
dictIterator *di = dictGetIterator(server.orig_commands);
|
||||
dictEntry *de;
|
||||
while ((de = dictNext(di)) != NULL) {
|
||||
struct redisCommand *cmd = dictGetVal(de);
|
||||
struct redisCommand *cmd = (redisCommand*)dictGetVal(de);
|
||||
int userbit = ACLGetUserCommandBit(u,cmd->id);
|
||||
int fakebit = ACLGetUserCommandBit(fakeuser,cmd->id);
|
||||
if (userbit != fakebit) {
|
||||
@@ -501,7 +501,7 @@ sds ACLDescribeUser(user *u) {
|
||||
listNode *ln;
|
||||
listRewind(u->passwords,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
sds thispass = listNodeValue(ln);
|
||||
sds thispass = (sds)listNodeValue(ln);
|
||||
res = sdscatlen(res,">",1);
|
||||
res = sdscatsds(res,thispass);
|
||||
res = sdscatlen(res," ",1);
|
||||
@@ -513,7 +513,7 @@ sds ACLDescribeUser(user *u) {
|
||||
} else {
|
||||
listRewind(u->patterns,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
sds thispat = listNodeValue(ln);
|
||||
sds thispat = (sds)listNodeValue(ln);
|
||||
res = sdscatlen(res,"~",1);
|
||||
res = sdscatsds(res,thispat);
|
||||
res = sdscatlen(res," ",1);
|
||||
@@ -533,7 +533,7 @@ sds ACLDescribeUser(user *u) {
|
||||
struct redisCommand *ACLLookupCommand(const char *name) {
|
||||
struct redisCommand *cmd;
|
||||
sds sdsname = sdsnew(name);
|
||||
cmd = dictFetchValue(server.orig_commands, sdsname);
|
||||
cmd = (redisCommand*)dictFetchValue(server.orig_commands, sdsname);
|
||||
sdsfree(sdsname);
|
||||
return cmd;
|
||||
}
|
||||
@@ -570,7 +570,7 @@ void ACLAddAllowedSubcommand(user *u, unsigned long id, const char *sub) {
|
||||
/* If this is the first subcommand to be configured for
|
||||
* this user, we have to allocate the subcommands array. */
|
||||
if (u->allowed_subcommands == NULL) {
|
||||
u->allowed_subcommands = zcalloc(USER_COMMAND_BITS_COUNT *
|
||||
u->allowed_subcommands = (sds**)zcalloc(USER_COMMAND_BITS_COUNT *
|
||||
sizeof(sds*), MALLOC_LOCAL);
|
||||
}
|
||||
|
||||
@@ -589,7 +589,7 @@ void ACLAddAllowedSubcommand(user *u, unsigned long id, const char *sub) {
|
||||
|
||||
/* Now we can make space for the new item (and the null term). */
|
||||
items += 2;
|
||||
u->allowed_subcommands[id] = zrealloc(u->allowed_subcommands[id],
|
||||
u->allowed_subcommands[id] = (sds*)zrealloc(u->allowed_subcommands[id],
|
||||
sizeof(sds)*items, MALLOC_LOCAL);
|
||||
u->allowed_subcommands[id][items-2] = sdsnew(sub);
|
||||
u->allowed_subcommands[id][items-1] = NULL;
|
||||
@@ -802,8 +802,8 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen) {
|
||||
|
||||
/* Return a description of the error that occurred in ACLSetUser() according to
|
||||
* the errno value set by the function on error. */
|
||||
char *ACLSetUserStringError(void) {
|
||||
char *errmsg = "Wrong format";
|
||||
const char *ACLSetUserStringError(void) {
|
||||
const char *errmsg = "Wrong format";
|
||||
if (errno == ENOENT)
|
||||
errmsg = "Unknown command or category name in ACL";
|
||||
else if (errno == EINVAL)
|
||||
@@ -830,7 +830,7 @@ char *ACLSetUserStringError(void) {
|
||||
sds ACLDefaultUserFirstPassword(void) {
|
||||
if (listLength(DefaultUser->passwords) == 0) return NULL;
|
||||
listNode *first = listFirst(DefaultUser->passwords);
|
||||
return listNodeValue(first);
|
||||
return (sds)listNodeValue(first);
|
||||
}
|
||||
|
||||
/* Initialize the default user, that will always exist for all the process
|
||||
@@ -857,7 +857,7 @@ void ACLInit(void) {
|
||||
* ENONENT: if the specified user does not exist at all.
|
||||
*/
|
||||
int ACLCheckUserCredentials(robj *username, robj *password) {
|
||||
user *u = ACLGetUserByName(ptrFromObj(username),sdslen(ptrFromObj(username)));
|
||||
user *u = ACLGetUserByName(szFromObj(username),sdslen(szFromObj(username)));
|
||||
if (u == NULL) {
|
||||
errno = ENOENT;
|
||||
return C_ERR;
|
||||
@@ -878,8 +878,8 @@ int ACLCheckUserCredentials(robj *username, robj *password) {
|
||||
listNode *ln;
|
||||
listRewind(u->passwords,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
sds thispass = listNodeValue(ln);
|
||||
if (!time_independent_strcmp(ptrFromObj(password), thispass))
|
||||
sds thispass = (sds)listNodeValue(ln);
|
||||
if (!time_independent_strcmp(szFromObj(password), thispass))
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
@@ -944,7 +944,7 @@ unsigned long ACLGetCommandID(const char *cmdname) {
|
||||
user *ACLGetUserByName(const char *name, size_t namelen) {
|
||||
void *myuser = raxFind(Users,(unsigned char*)name,namelen);
|
||||
if (myuser == raxNotFound) return NULL;
|
||||
return myuser;
|
||||
return (user*)myuser;
|
||||
}
|
||||
|
||||
/* Check if the command ready to be excuted in the client 'c', and already
|
||||
@@ -982,7 +982,7 @@ int ACLCheckCommandPerm(client *c) {
|
||||
while (1) {
|
||||
if (u->allowed_subcommands[id][subid] == NULL)
|
||||
return ACL_DENIED_CMD;
|
||||
if (!strcasecmp(ptrFromObj(c->argv[1]),
|
||||
if (!strcasecmp(szFromObj(c->argv[1]),
|
||||
u->allowed_subcommands[id][subid]))
|
||||
break; /* Subcommand match found. Stop here. */
|
||||
subid++;
|
||||
@@ -1005,11 +1005,11 @@ int ACLCheckCommandPerm(client *c) {
|
||||
/* Test this key against every pattern. */
|
||||
int match = 0;
|
||||
while((ln = listNext(&li))) {
|
||||
sds pattern = listNodeValue(ln);
|
||||
sds pattern = (sds)listNodeValue(ln);
|
||||
size_t plen = sdslen(pattern);
|
||||
int idx = keyidx[j];
|
||||
if (stringmatchlen(pattern,plen,ptrFromObj(c->argv[idx]),
|
||||
sdslen(ptrFromObj(c->argv[idx])),0))
|
||||
if (stringmatchlen(pattern,plen,szFromObj(c->argv[idx]),
|
||||
sdslen(szFromObj(c->argv[idx])),0))
|
||||
{
|
||||
match = 1;
|
||||
break;
|
||||
@@ -1071,7 +1071,7 @@ int ACLAppendUserForLoading(sds *argv, int argc, int *argc_err) {
|
||||
}
|
||||
|
||||
/* Rules look valid, let's append the user to the list. */
|
||||
sds *copy = zmalloc(sizeof(sds)*argc, MALLOC_LOCAL);
|
||||
sds *copy = (sds*)zmalloc(sizeof(sds)*argc, MALLOC_LOCAL);
|
||||
for (int j = 1; j < argc; j++) copy[j-1] = sdsdup(argv[j]);
|
||||
copy[argc-1] = NULL;
|
||||
listAddNodeTail(UsersToLoad,copy);
|
||||
@@ -1087,7 +1087,7 @@ int ACLLoadConfiguredUsers(void) {
|
||||
listNode *ln;
|
||||
listRewind(UsersToLoad,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
sds *aclrules = listNodeValue(ln);
|
||||
sds *aclrules = (sds*)listNodeValue(ln);
|
||||
sds username = aclrules[0];
|
||||
user *u = ACLCreateUser(username,sdslen(username));
|
||||
if (!u) {
|
||||
@@ -1099,7 +1099,7 @@ int ACLLoadConfiguredUsers(void) {
|
||||
/* Load every rule defined for this user. */
|
||||
for (int j = 1; aclrules[j]; j++) {
|
||||
if (ACLSetUser(u,aclrules[j],sdslen(aclrules[j])) != C_OK) {
|
||||
char *errmsg = ACLSetUserStringError();
|
||||
const char *errmsg = ACLSetUserStringError();
|
||||
serverLog(LL_WARNING,"Error loading ACL rule '%s' for "
|
||||
"the user named '%s': %s",
|
||||
aclrules[j],aclrules[0],errmsg);
|
||||
@@ -1220,7 +1220,7 @@ sds ACLLoadFromFile(const char *filename) {
|
||||
int j;
|
||||
for (j = 2; j < argc; j++) {
|
||||
if (ACLSetUser(fakeuser,argv[j],sdslen(argv[j])) != C_OK) {
|
||||
char *errmsg = ACLSetUserStringError();
|
||||
const char *errmsg = ACLSetUserStringError();
|
||||
errors = sdscatprintf(errors,
|
||||
"%s:%d: %s. ",
|
||||
server.acl_filename, linenum, errmsg);
|
||||
@@ -1262,10 +1262,10 @@ sds ACLLoadFromFile(const char *filename) {
|
||||
/* The default user pointer is referenced in different places: instead
|
||||
* of replacing such occurrences it is much simpler to copy the new
|
||||
* default user configuration in the old one. */
|
||||
user *new = ACLGetUserByName("default",7);
|
||||
serverAssert(new != NULL);
|
||||
ACLCopyUser(DefaultUser,new);
|
||||
ACLFreeUser(new);
|
||||
user *newuser = ACLGetUserByName("default",7);
|
||||
serverAssert(newuser != NULL);
|
||||
ACLCopyUser(DefaultUser,newuser);
|
||||
ACLFreeUser(newuser);
|
||||
raxInsert(Users,(unsigned char*)"default",7,DefaultUser,NULL);
|
||||
raxRemove(old_users,(unsigned char*)"default",7,NULL);
|
||||
ACLFreeUsersSet(old_users);
|
||||
@@ -1294,7 +1294,7 @@ int ACLSaveToFile(const char *filename) {
|
||||
raxStart(&ri,Users);
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
while(raxNext(&ri)) {
|
||||
user *u = ri.data;
|
||||
user *u = (user*)ri.data;
|
||||
/* Return information in the configuration file format. */
|
||||
sds user = sdsnew("user ");
|
||||
user = sdscatsds(user,u->name);
|
||||
@@ -1393,9 +1393,9 @@ void ACLLoadUsersAtStartup(void) {
|
||||
* ACL WHOAMI
|
||||
*/
|
||||
void aclCommand(client *c) {
|
||||
char *sub = ptrFromObj(c->argv[1]);
|
||||
char *sub = szFromObj(c->argv[1]);
|
||||
if (!strcasecmp(sub,"setuser") && c->argc >= 3) {
|
||||
sds username = ptrFromObj(c->argv[2]);
|
||||
sds username = szFromObj(c->argv[2]);
|
||||
/* Create a temporary user to validate and stage all changes against
|
||||
* before applying to an existing user or creating a new user. If all
|
||||
* arguments are valid the user parameters will all be applied together.
|
||||
@@ -1405,8 +1405,8 @@ void aclCommand(client *c) {
|
||||
if (u) ACLCopyUser(tempu, u);
|
||||
|
||||
for (int j = 3; j < c->argc; j++) {
|
||||
if (ACLSetUser(tempu,ptrFromObj(c->argv[j]),sdslen(ptrFromObj(c->argv[j]))) != C_OK) {
|
||||
char *errmsg = ACLSetUserStringError();
|
||||
if (ACLSetUser(tempu,szFromObj(c->argv[j]),sdslen(szFromObj(c->argv[j]))) != C_OK) {
|
||||
const char *errmsg = ACLSetUserStringError();
|
||||
addReplyErrorFormat(c,
|
||||
"Error in ACL SETUSER modifier '%s': %s",
|
||||
(char*)ptrFromObj(c->argv[j]), errmsg);
|
||||
@@ -1425,7 +1425,7 @@ void aclCommand(client *c) {
|
||||
} else if (!strcasecmp(sub,"deluser") && c->argc >= 3) {
|
||||
int deleted = 0;
|
||||
for (int j = 2; j < c->argc; j++) {
|
||||
sds username = ptrFromObj(c->argv[j]);
|
||||
sds username = szFromObj(c->argv[j]);
|
||||
if (!strcmp(username,"default")) {
|
||||
addReplyError(c,"The 'default' user cannot be removed");
|
||||
return;
|
||||
@@ -1433,7 +1433,7 @@ void aclCommand(client *c) {
|
||||
}
|
||||
|
||||
for (int j = 2; j < c->argc; j++) {
|
||||
sds username = ptrFromObj(c->argv[j]);
|
||||
sds username = szFromObj(c->argv[j]);
|
||||
user *u;
|
||||
if (raxRemove(Users,(unsigned char*)username,
|
||||
sdslen(username),
|
||||
@@ -1445,7 +1445,7 @@ void aclCommand(client *c) {
|
||||
}
|
||||
addReplyLongLong(c,deleted);
|
||||
} else if (!strcasecmp(sub,"getuser") && c->argc == 3) {
|
||||
user *u = ACLGetUserByName(ptrFromObj(c->argv[2]),sdslen(ptrFromObj(c->argv[2])));
|
||||
user *u = ACLGetUserByName(szFromObj(c->argv[2]),sdslen(szFromObj(c->argv[2])));
|
||||
if (u == NULL) {
|
||||
addReplyNull(c);
|
||||
return;
|
||||
@@ -1472,7 +1472,7 @@ void aclCommand(client *c) {
|
||||
listNode *ln;
|
||||
listRewind(u->passwords,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
sds thispass = listNodeValue(ln);
|
||||
sds thispass = (sds)listNodeValue(ln);
|
||||
addReplyBulkCBuffer(c,thispass,sdslen(thispass));
|
||||
}
|
||||
|
||||
@@ -1492,7 +1492,7 @@ void aclCommand(client *c) {
|
||||
listNode *ln;
|
||||
listRewind(u->patterns,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
sds thispat = listNodeValue(ln);
|
||||
sds thispat = (sds)listNodeValue(ln);
|
||||
addReplyBulkCBuffer(c,thispat,sdslen(thispat));
|
||||
}
|
||||
}
|
||||
@@ -1505,7 +1505,7 @@ void aclCommand(client *c) {
|
||||
raxStart(&ri,Users);
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
while(raxNext(&ri)) {
|
||||
user *u = ri.data;
|
||||
user *u = (user*)ri.data;
|
||||
if (justnames) {
|
||||
addReplyBulkCBuffer(c,u->name,sdslen(u->name));
|
||||
} else {
|
||||
@@ -1554,7 +1554,7 @@ void aclCommand(client *c) {
|
||||
addReplyBulkCString(c,ACLCommandCategories[j].name);
|
||||
setDeferredArrayLen(c,dl,j);
|
||||
} else if (!strcasecmp(sub,"cat") && c->argc == 3) {
|
||||
uint64_t cflag = ACLGetCommandCategoryFlagByName(ptrFromObj(c->argv[2]));
|
||||
uint64_t cflag = ACLGetCommandCategoryFlagByName(szFromObj(c->argv[2]));
|
||||
if (cflag == 0) {
|
||||
addReplyErrorFormat(c, "Unknown category '%s'", (char*)ptrFromObj(c->argv[2]));
|
||||
return;
|
||||
@@ -1564,7 +1564,7 @@ void aclCommand(client *c) {
|
||||
dictIterator *di = dictGetIterator(server.orig_commands);
|
||||
dictEntry *de;
|
||||
while ((de = dictNext(di)) != NULL) {
|
||||
struct redisCommand *cmd = dictGetVal(de);
|
||||
struct redisCommand *cmd = (redisCommand*)dictGetVal(de);
|
||||
if (cmd->flags & CMD_MODULE) continue;
|
||||
if (cmd->flags & cflag) {
|
||||
addReplyBulkCString(c,cmd->name);
|
||||
+9
-9
@@ -39,10 +39,10 @@ typedef struct aeApiState {
|
||||
} aeApiState;
|
||||
|
||||
static int aeApiCreate(aeEventLoop *eventLoop) {
|
||||
aeApiState *state = zmalloc(sizeof(aeApiState));
|
||||
aeApiState *state = (aeApiState*)zmalloc(sizeof(aeApiState), MALLOC_LOCAL);
|
||||
|
||||
if (!state) return -1;
|
||||
state->events = zmalloc(sizeof(struct kevent)*eventLoop->setsize, MALLOC_LOCAL);
|
||||
state->events = (struct kevent*)zmalloc(sizeof(struct kevent)*eventLoop->setsize, MALLOC_LOCAL);
|
||||
if (!state->events) {
|
||||
zfree(state);
|
||||
return -1;
|
||||
@@ -58,14 +58,14 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
|
||||
}
|
||||
|
||||
static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
|
||||
aeApiState *state = eventLoop->apidata;
|
||||
aeApiState *state = (aeApiState*)eventLoop->apidata;
|
||||
|
||||
state->events = zrealloc(state->events, sizeof(struct kevent)*setsize, MALLOC_LOCAL);
|
||||
state->events = (struct kevent*)zrealloc(state->events, sizeof(struct kevent)*setsize, MALLOC_LOCAL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aeApiFree(aeEventLoop *eventLoop) {
|
||||
aeApiState *state = eventLoop->apidata;
|
||||
aeApiState *state = (aeApiState*)eventLoop->apidata;
|
||||
|
||||
close(state->kqfd);
|
||||
zfree(state->events);
|
||||
@@ -73,7 +73,7 @@ static void aeApiFree(aeEventLoop *eventLoop) {
|
||||
}
|
||||
|
||||
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
|
||||
aeApiState *state = eventLoop->apidata;
|
||||
aeApiState *state = (aeApiState*)eventLoop->apidata;
|
||||
struct kevent ke;
|
||||
|
||||
if (mask & AE_READABLE) {
|
||||
@@ -88,7 +88,7 @@ static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
|
||||
}
|
||||
|
||||
static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
|
||||
aeApiState *state = eventLoop->apidata;
|
||||
aeApiState *state = (aeApiState*)eventLoop->apidata;
|
||||
struct kevent ke;
|
||||
|
||||
if (mask & AE_READABLE) {
|
||||
@@ -102,7 +102,7 @@ static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
|
||||
}
|
||||
|
||||
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
|
||||
aeApiState *state = eventLoop->apidata;
|
||||
aeApiState *state = (aeApiState*)eventLoop->apidata;
|
||||
int retval, numevents = 0;
|
||||
|
||||
if (tvp != NULL) {
|
||||
@@ -133,6 +133,6 @@ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
|
||||
return numevents;
|
||||
}
|
||||
|
||||
static char *aeApiName(void) {
|
||||
static const char *aeApiName(void) {
|
||||
return "kqueue";
|
||||
}
|
||||
+36
-34
@@ -83,7 +83,7 @@ unsigned long aofRewriteBufferSize(void) {
|
||||
|
||||
listRewind(server.aof_rewrite_buf_blocks,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
aofrwblock *block = listNodeValue(ln);
|
||||
aofrwblock *block = (aofrwblock*)listNodeValue(ln);
|
||||
size += block->used;
|
||||
}
|
||||
return size;
|
||||
@@ -105,7 +105,7 @@ void aofChildWriteDiffData(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
|
||||
while(1) {
|
||||
ln = listFirst(server.aof_rewrite_buf_blocks);
|
||||
block = ln ? ln->value : NULL;
|
||||
block = (aofrwblock*)(ln ? ln->value : NULL);
|
||||
if (server.aof_stop_sending_diff || !block) {
|
||||
aeDeleteFileEvent(el,server.aof_pipe_write_data_to_child,
|
||||
AE_WRITABLE);
|
||||
@@ -126,7 +126,7 @@ void aofChildWriteDiffData(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
/* Append data to the AOF rewrite buffer, allocating new blocks if needed. */
|
||||
void aofRewriteBufferAppend(unsigned char *s, unsigned long len) {
|
||||
listNode *ln = listLast(server.aof_rewrite_buf_blocks);
|
||||
aofrwblock *block = ln ? ln->value : NULL;
|
||||
aofrwblock *block = (aofrwblock*)(ln ? ln->value : NULL);
|
||||
|
||||
while(len) {
|
||||
/* If we already got at least an allocated block, try appending
|
||||
@@ -145,7 +145,7 @@ void aofRewriteBufferAppend(unsigned char *s, unsigned long len) {
|
||||
if (len) { /* First block to allocate, or need another block. */
|
||||
int numblocks;
|
||||
|
||||
block = zmalloc(sizeof(*block), MALLOC_LOCAL);
|
||||
block = (aofrwblock*)zmalloc(sizeof(*block), MALLOC_LOCAL);
|
||||
block->free = AOF_RW_BUF_BLOCK_SIZE;
|
||||
block->used = 0;
|
||||
listAddNodeTail(server.aof_rewrite_buf_blocks,block);
|
||||
@@ -180,7 +180,7 @@ ssize_t aofRewriteBufferWrite(int fd) {
|
||||
|
||||
listRewind(server.aof_rewrite_buf_blocks,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
aofrwblock *block = listNodeValue(ln);
|
||||
aofrwblock *block = (aofrwblock*)listNodeValue(ln);
|
||||
ssize_t nwritten;
|
||||
|
||||
if (block->used) {
|
||||
@@ -508,11 +508,11 @@ sds catAppendOnlyGenericCommand(sds dst, int argc, robj **argv) {
|
||||
for (j = 0; j < argc; j++) {
|
||||
o = getDecodedObject(argv[j]);
|
||||
buf[0] = '$';
|
||||
len = 1+ll2string(buf+1,sizeof(buf)-1,sdslen(ptrFromObj(o)));
|
||||
len = 1+ll2string(buf+1,sizeof(buf)-1,sdslen(szFromObj(o)));
|
||||
buf[len++] = '\r';
|
||||
buf[len++] = '\n';
|
||||
dst = sdscatlen(dst,buf,len);
|
||||
dst = sdscatlen(dst,ptrFromObj(o),sdslen(ptrFromObj(o)));
|
||||
dst = sdscatlen(dst,ptrFromObj(o),sdslen(szFromObj(o)));
|
||||
dst = sdscatlen(dst,"\r\n",2);
|
||||
decrRefCount(o);
|
||||
}
|
||||
@@ -532,7 +532,7 @@ sds catAppendOnlyExpireAtCommand(sds buf, struct redisCommand *cmd, robj *key, r
|
||||
|
||||
/* Make sure we can use strtoll */
|
||||
seconds = getDecodedObject(seconds);
|
||||
when = strtoll(ptrFromObj(seconds),NULL,10);
|
||||
when = strtoll(szFromObj(seconds),NULL,10);
|
||||
/* Convert argument into milliseconds for EXPIRE, SETEX, EXPIREAT */
|
||||
if (cmd->proc == expireCommand || cmd->proc == setexCommand ||
|
||||
cmd->proc == expireatCommand)
|
||||
@@ -589,8 +589,8 @@ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int a
|
||||
/* Translate SET [EX seconds][PX milliseconds] to SET and PEXPIREAT */
|
||||
buf = catAppendOnlyGenericCommand(buf,3,argv);
|
||||
for (i = 3; i < argc; i ++) {
|
||||
if (!strcasecmp(ptrFromObj(argv[i]), "ex")) exarg = argv[i+1];
|
||||
if (!strcasecmp(ptrFromObj(argv[i]), "px")) pxarg = argv[i+1];
|
||||
if (!strcasecmp(szFromObj(argv[i]), "ex")) exarg = argv[i+1];
|
||||
if (!strcasecmp(szFromObj(argv[i]), "px")) pxarg = argv[i+1];
|
||||
}
|
||||
serverAssert(!(exarg && pxarg));
|
||||
if (exarg)
|
||||
@@ -628,8 +628,8 @@ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int a
|
||||
|
||||
/* In Redis commands are always executed in the context of a client, so in
|
||||
* order to load the append only file we need to create a fake client. */
|
||||
struct client *createFakeClient(void) {
|
||||
struct client *c = zmalloc(sizeof(*c), MALLOC_LOCAL);
|
||||
client *createFakeClient(void) {
|
||||
client *c = (client*)zmalloc(sizeof(*c), MALLOC_LOCAL);
|
||||
|
||||
selectDb(c,0);
|
||||
c->fd = -1;
|
||||
@@ -727,7 +727,8 @@ int loadAppendOnlyFile(char *filename) {
|
||||
serverLog(LL_NOTICE,"Reading RDB preamble from AOF file...");
|
||||
if (fseek(fp,0,SEEK_SET) == -1) goto readerr;
|
||||
rioInitWithFile(&rdb,fileno(fp));
|
||||
if (rdbLoadRio(&rdb,NULL,1) != C_OK) {
|
||||
rdbSaveInfo rsi = RDB_SAVE_INFO_INIT;
|
||||
if (rdbLoadRio(&rdb,&rsi,1) != C_OK) {
|
||||
serverLog(LL_WARNING,"Error reading the RDB preamble of the AOF file, AOF loading aborted");
|
||||
goto readerr;
|
||||
} else {
|
||||
@@ -761,7 +762,7 @@ int loadAppendOnlyFile(char *filename) {
|
||||
argc = atoi(buf+1);
|
||||
if (argc < 1) goto fmterr;
|
||||
|
||||
argv = zmalloc(sizeof(robj*)*argc, MALLOC_LOCAL);
|
||||
argv = (robj**)zmalloc(sizeof(robj*)*argc, MALLOC_LOCAL);
|
||||
fakeClient->argc = argc;
|
||||
fakeClient->argv = argv;
|
||||
|
||||
@@ -789,7 +790,7 @@ int loadAppendOnlyFile(char *filename) {
|
||||
}
|
||||
|
||||
/* Command lookup */
|
||||
cmd = lookupCommand(ptrFromObj(argv[0]));
|
||||
cmd = lookupCommand(szFromObj(argv[0]));
|
||||
if (!cmd) {
|
||||
serverLog(LL_WARNING,
|
||||
"Unknown command '%s' reading the append only file",
|
||||
@@ -897,7 +898,7 @@ int rioWriteBulkObject(rio *r, robj *obj) {
|
||||
if (obj->encoding == OBJ_ENCODING_INT) {
|
||||
return rioWriteBulkLongLong(r,(long)obj->m_ptr);
|
||||
} else if (sdsEncodedObject(obj)) {
|
||||
return rioWriteBulkString(r,ptrFromObj(obj),sdslen(ptrFromObj(obj)));
|
||||
return rioWriteBulkString(r,szFromObj(obj),sdslen(szFromObj(obj)));
|
||||
} else {
|
||||
serverPanic("Unknown string encoding");
|
||||
}
|
||||
@@ -909,7 +910,7 @@ int rewriteListObject(rio *r, robj *key, robj *o) {
|
||||
long long count = 0, items = listTypeLength(o);
|
||||
|
||||
if (o->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
quicklist *list = ptrFromObj(o);
|
||||
quicklist *list = (quicklist*)ptrFromObj(o);
|
||||
quicklistIter *li = quicklistGetIterator(list, AL_START_HEAD);
|
||||
quicklistEntry entry;
|
||||
|
||||
@@ -946,7 +947,7 @@ int rewriteSetObject(rio *r, robj *key, robj *o) {
|
||||
int ii = 0;
|
||||
int64_t llval;
|
||||
|
||||
while(intsetGet(ptrFromObj(o),ii++,&llval)) {
|
||||
while(intsetGet((intset*)ptrFromObj(o),ii++,&llval)) {
|
||||
if (count == 0) {
|
||||
int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ?
|
||||
AOF_REWRITE_ITEMS_PER_CMD : items;
|
||||
@@ -960,11 +961,11 @@ int rewriteSetObject(rio *r, robj *key, robj *o) {
|
||||
items--;
|
||||
}
|
||||
} else if (o->encoding == OBJ_ENCODING_HT) {
|
||||
dictIterator *di = dictGetIterator(ptrFromObj(o));
|
||||
dictIterator *di = dictGetIterator((dict*)ptrFromObj(o));
|
||||
dictEntry *de;
|
||||
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sds ele = dictGetKey(de);
|
||||
sds ele = (sds)dictGetKey(de);
|
||||
if (count == 0) {
|
||||
int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ?
|
||||
AOF_REWRITE_ITEMS_PER_CMD : items;
|
||||
@@ -990,7 +991,7 @@ int rewriteSortedSetObject(rio *r, robj *key, robj *o) {
|
||||
long long count = 0, items = zsetLength(o);
|
||||
|
||||
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = ptrFromObj(o);
|
||||
unsigned char *zl = (unsigned char*)ptrFromObj(o);
|
||||
unsigned char *eptr, *sptr;
|
||||
unsigned char *vstr;
|
||||
unsigned int vlen;
|
||||
@@ -1025,13 +1026,13 @@ int rewriteSortedSetObject(rio *r, robj *key, robj *o) {
|
||||
items--;
|
||||
}
|
||||
} else if (o->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = ptrFromObj(o);
|
||||
zset *zs = (zset*)ptrFromObj(o);
|
||||
dictIterator *di = dictGetIterator(zs->pdict);
|
||||
dictEntry *de;
|
||||
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sds ele = dictGetKey(de);
|
||||
double *score = dictGetVal(de);
|
||||
sds ele = (sds)dictGetKey(de);
|
||||
double *score = (double*)dictGetVal(de);
|
||||
|
||||
if (count == 0) {
|
||||
int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ?
|
||||
@@ -1146,7 +1147,7 @@ int rioWriteStreamPendingEntry(rio *r, robj *key, const char *groupname, size_t
|
||||
/* Emit the commands needed to rebuild a stream object.
|
||||
* The function returns 0 on error, 1 on success. */
|
||||
int rewriteStreamObject(rio *r, robj *key, robj *o) {
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
streamIterator si;
|
||||
streamIteratorStart(&si,s,NULL,NULL,0);
|
||||
streamID id;
|
||||
@@ -1199,7 +1200,7 @@ int rewriteStreamObject(rio *r, robj *key, robj *o) {
|
||||
raxStart(&ri,s->cgroups);
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
while(raxNext(&ri)) {
|
||||
streamCG *group = ri.data;
|
||||
streamCG *group = (streamCG*)ri.data;
|
||||
/* Emit the XGROUP CREATE in order to create the group. */
|
||||
if (rioWriteBulkCount(r,'*',5) == 0) return 0;
|
||||
if (rioWriteBulkString(r,"XGROUP",6) == 0) return 0;
|
||||
@@ -1215,14 +1216,14 @@ int rewriteStreamObject(rio *r, robj *key, robj *o) {
|
||||
raxStart(&ri_cons,group->consumers);
|
||||
raxSeek(&ri_cons,"^",NULL,0);
|
||||
while(raxNext(&ri_cons)) {
|
||||
streamConsumer *consumer = ri_cons.data;
|
||||
streamConsumer *consumer = (streamConsumer*)ri_cons.data;
|
||||
/* For the current consumer, iterate all the PEL entries
|
||||
* to emit the XCLAIM protocol. */
|
||||
raxIterator ri_pel;
|
||||
raxStart(&ri_pel,consumer->pel);
|
||||
raxSeek(&ri_pel,"^",NULL,0);
|
||||
while(raxNext(&ri_pel)) {
|
||||
streamNACK *nack = ri_pel.data;
|
||||
streamNACK *nack = (streamNACK*)ri_pel.data;
|
||||
if (rioWriteStreamPendingEntry(r,key,(char*)ri.key,
|
||||
ri.key_len,consumer,
|
||||
ri_pel.key,nack) == 0)
|
||||
@@ -1246,9 +1247,9 @@ int rewriteStreamObject(rio *r, robj *key, robj *o) {
|
||||
* The function returns 0 on error, 1 on success. */
|
||||
int rewriteModuleObject(rio *r, robj *key, robj *o) {
|
||||
RedisModuleIO io;
|
||||
moduleValue *mv = ptrFromObj(o);
|
||||
moduleValue *mv = (moduleValue*)ptrFromObj(o);
|
||||
moduleType *mt = mv->type;
|
||||
moduleInitIOContext(io,mt,r);
|
||||
moduleInitIOContext(io,mt,r,key);
|
||||
mt->aof_rewrite(&io,key,mv->value);
|
||||
if (io.ctx) {
|
||||
moduleFreeContext(io.ctx);
|
||||
@@ -1295,8 +1296,8 @@ int rewriteAppendOnlyFileRio(rio *aof) {
|
||||
robj key, *o;
|
||||
long long expiretime;
|
||||
|
||||
keystr = dictGetKey(de);
|
||||
o = dictGetVal(de);
|
||||
keystr = (sds)dictGetKey(de);
|
||||
o = (robj*)dictGetVal(de);
|
||||
initStaticStringObject(key,keystr);
|
||||
|
||||
expiretime = getExpire(db,&key);
|
||||
@@ -1359,6 +1360,8 @@ int rewriteAppendOnlyFile(char *filename) {
|
||||
FILE *fp;
|
||||
char tmpfile[256];
|
||||
char byte;
|
||||
int nodata = 0;
|
||||
mstime_t start = 0;
|
||||
|
||||
/* Note that we have to use a different temp name here compared to the
|
||||
* one used by rewriteAppendOnlyFileBackground() function. */
|
||||
@@ -1396,8 +1399,7 @@ int rewriteAppendOnlyFile(char *filename) {
|
||||
* some more data in a loop as soon as there is a good chance more data
|
||||
* will come. If it looks like we are wasting time, we abort (this
|
||||
* happens after 20 ms without new data). */
|
||||
int nodata = 0;
|
||||
mstime_t start = mstime();
|
||||
start = mstime();
|
||||
while(mstime()-start < 1000 && nodata < 20) {
|
||||
if (aeWait(server.aof_pipe_read_data_from_parent, AE_READABLE, 1) <= 0)
|
||||
{
|
||||
@@ -129,7 +129,7 @@ void bioInit(void) {
|
||||
}
|
||||
|
||||
void bioCreateBackgroundJob(int type, void *arg1, void *arg2, void *arg3) {
|
||||
struct bio_job *job = zmalloc(sizeof(*job), MALLOC_LOCAL);
|
||||
struct bio_job *job = (bio_job*)zmalloc(sizeof(*job), MALLOC_LOCAL);
|
||||
|
||||
job->time = time(NULL);
|
||||
job->arg1 = arg1;
|
||||
@@ -178,7 +178,7 @@ void *bioProcessBackgroundJobs(void *arg) {
|
||||
}
|
||||
/* Pop the job from the queue. */
|
||||
ln = listFirst(bio_jobs[type]);
|
||||
job = ln->value;
|
||||
job = (bio_job*)ln->value;
|
||||
/* It is now possible to unlock the background system as we know have
|
||||
* a stand alone job structure to process.*/
|
||||
pthread_mutex_unlock(&bio_mutex[type]);
|
||||
@@ -194,11 +194,11 @@ void *bioProcessBackgroundJobs(void *arg) {
|
||||
* arg2 & arg3 -> free two dictionaries (a Redis DB).
|
||||
* only arg3 -> free the skiplist. */
|
||||
if (job->arg1)
|
||||
lazyfreeFreeObjectFromBioThread(job->arg1);
|
||||
lazyfreeFreeObjectFromBioThread((robj*)job->arg1);
|
||||
else if (job->arg2 && job->arg3)
|
||||
lazyfreeFreeDatabaseFromBioThread(job->arg2,job->arg3);
|
||||
lazyfreeFreeDatabaseFromBioThread((dict*)job->arg2,(dict*)job->arg3);
|
||||
else if (job->arg3)
|
||||
lazyfreeFreeSlotsMapFromBioThread(job->arg3);
|
||||
lazyfreeFreeSlotsMapFromBioThread((rax*)job->arg3);
|
||||
} else {
|
||||
serverPanic("Wrong job type in bioProcessBackgroundJobs().");
|
||||
}
|
||||
@@ -39,7 +39,7 @@
|
||||
* work with a input string length up to 512 MB. */
|
||||
size_t redisPopcount(void *s, long count) {
|
||||
size_t bits = 0;
|
||||
unsigned char *p = s;
|
||||
unsigned char *p = (unsigned char*)s;
|
||||
uint32_t *p4;
|
||||
static const unsigned char bitsinbyte[256] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
|
||||
|
||||
@@ -410,8 +410,8 @@ void printBits(unsigned char *p, unsigned long count) {
|
||||
* is multiplied by 'bits'. This is useful for the BITFIELD command. */
|
||||
int getBitOffsetFromArgument(client *c, robj *o, size_t *offset, int hash, int bits) {
|
||||
long long loffset;
|
||||
char *err = "bit offset is not an integer or out of range";
|
||||
char *p = ptrFromObj(o);
|
||||
const char *err = "bit offset is not an integer or out of range";
|
||||
char *p = szFromObj(o);
|
||||
size_t plen = sdslen(p);
|
||||
int usehash = 0;
|
||||
|
||||
@@ -445,8 +445,8 @@ int getBitOffsetFromArgument(client *c, robj *o, size_t *offset, int hash, int b
|
||||
*
|
||||
* On error C_ERR is returned and an error is sent to the client. */
|
||||
int getBitfieldTypeFromArgument(client *c, robj *o, int *sign, int *bits) {
|
||||
char *p = ptrFromObj(o);
|
||||
char *err = "Invalid bitfield type. Use something like i16 u8. Note that u64 is not supported but i64 is.";
|
||||
char *p = szFromObj(o);
|
||||
const char *err = "Invalid bitfield type. Use something like i16 u8. Note that u64 is not supported but i64 is.";
|
||||
long long llbits;
|
||||
|
||||
if (p[0] == 'i') {
|
||||
@@ -485,7 +485,7 @@ robj *lookupStringForBitCommand(client *c, size_t maxbit) {
|
||||
} else {
|
||||
if (checkType(c,o,OBJ_STRING)) return NULL;
|
||||
o = dbUnshareStringValue(c->db,c->argv[1],o);
|
||||
o->m_ptr = sdsgrowzero(ptrFromObj(o),byte+1);
|
||||
o->m_ptr = sdsgrowzero(szFromObj(o),byte+1);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
@@ -514,7 +514,7 @@ unsigned char *getObjectReadOnlyString(robj *o, long *len, char *llbuf) {
|
||||
if (len) *len = ll2string(llbuf,LONG_STR_SIZE,(long)ptrFromObj(o));
|
||||
} else if (o) {
|
||||
p = (unsigned char*) ptrFromObj(o);
|
||||
if (len) *len = sdslen(ptrFromObj(o));
|
||||
if (len) *len = sdslen(szFromObj(o));
|
||||
} else {
|
||||
if (len) *len = 0;
|
||||
}
|
||||
@@ -524,7 +524,7 @@ unsigned char *getObjectReadOnlyString(robj *o, long *len, char *llbuf) {
|
||||
/* SETBIT key offset bitvalue */
|
||||
void setbitCommand(client *c) {
|
||||
robj *o;
|
||||
char *err = "bit is not an integer or out of range";
|
||||
const char *err = "bit is not an integer or out of range";
|
||||
size_t bitoffset;
|
||||
ssize_t byte, bit;
|
||||
int byteval, bitval;
|
||||
@@ -577,7 +577,7 @@ void getbitCommand(client *c) {
|
||||
byte = bitoffset >> 3;
|
||||
bit = 7 - (bitoffset & 0x7);
|
||||
if (sdsEncodedObject(o)) {
|
||||
if (byte < sdslen(ptrFromObj(o)))
|
||||
if (byte < sdslen(szFromObj(o)))
|
||||
bitval = ((uint8_t*)ptrFromObj(o))[byte] & (1 << bit);
|
||||
} else {
|
||||
if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)ptrFromObj(o)))
|
||||
@@ -589,7 +589,7 @@ void getbitCommand(client *c) {
|
||||
|
||||
/* BITOP op_name target_key src_key1 src_key2 src_key3 ... src_keyN */
|
||||
void bitopCommand(client *c) {
|
||||
char *opname = ptrFromObj(c->argv[1]);
|
||||
char *opname = szFromObj(c->argv[1]);
|
||||
robj *o, *targetkey = c->argv[2];
|
||||
unsigned long op, j, numkeys;
|
||||
robj **objects; /* Array of source objects. */
|
||||
@@ -621,9 +621,9 @@ void bitopCommand(client *c) {
|
||||
|
||||
/* Lookup keys, and store pointers to the string objects into an array. */
|
||||
numkeys = c->argc - 3;
|
||||
src = zmalloc(sizeof(unsigned char*) * numkeys, MALLOC_LOCAL);
|
||||
len = zmalloc(sizeof(long) * numkeys, MALLOC_LOCAL);
|
||||
objects = zmalloc(sizeof(robj*) * numkeys, MALLOC_LOCAL);
|
||||
src = (unsigned char**)zmalloc(sizeof(unsigned char*) * numkeys, MALLOC_LOCAL);
|
||||
len = (unsigned long*)zmalloc(sizeof(long) * numkeys, MALLOC_LOCAL);
|
||||
objects = (robj**)zmalloc(sizeof(robj*) * numkeys, MALLOC_LOCAL);
|
||||
for (j = 0; j < numkeys; j++) {
|
||||
o = lookupKeyRead(c->db,c->argv[j+3]);
|
||||
/* Handle non-existing keys as empty strings. */
|
||||
@@ -647,8 +647,8 @@ void bitopCommand(client *c) {
|
||||
return;
|
||||
}
|
||||
objects[j] = getDecodedObject(o);
|
||||
src[j] = ptrFromObj(objects[j]);
|
||||
len[j] = sdslen(ptrFromObj(objects[j]));
|
||||
src[j] = (unsigned char*)ptrFromObj(objects[j]);
|
||||
len[j] = sdslen(szFromObj(objects[j]));
|
||||
if (len[j] > maxlen) maxlen = len[j];
|
||||
if (j == 0 || len[j] < minlen) minlen = len[j];
|
||||
}
|
||||
@@ -922,7 +922,7 @@ void bitfieldCommand(client *c) {
|
||||
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
int remargs = c->argc-j-1; /* Remaining args other than current. */
|
||||
char *subcmd = ptrFromObj(c->argv[j]); /* Current command name. */
|
||||
char *subcmd = szFromObj(c->argv[j]); /* Current command name. */
|
||||
int opcode; /* Current operation code. */
|
||||
long long i64 = 0; /* Signed SET value. */
|
||||
int sign = 0; /* Signed or unsigned type? */
|
||||
@@ -935,7 +935,7 @@ void bitfieldCommand(client *c) {
|
||||
else if (!strcasecmp(subcmd,"incrby") && remargs >= 3)
|
||||
opcode = BITFIELDOP_INCRBY;
|
||||
else if (!strcasecmp(subcmd,"overflow") && remargs >= 1) {
|
||||
char *owtypename = ptrFromObj(c->argv[j+1]);
|
||||
char *owtypename = szFromObj(c->argv[j+1]);
|
||||
j++;
|
||||
if (!strcasecmp(owtypename,"wrap"))
|
||||
owtype = BFOVERFLOW_WRAP;
|
||||
@@ -978,7 +978,7 @@ void bitfieldCommand(client *c) {
|
||||
}
|
||||
|
||||
/* Populate the array of operations we'll process. */
|
||||
ops = zrealloc(ops,sizeof(*ops)*(numops+1), MALLOC_SHARED);
|
||||
ops = (bitfieldOp*)zrealloc(ops,sizeof(*ops)*(numops+1), MALLOC_SHARED);
|
||||
ops[numops].offset = bitoffset;
|
||||
ops[numops].i64 = i64;
|
||||
ops[numops].opcode = opcode;
|
||||
@@ -1023,7 +1023,7 @@ void bitfieldCommand(client *c) {
|
||||
int64_t oldval, newval, wrapped, retval;
|
||||
int overflow;
|
||||
|
||||
oldval = getSignedBitfield(ptrFromObj(o),thisop->offset,
|
||||
oldval = getSignedBitfield((unsigned char*)ptrFromObj(o),thisop->offset,
|
||||
thisop->bits);
|
||||
|
||||
if (thisop->opcode == BITFIELDOP_INCRBY) {
|
||||
@@ -1044,7 +1044,7 @@ void bitfieldCommand(client *c) {
|
||||
* NULL to signal the condition. */
|
||||
if (!(overflow && thisop->owtype == BFOVERFLOW_FAIL)) {
|
||||
addReplyLongLong(c,retval);
|
||||
setSignedBitfield(ptrFromObj(o),thisop->offset,
|
||||
setSignedBitfield((unsigned char*)ptrFromObj(o),thisop->offset,
|
||||
thisop->bits,newval);
|
||||
} else {
|
||||
addReplyNull(c);
|
||||
@@ -1053,7 +1053,7 @@ void bitfieldCommand(client *c) {
|
||||
uint64_t oldval, newval, wrapped, retval;
|
||||
int overflow;
|
||||
|
||||
oldval = getUnsignedBitfield(ptrFromObj(o),thisop->offset,
|
||||
oldval = getUnsignedBitfield((unsigned char*)ptrFromObj(o),thisop->offset,
|
||||
thisop->bits);
|
||||
|
||||
if (thisop->opcode == BITFIELDOP_INCRBY) {
|
||||
@@ -1073,7 +1073,7 @@ void bitfieldCommand(client *c) {
|
||||
* NULL to signal the condition. */
|
||||
if (!(overflow && thisop->owtype == BFOVERFLOW_FAIL)) {
|
||||
addReplyLongLong(c,retval);
|
||||
setUnsignedBitfield(ptrFromObj(o),thisop->offset,
|
||||
setUnsignedBitfield((unsigned char*)ptrFromObj(o),thisop->offset,
|
||||
thisop->bits,newval);
|
||||
} else {
|
||||
addReplyNull(c);
|
||||
@@ -128,7 +128,7 @@ void processUnblockedClients(int iel) {
|
||||
while (listLength(unblocked_clients)) {
|
||||
ln = listFirst(unblocked_clients);
|
||||
serverAssert(ln != NULL);
|
||||
c = ln->value;
|
||||
c = (client*)ln->value;
|
||||
listDelNode(unblocked_clients,ln);
|
||||
AssertCorrectThread(c);
|
||||
|
||||
@@ -231,7 +231,7 @@ void disconnectAllBlockedClients(void) {
|
||||
|
||||
listRewind(server.clients,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
client *c = listNodeValue(ln);
|
||||
client *c = (client*)listNodeValue(ln);
|
||||
|
||||
fastlock_lock(&c->lock);
|
||||
if (c->flags & CLIENT_BLOCKED) {
|
||||
@@ -280,7 +280,7 @@ void handleClientsBlockedOnKeys(void) {
|
||||
|
||||
while(listLength(l) != 0) {
|
||||
listNode *ln = listFirst(l);
|
||||
readyList *rl = ln->value;
|
||||
readyList *rl = (readyList*)ln->value;
|
||||
|
||||
/* First of all remove this key from db->ready_keys so that
|
||||
* we can safely call signalKeyAsReady() against this key. */
|
||||
@@ -295,12 +295,12 @@ void handleClientsBlockedOnKeys(void) {
|
||||
* this key, from the first blocked to the last. */
|
||||
de = dictFind(rl->db->blocking_keys,rl->key);
|
||||
if (de) {
|
||||
list *clients = dictGetVal(de);
|
||||
list *clients = (list*)dictGetVal(de);
|
||||
int numclients = listLength(clients);
|
||||
|
||||
while(numclients--) {
|
||||
listNode *clientnode = listFirst(clients);
|
||||
client *receiver = clientnode->value;
|
||||
client *receiver = (client*)clientnode->value;
|
||||
|
||||
if (receiver->btype != BLOCKED_LIST) {
|
||||
/* Put at the tail, so that at the next call
|
||||
@@ -358,13 +358,13 @@ void handleClientsBlockedOnKeys(void) {
|
||||
* this key, from the first blocked to the last. */
|
||||
de = dictFind(rl->db->blocking_keys,rl->key);
|
||||
if (de) {
|
||||
list *clients = dictGetVal(de);
|
||||
list *clients = (list*)dictGetVal(de);
|
||||
int numclients = listLength(clients);
|
||||
unsigned long zcard = zsetLength(o);
|
||||
|
||||
while(numclients-- && zcard) {
|
||||
listNode *clientnode = listFirst(clients);
|
||||
client *receiver = clientnode->value;
|
||||
client *receiver = (client*)clientnode->value;
|
||||
|
||||
if (receiver->btype != BLOCKED_ZSET) {
|
||||
/* Put at the tail, so that at the next call
|
||||
@@ -402,21 +402,21 @@ void handleClientsBlockedOnKeys(void) {
|
||||
/* Serve clients blocked on stream key. */
|
||||
else if (o != NULL && o->type == OBJ_STREAM) {
|
||||
dictEntry *de = dictFind(rl->db->blocking_keys,rl->key);
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
|
||||
/* We need to provide the new data arrived on the stream
|
||||
* to all the clients that are waiting for an offset smaller
|
||||
* than the current top item. */
|
||||
if (de) {
|
||||
list *clients = dictGetVal(de);
|
||||
list *clients = (list*)dictGetVal(de);
|
||||
listNode *ln;
|
||||
listIter li;
|
||||
listRewind(clients,&li);
|
||||
|
||||
while((ln = listNext(&li))) {
|
||||
client *receiver = listNodeValue(ln);
|
||||
client *receiver = (client*)listNodeValue(ln);
|
||||
if (receiver->btype != BLOCKED_STREAM) continue;
|
||||
streamID *gt = dictFetchValue(receiver->bpop.keys,
|
||||
streamID *gt = (streamID*)dictFetchValue(receiver->bpop.keys,
|
||||
rl->key);
|
||||
|
||||
/* If we blocked in the context of a consumer
|
||||
@@ -431,7 +431,7 @@ void handleClientsBlockedOnKeys(void) {
|
||||
streamCG *group = NULL;
|
||||
if (receiver->bpop.xread_group) {
|
||||
group = streamLookupCG(s,
|
||||
ptrFromObj(receiver->bpop.xread_group));
|
||||
szFromObj(receiver->bpop.xread_group));
|
||||
/* If the group was not found, send an error
|
||||
* to the consumer. */
|
||||
if (!group) {
|
||||
@@ -457,7 +457,7 @@ void handleClientsBlockedOnKeys(void) {
|
||||
|
||||
if (group) {
|
||||
consumer = streamLookupConsumer(group,
|
||||
ptrFromObj(receiver->bpop.xread_consumer),
|
||||
szFromObj(receiver->bpop.xread_consumer),
|
||||
1);
|
||||
noack = receiver->bpop.xread_group_noack;
|
||||
}
|
||||
@@ -568,7 +568,7 @@ void blockForKeys(client *c, int btype, robj **keys, int numkeys, mstime_t timeo
|
||||
incrRefCount(keys[j]);
|
||||
serverAssertWithInfo(c,keys[j],retval == DICT_OK);
|
||||
} else {
|
||||
l = dictGetVal(de);
|
||||
l = (list*)dictGetVal(de);
|
||||
}
|
||||
listAddNodeTail(l,c);
|
||||
}
|
||||
@@ -586,10 +586,10 @@ void unblockClientWaitingData(client *c) {
|
||||
di = dictGetIterator(c->bpop.keys);
|
||||
/* The client may wait for multiple keys, so unblock it for every key. */
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
robj *key = dictGetKey(de);
|
||||
robj *key = (robj*)dictGetKey(de);
|
||||
|
||||
/* Remove this client from the list of clients waiting for this key. */
|
||||
l = dictFetchValue(c->db->blocking_keys,key);
|
||||
l = (list*)dictFetchValue(c->db->blocking_keys,key);
|
||||
serverAssertWithInfo(c,key,l != NULL);
|
||||
listDelNode(l,listSearchKey(l,c));
|
||||
/* If the list is empty we need to remove it to avoid wasting memory */
|
||||
@@ -629,7 +629,7 @@ void signalKeyAsReady(redisDb *db, robj *key) {
|
||||
if (dictFind(db->ready_keys,key) != NULL) return;
|
||||
|
||||
/* Ok, we need to queue this key into server.ready_keys. */
|
||||
rl = zmalloc(sizeof(*rl), MALLOC_SHARED);
|
||||
rl = (readyList*)zmalloc(sizeof(*rl), MALLOC_SHARED);
|
||||
rl->key = key;
|
||||
rl->db = db;
|
||||
incrRefCount(key);
|
||||
File renamed without changes.
+171
-150
@@ -77,6 +77,14 @@ uint64_t clusterGetMaxEpoch(void);
|
||||
int clusterBumpConfigEpochWithoutConsensus(void);
|
||||
void moduleCallClusterReceivers(const char *sender_id, uint64_t module_id, uint8_t type, const unsigned char *payload, uint32_t len);
|
||||
|
||||
struct redisMaster *getFirstMaster()
|
||||
{
|
||||
serverAssert(listLength(server.masters) <= 1);
|
||||
if (!listLength(server.masters))
|
||||
return NULL;
|
||||
return (redisMaster*)listFirst(server.masters)->value;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization
|
||||
* -------------------------------------------------------------------------- */
|
||||
@@ -119,7 +127,7 @@ int clusterLoadConfig(char *filename) {
|
||||
*
|
||||
* To simplify we allocate 1024+CLUSTER_SLOTS*128 bytes per line. */
|
||||
maxline = 1024+CLUSTER_SLOTS*128;
|
||||
line = zmalloc(maxline, MALLOC_LOCAL);
|
||||
line = (char*)zmalloc(maxline, MALLOC_LOCAL);
|
||||
while(fgets(line,maxline,fp) != NULL) {
|
||||
int argc;
|
||||
sds *argv;
|
||||
@@ -428,8 +436,13 @@ void clusterUpdateMyselfFlags(void) {
|
||||
|
||||
void clusterInit(void) {
|
||||
int saveconf = 0;
|
||||
if (server.enable_multimaster)
|
||||
{
|
||||
serverLog(LL_WARNING, "Clusters are not compatible with multi-master");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
server.cluster = zmalloc(sizeof(clusterState), MALLOC_LOCAL);
|
||||
server.cluster = (clusterState*)zmalloc(sizeof(clusterState), MALLOC_LOCAL);
|
||||
server.cluster->myself = NULL;
|
||||
server.cluster->currentEpoch = 0;
|
||||
server.cluster->state = CLUSTER_FAIL;
|
||||
@@ -536,7 +549,11 @@ void clusterReset(int hard) {
|
||||
/* Turn into master. */
|
||||
if (nodeIsSlave(myself)) {
|
||||
clusterSetNodeAsMaster(myself);
|
||||
replicationUnsetMaster();
|
||||
if (listLength(server.masters) > 0)
|
||||
{
|
||||
serverAssert(listLength(server.masters) == 1);
|
||||
replicationUnsetMaster((redisMaster*)listFirst(server.masters)->value);
|
||||
}
|
||||
emptyDb(-1,EMPTYDB_NO_FLAGS,NULL);
|
||||
}
|
||||
|
||||
@@ -550,7 +567,7 @@ void clusterReset(int hard) {
|
||||
/* Forget all the nodes, but myself. */
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
|
||||
if (node == myself) continue;
|
||||
clusterDelNode(node);
|
||||
@@ -587,7 +604,7 @@ void clusterReset(int hard) {
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
clusterLink *createClusterLink(clusterNode *node) {
|
||||
clusterLink *link = zmalloc(sizeof(*link), MALLOC_LOCAL);
|
||||
clusterLink *link = (clusterLink*)zmalloc(sizeof(*link), MALLOC_LOCAL);
|
||||
link->ctime = mstime();
|
||||
link->sndbuf = sdsempty();
|
||||
link->rcvbuf = sdsempty();
|
||||
@@ -623,7 +640,7 @@ void clusterAcceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
|
||||
/* If the server is starting up, don't accept cluster connections:
|
||||
* UPDATE messages may interact with the database content. */
|
||||
if (server.masterhost == NULL && server.loading) return;
|
||||
if (listLength(server.masters) == 0 && server.loading) return;
|
||||
|
||||
while(max--) {
|
||||
cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
|
||||
@@ -692,7 +709,7 @@ unsigned int keyHashSlot(char *key, int keylen) {
|
||||
* The node is created and returned to the user, but it is not automatically
|
||||
* added to the nodes hash table. */
|
||||
clusterNode *createClusterNode(char *nodename, int flags) {
|
||||
clusterNode *node = zmalloc(sizeof(*node), MALLOC_LOCAL);
|
||||
clusterNode *node = (clusterNode*)zmalloc(sizeof(*node), MALLOC_LOCAL);
|
||||
|
||||
if (nodename)
|
||||
memcpy(node->name, nodename, CLUSTER_NAMELEN);
|
||||
@@ -741,7 +758,7 @@ int clusterNodeAddFailureReport(clusterNode *failing, clusterNode *sender) {
|
||||
* the timestamp. */
|
||||
listRewind(l,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
fr = ln->value;
|
||||
fr = (clusterNodeFailReport*)ln->value;
|
||||
if (fr->node == sender) {
|
||||
fr->time = mstime();
|
||||
return 0;
|
||||
@@ -749,7 +766,7 @@ int clusterNodeAddFailureReport(clusterNode *failing, clusterNode *sender) {
|
||||
}
|
||||
|
||||
/* Otherwise create a new report. */
|
||||
fr = zmalloc(sizeof(*fr), MALLOC_LOCAL);
|
||||
fr = (clusterNodeFailReport*)zmalloc(sizeof(*fr), MALLOC_LOCAL);
|
||||
fr->node = sender;
|
||||
fr->time = mstime();
|
||||
listAddNodeTail(l,fr);
|
||||
@@ -772,7 +789,7 @@ void clusterNodeCleanupFailureReports(clusterNode *node) {
|
||||
|
||||
listRewind(l,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
fr = ln->value;
|
||||
fr = (clusterNodeFailReport*)ln->value;
|
||||
if (now - fr->time > maxtime) listDelNode(l,ln);
|
||||
}
|
||||
}
|
||||
@@ -797,7 +814,7 @@ int clusterNodeDelFailureReport(clusterNode *node, clusterNode *sender) {
|
||||
/* Search for a failure report from this sender. */
|
||||
listRewind(l,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
fr = ln->value;
|
||||
fr = (clusterNodeFailReport*)ln->value;
|
||||
if (fr->node == sender) break;
|
||||
}
|
||||
if (!ln) return 0; /* No failure report from this sender. */
|
||||
@@ -841,7 +858,7 @@ int clusterNodeAddSlave(clusterNode *master, clusterNode *slave) {
|
||||
/* If it's already a slave, don't add it again. */
|
||||
for (j = 0; j < master->numslaves; j++)
|
||||
if (master->slaves[j] == slave) return C_ERR;
|
||||
master->slaves = zrealloc(master->slaves,
|
||||
master->slaves = (clusterNode**)zrealloc(master->slaves,
|
||||
sizeof(clusterNode*)*(master->numslaves+1), MALLOC_LOCAL);
|
||||
master->slaves[master->numslaves] = slave;
|
||||
master->numslaves++;
|
||||
@@ -920,7 +937,7 @@ void clusterDelNode(clusterNode *delnode) {
|
||||
/* 2) Remove failure reports. */
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
|
||||
if (node == delnode) continue;
|
||||
clusterNodeDelFailureReport(node,delnode);
|
||||
@@ -939,7 +956,7 @@ clusterNode *clusterLookupNode(const char *name) {
|
||||
de = dictFind(server.cluster->nodes,s);
|
||||
sdsfree(s);
|
||||
if (de == NULL) return NULL;
|
||||
return dictGetVal(de);
|
||||
return (clusterNode*)dictGetVal(de);
|
||||
}
|
||||
|
||||
/* This is only used after the handshake. When we connect a given IP/PORT
|
||||
@@ -972,7 +989,7 @@ uint64_t clusterGetMaxEpoch(void) {
|
||||
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
if (node->configEpoch > max) max = node->configEpoch;
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
@@ -1260,7 +1277,7 @@ int clusterHandshakeInProgress(char *ip, int port, int cport) {
|
||||
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
|
||||
if (!nodeInHandshake(node)) continue;
|
||||
if (!strcasecmp(node->ip,ip) &&
|
||||
@@ -1493,7 +1510,11 @@ int nodeUpdateAddressIfNeeded(clusterNode *node, clusterLink *link,
|
||||
/* Check if this is our master and we have to change the
|
||||
* replication target as well. */
|
||||
if (nodeIsSlave(myself) && myself->slaveof == node)
|
||||
replicationSetMaster(node->ip, node->port);
|
||||
{
|
||||
serverAssert(listLength(server.masters) == 1);
|
||||
replicationAddMaster(node->ip, node->port);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2232,12 +2253,12 @@ void clusterBroadcastMessage(void *buf, size_t len) {
|
||||
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
|
||||
if (!node->link) continue;
|
||||
if (node->flags & (CLUSTER_NODE_MYSELF|CLUSTER_NODE_HANDSHAKE))
|
||||
continue;
|
||||
clusterSendMessage(node->link,buf,len);
|
||||
clusterSendMessage(node->link,(unsigned char*)buf,len);
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
}
|
||||
@@ -2296,7 +2317,7 @@ void clusterBuildMessageHdr(clusterMsg *hdr, int type) {
|
||||
|
||||
/* Set the replication offset. */
|
||||
if (nodeIsSlave(myself))
|
||||
offset = replicationGetSlaveOffset();
|
||||
offset = replicationGetSlaveOffset(getFirstMaster());
|
||||
else
|
||||
offset = server.master_repl_offset;
|
||||
hdr->offset = htonu64(offset);
|
||||
@@ -2401,7 +2422,7 @@ void clusterSendPing(clusterLink *link, int type) {
|
||||
/* Note: clusterBuildMessageHdr() expects the buffer to be always at least
|
||||
* sizeof(clusterMsg) or more. */
|
||||
if (totlen < (int)sizeof(clusterMsg)) totlen = sizeof(clusterMsg);
|
||||
buf = zcalloc(totlen, MALLOC_LOCAL);
|
||||
buf = (unsigned char*)zcalloc(totlen, MALLOC_LOCAL);
|
||||
hdr = (clusterMsg*) buf;
|
||||
|
||||
/* Populate the header. */
|
||||
@@ -2413,32 +2434,32 @@ void clusterSendPing(clusterLink *link, int type) {
|
||||
int maxiterations = wanted*3;
|
||||
while(freshnodes > 0 && gossipcount < wanted && maxiterations--) {
|
||||
dictEntry *de = dictGetRandomKey(server.cluster->nodes);
|
||||
clusterNode *this = dictGetVal(de);
|
||||
clusterNode *thisNode = (clusterNode*)dictGetVal(de);
|
||||
|
||||
/* Don't include this node: the whole packet header is about us
|
||||
* already, so we just gossip about other nodes. */
|
||||
if (this == myself) continue;
|
||||
if (thisNode == myself) continue;
|
||||
|
||||
/* PFAIL nodes will be added later. */
|
||||
if (this->flags & CLUSTER_NODE_PFAIL) continue;
|
||||
if (thisNode->flags & CLUSTER_NODE_PFAIL) continue;
|
||||
|
||||
/* In the gossip section don't include:
|
||||
* 1) Nodes in HANDSHAKE state.
|
||||
* 3) Nodes with the NOADDR flag set.
|
||||
* 4) Disconnected nodes if they don't have configured slots.
|
||||
*/
|
||||
if (this->flags & (CLUSTER_NODE_HANDSHAKE|CLUSTER_NODE_NOADDR) ||
|
||||
(this->link == NULL && this->numslots == 0))
|
||||
if (thisNode->flags & (CLUSTER_NODE_HANDSHAKE|CLUSTER_NODE_NOADDR) ||
|
||||
(thisNode->link == NULL && thisNode->numslots == 0))
|
||||
{
|
||||
freshnodes--; /* Tecnically not correct, but saves CPU. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Do not add a node we already have. */
|
||||
if (clusterNodeIsInGossipSection(hdr,gossipcount,this)) continue;
|
||||
if (clusterNodeIsInGossipSection(hdr,gossipcount,thisNode)) continue;
|
||||
|
||||
/* Add it */
|
||||
clusterSetGossipEntry(hdr,gossipcount,this);
|
||||
clusterSetGossipEntry(hdr,gossipcount,thisNode);
|
||||
freshnodes--;
|
||||
gossipcount++;
|
||||
}
|
||||
@@ -2450,7 +2471,7 @@ void clusterSendPing(clusterLink *link, int type) {
|
||||
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL && pfail_wanted > 0) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
if (node->flags & CLUSTER_NODE_HANDSHAKE) continue;
|
||||
if (node->flags & CLUSTER_NODE_NOADDR) continue;
|
||||
if (!(node->flags & CLUSTER_NODE_PFAIL)) continue;
|
||||
@@ -2497,7 +2518,7 @@ void clusterBroadcastPong(int target) {
|
||||
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
|
||||
if (!node->link) continue;
|
||||
if (node == myself || nodeInHandshake(node)) continue;
|
||||
@@ -2523,8 +2544,8 @@ void clusterSendPublish(clusterLink *link, robj *channel, robj *message) {
|
||||
|
||||
channel = getDecodedObject(channel);
|
||||
message = getDecodedObject(message);
|
||||
channel_len = sdslen(ptrFromObj(channel));
|
||||
message_len = sdslen(ptrFromObj(message));
|
||||
channel_len = sdslen(szFromObj(channel));
|
||||
message_len = sdslen(szFromObj(message));
|
||||
|
||||
clusterBuildMessageHdr(hdr,CLUSTERMSG_TYPE_PUBLISH);
|
||||
totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData);
|
||||
@@ -2538,13 +2559,13 @@ void clusterSendPublish(clusterLink *link, robj *channel, robj *message) {
|
||||
if (totlen < sizeof(buf)) {
|
||||
payload = buf;
|
||||
} else {
|
||||
payload = zmalloc(totlen, MALLOC_LOCAL);
|
||||
payload = (unsigned char*)zmalloc(totlen, MALLOC_LOCAL);
|
||||
memcpy(payload,hdr,sizeof(*hdr));
|
||||
hdr = (clusterMsg*) payload;
|
||||
}
|
||||
memcpy(hdr->data.publish.msg.bulk_data,ptrFromObj(channel),sdslen(ptrFromObj(channel)));
|
||||
memcpy(hdr->data.publish.msg.bulk_data+sdslen(ptrFromObj(channel)),
|
||||
ptrFromObj(message),sdslen(ptrFromObj(message)));
|
||||
memcpy(hdr->data.publish.msg.bulk_data,ptrFromObj(channel),sdslen(szFromObj(channel)));
|
||||
memcpy(hdr->data.publish.msg.bulk_data+sdslen(szFromObj(channel)),
|
||||
ptrFromObj(message),sdslen(szFromObj(message)));
|
||||
|
||||
if (link)
|
||||
clusterSendMessage(link,payload,totlen);
|
||||
@@ -2607,7 +2628,7 @@ void clusterSendModule(clusterLink *link, uint64_t module_id, uint8_t type,
|
||||
if (totlen < sizeof(buf)) {
|
||||
heapbuf = buf;
|
||||
} else {
|
||||
heapbuf = zmalloc(totlen, MALLOC_LOCAL);
|
||||
heapbuf = (unsigned char*)zmalloc(totlen, MALLOC_LOCAL);
|
||||
memcpy(heapbuf,hdr,sizeof(*hdr));
|
||||
hdr = (clusterMsg*) heapbuf;
|
||||
}
|
||||
@@ -2827,7 +2848,7 @@ int clusterGetSlaveRank(void) {
|
||||
master = myself->slaveof;
|
||||
if (master == NULL) return 0; /* Never called by slaves without master. */
|
||||
|
||||
myoffset = replicationGetSlaveOffset();
|
||||
myoffset = replicationGetSlaveOffset(getFirstMaster());
|
||||
for (j = 0; j < master->numslaves; j++)
|
||||
if (master->slaves[j] != myself &&
|
||||
!nodeCantFailover(master->slaves[j]) &&
|
||||
@@ -2858,7 +2879,7 @@ int clusterGetSlaveRank(void) {
|
||||
*
|
||||
* The function is guaranteed to be called only if 'myself' is a slave. */
|
||||
void clusterLogCantFailover(int reason) {
|
||||
char *msg;
|
||||
const char *msg;
|
||||
static time_t lastlog_time = 0;
|
||||
mstime_t nolog_fail_time = server.cluster_node_timeout + 5000;
|
||||
|
||||
@@ -2913,7 +2934,7 @@ void clusterFailoverReplaceYourMaster(void) {
|
||||
|
||||
/* 1) Turn this node into a master. */
|
||||
clusterSetNodeAsMaster(myself);
|
||||
replicationUnsetMaster();
|
||||
replicationUnsetMaster(getFirstMaster());
|
||||
|
||||
/* 2) Claim all the slots assigned to our master. */
|
||||
for (j = 0; j < CLUSTER_SLOTS; j++) {
|
||||
@@ -2985,11 +3006,11 @@ void clusterHandleSlaveFailover(void) {
|
||||
|
||||
/* Set data_age to the number of seconds we are disconnected from
|
||||
* the master. */
|
||||
if (server.repl_state == REPL_STATE_CONNECTED) {
|
||||
data_age = (mstime_t)(server.unixtime - server.master->lastinteraction)
|
||||
if (getFirstMaster()->repl_state == REPL_STATE_CONNECTED) {
|
||||
data_age = (mstime_t)(server.unixtime - getFirstMaster()->master->lastinteraction)
|
||||
* 1000;
|
||||
} else {
|
||||
data_age = (mstime_t)(server.unixtime - server.repl_down_since) * 1000;
|
||||
data_age = (mstime_t)(server.unixtime - getFirstMaster()->repl_down_since) * 1000;
|
||||
}
|
||||
|
||||
/* Remove the node timeout from the data age as it is fine that we are
|
||||
@@ -3038,7 +3059,7 @@ void clusterHandleSlaveFailover(void) {
|
||||
"(rank #%d, offset %lld).",
|
||||
server.cluster->failover_auth_time - mstime(),
|
||||
server.cluster->failover_auth_rank,
|
||||
replicationGetSlaveOffset());
|
||||
replicationGetSlaveOffset(getFirstMaster()));
|
||||
/* Now that we have a scheduled election, broadcast our offset
|
||||
* to all the other slaves so that they'll updated their offsets
|
||||
* if our offset is better. */
|
||||
@@ -3171,7 +3192,7 @@ void clusterHandleSlaveMigration(int max_slaves) {
|
||||
candidate = myself;
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
int okslaves = 0, is_orphaned = 1;
|
||||
|
||||
/* We want to migrate only if this master is working, orphaned, and
|
||||
@@ -3291,7 +3312,7 @@ void clusterHandleManualFailover(void) {
|
||||
|
||||
if (server.cluster->mf_master_offset == 0) return; /* Wait for offset... */
|
||||
|
||||
if (server.cluster->mf_master_offset == replicationGetSlaveOffset()) {
|
||||
if (server.cluster->mf_master_offset == replicationGetSlaveOffset(getFirstMaster())) {
|
||||
/* Our replication offset matches the master replication offset
|
||||
* announced after clients were paused. We can start the failover. */
|
||||
server.cluster->mf_can_start = 1;
|
||||
@@ -3365,7 +3386,7 @@ void clusterCron(void) {
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
server.cluster->stats_pfail_nodes = 0;
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
|
||||
/* Not interested in reconnecting the link with myself or nodes
|
||||
* for which we have no address. */
|
||||
@@ -3442,15 +3463,15 @@ void clusterCron(void) {
|
||||
* pong_received time. */
|
||||
for (j = 0; j < 5; j++) {
|
||||
de = dictGetRandomKey(server.cluster->nodes);
|
||||
clusterNode *this = dictGetVal(de);
|
||||
clusterNode *thisNode = (clusterNode*)dictGetVal(de);
|
||||
|
||||
/* Don't ping nodes disconnected or with a ping currently active. */
|
||||
if (this->link == NULL || this->ping_sent != 0) continue;
|
||||
if (this->flags & (CLUSTER_NODE_MYSELF|CLUSTER_NODE_HANDSHAKE))
|
||||
if (thisNode->link == NULL || thisNode->ping_sent != 0) continue;
|
||||
if (thisNode->flags & (CLUSTER_NODE_MYSELF|CLUSTER_NODE_HANDSHAKE))
|
||||
continue;
|
||||
if (min_pong_node == NULL || min_pong > this->pong_received) {
|
||||
min_pong_node = this;
|
||||
min_pong = this->pong_received;
|
||||
if (min_pong_node == NULL || min_pong > thisNode->pong_received) {
|
||||
min_pong_node = thisNode;
|
||||
min_pong = thisNode->pong_received;
|
||||
}
|
||||
}
|
||||
if (min_pong_node) {
|
||||
@@ -3470,7 +3491,7 @@ void clusterCron(void) {
|
||||
this_slaves = 0;
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
now = mstime(); /* Use an updated time at every iteration. */
|
||||
mstime_t delay;
|
||||
|
||||
@@ -3559,11 +3580,11 @@ void clusterCron(void) {
|
||||
* enable it if we know the address of our master and it appears to
|
||||
* be up. */
|
||||
if (nodeIsSlave(myself) &&
|
||||
server.masterhost == NULL &&
|
||||
listLength(server.masters) == 0 &&
|
||||
myself->slaveof &&
|
||||
nodeHasAddr(myself->slaveof))
|
||||
{
|
||||
replicationSetMaster(myself->slaveof->ip, myself->slaveof->port);
|
||||
replicationAddMaster(myself->slaveof->ip, myself->slaveof->port);
|
||||
}
|
||||
|
||||
/* Abourt a manual failover if the timeout is reached. */
|
||||
@@ -3651,7 +3672,7 @@ int clusterMastersHaveSlaves(void) {
|
||||
dictEntry *de;
|
||||
int slaves = 0;
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
|
||||
if (nodeIsSlave(node)) continue;
|
||||
slaves += node->numslaves;
|
||||
@@ -3803,7 +3824,7 @@ void clusterUpdateState(void) {
|
||||
server.cluster->size = 0;
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
|
||||
if (nodeIsMaster(node) && node->numslots) {
|
||||
server.cluster->size++;
|
||||
@@ -3943,7 +3964,7 @@ void clusterSetMaster(clusterNode *n) {
|
||||
}
|
||||
myself->slaveof = n;
|
||||
clusterNodeAddSlave(n,myself);
|
||||
replicationSetMaster(n->ip, n->port);
|
||||
replicationAddMaster(n->ip, n->port);
|
||||
resetManualFailover();
|
||||
}
|
||||
|
||||
@@ -3953,7 +3974,7 @@ void clusterSetMaster(clusterNode *n) {
|
||||
|
||||
struct redisNodeFlags {
|
||||
uint16_t flag;
|
||||
char *name;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static struct redisNodeFlags redisNodeFlagsTable[] = {
|
||||
@@ -4070,7 +4091,7 @@ sds clusterGenNodesDescription(int filter) {
|
||||
|
||||
di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
|
||||
if (node->flags & filter) continue;
|
||||
ni = clusterGenNodeDescription(node);
|
||||
@@ -4132,7 +4153,7 @@ void clusterReplyMultiBulkSlots(client *c) {
|
||||
dictEntry *de;
|
||||
dictIterator *di = dictGetSafeIterator(server.cluster->nodes);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
clusterNode *node = dictGetVal(de);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(de);
|
||||
int j = 0, start = -1;
|
||||
|
||||
/* Skip slaves (that are iterated when producing the output of their
|
||||
@@ -4194,7 +4215,7 @@ void clusterCommand(client *c) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->argc == 2 && !strcasecmp(ptrFromObj(c->argv[1]),"help")) {
|
||||
if (c->argc == 2 && !strcasecmp(szFromObj(c->argv[1]),"help")) {
|
||||
const char *help[] = {
|
||||
"ADDSLOTS <slot> [slot ...] -- Assign slots to current node.",
|
||||
"BUMPEPOCH -- Advance the cluster config epoch.",
|
||||
@@ -4221,7 +4242,7 @@ void clusterCommand(client *c) {
|
||||
NULL
|
||||
};
|
||||
addReplyHelp(c, help);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"meet") && (c->argc == 4 || c->argc == 5)) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"meet") && (c->argc == 4 || c->argc == 5)) {
|
||||
/* CLUSTER MEET <ip> <port> [cport] */
|
||||
long long port, cport;
|
||||
|
||||
@@ -4241,7 +4262,7 @@ NULL
|
||||
cport = port + CLUSTER_PORT_INCR;
|
||||
}
|
||||
|
||||
if (clusterStartHandshake(ptrFromObj(c->argv[2]),port,cport) == 0 &&
|
||||
if (clusterStartHandshake(szFromObj(c->argv[2]),port,cport) == 0 &&
|
||||
errno == EINVAL)
|
||||
{
|
||||
addReplyErrorFormat(c,"Invalid node address specified: %s:%s",
|
||||
@@ -4249,7 +4270,7 @@ NULL
|
||||
} else {
|
||||
addReply(c,shared.ok);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"nodes") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"nodes") && c->argc == 2) {
|
||||
/* CLUSTER NODES */
|
||||
robj *o;
|
||||
sds ci = clusterGenNodesDescription(0);
|
||||
@@ -4257,13 +4278,13 @@ NULL
|
||||
o = createObject(OBJ_STRING,ci);
|
||||
addReplyBulk(c,o);
|
||||
decrRefCount(o);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"myid") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"myid") && c->argc == 2) {
|
||||
/* CLUSTER MYID */
|
||||
addReplyBulkCBuffer(c,myself->name, CLUSTER_NAMELEN);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"slots") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"slots") && c->argc == 2) {
|
||||
/* CLUSTER SLOTS */
|
||||
clusterReplyMultiBulkSlots(c);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"flushslots") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"flushslots") && c->argc == 2) {
|
||||
/* CLUSTER FLUSHSLOTS */
|
||||
if (dictSize(server.db[0].pdict) != 0) {
|
||||
addReplyError(c,"DB must be empty to perform CLUSTER FLUSHSLOTS.");
|
||||
@@ -4272,14 +4293,14 @@ NULL
|
||||
clusterDelNodeSlots(myself);
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG);
|
||||
addReply(c,shared.ok);
|
||||
} else if ((!strcasecmp(ptrFromObj(c->argv[1]),"addslots") ||
|
||||
!strcasecmp(ptrFromObj(c->argv[1]),"delslots")) && c->argc >= 3)
|
||||
} else if ((!strcasecmp(szFromObj(c->argv[1]),"addslots") ||
|
||||
!strcasecmp(szFromObj(c->argv[1]),"delslots")) && c->argc >= 3)
|
||||
{
|
||||
/* CLUSTER ADDSLOTS <slot> [slot] ... */
|
||||
/* CLUSTER DELSLOTS <slot> [slot] ... */
|
||||
int j, slot;
|
||||
unsigned char *slots = zmalloc(CLUSTER_SLOTS, MALLOC_LOCAL);
|
||||
int del = !strcasecmp(ptrFromObj(c->argv[1]),"delslots");
|
||||
unsigned char *slots = (unsigned char*)zmalloc(CLUSTER_SLOTS, MALLOC_LOCAL);
|
||||
int del = !strcasecmp(szFromObj(c->argv[1]),"delslots");
|
||||
|
||||
memset(slots,0,CLUSTER_SLOTS);
|
||||
/* Check that all the arguments are parseable and that all the
|
||||
@@ -4322,7 +4343,7 @@ NULL
|
||||
zfree(slots);
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG);
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"setslot") && c->argc >= 4) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"setslot") && c->argc >= 4) {
|
||||
/* SETSLOT 10 MIGRATING <node ID> */
|
||||
/* SETSLOT 10 IMPORTING <node ID> */
|
||||
/* SETSLOT 10 STABLE */
|
||||
@@ -4337,36 +4358,36 @@ NULL
|
||||
|
||||
if ((slot = getSlotOrReply(c,c->argv[2])) == -1) return;
|
||||
|
||||
if (!strcasecmp(ptrFromObj(c->argv[3]),"migrating") && c->argc == 5) {
|
||||
if (!strcasecmp(szFromObj(c->argv[3]),"migrating") && c->argc == 5) {
|
||||
if (server.cluster->slots[slot] != myself) {
|
||||
addReplyErrorFormat(c,"I'm not the owner of hash slot %u",slot);
|
||||
return;
|
||||
}
|
||||
if ((n = clusterLookupNode(ptrFromObj(c->argv[4]))) == NULL) {
|
||||
if ((n = clusterLookupNode(szFromObj(c->argv[4]))) == NULL) {
|
||||
addReplyErrorFormat(c,"I don't know about node %s",
|
||||
(char*)ptrFromObj(c->argv[4]));
|
||||
return;
|
||||
}
|
||||
server.cluster->migrating_slots_to[slot] = n;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[3]),"importing") && c->argc == 5) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[3]),"importing") && c->argc == 5) {
|
||||
if (server.cluster->slots[slot] == myself) {
|
||||
addReplyErrorFormat(c,
|
||||
"I'm already the owner of hash slot %u",slot);
|
||||
return;
|
||||
}
|
||||
if ((n = clusterLookupNode(ptrFromObj(c->argv[4]))) == NULL) {
|
||||
if ((n = clusterLookupNode(szFromObj(c->argv[4]))) == NULL) {
|
||||
addReplyErrorFormat(c,"I don't know about node %s",
|
||||
(char*)ptrFromObj(c->argv[4]));
|
||||
return;
|
||||
}
|
||||
server.cluster->importing_slots_from[slot] = n;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[3]),"stable") && c->argc == 4) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[3]),"stable") && c->argc == 4) {
|
||||
/* CLUSTER SETSLOT <SLOT> STABLE */
|
||||
server.cluster->importing_slots_from[slot] = NULL;
|
||||
server.cluster->migrating_slots_to[slot] = NULL;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[3]),"node") && c->argc == 5) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[3]),"node") && c->argc == 5) {
|
||||
/* CLUSTER SETSLOT <SLOT> NODE <NODE ID> */
|
||||
clusterNode *n = clusterLookupNode(ptrFromObj(c->argv[4]));
|
||||
clusterNode *n = clusterLookupNode(szFromObj(c->argv[4]));
|
||||
|
||||
if (!n) {
|
||||
addReplyErrorFormat(c,"Unknown node %s",
|
||||
@@ -4419,16 +4440,16 @@ NULL
|
||||
}
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG|CLUSTER_TODO_UPDATE_STATE);
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"bumpepoch") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"bumpepoch") && c->argc == 2) {
|
||||
/* CLUSTER BUMPEPOCH */
|
||||
int retval = clusterBumpConfigEpochWithoutConsensus();
|
||||
sds reply = sdscatprintf(sdsempty(),"+%s %llu\r\n",
|
||||
(retval == C_OK) ? "BUMPED" : "STILL",
|
||||
(unsigned long long) myself->configEpoch);
|
||||
addReplySds(c,reply);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"info") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"info") && c->argc == 2) {
|
||||
/* CLUSTER INFO */
|
||||
char *statestr[] = {"ok","fail","needhelp"};
|
||||
const char *statestr[] = {"ok","fail","needhelp"};
|
||||
int slots_assigned = 0, slots_ok = 0, slots_pfail = 0, slots_fail = 0;
|
||||
uint64_t myepoch;
|
||||
int j;
|
||||
@@ -4502,7 +4523,7 @@ NULL
|
||||
(unsigned long)sdslen(info)));
|
||||
addReplySds(c,info);
|
||||
addReply(c,shared.crlf);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"saveconfig") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"saveconfig") && c->argc == 2) {
|
||||
int retval = clusterSaveConfig(1);
|
||||
|
||||
if (retval == 0)
|
||||
@@ -4510,12 +4531,12 @@ NULL
|
||||
else
|
||||
addReplyErrorFormat(c,"error saving the cluster node config: %s",
|
||||
strerror(errno));
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"keyslot") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"keyslot") && c->argc == 3) {
|
||||
/* CLUSTER KEYSLOT <key> */
|
||||
sds key = ptrFromObj(c->argv[2]);
|
||||
sds key = szFromObj(c->argv[2]);
|
||||
|
||||
addReplyLongLong(c,keyHashSlot(key,sdslen(key)));
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"countkeysinslot") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"countkeysinslot") && c->argc == 3) {
|
||||
/* CLUSTER COUNTKEYSINSLOT <slot> */
|
||||
long long slot;
|
||||
|
||||
@@ -4526,7 +4547,7 @@ NULL
|
||||
return;
|
||||
}
|
||||
addReplyLongLong(c,countKeysInSlot(slot));
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"getkeysinslot") && c->argc == 4) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"getkeysinslot") && c->argc == 4) {
|
||||
/* CLUSTER GETKEYSINSLOT <slot> <count> */
|
||||
long long maxkeys, slot;
|
||||
unsigned int numkeys, j;
|
||||
@@ -4547,7 +4568,7 @@ NULL
|
||||
unsigned int keys_in_slot = countKeysInSlot(slot);
|
||||
if (maxkeys > keys_in_slot) maxkeys = keys_in_slot;
|
||||
|
||||
keys = zmalloc(sizeof(robj*)*maxkeys, MALLOC_LOCAL);
|
||||
keys = (robj**)zmalloc(sizeof(robj*)*maxkeys, MALLOC_LOCAL);
|
||||
numkeys = getKeysInSlot(slot, keys, maxkeys);
|
||||
addReplyArrayLen(c,numkeys);
|
||||
for (j = 0; j < numkeys; j++) {
|
||||
@@ -4555,9 +4576,9 @@ NULL
|
||||
decrRefCount(keys[j]);
|
||||
}
|
||||
zfree(keys);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"forget") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"forget") && c->argc == 3) {
|
||||
/* CLUSTER FORGET <NODE ID> */
|
||||
clusterNode *n = clusterLookupNode(ptrFromObj(c->argv[2]));
|
||||
clusterNode *n = clusterLookupNode(szFromObj(c->argv[2]));
|
||||
|
||||
if (!n) {
|
||||
addReplyErrorFormat(c,"Unknown node %s", (char*)ptrFromObj(c->argv[2]));
|
||||
@@ -4574,9 +4595,9 @@ NULL
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|
|
||||
CLUSTER_TODO_SAVE_CONFIG);
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"replicate") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"replicate") && c->argc == 3) {
|
||||
/* CLUSTER REPLICATE <NODE ID> */
|
||||
clusterNode *n = clusterLookupNode(ptrFromObj(c->argv[2]));
|
||||
clusterNode *n = clusterLookupNode(szFromObj(c->argv[2]));
|
||||
|
||||
/* Lookup the specified node in our table. */
|
||||
if (!n) {
|
||||
@@ -4611,10 +4632,10 @@ NULL
|
||||
clusterSetMaster(n);
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG);
|
||||
addReply(c,shared.ok);
|
||||
} else if ((!strcasecmp(ptrFromObj(c->argv[1]),"slaves") ||
|
||||
!strcasecmp(ptrFromObj(c->argv[1]),"replicas")) && c->argc == 3) {
|
||||
} else if ((!strcasecmp(szFromObj(c->argv[1]),"slaves") ||
|
||||
!strcasecmp(szFromObj(c->argv[1]),"replicas")) && c->argc == 3) {
|
||||
/* CLUSTER SLAVES <NODE ID> */
|
||||
clusterNode *n = clusterLookupNode(ptrFromObj(c->argv[2]));
|
||||
clusterNode *n = clusterLookupNode(szFromObj(c->argv[2]));
|
||||
int j;
|
||||
|
||||
/* Lookup the specified node in our table. */
|
||||
@@ -4634,11 +4655,11 @@ NULL
|
||||
addReplyBulkCString(c,ni);
|
||||
sdsfree(ni);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"count-failure-reports") &&
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"count-failure-reports") &&
|
||||
c->argc == 3)
|
||||
{
|
||||
/* CLUSTER COUNT-FAILURE-REPORTS <NODE ID> */
|
||||
clusterNode *n = clusterLookupNode(ptrFromObj(c->argv[2]));
|
||||
clusterNode *n = clusterLookupNode(szFromObj(c->argv[2]));
|
||||
|
||||
if (!n) {
|
||||
addReplyErrorFormat(c,"Unknown node %s", (char*)ptrFromObj(c->argv[2]));
|
||||
@@ -4646,16 +4667,16 @@ NULL
|
||||
} else {
|
||||
addReplyLongLong(c,clusterNodeFailureReportsCount(n));
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"failover") &&
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"failover") &&
|
||||
(c->argc == 2 || c->argc == 3))
|
||||
{
|
||||
/* CLUSTER FAILOVER [FORCE|TAKEOVER] */
|
||||
int force = 0, takeover = 0;
|
||||
|
||||
if (c->argc == 3) {
|
||||
if (!strcasecmp(ptrFromObj(c->argv[2]),"force")) {
|
||||
if (!strcasecmp(szFromObj(c->argv[2]),"force")) {
|
||||
force = 1;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[2]),"takeover")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[2]),"takeover")) {
|
||||
takeover = 1;
|
||||
force = 1; /* Takeover also implies force. */
|
||||
} else {
|
||||
@@ -4701,7 +4722,7 @@ NULL
|
||||
clusterSendMFStart(myself->slaveof);
|
||||
}
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"set-config-epoch") && c->argc == 3)
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"set-config-epoch") && c->argc == 3)
|
||||
{
|
||||
/* CLUSTER SET-CONFIG-EPOCH <epoch>
|
||||
*
|
||||
@@ -4737,7 +4758,7 @@ NULL
|
||||
CLUSTER_TODO_SAVE_CONFIG);
|
||||
addReply(c,shared.ok);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"reset") &&
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"reset") &&
|
||||
(c->argc == 2 || c->argc == 3))
|
||||
{
|
||||
/* CLUSTER RESET [SOFT|HARD] */
|
||||
@@ -4745,9 +4766,9 @@ NULL
|
||||
|
||||
/* Parse soft/hard argument. Default is soft. */
|
||||
if (c->argc == 3) {
|
||||
if (!strcasecmp(ptrFromObj(c->argv[2]),"hard")) {
|
||||
if (!strcasecmp(szFromObj(c->argv[2]),"hard")) {
|
||||
hard = 1;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[2]),"soft")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[2]),"soft")) {
|
||||
hard = 0;
|
||||
} else {
|
||||
addReply(c,shared.syntaxerr);
|
||||
@@ -4776,7 +4797,7 @@ NULL
|
||||
|
||||
/* Generates a DUMP-format representation of the object 'o', adding it to the
|
||||
* io stream pointed by 'rio'. This function can't fail. */
|
||||
void createDumpPayload(rio *payload, robj *o) {
|
||||
void createDumpPayload(rio *payload, robj *o, robj *key) {
|
||||
unsigned char buf[2];
|
||||
uint64_t crc;
|
||||
|
||||
@@ -4784,7 +4805,7 @@ void createDumpPayload(rio *payload, robj *o) {
|
||||
* byte followed by the serialized object. This is understood by RESTORE. */
|
||||
rioInitWithBuffer(payload,sdsempty());
|
||||
serverAssert(rdbSaveObjectType(payload,o));
|
||||
serverAssert(rdbSaveObject(payload,o));
|
||||
serverAssert(rdbSaveObject(payload,o,key));
|
||||
|
||||
/* Write the footer, this is how it looks like:
|
||||
* ----------------+---------------------+---------------+
|
||||
@@ -4842,7 +4863,7 @@ void dumpCommand(client *c) {
|
||||
}
|
||||
|
||||
/* Create the DUMP encoded representation. */
|
||||
createDumpPayload(&payload,o);
|
||||
createDumpPayload(&payload,o,c->argv[1]);
|
||||
|
||||
/* Transfer to the client */
|
||||
dumpobj = createObject(OBJ_STRING,payload.io.buffer.ptr);
|
||||
@@ -4861,11 +4882,11 @@ void restoreCommand(client *c) {
|
||||
/* Parse additional options */
|
||||
for (j = 4; j < c->argc; j++) {
|
||||
int additional = c->argc-j-1;
|
||||
if (!strcasecmp(ptrFromObj(c->argv[j]),"replace")) {
|
||||
if (!strcasecmp(szFromObj(c->argv[j]),"replace")) {
|
||||
replace = 1;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"absttl")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"absttl")) {
|
||||
absttl = 1;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"idletime") && additional >= 1 &&
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"idletime") && additional >= 1 &&
|
||||
lfu_freq == -1)
|
||||
{
|
||||
if (getLongLongFromObjectOrReply(c,c->argv[j+1],&lru_idle,NULL)
|
||||
@@ -4876,7 +4897,7 @@ void restoreCommand(client *c) {
|
||||
}
|
||||
lru_clock = LRU_CLOCK();
|
||||
j++; /* Consume additional arg. */
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"freq") && additional >= 1 &&
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"freq") && additional >= 1 &&
|
||||
lru_idle == -1)
|
||||
{
|
||||
if (getLongLongFromObjectOrReply(c,c->argv[j+1],&lfu_freq,NULL)
|
||||
@@ -4907,15 +4928,15 @@ void restoreCommand(client *c) {
|
||||
}
|
||||
|
||||
/* Verify RDB version and data checksum. */
|
||||
if (verifyDumpPayload(ptrFromObj(c->argv[3]),sdslen(ptrFromObj(c->argv[3]))) == C_ERR)
|
||||
if (verifyDumpPayload((unsigned char*)ptrFromObj(c->argv[3]),sdslen(szFromObj(c->argv[3]))) == C_ERR)
|
||||
{
|
||||
addReplyError(c,"DUMP payload version or checksum are wrong");
|
||||
return;
|
||||
}
|
||||
|
||||
rioInitWithBuffer(&payload,ptrFromObj(c->argv[3]));
|
||||
rioInitWithBuffer(&payload,szFromObj(c->argv[3]));
|
||||
if (((type = rdbLoadObjectType(&payload)) == -1) ||
|
||||
((obj = rdbLoadObject(type,&payload)) == NULL))
|
||||
((obj = rdbLoadObject(type,&payload,c->argv[1])) == NULL))
|
||||
{
|
||||
addReplyError(c,"Bad data format");
|
||||
return;
|
||||
@@ -4968,10 +4989,10 @@ migrateCachedSocket* migrateGetSocket(client *c, robj *host, robj *port, long ti
|
||||
migrateCachedSocket *cs;
|
||||
|
||||
/* Check if we have an already cached socket for this ip:port pair. */
|
||||
name = sdscatlen(name,ptrFromObj(host),sdslen(ptrFromObj(host)));
|
||||
name = sdscatlen(name,ptrFromObj(host),sdslen(szFromObj(host)));
|
||||
name = sdscatlen(name,":",1);
|
||||
name = sdscatlen(name,ptrFromObj(port),sdslen(ptrFromObj(port)));
|
||||
cs = dictFetchValue(server.migrate_cached_sockets,name);
|
||||
name = sdscatlen(name,ptrFromObj(port),sdslen(szFromObj(port)));
|
||||
cs = (migrateCachedSocket*)dictFetchValue(server.migrate_cached_sockets,name);
|
||||
if (cs) {
|
||||
sdsfree(name);
|
||||
cs->last_use_time = server.unixtime;
|
||||
@@ -4982,15 +5003,15 @@ migrateCachedSocket* migrateGetSocket(client *c, robj *host, robj *port, long ti
|
||||
if (dictSize(server.migrate_cached_sockets) == MIGRATE_SOCKET_CACHE_ITEMS) {
|
||||
/* Too many items, drop one at random. */
|
||||
dictEntry *de = dictGetRandomKey(server.migrate_cached_sockets);
|
||||
cs = dictGetVal(de);
|
||||
cs = (migrateCachedSocket*)dictGetVal(de);
|
||||
close(cs->fd);
|
||||
zfree(cs);
|
||||
dictDelete(server.migrate_cached_sockets,dictGetKey(de));
|
||||
}
|
||||
|
||||
/* Create the socket */
|
||||
fd = anetTcpNonBlockConnect(server.neterr,ptrFromObj(c->argv[1]),
|
||||
atoi(ptrFromObj(c->argv[2])));
|
||||
fd = anetTcpNonBlockConnect(server.neterr,szFromObj(c->argv[1]),
|
||||
atoi(szFromObj(c->argv[2])));
|
||||
if (fd == -1) {
|
||||
sdsfree(name);
|
||||
addReplyErrorFormat(c,"Can't connect to target node: %s",
|
||||
@@ -5009,7 +5030,7 @@ migrateCachedSocket* migrateGetSocket(client *c, robj *host, robj *port, long ti
|
||||
}
|
||||
|
||||
/* Add to the cache and return it to the caller. */
|
||||
cs = zmalloc(sizeof(*cs), MALLOC_LOCAL);
|
||||
cs = (migrateCachedSocket*)zmalloc(sizeof(*cs), MALLOC_LOCAL);
|
||||
cs->fd = fd;
|
||||
cs->last_dbid = -1;
|
||||
cs->last_use_time = server.unixtime;
|
||||
@@ -5022,10 +5043,10 @@ void migrateCloseSocket(robj *host, robj *port) {
|
||||
sds name = sdsempty();
|
||||
migrateCachedSocket *cs;
|
||||
|
||||
name = sdscatlen(name,ptrFromObj(host),sdslen(ptrFromObj(host)));
|
||||
name = sdscatlen(name,ptrFromObj(host),sdslen(szFromObj(host)));
|
||||
name = sdscatlen(name,":",1);
|
||||
name = sdscatlen(name,ptrFromObj(port),sdslen(ptrFromObj(port)));
|
||||
cs = dictFetchValue(server.migrate_cached_sockets,name);
|
||||
name = sdscatlen(name,ptrFromObj(port),sdslen(szFromObj(port)));
|
||||
cs = (migrateCachedSocket*)dictFetchValue(server.migrate_cached_sockets,name);
|
||||
if (!cs) {
|
||||
sdsfree(name);
|
||||
return;
|
||||
@@ -5042,7 +5063,7 @@ void migrateCloseTimedoutSockets(void) {
|
||||
dictEntry *de;
|
||||
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
migrateCachedSocket *cs = dictGetVal(de);
|
||||
migrateCachedSocket *cs = (migrateCachedSocket*)dictGetVal(de);
|
||||
|
||||
if ((server.unixtime - cs->last_use_time) > MIGRATE_SOCKET_CACHE_TTL) {
|
||||
close(cs->fd);
|
||||
@@ -5080,19 +5101,19 @@ void migrateCommand(client *c) {
|
||||
/* Parse additional options */
|
||||
for (j = 6; j < c->argc; j++) {
|
||||
int moreargs = j < c->argc-1;
|
||||
if (!strcasecmp(ptrFromObj(c->argv[j]),"copy")) {
|
||||
if (!strcasecmp(szFromObj(c->argv[j]),"copy")) {
|
||||
copy = 1;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"replace")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"replace")) {
|
||||
replace = 1;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"auth")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"auth")) {
|
||||
if (!moreargs) {
|
||||
addReply(c,shared.syntaxerr);
|
||||
return;
|
||||
}
|
||||
j++;
|
||||
password = ptrFromObj(c->argv[j]);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"keys")) {
|
||||
if (sdslen(ptrFromObj(c->argv[3])) != 0) {
|
||||
password = szFromObj(c->argv[j]);
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"keys")) {
|
||||
if (sdslen(szFromObj(c->argv[3])) != 0) {
|
||||
addReplyError(c,
|
||||
"When using MIGRATE KEYS option, the key argument"
|
||||
" must be set to the empty string");
|
||||
@@ -5120,8 +5141,8 @@ void migrateCommand(client *c) {
|
||||
* the caller there was nothing to migrate. We don't return an error in
|
||||
* this case, since often this is due to a normal condition like the key
|
||||
* expiring in the meantime. */
|
||||
ov = zrealloc(ov,sizeof(robj*)*num_keys, MALLOC_LOCAL);
|
||||
kv = zrealloc(kv,sizeof(robj*)*num_keys, MALLOC_LOCAL);
|
||||
ov = (robj**)zrealloc(ov,sizeof(robj*)*num_keys, MALLOC_LOCAL);
|
||||
kv = (robj**)zrealloc(kv,sizeof(robj*)*num_keys, MALLOC_LOCAL);
|
||||
int oi = 0;
|
||||
|
||||
for (j = 0; j < num_keys; j++) {
|
||||
@@ -5197,13 +5218,13 @@ try_again:
|
||||
else
|
||||
serverAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,"RESTORE",7));
|
||||
serverAssertWithInfo(c,NULL,sdsEncodedObject(kv[j]));
|
||||
serverAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,ptrFromObj(kv[j]),
|
||||
sdslen(ptrFromObj(kv[j]))));
|
||||
serverAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,szFromObj(kv[j]),
|
||||
sdslen(szFromObj(kv[j]))));
|
||||
serverAssertWithInfo(c,NULL,rioWriteBulkLongLong(&cmd,ttl));
|
||||
|
||||
/* Emit the payload argument, that is the serialized object using
|
||||
* the DUMP format. */
|
||||
createDumpPayload(&payload,ov[j]);
|
||||
createDumpPayload(&payload,ov[j],kv[j]);
|
||||
serverAssertWithInfo(c,NULL,
|
||||
rioWriteBulkString(&cmd,payload.io.buffer.ptr,
|
||||
sdslen(payload.io.buffer.ptr)));
|
||||
@@ -5218,6 +5239,13 @@ try_again:
|
||||
/* Fix the actual number of keys we are migrating. */
|
||||
num_keys = non_expired;
|
||||
|
||||
char buf0[1024]; /* Auth reply. */
|
||||
char buf1[1024]; /* Select reply. */
|
||||
char buf2[1024]; /* Restore reply. */
|
||||
int error_from_target = 0;
|
||||
int socket_error = 0;
|
||||
int del_idx = 1; /* Index of the key argument for the replicated DEL op. */
|
||||
|
||||
/* Transfer the query to the other node in 64K chunks. */
|
||||
errno = 0;
|
||||
{
|
||||
@@ -5236,9 +5264,6 @@ try_again:
|
||||
}
|
||||
}
|
||||
|
||||
char buf0[1024]; /* Auth reply. */
|
||||
char buf1[1024]; /* Select reply. */
|
||||
char buf2[1024]; /* Restore reply. */
|
||||
|
||||
/* Read the AUTH reply if needed. */
|
||||
if (password && syncReadLine(cs->fd, buf0, sizeof(buf0), timeout) <= 0)
|
||||
@@ -5248,17 +5273,13 @@ try_again:
|
||||
if (select && syncReadLine(cs->fd, buf1, sizeof(buf1), timeout) <= 0)
|
||||
goto socket_err;
|
||||
|
||||
/* Read the RESTORE replies. */
|
||||
int error_from_target = 0;
|
||||
int socket_error = 0;
|
||||
int del_idx = 1; /* Index of the key argument for the replicated DEL op. */
|
||||
|
||||
/* Allocate the new argument vector that will replace the current command,
|
||||
* to propagate the MIGRATE as a DEL command (if no COPY option was given).
|
||||
* We allocate num_keys+1 because the additional argument is for "DEL"
|
||||
* command name itself. */
|
||||
if (!copy) newargv = zmalloc(sizeof(robj*)*(num_keys+1), MALLOC_LOCAL);
|
||||
if (!copy) newargv = (robj**)zmalloc(sizeof(robj*)*(num_keys+1), MALLOC_LOCAL);
|
||||
|
||||
/* Read the RESTORE replies. */
|
||||
for (j = 0; j < num_keys; j++) {
|
||||
if (syncReadLine(cs->fd, buf2, sizeof(buf2), timeout) <= 0) {
|
||||
socket_error = 1;
|
||||
@@ -5510,7 +5531,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
|
||||
for (j = 0; j < numkeys; j++) {
|
||||
robj *thiskey = margv[keyindex[j]];
|
||||
int thisslot = keyHashSlot((char*)ptrFromObj(thiskey),
|
||||
sdslen(ptrFromObj(thiskey)));
|
||||
sdslen(szFromObj(thiskey)));
|
||||
|
||||
if (firstkey == NULL) {
|
||||
/* This is the first key we see. Check what is the slot
|
||||
@@ -5690,8 +5711,8 @@ int clusterRedirectBlockedClientIfNeeded(client *c) {
|
||||
/* All keys must belong to the same slot, so check first key only. */
|
||||
di = dictGetIterator(c->bpop.keys);
|
||||
if ((de = dictNext(di)) != NULL) {
|
||||
robj *key = dictGetKey(de);
|
||||
int slot = keyHashSlot((char*)ptrFromObj(key), sdslen(ptrFromObj(key)));
|
||||
robj *key = (robj*)dictGetKey(de);
|
||||
int slot = keyHashSlot((char*)ptrFromObj(key), sdslen(szFromObj(key)));
|
||||
clusterNode *node = server.cluster->slots[slot];
|
||||
|
||||
/* We send an error and unblock the client if:
|
||||
+129
-103
@@ -143,7 +143,7 @@ int yesnotoi(char *s) {
|
||||
}
|
||||
|
||||
void appendServerSaveParams(time_t seconds, int changes) {
|
||||
server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1), MALLOC_LOCAL);
|
||||
server.saveparams = (saveparam*)zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1), MALLOC_LOCAL);
|
||||
server.saveparams[server.saveparamslen].seconds = seconds;
|
||||
server.saveparams[server.saveparamslen].changes = changes;
|
||||
server.saveparamslen++;
|
||||
@@ -159,8 +159,8 @@ void queueLoadModule(sds path, sds *argv, int argc) {
|
||||
int i;
|
||||
struct moduleLoadQueueEntry *loadmod;
|
||||
|
||||
loadmod = zmalloc(sizeof(struct moduleLoadQueueEntry), MALLOC_LOCAL);
|
||||
loadmod->argv = zmalloc(sizeof(robj*)*argc, MALLOC_LOCAL);
|
||||
loadmod = (moduleLoadQueueEntry*)zmalloc(sizeof(struct moduleLoadQueueEntry), MALLOC_LOCAL);
|
||||
loadmod->argv = (robj**)zmalloc(sizeof(robj*)*argc, MALLOC_LOCAL);
|
||||
loadmod->path = sdsnew(path);
|
||||
loadmod->argc = argc;
|
||||
for (i = 0; i < argc; i++) {
|
||||
@@ -170,7 +170,7 @@ void queueLoadModule(sds path, sds *argv, int argc) {
|
||||
}
|
||||
|
||||
void loadServerConfigFromString(char *config) {
|
||||
char *err = NULL;
|
||||
const char *err = NULL;
|
||||
int linenum = 0, totlines, i;
|
||||
int slaveof_linenum = 0;
|
||||
sds *lines;
|
||||
@@ -216,10 +216,6 @@ void loadServerConfigFromString(char *config) {
|
||||
if ((server.protected_mode = yesnotoi(argv[1])) == -1) {
|
||||
err = "argument must be 'yes' or 'no'"; goto loaderr;
|
||||
}
|
||||
} else if (!strcasecmp(argv[0],"gopher-enabled") && argc == 2) {
|
||||
if ((server.gopher_enabled = yesnotoi(argv[1])) == -1) {
|
||||
err = "argument must be 'yes' or 'no'"; goto loaderr;
|
||||
}
|
||||
} else if (!strcasecmp(argv[0],"port") && argc == 2) {
|
||||
server.port = atoi(argv[1]);
|
||||
if (server.port < 0 || server.port > 65535) {
|
||||
@@ -354,9 +350,7 @@ void loadServerConfigFromString(char *config) {
|
||||
} else if ((!strcasecmp(argv[0],"slaveof") ||
|
||||
!strcasecmp(argv[0],"replicaof")) && argc == 3) {
|
||||
slaveof_linenum = linenum;
|
||||
server.masterhost = sdsnew(argv[1]);
|
||||
server.masterport = atoi(argv[2]);
|
||||
server.repl_state = REPL_STATE_CONNECT;
|
||||
replicationAddMaster(sdsnew(argv[1]), atoi(argv[2]));
|
||||
} else if ((!strcasecmp(argv[0],"repl-ping-slave-period") ||
|
||||
!strcasecmp(argv[0],"repl-ping-replica-period")) &&
|
||||
argc == 2)
|
||||
@@ -400,11 +394,11 @@ void loadServerConfigFromString(char *config) {
|
||||
goto loaderr;
|
||||
}
|
||||
} else if (!strcasecmp(argv[0],"masteruser") && argc == 2) {
|
||||
zfree(server.masteruser);
|
||||
server.masteruser = argv[1][0] ? zstrdup(argv[1]) : NULL;
|
||||
zfree(server.default_masteruser);
|
||||
server.default_masteruser = argv[1][0] ? zstrdup(argv[1]) : NULL;
|
||||
} else if (!strcasecmp(argv[0],"masterauth") && argc == 2) {
|
||||
zfree(server.masterauth);
|
||||
server.masterauth = argv[1][0] ? zstrdup(argv[1]) : NULL;
|
||||
zfree(server.default_masterauth);
|
||||
server.default_masterauth = argv[1][0] ? zstrdup(argv[1]) : NULL;
|
||||
} else if ((!strcasecmp(argv[0],"slave-serve-stale-data") ||
|
||||
!strcasecmp(argv[0],"replica-serve-stale-data"))
|
||||
&& argc == 2)
|
||||
@@ -731,11 +725,11 @@ void loadServerConfigFromString(char *config) {
|
||||
} else if (!strcasecmp(argv[0],"client-output-buffer-limit") &&
|
||||
argc == 5)
|
||||
{
|
||||
int class = getClientTypeByName(argv[1]);
|
||||
int type = getClientTypeByName(argv[1]);
|
||||
unsigned long long hard, soft;
|
||||
int soft_seconds;
|
||||
|
||||
if (class == -1 || class == CLIENT_TYPE_MASTER) {
|
||||
if (type == -1 || type == CLIENT_TYPE_MASTER) {
|
||||
err = "Unrecognized client limit class: the user specified "
|
||||
"an invalid one, or 'master' which has no buffer limits.";
|
||||
goto loaderr;
|
||||
@@ -747,9 +741,9 @@ void loadServerConfigFromString(char *config) {
|
||||
err = "Negative number of seconds in soft limit is invalid";
|
||||
goto loaderr;
|
||||
}
|
||||
server.client_obuf_limits[class].hard_limit_bytes = hard;
|
||||
server.client_obuf_limits[class].soft_limit_bytes = soft;
|
||||
server.client_obuf_limits[class].soft_limit_seconds = soft_seconds;
|
||||
server.client_obuf_limits[type].hard_limit_bytes = hard;
|
||||
server.client_obuf_limits[type].soft_limit_bytes = soft;
|
||||
server.client_obuf_limits[type].soft_limit_seconds = soft_seconds;
|
||||
} else if (!strcasecmp(argv[0],"stop-writes-on-bgsave-error") &&
|
||||
argc == 2) {
|
||||
if ((server.stop_writes_on_bgsave_err = yesnotoi(argv[1])) == -1) {
|
||||
@@ -808,7 +802,7 @@ void loadServerConfigFromString(char *config) {
|
||||
int argc_err;
|
||||
if (ACLAppendUserForLoading(argv,argc,&argc_err) == C_ERR) {
|
||||
char buf[1024];
|
||||
char *errmsg = ACLSetUserStringError();
|
||||
const char *errmsg = ACLSetUserStringError();
|
||||
snprintf(buf,sizeof(buf),"Error in user declaration '%s': %s",
|
||||
argv[argc_err],errmsg);
|
||||
err = buf;
|
||||
@@ -849,6 +843,20 @@ void loadServerConfigFromString(char *config) {
|
||||
err = "Unknown argument: server-thread-affinity expects either true or false";
|
||||
goto loaderr;
|
||||
}
|
||||
} else if (!strcasecmp(argv[0], "active-replica") && argc == 2) {
|
||||
server.fActiveReplica = yesnotoi(argv[1]);
|
||||
if (server.repl_slave_ro) {
|
||||
server.repl_slave_ro = FALSE;
|
||||
serverLog(LL_NOTICE, "Notice: \"active-replica yes\" implies \"replica-read-only no\"");
|
||||
}
|
||||
if (server.fActiveReplica == -1) {
|
||||
server.fActiveReplica = CONFIG_DEFAULT_ACTIVE_REPLICA;
|
||||
err = "argument must be 'yes' or 'no'"; goto loaderr;
|
||||
}
|
||||
} else if (!strcasecmp(argv[0],"multi-master") && argc == 2){
|
||||
if ((server.enable_multimaster = yesnotoi(argv[1])) == -1) {
|
||||
err = "argument must be 'yes' or 'no'"; goto loaderr;
|
||||
}
|
||||
} else {
|
||||
err = "Bad directive or wrong number of arguments"; goto loaderr;
|
||||
}
|
||||
@@ -856,7 +864,7 @@ void loadServerConfigFromString(char *config) {
|
||||
}
|
||||
|
||||
/* Sanity checks. */
|
||||
if (server.cluster_enabled && server.masterhost) {
|
||||
if (server.cluster_enabled && listLength(server.masters)) {
|
||||
linenum = slaveof_linenum;
|
||||
i = linenum-1;
|
||||
err = "replicaof directive not allowed in cluster mode";
|
||||
@@ -916,36 +924,36 @@ void loadServerConfig(char *filename, char *options) {
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#define config_set_bool_field(_name,_var) \
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[2]),_name)) { \
|
||||
int yn = yesnotoi(ptrFromObj(o)); \
|
||||
} else if (!strcasecmp(szFromObj(c->argv[2]),_name)) { \
|
||||
int yn = yesnotoi(szFromObj(o)); \
|
||||
if (yn == -1) goto badfmt; \
|
||||
_var = yn;
|
||||
|
||||
#define config_set_numerical_field(_name,_var,min,max) \
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[2]),_name)) { \
|
||||
} else if (!strcasecmp(szFromObj(c->argv[2]),_name)) { \
|
||||
if (getLongLongFromObject(o,&ll) == C_ERR) goto badfmt; \
|
||||
if (min != LLONG_MIN && ll < min) goto badfmt; \
|
||||
if (max != LLONG_MAX && ll > max) goto badfmt; \
|
||||
_var = ll;
|
||||
|
||||
#define config_set_memory_field(_name,_var) \
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[2]),_name)) { \
|
||||
ll = memtoll(ptrFromObj(o),&err); \
|
||||
} else if (!strcasecmp(szFromObj(c->argv[2]),_name)) { \
|
||||
ll = memtoll(szFromObj(o),&err); \
|
||||
if (err || ll < 0) goto badfmt; \
|
||||
_var = ll;
|
||||
|
||||
#define config_set_enum_field(_name,_var,_enumvar) \
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[2]),_name)) { \
|
||||
int enumval = configEnumGetValue(_enumvar,ptrFromObj(o)); \
|
||||
} else if (!strcasecmp(szFromObj(c->argv[2]),_name)) { \
|
||||
int enumval = configEnumGetValue(_enumvar,szFromObj(o)); \
|
||||
if (enumval == INT_MIN) goto badfmt; \
|
||||
_var = enumval;
|
||||
|
||||
#define config_set_special_field(_name) \
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[2]),_name)) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[2]),_name)) {
|
||||
|
||||
#define config_set_special_field_with_alias(_name1,_name2) \
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[2]),_name1) || \
|
||||
!strcasecmp(ptrFromObj(c->argv[2]),_name2)) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[2]),_name1) || \
|
||||
!strcasecmp(szFromObj(c->argv[2]),_name2)) {
|
||||
|
||||
#define config_set_else } else
|
||||
|
||||
@@ -961,14 +969,14 @@ void configSetCommand(client *c) {
|
||||
|
||||
/* Special fields that can't be handled with general macros. */
|
||||
config_set_special_field("dbfilename") {
|
||||
if (!pathIsBaseName(ptrFromObj(o))) {
|
||||
if (!pathIsBaseName(szFromObj(o))) {
|
||||
addReplyError(c, "dbfilename can't be a path, just a filename");
|
||||
return;
|
||||
}
|
||||
zfree(server.rdb_filename);
|
||||
server.rdb_filename = zstrdup(ptrFromObj(o));
|
||||
server.rdb_filename = zstrdup(szFromObj(o));
|
||||
} config_set_special_field("requirepass") {
|
||||
if (sdslen(ptrFromObj(o)) > CONFIG_AUTHPASS_MAX_LEN) goto badfmt;
|
||||
if (sdslen(szFromObj(o)) > CONFIG_AUTHPASS_MAX_LEN) goto badfmt;
|
||||
/* The old "requirepass" directive just translates to setting
|
||||
* a password to the default user. */
|
||||
ACLSetUser(DefaultUser,"resetpass",-1);
|
||||
@@ -976,14 +984,14 @@ void configSetCommand(client *c) {
|
||||
ACLSetUser(DefaultUser,aclop,sdslen(aclop));
|
||||
sdsfree(aclop);
|
||||
} config_set_special_field("masteruser") {
|
||||
zfree(server.masteruser);
|
||||
server.masteruser = ((char*)ptrFromObj(o))[0] ? zstrdup(ptrFromObj(o)) : NULL;
|
||||
zfree(server.default_masteruser);
|
||||
server.default_masteruser = ((char*)ptrFromObj(o))[0] ? zstrdup(szFromObj(o)) : NULL;
|
||||
} config_set_special_field("masterauth") {
|
||||
zfree(server.masterauth);
|
||||
server.masterauth = ((char*)ptrFromObj(o))[0] ? zstrdup(ptrFromObj(o)) : NULL;
|
||||
zfree(server.default_masterauth);
|
||||
server.default_masterauth = ((char*)ptrFromObj(o))[0] ? zstrdup(szFromObj(o)) : NULL;
|
||||
} config_set_special_field("cluster-announce-ip") {
|
||||
zfree(server.cluster_announce_ip);
|
||||
server.cluster_announce_ip = ((char*)ptrFromObj(o))[0] ? zstrdup(ptrFromObj(o)) : NULL;
|
||||
server.cluster_announce_ip = ((char*)ptrFromObj(o))[0] ? zstrdup(szFromObj(o)) : NULL;
|
||||
} config_set_special_field("maxclients") {
|
||||
int orig_value = server.maxclients;
|
||||
|
||||
@@ -1015,7 +1023,7 @@ void configSetCommand(client *c) {
|
||||
}
|
||||
}
|
||||
} config_set_special_field("appendonly") {
|
||||
int enable = yesnotoi(ptrFromObj(o));
|
||||
int enable = yesnotoi(szFromObj(o));
|
||||
|
||||
if (enable == -1) goto badfmt;
|
||||
if (enable == 0 && server.aof_state != AOF_OFF) {
|
||||
@@ -1029,7 +1037,7 @@ void configSetCommand(client *c) {
|
||||
}
|
||||
} config_set_special_field("save") {
|
||||
int vlen, j;
|
||||
sds *v = sdssplitlen(ptrFromObj(o),sdslen(ptrFromObj(o))," ",1,&vlen);
|
||||
sds *v = sdssplitlen(szFromObj(o),sdslen(szFromObj(o))," ",1,&vlen);
|
||||
|
||||
/* Perform sanity check before setting the new config:
|
||||
* - Even number of args
|
||||
@@ -1068,7 +1076,7 @@ void configSetCommand(client *c) {
|
||||
}
|
||||
} config_set_special_field("client-output-buffer-limit") {
|
||||
int vlen, j;
|
||||
sds *v = sdssplitlen(ptrFromObj(o),sdslen(ptrFromObj(o))," ",1,&vlen);
|
||||
sds *v = sdssplitlen(szFromObj(o),sdslen(szFromObj(o))," ",1,&vlen);
|
||||
|
||||
/* We need a multiple of 4: <class> <hard> <soft> <soft_seconds> */
|
||||
if (vlen % 4) {
|
||||
@@ -1083,8 +1091,8 @@ void configSetCommand(client *c) {
|
||||
long val;
|
||||
|
||||
if ((j % 4) == 0) {
|
||||
int class = getClientTypeByName(v[j]);
|
||||
if (class == -1 || class == CLIENT_TYPE_MASTER) {
|
||||
int type = getClientTypeByName(v[j]);
|
||||
if (type == -1 || type == CLIENT_TYPE_MASTER) {
|
||||
sdsfreesplitres(v,vlen);
|
||||
goto badfmt;
|
||||
}
|
||||
@@ -1098,22 +1106,21 @@ void configSetCommand(client *c) {
|
||||
}
|
||||
/* Finally set the new config */
|
||||
for (j = 0; j < vlen; j += 4) {
|
||||
int class;
|
||||
unsigned long long hard, soft;
|
||||
int soft_seconds;
|
||||
|
||||
class = getClientTypeByName(v[j]);
|
||||
int type = getClientTypeByName(v[j]);
|
||||
hard = memtoll(v[j+1],NULL);
|
||||
soft = memtoll(v[j+2],NULL);
|
||||
soft_seconds = strtoll(v[j+3],NULL,10);
|
||||
|
||||
server.client_obuf_limits[class].hard_limit_bytes = hard;
|
||||
server.client_obuf_limits[class].soft_limit_bytes = soft;
|
||||
server.client_obuf_limits[class].soft_limit_seconds = soft_seconds;
|
||||
server.client_obuf_limits[type].hard_limit_bytes = hard;
|
||||
server.client_obuf_limits[type].soft_limit_bytes = soft;
|
||||
server.client_obuf_limits[type].soft_limit_seconds = soft_seconds;
|
||||
}
|
||||
sdsfreesplitres(v,vlen);
|
||||
} config_set_special_field("notify-keyspace-events") {
|
||||
int flags = keyspaceEventsStringToFlags(ptrFromObj(o));
|
||||
int flags = keyspaceEventsStringToFlags(szFromObj(o));
|
||||
|
||||
if (flags == -1) goto badfmt;
|
||||
server.notify_keyspace_events = flags;
|
||||
@@ -1121,7 +1128,7 @@ void configSetCommand(client *c) {
|
||||
"replica-announce-ip")
|
||||
{
|
||||
zfree(server.slave_announce_ip);
|
||||
server.slave_announce_ip = ((char*)ptrFromObj(o))[0] ? zstrdup(ptrFromObj(o)) : NULL;
|
||||
server.slave_announce_ip = ((char*)ptrFromObj(o))[0] ? zstrdup(szFromObj(o)) : NULL;
|
||||
|
||||
/* Boolean fields.
|
||||
* config_set_bool_field(name,var). */
|
||||
@@ -1174,8 +1181,6 @@ void configSetCommand(client *c) {
|
||||
#endif
|
||||
} config_set_bool_field(
|
||||
"protected-mode",server.protected_mode) {
|
||||
} config_set_bool_field(
|
||||
"gopher-enabled",server.gopher_enabled) {
|
||||
} config_set_bool_field(
|
||||
"stop-writes-on-bgsave-error",server.stop_writes_on_bgsave_err) {
|
||||
} config_set_bool_field(
|
||||
@@ -1328,6 +1333,8 @@ void configSetCommand(client *c) {
|
||||
"loglevel",server.verbosity,loglevel_enum) {
|
||||
} config_set_enum_field(
|
||||
"maxmemory-policy",server.maxmemory_policy,maxmemory_policy_enum) {
|
||||
} config_set_bool_field(
|
||||
"multi-master", server.enable_multimaster) {
|
||||
} config_set_enum_field(
|
||||
"appendfsync",server.aof_fsync,aof_fsync_enum) {
|
||||
|
||||
@@ -1388,15 +1395,15 @@ badfmt: /* Bad format errors */
|
||||
void configGetCommand(client *c) {
|
||||
robj *o = c->argv[2];
|
||||
void *replylen = addReplyDeferredLen(c);
|
||||
char *pattern = ptrFromObj(o);
|
||||
char *pattern = szFromObj(o);
|
||||
char buf[128];
|
||||
int matches = 0;
|
||||
serverAssertWithInfo(c,o,sdsEncodedObject(o));
|
||||
|
||||
/* String values */
|
||||
config_get_string_field("dbfilename",server.rdb_filename);
|
||||
config_get_string_field("masteruser",server.masteruser);
|
||||
config_get_string_field("masterauth",server.masterauth);
|
||||
config_get_string_field("masteruser",server.default_masteruser);
|
||||
config_get_string_field("masterauth",server.default_masterauth);
|
||||
config_get_string_field("cluster-announce-ip",server.cluster_announce_ip);
|
||||
config_get_string_field("unixsocket",server.unixsocket);
|
||||
config_get_string_field("logfile",server.logfile);
|
||||
@@ -1507,7 +1514,6 @@ void configGetCommand(client *c) {
|
||||
config_get_bool_field("activerehashing", server.activerehashing);
|
||||
config_get_bool_field("activedefrag", server.active_defrag_enabled);
|
||||
config_get_bool_field("protected-mode", server.protected_mode);
|
||||
config_get_bool_field("gopher-enabled", server.gopher_enabled);
|
||||
config_get_bool_field("repl-disable-tcp-nodelay",
|
||||
server.repl_disable_tcp_nodelay);
|
||||
config_get_bool_field("repl-diskless-sync",
|
||||
@@ -1606,17 +1612,28 @@ void configGetCommand(client *c) {
|
||||
if (stringmatch(pattern,"slaveof",1) ||
|
||||
stringmatch(pattern,"replicaof",1))
|
||||
{
|
||||
char *optname = stringmatch(pattern,"slaveof",1) ?
|
||||
const char *optname = stringmatch(pattern,"slaveof",1) ?
|
||||
"slaveof" : "replicaof";
|
||||
char buf[256];
|
||||
|
||||
addReplyBulkCString(c,optname);
|
||||
if (server.masterhost)
|
||||
snprintf(buf,sizeof(buf),"%s %d",
|
||||
server.masterhost, server.masterport);
|
||||
else
|
||||
if (listLength(server.masters) == 0)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
addReplyBulkCString(c,buf);
|
||||
addReplyBulkCString(c,buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(server.masters, &li);
|
||||
while ((ln = listNext(&li)))
|
||||
{
|
||||
struct redisMaster *mi = (struct redisMaster*)listNodeValue(ln);
|
||||
snprintf(buf,sizeof(buf),"%s %d",
|
||||
mi->masterhost, mi->masterport);
|
||||
addReplyBulkCString(c,buf);
|
||||
}
|
||||
}
|
||||
matches++;
|
||||
}
|
||||
if (stringmatch(pattern,"notify-keyspace-events",1)) {
|
||||
@@ -1697,13 +1714,13 @@ struct rewriteConfigState {
|
||||
|
||||
/* Append the new line to the current configuration state. */
|
||||
void rewriteConfigAppendLine(struct rewriteConfigState *state, sds line) {
|
||||
state->lines = zrealloc(state->lines, sizeof(char*) * (state->numlines+1), MALLOC_LOCAL);
|
||||
state->lines = (sds*)zrealloc(state->lines, sizeof(char*) * (state->numlines+1), MALLOC_LOCAL);
|
||||
state->lines[state->numlines++] = line;
|
||||
}
|
||||
|
||||
/* Populate the option -> list of line numbers map. */
|
||||
void rewriteConfigAddLineNumberToOption(struct rewriteConfigState *state, sds option, int linenum) {
|
||||
list *l = dictFetchValue(state->option_to_line,option);
|
||||
list *l = (list*)dictFetchValue(state->option_to_line,option);
|
||||
|
||||
if (l == NULL) {
|
||||
l = listCreate();
|
||||
@@ -1729,7 +1746,7 @@ void rewriteConfigMarkAsProcessed(struct rewriteConfigState *state, const char *
|
||||
* If the old file does not exist at all, an empty state is returned. */
|
||||
struct rewriteConfigState *rewriteConfigReadOldFile(char *path) {
|
||||
FILE *fp = fopen(path,"r");
|
||||
struct rewriteConfigState *state = zmalloc(sizeof(*state), MALLOC_LOCAL);
|
||||
struct rewriteConfigState *state = (rewriteConfigState*)zmalloc(sizeof(*state), MALLOC_LOCAL);
|
||||
char buf[CONFIG_MAX_LINE+1];
|
||||
int linenum = -1;
|
||||
|
||||
@@ -1814,7 +1831,7 @@ struct rewriteConfigState *rewriteConfigReadOldFile(char *path) {
|
||||
* in any way. */
|
||||
void rewriteConfigRewriteLine(struct rewriteConfigState *state, const char *option, sds line, int force) {
|
||||
sds o = sdsnew(option);
|
||||
list *l = dictFetchValue(state->option_to_line,o);
|
||||
list *l = (list*)dictFetchValue(state->option_to_line,o);
|
||||
|
||||
rewriteConfigMarkAsProcessed(state,option);
|
||||
|
||||
@@ -1866,7 +1883,7 @@ int rewriteConfigFormatMemory(char *buf, size_t len, long long bytes) {
|
||||
}
|
||||
|
||||
/* Rewrite a simple "option-name <bytes>" configuration option. */
|
||||
void rewriteConfigBytesOption(struct rewriteConfigState *state, char *option, long long value, long long defvalue) {
|
||||
void rewriteConfigBytesOption(struct rewriteConfigState *state, const char *option, long long value, long long defvalue) {
|
||||
char buf[64];
|
||||
int force = value != defvalue;
|
||||
sds line;
|
||||
@@ -1877,7 +1894,7 @@ void rewriteConfigBytesOption(struct rewriteConfigState *state, char *option, lo
|
||||
}
|
||||
|
||||
/* Rewrite a yes/no option. */
|
||||
void rewriteConfigYesNoOption(struct rewriteConfigState *state, char *option, int value, int defvalue) {
|
||||
void rewriteConfigYesNoOption(struct rewriteConfigState *state, const char *option, int value, int defvalue) {
|
||||
int force = value != defvalue;
|
||||
sds line = sdscatprintf(sdsempty(),"%s %s",option,
|
||||
value ? "yes" : "no");
|
||||
@@ -1886,7 +1903,7 @@ void rewriteConfigYesNoOption(struct rewriteConfigState *state, char *option, in
|
||||
}
|
||||
|
||||
/* Rewrite a string option. */
|
||||
void rewriteConfigStringOption(struct rewriteConfigState *state, char *option, char *value, char *defvalue) {
|
||||
void rewriteConfigStringOption(struct rewriteConfigState *state, const char *option, const char *value, const char *defvalue) {
|
||||
int force = 1;
|
||||
sds line;
|
||||
|
||||
@@ -1908,7 +1925,7 @@ void rewriteConfigStringOption(struct rewriteConfigState *state, char *option, c
|
||||
}
|
||||
|
||||
/* Rewrite a numerical (long long range) option. */
|
||||
void rewriteConfigNumericalOption(struct rewriteConfigState *state, char *option, long long value, long long defvalue) {
|
||||
void rewriteConfigNumericalOption(struct rewriteConfigState *state, const char *option, long long value, long long defvalue) {
|
||||
int force = value != defvalue;
|
||||
sds line = sdscatprintf(sdsempty(),"%s %lld",option,value);
|
||||
|
||||
@@ -1916,7 +1933,7 @@ void rewriteConfigNumericalOption(struct rewriteConfigState *state, char *option
|
||||
}
|
||||
|
||||
/* Rewrite a octal option. */
|
||||
void rewriteConfigOctalOption(struct rewriteConfigState *state, char *option, int value, int defvalue) {
|
||||
void rewriteConfigOctalOption(struct rewriteConfigState *state, const char *option, int value, int defvalue) {
|
||||
int force = value != defvalue;
|
||||
sds line = sdscatprintf(sdsempty(),"%s %o",option,value);
|
||||
|
||||
@@ -1926,7 +1943,7 @@ void rewriteConfigOctalOption(struct rewriteConfigState *state, char *option, in
|
||||
/* Rewrite an enumeration option. It takes as usually state and option name,
|
||||
* and in addition the enumeration array and the default value for the
|
||||
* option. */
|
||||
void rewriteConfigEnumOption(struct rewriteConfigState *state, char *option, int value, configEnum *ce, int defval) {
|
||||
void rewriteConfigEnumOption(struct rewriteConfigState *state, const char *option, int value, configEnum *ce, int defval) {
|
||||
sds line;
|
||||
const char *name = configEnumGetNameOrUnknown(ce,value);
|
||||
int force = value != defval;
|
||||
@@ -1981,7 +1998,7 @@ void rewriteConfigUserOption(struct rewriteConfigState *state) {
|
||||
raxStart(&ri,Users);
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
while(raxNext(&ri)) {
|
||||
user *u = ri.data;
|
||||
user *u = (user*)ri.data;
|
||||
sds line = sdsnew("user ");
|
||||
line = sdscatsds(line,u->name);
|
||||
line = sdscatlen(line," ",1);
|
||||
@@ -2008,25 +2025,33 @@ void rewriteConfigDirOption(struct rewriteConfigState *state) {
|
||||
}
|
||||
|
||||
/* Rewrite the slaveof option. */
|
||||
void rewriteConfigSlaveofOption(struct rewriteConfigState *state, char *option) {
|
||||
sds line;
|
||||
|
||||
void rewriteConfigSlaveofOption(struct rewriteConfigState *state, const char *option) {
|
||||
/* If this is a master, we want all the slaveof config options
|
||||
* in the file to be removed. Note that if this is a cluster instance
|
||||
* we don't want a slaveof directive inside redis.conf. */
|
||||
if (server.cluster_enabled || server.masterhost == NULL) {
|
||||
* in the file to be removed. Note that if this is a cluster instance
|
||||
* we don't want a slaveof directive inside redis.conf. */
|
||||
if (server.cluster_enabled || listLength(server.masters) == 0) {
|
||||
rewriteConfigMarkAsProcessed(state,option);
|
||||
return;
|
||||
}
|
||||
line = sdscatprintf(sdsempty(),"%s %s %d", option,
|
||||
server.masterhost, server.masterport);
|
||||
rewriteConfigRewriteLine(state,option,line,1);
|
||||
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(server.masters, &li);
|
||||
while ((ln = listNext(&li)))
|
||||
{
|
||||
struct redisMaster *mi = (struct redisMaster*)listNodeValue(ln);
|
||||
sds line;
|
||||
|
||||
line = sdscatprintf(sdsempty(),"%s %s %d", option,
|
||||
mi->masterhost, mi->masterport);
|
||||
rewriteConfigRewriteLine(state,option,line,1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Rewrite the notify-keyspace-events option. */
|
||||
void rewriteConfigNotifykeyspaceeventsOption(struct rewriteConfigState *state) {
|
||||
int force = server.notify_keyspace_events != 0;
|
||||
char *option = "notify-keyspace-events";
|
||||
const char *option = "notify-keyspace-events";
|
||||
sds line, flags;
|
||||
|
||||
flags = keyspaceEventsFlagsToString(server.notify_keyspace_events);
|
||||
@@ -2040,7 +2065,7 @@ void rewriteConfigNotifykeyspaceeventsOption(struct rewriteConfigState *state) {
|
||||
/* Rewrite the client-output-buffer-limit option. */
|
||||
void rewriteConfigClientoutputbufferlimitOption(struct rewriteConfigState *state) {
|
||||
int j;
|
||||
char *option = "client-output-buffer-limit";
|
||||
const char *option = "client-output-buffer-limit";
|
||||
|
||||
for (j = 0; j < CLIENT_TYPE_OBUF_COUNT; j++) {
|
||||
int force = (server.client_obuf_limits[j].hard_limit_bytes !=
|
||||
@@ -2057,10 +2082,10 @@ void rewriteConfigClientoutputbufferlimitOption(struct rewriteConfigState *state
|
||||
rewriteConfigFormatMemory(soft,sizeof(soft),
|
||||
server.client_obuf_limits[j].soft_limit_bytes);
|
||||
|
||||
const char *typename = getClientTypeName(j);
|
||||
if (!strcmp(typename,"slave")) typename = "replica";
|
||||
const char *tname = getClientTypeName(j);
|
||||
if (!strcmp(tname,"slave")) tname = "replica";
|
||||
line = sdscatprintf(sdsempty(),"%s %s %s %s %ld",
|
||||
option, typename, hard, soft,
|
||||
option, tname, hard, soft,
|
||||
(long) server.client_obuf_limits[j].soft_limit_seconds);
|
||||
rewriteConfigRewriteLine(state,option,line,force);
|
||||
}
|
||||
@@ -2070,7 +2095,7 @@ void rewriteConfigClientoutputbufferlimitOption(struct rewriteConfigState *state
|
||||
void rewriteConfigBindOption(struct rewriteConfigState *state) {
|
||||
int force = 1;
|
||||
sds line, addresses;
|
||||
char *option = "bind";
|
||||
const char *option = "bind";
|
||||
|
||||
/* Nothing to rewrite if we don't have bind addresses. */
|
||||
if (server.bindaddr_count == 0) {
|
||||
@@ -2089,7 +2114,7 @@ void rewriteConfigBindOption(struct rewriteConfigState *state) {
|
||||
}
|
||||
|
||||
/* Rewrite the requirepass option. */
|
||||
void rewriteConfigRequirepassOption(struct rewriteConfigState *state, char *option) {
|
||||
void rewriteConfigRequirepassOption(struct rewriteConfigState *state, const char *option) {
|
||||
int force = 1;
|
||||
sds line;
|
||||
sds password = ACLDefaultUserFirstPassword();
|
||||
@@ -2149,8 +2174,8 @@ void rewriteConfigRemoveOrphaned(struct rewriteConfigState *state) {
|
||||
dictEntry *de;
|
||||
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
list *l = dictGetVal(de);
|
||||
sds option = dictGetKey(de);
|
||||
list *l = (list*)dictGetVal(de);
|
||||
sds option = (sds)dictGetKey(de);
|
||||
|
||||
/* Don't blank lines about options the rewrite process
|
||||
* don't understand. */
|
||||
@@ -2275,8 +2300,8 @@ int rewriteConfig(char *path) {
|
||||
rewriteConfigDirOption(state);
|
||||
rewriteConfigSlaveofOption(state,"replicaof");
|
||||
rewriteConfigStringOption(state,"replica-announce-ip",server.slave_announce_ip,CONFIG_DEFAULT_SLAVE_ANNOUNCE_IP);
|
||||
rewriteConfigStringOption(state,"masteruser",server.masteruser,NULL);
|
||||
rewriteConfigStringOption(state,"masterauth",server.masterauth,NULL);
|
||||
rewriteConfigStringOption(state,"masteruser",server.default_masteruser,NULL);
|
||||
rewriteConfigStringOption(state,"masterauth",server.default_masterauth,NULL);
|
||||
rewriteConfigStringOption(state,"cluster-announce-ip",server.cluster_announce_ip,NULL);
|
||||
rewriteConfigYesNoOption(state,"replica-serve-stale-data",server.repl_serve_stale_data,CONFIG_DEFAULT_SLAVE_SERVE_STALE_DATA);
|
||||
rewriteConfigYesNoOption(state,"replica-read-only",server.repl_slave_ro,CONFIG_DEFAULT_SLAVE_READ_ONLY);
|
||||
@@ -2337,7 +2362,6 @@ int rewriteConfig(char *path) {
|
||||
rewriteConfigYesNoOption(state,"activerehashing",server.activerehashing,CONFIG_DEFAULT_ACTIVE_REHASHING);
|
||||
rewriteConfigYesNoOption(state,"activedefrag",server.active_defrag_enabled,CONFIG_DEFAULT_ACTIVE_DEFRAG);
|
||||
rewriteConfigYesNoOption(state,"protected-mode",server.protected_mode,CONFIG_DEFAULT_PROTECTED_MODE);
|
||||
rewriteConfigYesNoOption(state,"gopher-enabled",server.gopher_enabled,CONFIG_DEFAULT_GOPHER_ENABLED);
|
||||
rewriteConfigClientoutputbufferlimitOption(state);
|
||||
rewriteConfigNumericalOption(state,"hz",server.config_hz,CONFIG_DEFAULT_HZ);
|
||||
rewriteConfigYesNoOption(state,"aof-rewrite-incremental-fsync",server.aof_rewrite_incremental_fsync,CONFIG_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC);
|
||||
@@ -2350,6 +2374,8 @@ int rewriteConfig(char *path) {
|
||||
rewriteConfigYesNoOption(state,"lazyfree-lazy-server-del",server.lazyfree_lazy_server_del,CONFIG_DEFAULT_LAZYFREE_LAZY_SERVER_DEL);
|
||||
rewriteConfigYesNoOption(state,"replica-lazy-flush",server.repl_slave_lazy_flush,CONFIG_DEFAULT_SLAVE_LAZY_FLUSH);
|
||||
rewriteConfigYesNoOption(state,"dynamic-hz",server.dynamic_hz,CONFIG_DEFAULT_DYNAMIC_HZ);
|
||||
rewriteConfigYesNoOption(state,"active-replica",server.fActiveReplica,CONFIG_DEFAULT_ACTIVE_REPLICA);
|
||||
rewriteConfigYesNoOption(state,"multi-master",server.enable_multimaster,CONFIG_DEFAULT_ENABLE_MULTIMASTER);
|
||||
|
||||
/* Rewrite Sentinel config if in Sentinel mode. */
|
||||
if (server.sentinel_mode) rewriteConfigSentinelOption(state);
|
||||
@@ -2375,12 +2401,12 @@ int rewriteConfig(char *path) {
|
||||
|
||||
void configCommand(client *c) {
|
||||
/* Only allow CONFIG GET while loading. */
|
||||
if (server.loading && strcasecmp(ptrFromObj(c->argv[1]),"get")) {
|
||||
if (server.loading && strcasecmp(szFromObj(c->argv[1]),"get")) {
|
||||
addReplyError(c,"Only CONFIG GET is allowed during loading");
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->argc == 2 && !strcasecmp(ptrFromObj(c->argv[1]),"help")) {
|
||||
if (c->argc == 2 && !strcasecmp(szFromObj(c->argv[1]),"help")) {
|
||||
const char *help[] = {
|
||||
"GET <pattern> -- Return parameters matching the glob-like <pattern> and their values.",
|
||||
"SET <parameter> <value> -- Set parameter to value.",
|
||||
@@ -2389,15 +2415,15 @@ void configCommand(client *c) {
|
||||
NULL
|
||||
};
|
||||
addReplyHelp(c, help);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"set") && c->argc == 4) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"set") && c->argc == 4) {
|
||||
configSetCommand(c);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"get") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"get") && c->argc == 3) {
|
||||
configGetCommand(c);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"resetstat") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"resetstat") && c->argc == 2) {
|
||||
resetServerStats();
|
||||
resetCommandTableStats();
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"rewrite") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"rewrite") && c->argc == 2) {
|
||||
if (server.configfile == NULL) {
|
||||
addReplyError(c,"The server is running without a config file");
|
||||
return;
|
||||
+2
-2
@@ -1,5 +1,3 @@
|
||||
#include "server.h"
|
||||
|
||||
/*
|
||||
* Copyright 2001-2010 Georges Menie (www.menie.org)
|
||||
* Copyright 2010-2012 Salvatore Sanfilippo (adapted to Redis coding style)
|
||||
@@ -29,6 +27,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* CRC16 implementation according to CCITT standards.
|
||||
*
|
||||
* Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the
|
||||
|
||||
+100
-67
@@ -55,7 +55,7 @@ void updateLFU(robj *val) {
|
||||
robj *lookupKey(redisDb *db, robj *key, int flags) {
|
||||
dictEntry *de = dictFind(db->pdict,ptrFromObj(key));
|
||||
if (de) {
|
||||
robj *val = dictGetVal(de);
|
||||
robj *val = (robj*)dictGetVal(de);
|
||||
|
||||
/* Update the access time for the ageing algorithm.
|
||||
* Don't do it if we have a saving child, as this will trigger
|
||||
@@ -83,6 +83,7 @@ robj *lookupKey(redisDb *db, robj *key, int flags) {
|
||||
* 1. A key gets expired if it reached it's TTL.
|
||||
* 2. The key last access time is updated.
|
||||
* 3. The global keys hits/misses stats are updated (reported in INFO).
|
||||
* 4. If keyspace notifications are enabled, a "keymiss" notification is fired.
|
||||
*
|
||||
* This API should not be used when we write to the key after obtaining
|
||||
* the object linked to the key, but only for read only operations.
|
||||
@@ -105,8 +106,9 @@ robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
|
||||
/* Key expired. If we are in the context of a master, expireIfNeeded()
|
||||
* returns 0 only when the key does not exist at all, so it's safe
|
||||
* to return NULL ASAP. */
|
||||
if (server.masterhost == NULL) {
|
||||
if (listLength(server.masters) == 0) {
|
||||
server.stat_keyspace_misses++;
|
||||
notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -123,17 +125,20 @@ robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
|
||||
*
|
||||
* Notably this covers GETs when slaves are used to scale reads. */
|
||||
if (server.current_client &&
|
||||
server.current_client != server.master &&
|
||||
!FActiveMaster(server.current_client) &&
|
||||
server.current_client->cmd &&
|
||||
server.current_client->cmd->flags & CMD_READONLY)
|
||||
{
|
||||
server.stat_keyspace_misses++;
|
||||
notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
val = lookupKey(db,key,flags);
|
||||
if (val == NULL)
|
||||
if (val == NULL) {
|
||||
server.stat_keyspace_misses++;
|
||||
notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id);
|
||||
}
|
||||
else
|
||||
server.stat_keyspace_hits++;
|
||||
return val;
|
||||
@@ -167,19 +172,47 @@ robj *lookupKeyWriteOrReply(client *c, robj *key, robj *reply) {
|
||||
return o;
|
||||
}
|
||||
|
||||
int dbAddCore(redisDb *db, robj *key, robj *val) {
|
||||
sds copy = sdsdup(szFromObj(key));
|
||||
int retval = dictAdd(db->pdict, copy, val);
|
||||
|
||||
if (retval == DICT_OK)
|
||||
{
|
||||
if (val->type == OBJ_LIST ||
|
||||
val->type == OBJ_ZSET)
|
||||
signalKeyAsReady(db, key);
|
||||
if (server.cluster_enabled) slotToKeyAdd(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
sdsfree(copy);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Add the key to the DB. It's up to the caller to increment the reference
|
||||
* counter of the value if needed.
|
||||
*
|
||||
* The program is aborted if the key already exists. */
|
||||
void dbAdd(redisDb *db, robj *key, robj *val) {
|
||||
sds copy = sdsdup(ptrFromObj(key));
|
||||
int retval = dictAdd(db->pdict, copy, val);
|
||||
|
||||
void dbAdd(redisDb *db, robj *key, robj *val)
|
||||
{
|
||||
int retval = dbAddCore(db, key, val);
|
||||
serverAssertWithInfo(NULL,key,retval == DICT_OK);
|
||||
if (val->type == OBJ_LIST ||
|
||||
val->type == OBJ_ZSET)
|
||||
signalKeyAsReady(db, key);
|
||||
if (server.cluster_enabled) slotToKeyAdd(key);
|
||||
}
|
||||
|
||||
/* Insert a key, handling duplicate keys according to fReplace */
|
||||
int dbMerge(redisDb *db, robj *key, robj *val, int fReplace)
|
||||
{
|
||||
if (fReplace)
|
||||
{
|
||||
setKey(db, key, val);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (dbAddCore(db, key, val) == DICT_OK);
|
||||
}
|
||||
}
|
||||
|
||||
/* Overwrite an existing key with a new value. Incrementing the reference
|
||||
@@ -192,7 +225,7 @@ void dbOverwrite(redisDb *db, robj *key, robj *val) {
|
||||
|
||||
serverAssertWithInfo(NULL,key,de != NULL);
|
||||
dictEntry auxentry = *de;
|
||||
robj *old = dictGetVal(de);
|
||||
robj *old = (robj*)dictGetVal(de);
|
||||
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
|
||||
val->lru = old->lru;
|
||||
}
|
||||
@@ -245,10 +278,10 @@ robj *dbRandomKey(redisDb *db) {
|
||||
de = dictGetRandomKey(db->pdict);
|
||||
if (de == NULL) return NULL;
|
||||
|
||||
key = dictGetKey(de);
|
||||
key = (sds)dictGetKey(de);
|
||||
keyobj = createStringObject(key,sdslen(key));
|
||||
if (dictFind(db->expires,key)) {
|
||||
if (allvolatile && server.masterhost && --maxtries == 0) {
|
||||
if (allvolatile && listLength(server.masters) && --maxtries == 0) {
|
||||
/* If the DB is composed only of keys with an expire set,
|
||||
* it could happen that all the keys are already logically
|
||||
* expired in the slave, so the function cannot stop because
|
||||
@@ -319,7 +352,7 @@ robj *dbUnshareStringValue(redisDb *db, robj *key, robj *o) {
|
||||
serverAssert(o->type == OBJ_STRING);
|
||||
if (o->refcount != 1 || o->encoding != OBJ_ENCODING_RAW) {
|
||||
robj *decoded = getDecodedObject(o);
|
||||
o = createRawStringObject(ptrFromObj(decoded), sdslen(ptrFromObj(decoded)));
|
||||
o = createRawStringObject(szFromObj(decoded), sdslen(szFromObj(decoded)));
|
||||
decrRefCount(decoded);
|
||||
dbOverwrite(db,key,o);
|
||||
}
|
||||
@@ -416,7 +449,7 @@ void signalFlushedDb(int dbid) {
|
||||
int getFlushCommandFlags(client *c, int *flags) {
|
||||
/* Parse the optional ASYNC option. */
|
||||
if (c->argc > 1) {
|
||||
if (c->argc > 2 || strcasecmp(ptrFromObj(c->argv[1]),"async")) {
|
||||
if (c->argc > 2 || strcasecmp(szFromObj(c->argv[1]),"async")) {
|
||||
addReply(c,shared.syntaxerr);
|
||||
return C_ERR;
|
||||
}
|
||||
@@ -534,7 +567,7 @@ void randomkeyCommand(client *c) {
|
||||
void keysCommand(client *c) {
|
||||
dictIterator *di;
|
||||
dictEntry *de;
|
||||
sds pattern = ptrFromObj(c->argv[1]);
|
||||
sds pattern = szFromObj(c->argv[1]);
|
||||
int plen = sdslen(pattern), allkeys;
|
||||
unsigned long numkeys = 0;
|
||||
void *replylen = addReplyDeferredLen(c);
|
||||
@@ -542,7 +575,7 @@ void keysCommand(client *c) {
|
||||
di = dictGetSafeIterator(c->db->pdict);
|
||||
allkeys = (pattern[0] == '*' && pattern[1] == '\0');
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sds key = dictGetKey(de);
|
||||
sds key = (sds)dictGetKey(de);
|
||||
robj *keyobj;
|
||||
|
||||
if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) {
|
||||
@@ -562,23 +595,23 @@ void keysCommand(client *c) {
|
||||
* returned by the dictionary iterator into a list. */
|
||||
void scanCallback(void *privdata, const dictEntry *de) {
|
||||
void **pd = (void**) privdata;
|
||||
list *keys = pd[0];
|
||||
robj *o = pd[1];
|
||||
list *keys = (list*)pd[0];
|
||||
robj *o = (robj*)pd[1];
|
||||
robj *key, *val = NULL;
|
||||
|
||||
if (o == NULL) {
|
||||
sds sdskey = dictGetKey(de);
|
||||
sds sdskey = (sds)dictGetKey(de);
|
||||
key = createStringObject(sdskey, sdslen(sdskey));
|
||||
} else if (o->type == OBJ_SET) {
|
||||
sds keysds = dictGetKey(de);
|
||||
sds keysds = (sds)dictGetKey(de);
|
||||
key = createStringObject(keysds,sdslen(keysds));
|
||||
} else if (o->type == OBJ_HASH) {
|
||||
sds sdskey = dictGetKey(de);
|
||||
sds sdsval = dictGetVal(de);
|
||||
sds sdskey = (sds)dictGetKey(de);
|
||||
sds sdsval = (sds)dictGetVal(de);
|
||||
key = createStringObject(sdskey,sdslen(sdskey));
|
||||
val = createStringObject(sdsval,sdslen(sdsval));
|
||||
} else if (o->type == OBJ_ZSET) {
|
||||
sds sdskey = dictGetKey(de);
|
||||
sds sdskey = (sds)dictGetKey(de);
|
||||
key = createStringObject(sdskey,sdslen(sdskey));
|
||||
val = createStringObjectFromLongDouble(*(double*)dictGetVal(de),0);
|
||||
} else {
|
||||
@@ -599,7 +632,7 @@ int parseScanCursorOrReply(client *c, robj *o, unsigned long *cursor) {
|
||||
/* Use strtoul() because we need an *unsigned* long, so
|
||||
* getLongLongFromObject() does not cover the whole cursor space. */
|
||||
errno = 0;
|
||||
*cursor = strtoul(ptrFromObj(o), &eptr, 10);
|
||||
*cursor = strtoul(szFromObj(o), &eptr, 10);
|
||||
if (isspace(((char*)ptrFromObj(o))[0]) || eptr[0] != '\0' || errno == ERANGE)
|
||||
{
|
||||
addReplyError(c, "invalid cursor");
|
||||
@@ -639,7 +672,7 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
||||
/* Step 1: Parse options. */
|
||||
while (i < c->argc) {
|
||||
j = c->argc - i;
|
||||
if (!strcasecmp(ptrFromObj(c->argv[i]), "count") && j >= 2) {
|
||||
if (!strcasecmp(szFromObj(c->argv[i]), "count") && j >= 2) {
|
||||
if (getLongFromObjectOrReply(c, c->argv[i+1], &count, NULL)
|
||||
!= C_OK)
|
||||
{
|
||||
@@ -652,8 +685,8 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
||||
}
|
||||
|
||||
i += 2;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[i]), "match") && j >= 2) {
|
||||
pat = ptrFromObj(c->argv[i+1]);
|
||||
} else if (!strcasecmp(szFromObj(c->argv[i]), "match") && j >= 2) {
|
||||
pat = szFromObj(c->argv[i+1]);
|
||||
patlen = sdslen(pat);
|
||||
|
||||
/* The pattern always matches if it is exactly "*", so it is
|
||||
@@ -680,12 +713,12 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
||||
if (o == NULL) {
|
||||
ht = c->db->pdict;
|
||||
} else if (o->type == OBJ_SET && o->encoding == OBJ_ENCODING_HT) {
|
||||
ht = ptrFromObj(o);
|
||||
ht = (dict*)ptrFromObj(o);
|
||||
} else if (o->type == OBJ_HASH && o->encoding == OBJ_ENCODING_HT) {
|
||||
ht = ptrFromObj(o);
|
||||
ht = (dict*)ptrFromObj(o);
|
||||
count *= 2; /* We return key / value for this type. */
|
||||
} else if (o->type == OBJ_ZSET && o->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = ptrFromObj(o);
|
||||
zset *zs = (zset*)ptrFromObj(o);
|
||||
ht = zs->pdict;
|
||||
count *= 2; /* We return key / value for this type. */
|
||||
}
|
||||
@@ -712,11 +745,11 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
||||
int pos = 0;
|
||||
int64_t ll;
|
||||
|
||||
while(intsetGet(ptrFromObj(o),pos++,&ll))
|
||||
while(intsetGet((intset*)ptrFromObj(o),pos++,&ll))
|
||||
listAddNodeTail(keys,createStringObjectFromLongLong(ll));
|
||||
cursor = 0;
|
||||
} else if (o->type == OBJ_HASH || o->type == OBJ_ZSET) {
|
||||
unsigned char *p = ziplistIndex(ptrFromObj(o),0);
|
||||
unsigned char *p = ziplistIndex((unsigned char*)ptrFromObj(o),0);
|
||||
unsigned char *vstr;
|
||||
unsigned int vlen;
|
||||
long long vll;
|
||||
@@ -726,7 +759,7 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
||||
listAddNodeTail(keys,
|
||||
(vstr != NULL) ? createStringObject((char*)vstr,vlen) :
|
||||
createStringObjectFromLongLong(vll));
|
||||
p = ziplistNext(ptrFromObj(o),p);
|
||||
p = ziplistNext((unsigned char*)ptrFromObj(o),p);
|
||||
}
|
||||
cursor = 0;
|
||||
} else {
|
||||
@@ -736,14 +769,14 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
||||
/* Step 3: Filter elements. */
|
||||
node = listFirst(keys);
|
||||
while (node) {
|
||||
robj *kobj = listNodeValue(node);
|
||||
robj *kobj = (robj*)listNodeValue(node);
|
||||
nextnode = listNextNode(node);
|
||||
int filter = 0;
|
||||
|
||||
/* Filter element if it does not match the pattern. */
|
||||
if (!filter && use_pattern) {
|
||||
if (sdsEncodedObject(kobj)) {
|
||||
if (!stringmatchlen(pat, patlen, ptrFromObj(kobj), sdslen(ptrFromObj(kobj)), 0))
|
||||
if (!stringmatchlen(pat, patlen, szFromObj(kobj), sdslen(szFromObj(kobj)), 0))
|
||||
filter = 1;
|
||||
} else {
|
||||
char buf[LONG_STR_SIZE];
|
||||
@@ -771,7 +804,7 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
||||
node = nextnode;
|
||||
nextnode = listNextNode(node);
|
||||
if (filter) {
|
||||
kobj = listNodeValue(node);
|
||||
kobj = (robj*)listNodeValue(node);
|
||||
decrRefCount(kobj);
|
||||
listDelNode(keys, node);
|
||||
}
|
||||
@@ -785,7 +818,7 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
||||
|
||||
addReplyArrayLen(c, listLength(keys));
|
||||
while ((node = listFirst(keys)) != NULL) {
|
||||
robj *kobj = listNodeValue(node);
|
||||
robj *kobj = (robj*)listNodeValue(node);
|
||||
addReplyBulk(c, kobj);
|
||||
decrRefCount(kobj);
|
||||
listDelNode(keys, node);
|
||||
@@ -813,7 +846,7 @@ void lastsaveCommand(client *c) {
|
||||
|
||||
void typeCommand(client *c) {
|
||||
robj *o;
|
||||
char *type;
|
||||
const char *type;
|
||||
|
||||
o = lookupKeyReadWithFlags(c->db,c->argv[1],LOOKUP_NOTOUCH);
|
||||
if (o == NULL) {
|
||||
@@ -827,7 +860,7 @@ void typeCommand(client *c) {
|
||||
case OBJ_HASH: type = "hash"; break;
|
||||
case OBJ_STREAM: type = "stream"; break;
|
||||
case OBJ_MODULE: {
|
||||
moduleValue *mv = ptrFromObj(o);
|
||||
moduleValue *mv = (moduleValue*)ptrFromObj(o);
|
||||
type = mv->type->name;
|
||||
}; break;
|
||||
default: type = "unknown"; break;
|
||||
@@ -843,9 +876,9 @@ void shutdownCommand(client *c) {
|
||||
addReply(c,shared.syntaxerr);
|
||||
return;
|
||||
} else if (c->argc == 2) {
|
||||
if (!strcasecmp(ptrFromObj(c->argv[1]),"nosave")) {
|
||||
if (!strcasecmp(szFromObj(c->argv[1]),"nosave")) {
|
||||
flags |= SHUTDOWN_NOSAVE;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"save")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"save")) {
|
||||
flags |= SHUTDOWN_SAVE;
|
||||
} else {
|
||||
addReply(c,shared.syntaxerr);
|
||||
@@ -871,7 +904,7 @@ void renameGenericCommand(client *c, int nx) {
|
||||
|
||||
/* When source and dest key is the same, no operation is performed,
|
||||
* if the key exists, however we still return an error on unexisting key. */
|
||||
if (sdscmp(ptrFromObj(c->argv[1]),ptrFromObj(c->argv[2])) == 0) samekey = 1;
|
||||
if (sdscmp(szFromObj(c->argv[1]),szFromObj(c->argv[2])) == 0) samekey = 1;
|
||||
|
||||
if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr)) == NULL)
|
||||
return;
|
||||
@@ -977,7 +1010,7 @@ void scanDatabaseForReadyLists(redisDb *db) {
|
||||
dictEntry *de;
|
||||
dictIterator *di = dictGetSafeIterator(db->blocking_keys);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
robj *key = dictGetKey(de);
|
||||
robj *key = (robj*)dictGetKey(de);
|
||||
robj *value = lookupKey(db,key,LOOKUP_NOTOUCH);
|
||||
if (value && (value->type == OBJ_LIST ||
|
||||
value->type == OBJ_STREAM ||
|
||||
@@ -1081,7 +1114,7 @@ void setExpire(client *c, redisDb *db, robj *key, long long when) {
|
||||
de = dictAddOrFind(db->expires,dictGetKey(kde));
|
||||
dictSetSignedIntegerVal(de,when);
|
||||
|
||||
int writable_slave = server.masterhost && server.repl_slave_ro == 0;
|
||||
int writable_slave = listLength(server.masters) && server.repl_slave_ro == 0;
|
||||
if (c && writable_slave && !(c->flags & CLIENT_MASTER))
|
||||
rememberSlaveKeyWithExpire(db,key);
|
||||
}
|
||||
@@ -1175,7 +1208,7 @@ int expireIfNeeded(redisDb *db, robj *key) {
|
||||
* Still we try to return the right information to the caller,
|
||||
* that is, 0 if we think the key should be still valid, 1 if
|
||||
* we think the key is expired at this time. */
|
||||
if (server.masterhost != NULL) return 1;
|
||||
if (listLength(server.masters)) return 1;
|
||||
|
||||
/* Delete the key */
|
||||
server.stat_expiredkeys++;
|
||||
@@ -1203,7 +1236,7 @@ int *getKeysUsingCommandTable(struct redisCommand *cmd,robj **argv, int argc, in
|
||||
|
||||
last = cmd->lastkey;
|
||||
if (last < 0) last = argc+last;
|
||||
keys = zmalloc(sizeof(int)*((last - cmd->firstkey)+1), MALLOC_SHARED);
|
||||
keys = (int*)zmalloc(sizeof(int)*((last - cmd->firstkey)+1), MALLOC_SHARED);
|
||||
for (j = cmd->firstkey; j <= last; j += cmd->keystep) {
|
||||
if (j >= argc) {
|
||||
/* Modules commands, and standard commands with a not fixed number
|
||||
@@ -1259,7 +1292,7 @@ int *zunionInterGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *nu
|
||||
int i, num, *keys;
|
||||
UNUSED(cmd);
|
||||
|
||||
num = atoi(ptrFromObj(argv[2]));
|
||||
num = atoi(szFromObj(argv[2]));
|
||||
/* Sanity check. Don't return any key if the command is going to
|
||||
* reply with syntax error. */
|
||||
if (num < 1 || num > (argc-3)) {
|
||||
@@ -1270,7 +1303,7 @@ int *zunionInterGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *nu
|
||||
/* Keys in z{union,inter}store come from two places:
|
||||
* argv[1] = storage key,
|
||||
* argv[3...n] = keys to intersect */
|
||||
keys = zmalloc(sizeof(int)*(num+1), MALLOC_SHARED);
|
||||
keys = (int*)zmalloc(sizeof(int)*(num+1), MALLOC_SHARED);
|
||||
|
||||
/* Add all key positions for argv[3...n] to keys[] */
|
||||
for (i = 0; i < num; i++) keys[i] = 3+i;
|
||||
@@ -1288,7 +1321,7 @@ int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
|
||||
int i, num, *keys;
|
||||
UNUSED(cmd);
|
||||
|
||||
num = atoi(ptrFromObj(argv[2]));
|
||||
num = atoi(szFromObj(argv[2]));
|
||||
/* Sanity check. Don't return any key if the command is going to
|
||||
* reply with syntax error. */
|
||||
if (num <= 0 || num > (argc-3)) {
|
||||
@@ -1296,7 +1329,7 @@ int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
keys = zmalloc(sizeof(int)*num, MALLOC_SHARED);
|
||||
keys = (int*)zmalloc(sizeof(int)*num, MALLOC_SHARED);
|
||||
*numkeys = num;
|
||||
|
||||
/* Add all key positions for argv[3...n] to keys[] */
|
||||
@@ -1317,7 +1350,7 @@ int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
|
||||
UNUSED(cmd);
|
||||
|
||||
num = 0;
|
||||
keys = zmalloc(sizeof(int)*2, MALLOC_SHARED); /* Alloc 2 places for the worst case. */
|
||||
keys = (int*)zmalloc(sizeof(int)*2, MALLOC_SHARED); /* Alloc 2 places for the worst case. */
|
||||
|
||||
keys[num++] = 1; /* <sort-key> is always present. */
|
||||
|
||||
@@ -1326,7 +1359,7 @@ int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
|
||||
* next. However there are options with 1 or 2 arguments, so we
|
||||
* provide a list here in order to skip the right number of args. */
|
||||
struct {
|
||||
char *name;
|
||||
const char *name;
|
||||
int skip;
|
||||
} skiplist[] = {
|
||||
{"limit", 2},
|
||||
@@ -1337,10 +1370,10 @@ int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
|
||||
|
||||
for (i = 2; i < argc; i++) {
|
||||
for (j = 0; skiplist[j].name != NULL; j++) {
|
||||
if (!strcasecmp(ptrFromObj(argv[i]),skiplist[j].name)) {
|
||||
if (!strcasecmp(szFromObj(argv[i]),skiplist[j].name)) {
|
||||
i += skiplist[j].skip;
|
||||
break;
|
||||
} else if (!strcasecmp(ptrFromObj(argv[i]),"store") && i+1 < argc) {
|
||||
} else if (!strcasecmp(szFromObj(argv[i]),"store") && i+1 < argc) {
|
||||
/* Note: we don't increment "num" here and continue the loop
|
||||
* to be sure to process the *last* "STORE" option if multiple
|
||||
* ones are provided. This is same behavior as SORT. */
|
||||
@@ -1365,8 +1398,8 @@ int *migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkey
|
||||
/* But check for the extended one with the KEYS option. */
|
||||
if (argc > 6) {
|
||||
for (i = 6; i < argc; i++) {
|
||||
if (!strcasecmp(ptrFromObj(argv[i]),"keys") &&
|
||||
sdslen(ptrFromObj(argv[3])) == 0)
|
||||
if (!strcasecmp(szFromObj(argv[i]),"keys") &&
|
||||
sdslen(szFromObj(argv[3])) == 0)
|
||||
{
|
||||
first = i+1;
|
||||
num = argc-first;
|
||||
@@ -1375,7 +1408,7 @@ int *migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkey
|
||||
}
|
||||
}
|
||||
|
||||
keys = zmalloc(sizeof(int)*num, MALLOC_SHARED);
|
||||
keys = (int*)zmalloc(sizeof(int)*num, MALLOC_SHARED);
|
||||
for (i = 0; i < num; i++) keys[i] = first+i;
|
||||
*numkeys = num;
|
||||
return keys;
|
||||
@@ -1392,7 +1425,7 @@ int *georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numk
|
||||
/* Check for the presence of the stored key in the command */
|
||||
int stored_key = -1;
|
||||
for (i = 5; i < argc; i++) {
|
||||
char *arg = ptrFromObj(argv[i]);
|
||||
char *arg = szFromObj(argv[i]);
|
||||
/* For the case when user specifies both "store" and "storedist" options, the
|
||||
* second key specified would override the first key. This behavior is kept
|
||||
* the same as in georadiusCommand method.
|
||||
@@ -1408,7 +1441,7 @@ int *georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numk
|
||||
* argv[1] = key,
|
||||
* argv[5...n] = stored key if present
|
||||
*/
|
||||
keys = zmalloc(sizeof(int) * num, MALLOC_SHARED);
|
||||
keys = (int*)zmalloc(sizeof(int) * num, MALLOC_SHARED);
|
||||
|
||||
/* Add all key positions to keys[] */
|
||||
keys[0] = 1;
|
||||
@@ -1431,7 +1464,7 @@ int *xreadGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
|
||||
* name of the stream key. */
|
||||
int streams_pos = -1;
|
||||
for (i = 1; i < argc; i++) {
|
||||
char *arg = ptrFromObj(argv[i]);
|
||||
char *arg = szFromObj(argv[i]);
|
||||
if (!strcasecmp(arg, "block")) {
|
||||
i++; /* Skip option argument. */
|
||||
} else if (!strcasecmp(arg, "count")) {
|
||||
@@ -1457,7 +1490,7 @@ int *xreadGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
|
||||
num /= 2; /* We have half the keys as there are arguments because
|
||||
there are also the IDs, one per key. */
|
||||
|
||||
keys = zmalloc(sizeof(int) * num, MALLOC_SHARED);
|
||||
keys = (int*)zmalloc(sizeof(int) * num, MALLOC_SHARED);
|
||||
for (i = streams_pos+1; i < argc-num; i++) keys[i-streams_pos-1] = i;
|
||||
*numkeys = num;
|
||||
return keys;
|
||||
@@ -1468,13 +1501,13 @@ int *xreadGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
|
||||
* while rehashing the cluster and in other conditions when we need to
|
||||
* understand if we have keys for a given hash slot. */
|
||||
void slotToKeyUpdateKey(robj *key, int add) {
|
||||
unsigned int hashslot = keyHashSlot(ptrFromObj(key),sdslen(ptrFromObj(key)));
|
||||
size_t keylen = sdslen(szFromObj(key));
|
||||
unsigned int hashslot = keyHashSlot(szFromObj(key),keylen);
|
||||
unsigned char buf[64];
|
||||
unsigned char *indexed = buf;
|
||||
size_t keylen = sdslen(ptrFromObj(key));
|
||||
|
||||
server.cluster->slots_keys_count[hashslot] += add ? 1 : -1;
|
||||
if (keylen+2 > 64) indexed = zmalloc(keylen+2, MALLOC_SHARED);
|
||||
if (keylen+2 > 64) indexed = (unsigned char*)zmalloc(keylen+2, MALLOC_SHARED);
|
||||
indexed[0] = (hashslot >> 8) & 0xff;
|
||||
indexed[1] = hashslot & 0xff;
|
||||
memcpy(indexed+2,ptrFromObj(key),keylen);
|
||||
+68
-66
@@ -61,9 +61,10 @@ typedef ucontext_t sigcontext_t;
|
||||
* "add" digests relative to unordered elements.
|
||||
*
|
||||
* So digest(a,b,c,d) will be the same of digest(b,a,c,d) */
|
||||
void xorDigest(unsigned char *digest, void *ptr, size_t len) {
|
||||
extern "C" void xorDigest(unsigned char *digest, const void *ptr, size_t len) {
|
||||
SHA1_CTX ctx;
|
||||
unsigned char hash[20], *s = ptr;
|
||||
unsigned char hash[20];
|
||||
const unsigned char *s = (const unsigned char*)ptr;
|
||||
int j;
|
||||
|
||||
SHA1Init(&ctx);
|
||||
@@ -76,7 +77,7 @@ void xorDigest(unsigned char *digest, void *ptr, size_t len) {
|
||||
|
||||
void xorStringObjectDigest(unsigned char *digest, robj *o) {
|
||||
o = getDecodedObject(o);
|
||||
xorDigest(digest,ptrFromObj(o),sdslen(ptrFromObj(o)));
|
||||
xorDigest(digest,(const unsigned char*)ptrFromObj(o),sdslen(szFromObj(o)));
|
||||
decrRefCount(o);
|
||||
}
|
||||
|
||||
@@ -96,7 +97,7 @@ void xorStringObjectDigest(unsigned char *digest, robj *o) {
|
||||
*/
|
||||
void mixDigest(unsigned char *digest, void *ptr, size_t len) {
|
||||
SHA1_CTX ctx;
|
||||
char *s = ptr;
|
||||
char *s = (char*)ptr;
|
||||
|
||||
xorDigest(digest,s,len);
|
||||
SHA1Init(&ctx);
|
||||
@@ -106,7 +107,7 @@ void mixDigest(unsigned char *digest, void *ptr, size_t len) {
|
||||
|
||||
void mixStringObjectDigest(unsigned char *digest, robj *o) {
|
||||
o = getDecodedObject(o);
|
||||
mixDigest(digest,ptrFromObj(o),sdslen(ptrFromObj(o)));
|
||||
mixDigest(digest,ptrFromObj(o),sdslen(szFromObj(o)));
|
||||
decrRefCount(o);
|
||||
}
|
||||
|
||||
@@ -148,7 +149,7 @@ void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o)
|
||||
unsigned char eledigest[20];
|
||||
|
||||
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = ptrFromObj(o);
|
||||
unsigned char *zl = (unsigned char*)ptrFromObj(o);
|
||||
unsigned char *eptr, *sptr;
|
||||
unsigned char *vstr;
|
||||
unsigned int vlen;
|
||||
@@ -178,13 +179,13 @@ void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o)
|
||||
zzlNext(zl,&eptr,&sptr);
|
||||
}
|
||||
} else if (o->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = ptrFromObj(o);
|
||||
zset *zs = (zset*)ptrFromObj(o);
|
||||
dictIterator *di = dictGetIterator(zs->pdict);
|
||||
dictEntry *de;
|
||||
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sds sdsele = dictGetKey(de);
|
||||
double *score = dictGetVal(de);
|
||||
sds sdsele = (sds)dictGetKey(de);
|
||||
double *score = (double*)dictGetVal(de);
|
||||
|
||||
snprintf(buf,sizeof(buf),"%.17g",*score);
|
||||
memset(eledigest,0,20);
|
||||
@@ -214,7 +215,7 @@ void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o)
|
||||
hashTypeReleaseIterator(hi);
|
||||
} else if (o->type == OBJ_STREAM) {
|
||||
streamIterator si;
|
||||
streamIteratorStart(&si,ptrFromObj(o),NULL,NULL,0);
|
||||
streamIteratorStart(&si,(stream*)ptrFromObj(o),NULL,NULL,0);
|
||||
streamID id;
|
||||
int64_t numfields;
|
||||
|
||||
@@ -235,7 +236,7 @@ void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o)
|
||||
streamIteratorStop(&si);
|
||||
} else if (o->type == OBJ_MODULE) {
|
||||
RedisModuleDigest md;
|
||||
moduleValue *mv = ptrFromObj(o);
|
||||
moduleValue *mv = (moduleValue*)ptrFromObj(o);
|
||||
moduleType *mt = mv->type;
|
||||
moduleInitDigestContext(md);
|
||||
if (mt->digest) {
|
||||
@@ -281,12 +282,12 @@ void computeDatasetDigest(unsigned char *final) {
|
||||
robj *keyobj, *o;
|
||||
|
||||
memset(digest,0,20); /* This key-val digest */
|
||||
key = dictGetKey(de);
|
||||
key = (sds)dictGetKey(de);
|
||||
keyobj = createStringObject(key,sdslen(key));
|
||||
|
||||
mixDigest(digest,key,sdslen(key));
|
||||
|
||||
o = dictGetVal(de);
|
||||
o = (robj*)dictGetVal(de);
|
||||
xorObjectDigest(db,keyobj,digest,o);
|
||||
|
||||
/* We can finally xor the key-val digest to the final digest */
|
||||
@@ -298,7 +299,7 @@ void computeDatasetDigest(unsigned char *final) {
|
||||
}
|
||||
|
||||
void debugCommand(client *c) {
|
||||
if (c->argc == 2 && !strcasecmp(ptrFromObj(c->argv[1]),"help")) {
|
||||
if (c->argc == 2 && !strcasecmp(szFromObj(c->argv[1]),"help")) {
|
||||
const char *help[] = {
|
||||
"ASSERT -- Crash by assertion failed.",
|
||||
"CHANGE-REPL-ID -- Change the replication IDs of the instance. Dangerous, should be used only for testing the replication subsystem.",
|
||||
@@ -326,12 +327,12 @@ void debugCommand(client *c) {
|
||||
NULL
|
||||
};
|
||||
addReplyHelp(c, help);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"segfault")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"segfault")) {
|
||||
*((char*)-1) = 'x';
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"panic")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"panic")) {
|
||||
serverPanic("DEBUG PANIC called at Unix time %ld", time(NULL));
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"restart") ||
|
||||
!strcasecmp(ptrFromObj(c->argv[1]),"crash-and-recover"))
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"restart") ||
|
||||
!strcasecmp(szFromObj(c->argv[1]),"crash-and-recover"))
|
||||
{
|
||||
long long delay = 0;
|
||||
if (c->argc >= 3) {
|
||||
@@ -339,21 +340,21 @@ NULL
|
||||
!= C_OK) return;
|
||||
if (delay < 0) delay = 0;
|
||||
}
|
||||
int flags = !strcasecmp(ptrFromObj(c->argv[1]),"restart") ?
|
||||
int flags = !strcasecmp(szFromObj(c->argv[1]),"restart") ?
|
||||
(RESTART_SERVER_GRACEFULLY|RESTART_SERVER_CONFIG_REWRITE) :
|
||||
RESTART_SERVER_NONE;
|
||||
restartServer(flags,delay);
|
||||
addReplyError(c,"failed to restart the server. Check server logs.");
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"oom")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"oom")) {
|
||||
void *ptr = zmalloc(ULONG_MAX, MALLOC_LOCAL); /* Should trigger an out of memory. */
|
||||
zfree(ptr);
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"assert")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"assert")) {
|
||||
serverAssertWithInfo(c,c->argv[0],1 == 2);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"log") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"log") && c->argc == 3) {
|
||||
serverLog(LL_WARNING, "DEBUG LOG: %s", (char*)ptrFromObj(c->argv[2]));
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"reload")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"reload")) {
|
||||
rdbSaveInfo rsi, *rsiptr;
|
||||
rsiptr = rdbPopulateSaveInfo(&rsi);
|
||||
if (rdbSave(rsiptr) != C_OK) {
|
||||
@@ -362,7 +363,8 @@ NULL
|
||||
}
|
||||
emptyDb(-1,EMPTYDB_NO_FLAGS,NULL);
|
||||
protectClient(c);
|
||||
int ret = rdbLoad(NULL);
|
||||
rdbSaveInfo rsiDft = RDB_SAVE_INFO_INIT;
|
||||
int ret = rdbLoad(&rsiDft);
|
||||
unprotectClient(c);
|
||||
if (ret != C_OK) {
|
||||
addReplyError(c,"Error trying to load the RDB dump");
|
||||
@@ -370,7 +372,7 @@ NULL
|
||||
}
|
||||
serverLog(LL_WARNING,"DB reloaded by DEBUG RELOAD");
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"loadaof")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"loadaof")) {
|
||||
if (server.aof_state != AOF_OFF) flushAppendOnlyFile(1);
|
||||
emptyDb(-1,EMPTYDB_NO_FLAGS,NULL);
|
||||
protectClient(c);
|
||||
@@ -383,23 +385,23 @@ NULL
|
||||
server.dirty = 0; /* Prevent AOF / replication */
|
||||
serverLog(LL_WARNING,"Append Only File loaded by DEBUG LOADAOF");
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"object") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"object") && c->argc == 3) {
|
||||
dictEntry *de;
|
||||
robj *val;
|
||||
char *strenc;
|
||||
const char *strenc;
|
||||
|
||||
if ((de = dictFind(c->db->pdict,ptrFromObj(c->argv[2]))) == NULL) {
|
||||
addReply(c,shared.nokeyerr);
|
||||
return;
|
||||
}
|
||||
val = dictGetVal(de);
|
||||
val = (robj*)dictGetVal(de);
|
||||
strenc = strEncoding(val->encoding);
|
||||
|
||||
char extra[138] = {0};
|
||||
if (val->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
char *nextra = extra;
|
||||
int remaining = sizeof(extra);
|
||||
quicklist *ql = val->m_ptr;
|
||||
quicklist *ql = (quicklist*)val->m_ptr;
|
||||
/* Add number of quicklist nodes */
|
||||
int used = snprintf(nextra, remaining, " ql_nodes:%lu", ql->len);
|
||||
nextra += used;
|
||||
@@ -435,7 +437,7 @@ NULL
|
||||
(void*)val, val->refcount,
|
||||
strenc, rdbSavedObjectLen(val),
|
||||
val->lru, estimateObjectIdleTime(val)/1000, extra);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"sdslen") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"sdslen") && c->argc == 3) {
|
||||
dictEntry *de;
|
||||
robj *val;
|
||||
sds key;
|
||||
@@ -444,8 +446,8 @@ NULL
|
||||
addReply(c,shared.nokeyerr);
|
||||
return;
|
||||
}
|
||||
val = dictGetVal(de);
|
||||
key = dictGetKey(de);
|
||||
val = (robj*)dictGetVal(de);
|
||||
key = (sds)dictGetKey(de);
|
||||
|
||||
if (val->type != OBJ_STRING || !sdsEncodedObject(val)) {
|
||||
addReplyError(c,"Not an sds encoded string.");
|
||||
@@ -456,11 +458,11 @@ NULL
|
||||
(long long) sdslen(key),
|
||||
(long long) sdsavail(key),
|
||||
(long long) sdsZmallocSize(key),
|
||||
(long long) sdslen(ptrFromObj(val)),
|
||||
(long long) sdsavail(ptrFromObj(val)),
|
||||
(long long) sdslen(szFromObj(val)),
|
||||
(long long) sdsavail(szFromObj(val)),
|
||||
(long long) getStringObjectSdsUsedMemory(val));
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"ziplist") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"ziplist") && c->argc == 3) {
|
||||
robj *o;
|
||||
|
||||
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nokeyerr))
|
||||
@@ -469,10 +471,10 @@ NULL
|
||||
if (o->encoding != OBJ_ENCODING_ZIPLIST) {
|
||||
addReplyError(c,"Not an sds encoded string.");
|
||||
} else {
|
||||
ziplistRepr(ptrFromObj(o));
|
||||
ziplistRepr((unsigned char*)ptrFromObj(o));
|
||||
addReplyStatus(c,"Ziplist structure printed on stdout");
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"populate") &&
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"populate") &&
|
||||
c->argc >= 3 && c->argc <= 5) {
|
||||
long keys, j;
|
||||
robj *key, *val;
|
||||
@@ -506,7 +508,7 @@ NULL
|
||||
decrRefCount(key);
|
||||
}
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"digest") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"digest") && c->argc == 2) {
|
||||
/* DEBUG DIGEST (form without keys specified) */
|
||||
unsigned char digest[20];
|
||||
sds d = sdsempty();
|
||||
@@ -515,7 +517,7 @@ NULL
|
||||
for (int i = 0; i < 20; i++) d = sdscatprintf(d, "%02x",digest[i]);
|
||||
addReplyStatus(c,d);
|
||||
sdsfree(d);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"digest-value") && c->argc >= 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"digest-value") && c->argc >= 2) {
|
||||
/* DEBUG DIGEST-VALUE key key key ... key. */
|
||||
addReplyArrayLen(c,c->argc-2);
|
||||
for (int j = 2; j < c->argc; j++) {
|
||||
@@ -529,10 +531,10 @@ NULL
|
||||
addReplyStatus(c,d);
|
||||
sdsfree(d);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"protocol") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"protocol") && c->argc == 3) {
|
||||
/* DEBUG PROTOCOL [string|integer|double|bignum|null|array|set|map|
|
||||
* attrib|push|verbatim|true|false|state|err|bloberr] */
|
||||
char *name = ptrFromObj(c->argv[2]);
|
||||
char *name = szFromObj(c->argv[2]);
|
||||
if (!strcasecmp(name,"string")) {
|
||||
addReplyBulkCString(c,"Hello World");
|
||||
} else if (!strcasecmp(name,"integer")) {
|
||||
@@ -581,8 +583,8 @@ NULL
|
||||
} else {
|
||||
addReplyError(c,"Wrong protocol type name. Please use one of the following: string|integer|double|bignum|null|array|set|map|attrib|push|verbatim|true|false|state|err|bloberr");
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"sleep") && c->argc == 3) {
|
||||
double dtime = strtod(ptrFromObj(c->argv[2]),NULL);
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"sleep") && c->argc == 3) {
|
||||
double dtime = strtod(szFromObj(c->argv[2]),NULL);
|
||||
long long utime = dtime*1000000;
|
||||
struct timespec tv;
|
||||
|
||||
@@ -590,24 +592,24 @@ NULL
|
||||
tv.tv_nsec = (utime % 1000000) * 1000;
|
||||
nanosleep(&tv, NULL);
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"set-active-expire") &&
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"set-active-expire") &&
|
||||
c->argc == 3)
|
||||
{
|
||||
server.active_expire_enabled = atoi(ptrFromObj(c->argv[2]));
|
||||
server.active_expire_enabled = atoi(szFromObj(c->argv[2]));
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"lua-always-replicate-commands") &&
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"lua-always-replicate-commands") &&
|
||||
c->argc == 3)
|
||||
{
|
||||
server.lua_always_replicate_commands = atoi(ptrFromObj(c->argv[2]));
|
||||
server.lua_always_replicate_commands = atoi(szFromObj(c->argv[2]));
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"error") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"error") && c->argc == 3) {
|
||||
sds errstr = sdsnewlen("-",1);
|
||||
|
||||
errstr = sdscatsds(errstr,ptrFromObj(c->argv[2]));
|
||||
errstr = sdscatsds(errstr,szFromObj(c->argv[2]));
|
||||
errstr = sdsmapchars(errstr,"\n\r"," ",2); /* no newlines in errors. */
|
||||
errstr = sdscatlen(errstr,"\r\n",2);
|
||||
addReplySds(c,errstr);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"structsize") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"structsize") && c->argc == 2) {
|
||||
sds sizes = sdsempty();
|
||||
sizes = sdscatprintf(sizes,"bits:%d ",(sizeof(void*) == 8)?64:32);
|
||||
sizes = sdscatprintf(sizes,"robj:%d ",(int)sizeof(robj));
|
||||
@@ -618,7 +620,7 @@ NULL
|
||||
sizes = sdscatprintf(sizes,"sdshdr32:%d ",(int)sizeof(struct sdshdr32));
|
||||
sizes = sdscatprintf(sizes,"sdshdr64:%d ",(int)sizeof(struct sdshdr64));
|
||||
addReplyBulkSds(c,sizes);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"htstats") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"htstats") && c->argc == 3) {
|
||||
long dbid;
|
||||
sds stats = sdsempty();
|
||||
char buf[4096];
|
||||
@@ -639,7 +641,7 @@ NULL
|
||||
stats = sdscat(stats,buf);
|
||||
|
||||
addReplyBulkSds(c,stats);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"htstats-key") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"htstats-key") && c->argc == 3) {
|
||||
robj *o;
|
||||
dict *ht = NULL;
|
||||
|
||||
@@ -650,12 +652,12 @@ NULL
|
||||
switch (o->encoding) {
|
||||
case OBJ_ENCODING_SKIPLIST:
|
||||
{
|
||||
zset *zs = ptrFromObj(o);
|
||||
zset *zs = (zset*)ptrFromObj(o);
|
||||
ht = zs->pdict;
|
||||
}
|
||||
break;
|
||||
case OBJ_ENCODING_HT:
|
||||
ht = ptrFromObj(o);
|
||||
ht = (dict*)ptrFromObj(o);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -667,12 +669,12 @@ NULL
|
||||
dictGetStats(buf,sizeof(buf),ht);
|
||||
addReplyBulkCString(c,buf);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"change-repl-id") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"change-repl-id") && c->argc == 2) {
|
||||
serverLog(LL_WARNING,"Changing replication IDs after receiving DEBUG change-repl-id");
|
||||
changeReplicationId();
|
||||
clearReplicationId2();
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"stringmatch-test") && c->argc == 2)
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"stringmatch-test") && c->argc == 2)
|
||||
{
|
||||
stringmatchlen_fuzz_test();
|
||||
addReplyStatus(c,"Apparently Redis did not crash: test passed");
|
||||
@@ -726,9 +728,9 @@ void serverLogObjectDebugInfo(const robj *o) {
|
||||
serverLog(LL_WARNING,"Object encoding: %d", o->encoding);
|
||||
serverLog(LL_WARNING,"Object refcount: %d", o->refcount);
|
||||
if (o->type == OBJ_STRING && sdsEncodedObject(o)) {
|
||||
serverLog(LL_WARNING,"Object raw string len: %zu", sdslen(ptrFromObj(o)));
|
||||
if (sdslen(ptrFromObj(o)) < 4096) {
|
||||
sds repr = sdscatrepr(sdsempty(),ptrFromObj(o),sdslen(ptrFromObj(o)));
|
||||
serverLog(LL_WARNING,"Object raw string len: %zu", sdslen(szFromObj(o)));
|
||||
if (sdslen(szFromObj(o)) < 4096) {
|
||||
sds repr = sdscatrepr(sdsempty(),szFromObj(o),sdslen(szFromObj(o)));
|
||||
serverLog(LL_WARNING,"Object raw string content: %s", repr);
|
||||
sdsfree(repr);
|
||||
}
|
||||
@@ -1148,8 +1150,8 @@ void logStackTrace(ucontext_t *uc) {
|
||||
trace_size = backtrace(trace+1, 100);
|
||||
|
||||
if (getMcontextEip(uc) != NULL) {
|
||||
char *msg1 = "EIP:\n";
|
||||
char *msg2 = "\nBacktrace:\n";
|
||||
const char *msg1 = "EIP:\n";
|
||||
const char *msg2 = "\nBacktrace:\n";
|
||||
if (write(fd,msg1,strlen(msg1)) == -1) {/* Avoid warning. */};
|
||||
trace[0] = getMcontextEip(uc);
|
||||
backtrace_symbols_fd(trace, 1, fd);
|
||||
@@ -1194,7 +1196,7 @@ void logCurrentClient(void) {
|
||||
key = getDecodedObject(cc->argv[1]);
|
||||
de = dictFind(cc->db->pdict, ptrFromObj(key));
|
||||
if (de) {
|
||||
val = dictGetVal(de);
|
||||
val = (robj*)dictGetVal(de);
|
||||
serverLog(LL_WARNING,"key '%s' found in DB containing the following object:", (char*)ptrFromObj(key));
|
||||
serverLogObjectDebugInfo(val);
|
||||
}
|
||||
@@ -1255,7 +1257,7 @@ int memtest_test_linux_anonymous_maps(void) {
|
||||
int errors = 0;
|
||||
for (j = 0; j < regions; j++) {
|
||||
if (write(fd,".",1) == -1) { /* Nothing to do. */ }
|
||||
errors += memtest_preserving_test((void*)start_vect[j],size_vect[j],1);
|
||||
errors += memtest_preserving_test((unsigned long*)start_vect[j],size_vect[j],1);
|
||||
if (write(fd, errors ? "E" : "O",1) == -1) { /* Nothing to do. */ }
|
||||
}
|
||||
if (write(fd,"\n",1) == -1) { /* Nothing to do. */ }
|
||||
@@ -1274,7 +1276,7 @@ int memtest_test_linux_anonymous_maps(void) {
|
||||
* and the call offset if they appear to be valid. */
|
||||
void dumpX86Calls(void *addr, size_t len) {
|
||||
size_t j;
|
||||
unsigned char *p = addr;
|
||||
unsigned char *p = (unsigned char*)addr;
|
||||
Dl_info info;
|
||||
/* Hash table to best-effort avoid printing the same symbol
|
||||
* multiple times. */
|
||||
@@ -1401,9 +1403,9 @@ void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
|
||||
|
||||
/* ==================== Logging functions for debugging ===================== */
|
||||
|
||||
void serverLogHexDump(int level, char *descr, void *value, size_t len) {
|
||||
void serverLogHexDump(int level, const char *descr, void *value, size_t len) {
|
||||
char buf[65], *b;
|
||||
unsigned char *v = value;
|
||||
unsigned char *v = (unsigned char*)value;
|
||||
char charset[] = "0123456789abcdef";
|
||||
|
||||
serverLog(level,"%s (hexdump of %zu bytes):", descr, len);
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
/* this method was added to jemalloc in order to help us understand which
|
||||
* pointers are worthwhile moving and which aren't */
|
||||
int je_get_defrag_hint(void* ptr, int *bin_util, int *run_util);
|
||||
extern "C" int je_get_defrag_hint(void* ptr, int *bin_util, int *run_util);
|
||||
|
||||
/* forward declarations*/
|
||||
void defragDictBucketCallback(void *privdata, dictEntry **bucketref);
|
||||
@@ -107,7 +107,7 @@ robj *activeDefragStringOb(robj* ob, long *defragged) {
|
||||
|
||||
/* try to defrag robj (only if not an EMBSTR type (handled below). */
|
||||
if (ob->type!=OBJ_STRING || ob->encoding!=OBJ_ENCODING_EMBSTR) {
|
||||
if ((ret = activeDefragAlloc(ob))) {
|
||||
if ((ret = (robj*)activeDefragAlloc(ob))) {
|
||||
ob = ret;
|
||||
(*defragged)++;
|
||||
}
|
||||
@@ -124,7 +124,7 @@ robj *activeDefragStringOb(robj* ob, long *defragged) {
|
||||
} else if (ob->encoding==OBJ_ENCODING_EMBSTR) {
|
||||
/* The sds is embedded in the object allocation, calculate the
|
||||
* offset and update the pointer in the new allocation. */
|
||||
if ((ret = activeDefragAlloc(ob))) {
|
||||
if ((ret = (robj*)activeDefragAlloc(ob))) {
|
||||
(*defragged)++;
|
||||
}
|
||||
} else if (ob->encoding!=OBJ_ENCODING_INT) {
|
||||
@@ -145,7 +145,7 @@ long dictIterDefragEntry(dictIterator *iter) {
|
||||
/* Handle the next entry (if there is one), and update the pointer in the
|
||||
* current entry. */
|
||||
if (iter->nextEntry) {
|
||||
dictEntry *newde = activeDefragAlloc(iter->nextEntry);
|
||||
dictEntry *newde = (dictEntry*)activeDefragAlloc(iter->nextEntry);
|
||||
if (newde) {
|
||||
defragged++;
|
||||
iter->nextEntry = newde;
|
||||
@@ -155,7 +155,7 @@ long dictIterDefragEntry(dictIterator *iter) {
|
||||
/* handle the case of the first entry in the hash bucket. */
|
||||
ht = &iter->d->ht[iter->table];
|
||||
if (ht->table[iter->index] == iter->entry) {
|
||||
dictEntry *newde = activeDefragAlloc(iter->entry);
|
||||
dictEntry *newde = (dictEntry*)activeDefragAlloc(iter->entry);
|
||||
if (newde) {
|
||||
iter->entry = newde;
|
||||
ht->table[iter->index] = newde;
|
||||
@@ -172,12 +172,12 @@ long dictDefragTables(dict* d) {
|
||||
dictEntry **newtable;
|
||||
long defragged = 0;
|
||||
/* handle the first hash table */
|
||||
newtable = activeDefragAlloc(d->ht[0].table);
|
||||
newtable = (dictEntry**)activeDefragAlloc(d->ht[0].table);
|
||||
if (newtable)
|
||||
defragged++, d->ht[0].table = newtable;
|
||||
/* handle the second hash table */
|
||||
if (d->ht[1].table) {
|
||||
newtable = activeDefragAlloc(d->ht[1].table);
|
||||
newtable = (dictEntry**)activeDefragAlloc(d->ht[1].table);
|
||||
if (newtable)
|
||||
defragged++, d->ht[1].table = newtable;
|
||||
}
|
||||
@@ -188,13 +188,13 @@ long dictDefragTables(dict* d) {
|
||||
void zslUpdateNode(zskiplist *zsl, zskiplistNode *oldnode, zskiplistNode *newnode, zskiplistNode **update) {
|
||||
int i;
|
||||
for (i = 0; i < zsl->level; i++) {
|
||||
if (update[i]->level[i].forward == oldnode)
|
||||
update[i]->level[i].forward = newnode;
|
||||
if (update[i]->level(i)->forward == oldnode)
|
||||
update[i]->level(i)->forward = newnode;
|
||||
}
|
||||
serverAssert(zsl->header!=oldnode);
|
||||
if (newnode->level[0].forward) {
|
||||
serverAssert(newnode->level[0].forward->backward==oldnode);
|
||||
newnode->level[0].forward->backward = newnode;
|
||||
if (newnode->level(0)->forward) {
|
||||
serverAssert(newnode->level(0)->forward->backward==oldnode);
|
||||
newnode->level(0)->forward->backward = newnode;
|
||||
} else {
|
||||
serverAssert(zsl->tail==oldnode);
|
||||
zsl->tail = newnode;
|
||||
@@ -217,25 +217,25 @@ double *zslDefrag(zskiplist *zsl, double score, sds oldele, sds newele) {
|
||||
* and all pointers that need to be updated if we'll end up moving the skiplist node. */
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
while (x->level[i].forward &&
|
||||
x->level[i].forward->ele != oldele && /* make sure not to access the
|
||||
while (x->level(i)->forward &&
|
||||
x->level(i)->forward->ele != oldele && /* make sure not to access the
|
||||
->obj pointer if it matches
|
||||
oldele */
|
||||
(x->level[i].forward->score < score ||
|
||||
(x->level[i].forward->score == score &&
|
||||
sdscmp(x->level[i].forward->ele,ele) < 0)))
|
||||
x = x->level[i].forward;
|
||||
(x->level(i)->forward->score < score ||
|
||||
(x->level(i)->forward->score == score &&
|
||||
sdscmp(x->level(i)->forward->ele,ele) < 0)))
|
||||
x = x->level(i)->forward;
|
||||
update[i] = x;
|
||||
}
|
||||
|
||||
/* update the robj pointer inside the skip list record. */
|
||||
x = x->level[0].forward;
|
||||
x = x->level(0)->forward;
|
||||
serverAssert(x && score == x->score && x->ele==oldele);
|
||||
if (newele)
|
||||
x->ele = newele;
|
||||
|
||||
/* try to defrag the skiplist record itself */
|
||||
newx = activeDefragAlloc(x);
|
||||
newx = (zskiplistNode*)activeDefragAlloc(x);
|
||||
if (newx) {
|
||||
zslUpdateNode(zsl, x, newx, update);
|
||||
return &newx->score;
|
||||
@@ -249,7 +249,7 @@ long activeDefragZsetEntry(zset *zs, dictEntry *de) {
|
||||
sds newsds;
|
||||
double* newscore;
|
||||
long defragged = 0;
|
||||
sds sdsele = dictGetKey(de);
|
||||
sds sdsele = (sds)dictGetKey(de);
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
defragged++, de->key = newsds;
|
||||
newscore = zslDefrag(zs->zsl, *(double*)dictGetVal(de), sdsele, newsds);
|
||||
@@ -272,16 +272,16 @@ long activeDefragSdsDict(dict* d, int val_type) {
|
||||
long defragged = 0;
|
||||
di = dictGetIterator(d);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sds sdsele = dictGetKey(de), newsds;
|
||||
sds sdsele = (sds)dictGetKey(de), newsds;
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
de->key = newsds, defragged++;
|
||||
/* defrag the value */
|
||||
if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
|
||||
sdsele = dictGetVal(de);
|
||||
sdsele = (sds)dictGetVal(de);
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
de->v.val = newsds, defragged++;
|
||||
} else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
|
||||
robj *newele, *ele = dictGetVal(de);
|
||||
robj *newele, *ele = (robj*)dictGetVal(de);
|
||||
if ((newele = activeDefragStringOb(ele, &defragged)))
|
||||
de->v.val = newele;
|
||||
} else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
|
||||
@@ -300,7 +300,7 @@ long activeDefragList(list *l, int val_type) {
|
||||
long defragged = 0;
|
||||
listNode *ln, *newln;
|
||||
for (ln = l->head; ln; ln = ln->next) {
|
||||
if ((newln = activeDefragAlloc(ln))) {
|
||||
if ((newln = (listNode*)activeDefragAlloc(ln))) {
|
||||
if (newln->prev)
|
||||
newln->prev->next = newln;
|
||||
else
|
||||
@@ -313,11 +313,11 @@ long activeDefragList(list *l, int val_type) {
|
||||
defragged++;
|
||||
}
|
||||
if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
|
||||
sds newsds, sdsele = ln->value;
|
||||
sds newsds, sdsele = (sds)ln->value;
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
ln->value = newsds, defragged++;
|
||||
} else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
|
||||
robj *newele, *ele = ln->value;
|
||||
robj *newele, *ele = (robj*)ln->value;
|
||||
if ((newele = activeDefragStringOb(ele, &defragged)))
|
||||
ln->value = newele;
|
||||
} else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
|
||||
@@ -338,7 +338,7 @@ long activeDefragSdsListAndDict(list *l, dict *d, int dict_val_type) {
|
||||
dictEntry *de;
|
||||
/* Defrag the list and it's sds values */
|
||||
for (ln = l->head; ln; ln = ln->next) {
|
||||
if ((newln = activeDefragAlloc(ln))) {
|
||||
if ((newln = (listNode*)activeDefragAlloc(ln))) {
|
||||
if (newln->prev)
|
||||
newln->prev->next = newln;
|
||||
else
|
||||
@@ -350,7 +350,7 @@ long activeDefragSdsListAndDict(list *l, dict *d, int dict_val_type) {
|
||||
ln = newln;
|
||||
defragged++;
|
||||
}
|
||||
sdsele = ln->value;
|
||||
sdsele = (sds)ln->value;
|
||||
if ((newsds = activeDefragSds(sdsele))) {
|
||||
/* When defragging an sds value, we need to update the dict key */
|
||||
unsigned int hash = dictGetHash(d, sdsele);
|
||||
@@ -364,11 +364,11 @@ long activeDefragSdsListAndDict(list *l, dict *d, int dict_val_type) {
|
||||
di = dictGetIterator(d);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
if (dict_val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
|
||||
sds newsds, sdsele = dictGetVal(de);
|
||||
sds newsds, sdsele = (sds)dictGetVal(de);
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
de->v.val = newsds, defragged++;
|
||||
} else if (dict_val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
|
||||
robj *newele, *ele = dictGetVal(de);
|
||||
robj *newele, *ele = (robj*)dictGetVal(de);
|
||||
if ((newele = activeDefragStringOb(ele, &defragged)))
|
||||
de->v.val = newele, defragged++;
|
||||
} else if (dict_val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
|
||||
@@ -394,7 +394,7 @@ dictEntry* replaceSateliteDictKeyPtrAndOrDefragDictEntry(dict *d, sds oldkey, sd
|
||||
dictEntry **deref = dictFindEntryRefByPtrAndHash(d, oldkey, hash);
|
||||
if (deref) {
|
||||
dictEntry *de = *deref;
|
||||
dictEntry *newde = activeDefragAlloc(de);
|
||||
dictEntry *newde = (dictEntry*)activeDefragAlloc(de);
|
||||
if (newde) {
|
||||
de = *deref = newde;
|
||||
(*defragged)++;
|
||||
@@ -411,7 +411,7 @@ long activeDefragQuickListNodes(quicklist *ql) {
|
||||
long defragged = 0;
|
||||
unsigned char *newzl;
|
||||
while (node) {
|
||||
if ((newnode = activeDefragAlloc(node))) {
|
||||
if ((newnode = (quicklistNode*)activeDefragAlloc(node))) {
|
||||
if (newnode->prev)
|
||||
newnode->prev->next = newnode;
|
||||
else
|
||||
@@ -423,7 +423,7 @@ long activeDefragQuickListNodes(quicklist *ql) {
|
||||
node = newnode;
|
||||
defragged++;
|
||||
}
|
||||
if ((newzl = activeDefragAlloc(node->zl)))
|
||||
if ((newzl = (unsigned char*)activeDefragAlloc(node->zl)))
|
||||
defragged++, node->zl = newzl;
|
||||
node = node->next;
|
||||
}
|
||||
@@ -434,12 +434,12 @@ long activeDefragQuickListNodes(quicklist *ql) {
|
||||
* oart of the main dictionary scan. this is needed in order to prevent latency
|
||||
* spikes when handling large items */
|
||||
void defragLater(redisDb *db, dictEntry *kde) {
|
||||
sds key = sdsdup(dictGetKey(kde));
|
||||
sds key = sdsdup((sds)dictGetKey(kde));
|
||||
listAddNodeTail(db->defrag_later, key);
|
||||
}
|
||||
|
||||
long scanLaterList(robj *ob) {
|
||||
quicklist *ql = ptrFromObj(ob);
|
||||
quicklist *ql = (quicklist*)ptrFromObj(ob);
|
||||
if (ob->type != OBJ_LIST || ob->encoding != OBJ_ENCODING_QUICKLIST)
|
||||
return 0;
|
||||
server.stat_active_defrag_scanned+=ql->len;
|
||||
@@ -453,7 +453,7 @@ typedef struct {
|
||||
|
||||
void scanLaterZsetCallback(void *privdata, const dictEntry *_de) {
|
||||
dictEntry *de = (dictEntry*)_de;
|
||||
scanLaterZsetData *data = privdata;
|
||||
scanLaterZsetData *data = (scanLaterZsetData*)privdata;
|
||||
data->defragged += activeDefragZsetEntry(data->zs, de);
|
||||
server.stat_active_defrag_scanned++;
|
||||
}
|
||||
@@ -470,8 +470,8 @@ long scanLaterZset(robj *ob, unsigned long *cursor) {
|
||||
|
||||
void scanLaterSetCallback(void *privdata, const dictEntry *_de) {
|
||||
dictEntry *de = (dictEntry*)_de;
|
||||
long *defragged = privdata;
|
||||
sds sdsele = dictGetKey(de), newsds;
|
||||
long *defragged = (long*)privdata;
|
||||
sds sdsele = (sds)dictGetKey(de), newsds;
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
(*defragged)++, de->key = newsds;
|
||||
server.stat_active_defrag_scanned++;
|
||||
@@ -481,18 +481,18 @@ long scanLaterSet(robj *ob, unsigned long *cursor) {
|
||||
long defragged = 0;
|
||||
if (ob->type != OBJ_SET || ob->encoding != OBJ_ENCODING_HT)
|
||||
return 0;
|
||||
dict *d = ptrFromObj(ob);
|
||||
dict *d = (dict*)ptrFromObj(ob);
|
||||
*cursor = dictScan(d, *cursor, scanLaterSetCallback, defragDictBucketCallback, &defragged);
|
||||
return defragged;
|
||||
}
|
||||
|
||||
void scanLaterHashCallback(void *privdata, const dictEntry *_de) {
|
||||
dictEntry *de = (dictEntry*)_de;
|
||||
long *defragged = privdata;
|
||||
sds sdsele = dictGetKey(de), newsds;
|
||||
long *defragged = (long*)privdata;
|
||||
sds sdsele = (sds)dictGetKey(de), newsds;
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
(*defragged)++, de->key = newsds;
|
||||
sdsele = dictGetVal(de);
|
||||
sdsele = (sds)dictGetVal(de);
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
(*defragged)++, de->v.val = newsds;
|
||||
server.stat_active_defrag_scanned++;
|
||||
@@ -502,17 +502,17 @@ long scanLaterHash(robj *ob, unsigned long *cursor) {
|
||||
long defragged = 0;
|
||||
if (ob->type != OBJ_HASH || ob->encoding != OBJ_ENCODING_HT)
|
||||
return 0;
|
||||
dict *d = ptrFromObj(ob);
|
||||
dict *d = (dict*)ptrFromObj(ob);
|
||||
*cursor = dictScan(d, *cursor, scanLaterHashCallback, defragDictBucketCallback, &defragged);
|
||||
return defragged;
|
||||
}
|
||||
|
||||
long defragQuicklist(redisDb *db, dictEntry *kde) {
|
||||
robj *ob = dictGetVal(kde);
|
||||
robj *ob = (robj*)dictGetVal(kde);
|
||||
long defragged = 0;
|
||||
quicklist *ql = ptrFromObj(ob), *newql;
|
||||
quicklist *ql = (quicklist*)ptrFromObj(ob), *newql;
|
||||
serverAssert(ob->type == OBJ_LIST && ob->encoding == OBJ_ENCODING_QUICKLIST);
|
||||
if ((newql = activeDefragAlloc(ql)))
|
||||
if ((newql = (quicklist*)activeDefragAlloc(ql)))
|
||||
defragged++, ob->m_ptr = ql = newql;
|
||||
if (ql->len > server.active_defrag_max_scan_fields)
|
||||
defragLater(db, kde);
|
||||
@@ -522,7 +522,7 @@ long defragQuicklist(redisDb *db, dictEntry *kde) {
|
||||
}
|
||||
|
||||
long defragZsetSkiplist(redisDb *db, dictEntry *kde) {
|
||||
robj *ob = dictGetVal(kde);
|
||||
robj *ob = (robj*)dictGetVal(kde);
|
||||
long defragged = 0;
|
||||
zset *zs = (zset*)ptrFromObj(ob);
|
||||
zset *newzs;
|
||||
@@ -531,11 +531,11 @@ long defragZsetSkiplist(redisDb *db, dictEntry *kde) {
|
||||
dictEntry *de;
|
||||
struct zskiplistNode *newheader;
|
||||
serverAssert(ob->type == OBJ_ZSET && ob->encoding == OBJ_ENCODING_SKIPLIST);
|
||||
if ((newzs = activeDefragAlloc(zs)))
|
||||
if ((newzs = (zset*)activeDefragAlloc(zs)))
|
||||
defragged++, ob->m_ptr = zs = newzs;
|
||||
if ((newzsl = activeDefragAlloc(zs->zsl)))
|
||||
if ((newzsl = (zskiplist*)activeDefragAlloc(zs->zsl)))
|
||||
defragged++, zs->zsl = newzsl;
|
||||
if ((newheader = activeDefragAlloc(zs->zsl->header)))
|
||||
if ((newheader = (zskiplistNode*)activeDefragAlloc(zs->zsl->header)))
|
||||
defragged++, zs->zsl->header = newheader;
|
||||
if (dictSize(zs->pdict) > server.active_defrag_max_scan_fields)
|
||||
defragLater(db, kde);
|
||||
@@ -547,7 +547,7 @@ long defragZsetSkiplist(redisDb *db, dictEntry *kde) {
|
||||
dictReleaseIterator(di);
|
||||
}
|
||||
/* handle the dict struct */
|
||||
if ((newdict = activeDefragAlloc(zs->pdict)))
|
||||
if ((newdict = (dict*)activeDefragAlloc(zs->pdict)))
|
||||
defragged++, zs->pdict = newdict;
|
||||
/* defrag the dict tables */
|
||||
defragged += dictDefragTables(zs->pdict);
|
||||
@@ -556,44 +556,44 @@ long defragZsetSkiplist(redisDb *db, dictEntry *kde) {
|
||||
|
||||
long defragHash(redisDb *db, dictEntry *kde) {
|
||||
long defragged = 0;
|
||||
robj *ob = dictGetVal(kde);
|
||||
robj *ob = (robj*)dictGetVal(kde);
|
||||
dict *d, *newd;
|
||||
serverAssert(ob->type == OBJ_HASH && ob->encoding == OBJ_ENCODING_HT);
|
||||
d = ptrFromObj(ob);
|
||||
d = (dict*)ptrFromObj(ob);
|
||||
if (dictSize(d) > server.active_defrag_max_scan_fields)
|
||||
defragLater(db, kde);
|
||||
else
|
||||
defragged += activeDefragSdsDict(d, DEFRAG_SDS_DICT_VAL_IS_SDS);
|
||||
/* handle the dict struct */
|
||||
if ((newd = activeDefragAlloc(ptrFromObj(ob))))
|
||||
if ((newd = (dict*)activeDefragAlloc(ptrFromObj(ob))))
|
||||
defragged++, ob->m_ptr = newd;
|
||||
/* defrag the dict tables */
|
||||
defragged += dictDefragTables(ptrFromObj(ob));
|
||||
defragged += dictDefragTables((dict*)ptrFromObj(ob));
|
||||
return defragged;
|
||||
}
|
||||
|
||||
long defragSet(redisDb *db, dictEntry *kde) {
|
||||
long defragged = 0;
|
||||
robj *ob = dictGetVal(kde);
|
||||
robj *ob = (robj*)dictGetVal(kde);
|
||||
dict *d, *newd;
|
||||
serverAssert(ob->type == OBJ_SET && ob->encoding == OBJ_ENCODING_HT);
|
||||
d = ptrFromObj(ob);
|
||||
d = (dict*)ptrFromObj(ob);
|
||||
if (dictSize(d) > server.active_defrag_max_scan_fields)
|
||||
defragLater(db, kde);
|
||||
else
|
||||
defragged += activeDefragSdsDict(d, DEFRAG_SDS_DICT_NO_VAL);
|
||||
/* handle the dict struct */
|
||||
if ((newd = activeDefragAlloc(ptrFromObj(ob))))
|
||||
if ((newd = (dict*)activeDefragAlloc(ptrFromObj(ob))))
|
||||
defragged++, ob->m_ptr = newd;
|
||||
/* defrag the dict tables */
|
||||
defragged += dictDefragTables(ptrFromObj(ob));
|
||||
defragged += dictDefragTables((dict*)ptrFromObj(ob));
|
||||
return defragged;
|
||||
}
|
||||
|
||||
/* Defrag callback for radix tree iterator, called for each node,
|
||||
* used in order to defrag the nodes allocations. */
|
||||
int defragRaxNode(raxNode **noderef) {
|
||||
raxNode *newnode = activeDefragAlloc(*noderef);
|
||||
raxNode *newnode = (raxNode*)activeDefragAlloc(*noderef);
|
||||
if (newnode) {
|
||||
*noderef = newnode;
|
||||
return 1;
|
||||
@@ -611,7 +611,7 @@ int scanLaterStraemListpacks(robj *ob, unsigned long *cursor, long long endtime,
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream *s = ptrFromObj(ob);
|
||||
stream *s = (stream*)ptrFromObj(ob);
|
||||
raxStart(&ri,s->prax);
|
||||
if (*cursor == 0) {
|
||||
/* if cursor is 0, we start new iteration */
|
||||
@@ -662,8 +662,8 @@ typedef void *(raxDefragFunction)(raxIterator *ri, void *privdata, long *defragg
|
||||
long defragRadixTree(rax **raxref, int defrag_data, raxDefragFunction *element_cb, void *element_cb_data) {
|
||||
long defragged = 0;
|
||||
raxIterator ri;
|
||||
rax* rax;
|
||||
if ((rax = activeDefragAlloc(*raxref)))
|
||||
::rax* rax;
|
||||
if ((rax = (::rax*)activeDefragAlloc(*raxref)))
|
||||
defragged++, *raxref = rax;
|
||||
rax = *raxref;
|
||||
raxStart(&ri,rax);
|
||||
@@ -690,10 +690,10 @@ typedef struct {
|
||||
|
||||
void* defragStreamConsumerPendingEntry(raxIterator *ri, void *privdata, long *defragged) {
|
||||
UNUSED(defragged);
|
||||
PendingEntryContext *ctx = privdata;
|
||||
streamNACK *nack = ri->data, *newnack;
|
||||
PendingEntryContext *ctx = (PendingEntryContext*)privdata;
|
||||
streamNACK *nack = (streamNACK*)ri->data, *newnack;
|
||||
nack->consumer = ctx->c; /* update nack pointer to consumer */
|
||||
newnack = activeDefragAlloc(nack);
|
||||
newnack = (streamNACK*)activeDefragAlloc(nack);
|
||||
if (newnack) {
|
||||
/* update consumer group pointer to the nack */
|
||||
void *prev;
|
||||
@@ -705,12 +705,12 @@ void* defragStreamConsumerPendingEntry(raxIterator *ri, void *privdata, long *de
|
||||
}
|
||||
|
||||
void* defragStreamConsumer(raxIterator *ri, void *privdata, long *defragged) {
|
||||
streamConsumer *c = ri->data;
|
||||
streamCG *cg = privdata;
|
||||
streamConsumer *c = (streamConsumer*)ri->data;
|
||||
streamCG *cg = (streamCG*)privdata;
|
||||
void *newc = activeDefragAlloc(c);
|
||||
if (newc) {
|
||||
/* note: we don't increment 'defragged' that's done by the caller */
|
||||
c = newc;
|
||||
c = (streamConsumer*)newc;
|
||||
}
|
||||
sds newsds = activeDefragSds(c->name);
|
||||
if (newsds)
|
||||
@@ -723,7 +723,7 @@ void* defragStreamConsumer(raxIterator *ri, void *privdata, long *defragged) {
|
||||
}
|
||||
|
||||
void* defragStreamConsumerGroup(raxIterator *ri, void *privdata, long *defragged) {
|
||||
streamCG *cg = ri->data;
|
||||
streamCG *cg = (streamCG*)ri->data;
|
||||
UNUSED(privdata);
|
||||
if (cg->consumers)
|
||||
*defragged += defragRadixTree(&cg->consumers, 0, defragStreamConsumer, cg);
|
||||
@@ -734,16 +734,16 @@ void* defragStreamConsumerGroup(raxIterator *ri, void *privdata, long *defragged
|
||||
|
||||
long defragStream(redisDb *db, dictEntry *kde) {
|
||||
long defragged = 0;
|
||||
robj *ob = dictGetVal(kde);
|
||||
robj *ob = (robj*)dictGetVal(kde);
|
||||
serverAssert(ob->type == OBJ_STREAM && ob->encoding == OBJ_ENCODING_STREAM);
|
||||
stream *s = ptrFromObj(ob), *news;
|
||||
stream *s = (stream*)ptrFromObj(ob), *news;
|
||||
|
||||
/* handle the main struct */
|
||||
if ((news = activeDefragAlloc(s)))
|
||||
if ((news = (stream*)activeDefragAlloc(s)))
|
||||
defragged++, ob->m_ptr = s = news;
|
||||
|
||||
if (raxSize(s->prax) > server.active_defrag_max_scan_fields) {
|
||||
rax *newrax = activeDefragAlloc(s->prax);
|
||||
rax *newrax = (rax*)activeDefragAlloc(s->prax);
|
||||
if (newrax)
|
||||
defragged++, s->prax = newrax;
|
||||
defragLater(db, kde);
|
||||
@@ -759,7 +759,7 @@ long defragStream(redisDb *db, dictEntry *kde) {
|
||||
* all the various pointers it has. Returns a stat of how many pointers were
|
||||
* moved. */
|
||||
long defragKey(redisDb *db, dictEntry *de) {
|
||||
sds keysds = dictGetKey(de);
|
||||
sds keysds = (sds)dictGetKey(de);
|
||||
robj *newob, *ob;
|
||||
unsigned char *newzl;
|
||||
long defragged = 0;
|
||||
@@ -778,7 +778,7 @@ long defragKey(redisDb *db, dictEntry *de) {
|
||||
}
|
||||
|
||||
/* Try to defrag robj and / or string value. */
|
||||
ob = dictGetVal(de);
|
||||
ob = (robj*)dictGetVal(de);
|
||||
if ((newob = activeDefragStringOb(ob, &defragged))) {
|
||||
de->v.val = newob;
|
||||
ob = newob;
|
||||
@@ -790,7 +790,7 @@ long defragKey(redisDb *db, dictEntry *de) {
|
||||
if (ob->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
defragged += defragQuicklist(db, de);
|
||||
} else if (ob->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
if ((newzl = activeDefragAlloc(ptrFromObj(ob))))
|
||||
if ((newzl = (unsigned char*)activeDefragAlloc(ptrFromObj(ob))))
|
||||
defragged++, ob->m_ptr = newzl;
|
||||
} else {
|
||||
serverPanic("Unknown list encoding");
|
||||
@@ -799,15 +799,15 @@ long defragKey(redisDb *db, dictEntry *de) {
|
||||
if (ob->encoding == OBJ_ENCODING_HT) {
|
||||
defragged += defragSet(db, de);
|
||||
} else if (ob->encoding == OBJ_ENCODING_INTSET) {
|
||||
intset *newis, *is = ptrFromObj(ob);
|
||||
if ((newis = activeDefragAlloc(is)))
|
||||
intset *newis, *is = (intset*)ptrFromObj(ob);
|
||||
if ((newis = (intset*)activeDefragAlloc(is)))
|
||||
defragged++, ob->m_ptr = newis;
|
||||
} else {
|
||||
serverPanic("Unknown set encoding");
|
||||
}
|
||||
} else if (ob->type == OBJ_ZSET) {
|
||||
if (ob->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
if ((newzl = activeDefragAlloc(ptrFromObj(ob))))
|
||||
if ((newzl = (unsigned char*)activeDefragAlloc(ptrFromObj(ob))))
|
||||
defragged++, ob->m_ptr = newzl;
|
||||
} else if (ob->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
defragged += defragZsetSkiplist(db, de);
|
||||
@@ -816,7 +816,7 @@ long defragKey(redisDb *db, dictEntry *de) {
|
||||
}
|
||||
} else if (ob->type == OBJ_HASH) {
|
||||
if (ob->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
if ((newzl = activeDefragAlloc(ptrFromObj(ob))))
|
||||
if ((newzl = (unsigned char*)activeDefragAlloc(ptrFromObj(ob))))
|
||||
defragged++, ob->m_ptr = newzl;
|
||||
} else if (ob->encoding == OBJ_ENCODING_HT) {
|
||||
defragged += defragHash(db, de);
|
||||
@@ -851,7 +851,7 @@ void defragDictBucketCallback(void *privdata, dictEntry **bucketref) {
|
||||
UNUSED(privdata); /* NOTE: this function is also used by both activeDefragCycle and scanLaterHash, etc. don't use privdata */
|
||||
while(*bucketref) {
|
||||
dictEntry *de = *bucketref, *newde;
|
||||
if ((newde = activeDefragAlloc(de))) {
|
||||
if ((newde = (dictEntry*)activeDefragAlloc(de))) {
|
||||
*bucketref = newde;
|
||||
}
|
||||
bucketref = &(*bucketref)->next;
|
||||
@@ -896,7 +896,7 @@ long defragOtherGlobals() {
|
||||
* and 1 if time is up and more work is needed. */
|
||||
int defragLaterItem(dictEntry *de, unsigned long *cursor, long long endtime) {
|
||||
if (de) {
|
||||
robj *ob = dictGetVal(de);
|
||||
robj *ob = (robj*)dictGetVal(de);
|
||||
if (ob->type == OBJ_LIST) {
|
||||
server.stat_active_defrag_hits += scanLaterList(ob);
|
||||
*cursor = 0; /* list has no scan, we must finish it in one go */
|
||||
@@ -934,7 +934,7 @@ int defragLaterStep(redisDb *db, long long endtime) {
|
||||
/* Move on to next key */
|
||||
if (current_key) {
|
||||
serverAssert(current_key == head->value);
|
||||
sdsfree(head->value);
|
||||
sdsfree((sds)head->value);
|
||||
listDelNode(db->defrag_later, head);
|
||||
cursor = 0;
|
||||
current_key = NULL;
|
||||
@@ -946,7 +946,7 @@ int defragLaterStep(redisDb *db, long long endtime) {
|
||||
return 0;
|
||||
|
||||
/* start a new key */
|
||||
current_key = head->value;
|
||||
current_key = (sds)head->value;
|
||||
cursor = 0;
|
||||
}
|
||||
|
||||
@@ -84,11 +84,11 @@ uint8_t *dictGetHashFunctionSeed(void) {
|
||||
/* The default hashing function uses SipHash implementation
|
||||
* in siphash.c. */
|
||||
|
||||
uint64_t siphash(const uint8_t *in, const size_t inlen, const uint8_t *k);
|
||||
uint64_t siphash_nocase(const uint8_t *in, const size_t inlen, const uint8_t *k);
|
||||
extern "C" uint64_t siphash(const uint8_t *in, const size_t inlen, const uint8_t *k);
|
||||
extern "C" uint64_t siphash_nocase(const uint8_t *in, const size_t inlen, const uint8_t *k);
|
||||
|
||||
uint64_t dictGenHashFunction(const void *key, int len) {
|
||||
return siphash(key,len,dict_hash_function_seed);
|
||||
return siphash((const uint8_t*)key,len,dict_hash_function_seed);
|
||||
}
|
||||
|
||||
uint64_t dictGenCaseHashFunction(const unsigned char *buf, int len) {
|
||||
@@ -111,7 +111,7 @@ static void _dictReset(dictht *ht)
|
||||
dict *dictCreate(dictType *type,
|
||||
void *privDataPtr)
|
||||
{
|
||||
dict *d = zmalloc(sizeof(*d), MALLOC_SHARED);
|
||||
dict *d = (dict*)zmalloc(sizeof(*d), MALLOC_SHARED);
|
||||
|
||||
_dictInit(d,type,privDataPtr);
|
||||
return d;
|
||||
@@ -160,7 +160,7 @@ int dictExpand(dict *d, unsigned long size)
|
||||
/* Allocate the new hash table and initialize all pointers to NULL */
|
||||
n.size = realsize;
|
||||
n.sizemask = realsize-1;
|
||||
n.table = zcalloc(realsize*sizeof(dictEntry*), MALLOC_SHARED);
|
||||
n.table = (dictEntry**)zcalloc(realsize*sizeof(dictEntry*), MALLOC_SHARED);
|
||||
n.used = 0;
|
||||
|
||||
/* Is this the first initialization? If so it's not really a rehashing
|
||||
@@ -307,7 +307,7 @@ dictEntry *dictAddRaw(dict *d, void *key, dictEntry **existing)
|
||||
* system it is more likely that recently added entries are accessed
|
||||
* more frequently. */
|
||||
ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];
|
||||
entry = zmalloc(sizeof(*entry), MALLOC_SHARED);
|
||||
entry = (dictEntry*)zmalloc(sizeof(*entry), MALLOC_SHARED);
|
||||
entry->next = ht->table[index];
|
||||
ht->table[index] = entry;
|
||||
ht->used++;
|
||||
@@ -541,7 +541,7 @@ long long dictFingerprint(dict *d) {
|
||||
|
||||
dictIterator *dictGetIterator(dict *d)
|
||||
{
|
||||
dictIterator *iter = zmalloc(sizeof(*iter), MALLOC_LOCAL);
|
||||
dictIterator *iter = (dictIterator*)zmalloc(sizeof(*iter), MALLOC_LOCAL);
|
||||
|
||||
iter->d = d;
|
||||
iter->table = 0;
|
||||
@@ -39,6 +39,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
#error "C++ Only"
|
||||
#endif
|
||||
|
||||
#ifndef __DICT_H
|
||||
#define __DICT_H
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ void evictionPoolAlloc(void) {
|
||||
struct evictionPoolEntry *ep;
|
||||
int j;
|
||||
|
||||
ep = zmalloc(sizeof(*ep)*EVPOOL_SIZE, MALLOC_LOCAL);
|
||||
ep = (evictionPoolEntry*)zmalloc(sizeof(*ep)*EVPOOL_SIZE, MALLOC_LOCAL);
|
||||
for (j = 0; j < EVPOOL_SIZE; j++) {
|
||||
ep[j].idle = 0;
|
||||
ep[j].key = NULL;
|
||||
@@ -161,7 +161,7 @@ void evictionPoolAlloc(void) {
|
||||
|
||||
void evictionPoolPopulate(int dbid, dict *sampledict, dict *keydict, struct evictionPoolEntry *pool) {
|
||||
int j, k, count;
|
||||
dictEntry *samples[server.maxmemory_samples];
|
||||
dictEntry **samples = (dictEntry**)alloca(server.maxmemory_samples * sizeof(dictEntry*));
|
||||
|
||||
count = dictGetSomeKeys(sampledict,samples,server.maxmemory_samples);
|
||||
for (j = 0; j < count; j++) {
|
||||
@@ -171,14 +171,14 @@ void evictionPoolPopulate(int dbid, dict *sampledict, dict *keydict, struct evic
|
||||
dictEntry *de;
|
||||
|
||||
de = samples[j];
|
||||
key = dictGetKey(de);
|
||||
key = (sds)dictGetKey(de);
|
||||
|
||||
/* If the dictionary we are sampling from is not the main
|
||||
* dictionary (but the expires one) we need to lookup the key
|
||||
* again in the key dictionary to obtain the value object. */
|
||||
if (server.maxmemory_policy != MAXMEMORY_VOLATILE_TTL) {
|
||||
if (sampledict != keydict) de = dictFind(keydict, key);
|
||||
o = dictGetVal(de);
|
||||
o = (robj*)dictGetVal(de);
|
||||
}
|
||||
|
||||
/* Calculate the idle time according to the policy. This is called
|
||||
@@ -360,7 +360,7 @@ size_t freeMemoryGetNotCountedMemory(void) {
|
||||
|
||||
listRewind(server.slaves,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
client *slave = listNodeValue(ln);
|
||||
client *slave = (client*)listNodeValue(ln);
|
||||
overhead += getClientOutputBufferMemoryUsage(slave);
|
||||
}
|
||||
}
|
||||
@@ -448,7 +448,7 @@ int freeMemoryIfNeeded(void) {
|
||||
serverAssert(GlobalLocksAcquired());
|
||||
/* By default replicas should ignore maxmemory
|
||||
* and just be masters exact copies. */
|
||||
if (server.masterhost && server.repl_slave_ignore_maxmemory) return C_OK;
|
||||
if (listLength(server.masters) && server.repl_slave_ignore_maxmemory) return C_OK;
|
||||
|
||||
size_t mem_reported, mem_tofree, mem_freed;
|
||||
mstime_t latency, eviction_latency;
|
||||
@@ -521,7 +521,7 @@ int freeMemoryIfNeeded(void) {
|
||||
/* If the key exists, is our pick. Otherwise it is
|
||||
* a ghost and we need to try the next element. */
|
||||
if (de) {
|
||||
bestkey = dictGetKey(de);
|
||||
bestkey = (sds)dictGetKey(de);
|
||||
break;
|
||||
} else {
|
||||
/* Ghost... Iterate again. */
|
||||
@@ -544,7 +544,7 @@ int freeMemoryIfNeeded(void) {
|
||||
db->pdict : db->expires;
|
||||
if (dictSize(dict) != 0) {
|
||||
de = dictGetRandomKey(dict);
|
||||
bestkey = dictGetKey(de);
|
||||
bestkey = (sds)dictGetKey(de);
|
||||
bestdbid = j;
|
||||
break;
|
||||
}
|
||||
@@ -54,7 +54,7 @@
|
||||
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
|
||||
long long t = dictGetSignedIntegerVal(de);
|
||||
if (now > t) {
|
||||
sds key = dictGetKey(de);
|
||||
sds key = (sds)dictGetKey(de);
|
||||
robj *keyobj = createStringObject(key,sdslen(key));
|
||||
|
||||
propagateExpire(db,keyobj,server.lazyfree_lazy_expire);
|
||||
@@ -290,7 +290,7 @@ void expireSlaveKeys(void) {
|
||||
mstime_t start = mstime();
|
||||
while(1) {
|
||||
dictEntry *de = dictGetRandomKey(slaveKeysWithExpire);
|
||||
sds keyname = dictGetKey(de);
|
||||
sds keyname = (sds)dictGetKey(de);
|
||||
uint64_t dbids = dictGetUnsignedIntegerVal(de);
|
||||
uint64_t new_dbids = 0;
|
||||
|
||||
@@ -361,7 +361,7 @@ void rememberSlaveKeyWithExpire(redisDb *db, robj *key) {
|
||||
* in sync with the main DB. The keys will be removed by expireSlaveKeys()
|
||||
* as it scans to find keys to remove. */
|
||||
if (de->key == ptrFromObj(key)) {
|
||||
de->key = sdsdup(ptrFromObj(key));
|
||||
de->key = sdsdup(szFromObj(key));
|
||||
dictSetUnsignedIntegerVal(de,0);
|
||||
}
|
||||
|
||||
@@ -424,7 +424,7 @@ void expireGenericCommand(client *c, long long basetime, int unit) {
|
||||
*
|
||||
* Instead we take the other branch of the IF statement setting an expire
|
||||
* (possibly in the past) and wait for an explicit DEL from the master. */
|
||||
if (when <= mstime() && !server.loading && !server.masterhost) {
|
||||
if (when <= mstime() && !server.loading && !listLength(server.masters)) {
|
||||
robj *aux;
|
||||
|
||||
int deleted = server.lazyfree_lazy_expire ? dbAsyncDelete(c->db,key) :
|
||||
+35
-2
@@ -34,6 +34,20 @@
|
||||
#include <sched.h>
|
||||
#include <atomic>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
#ifdef TARGET_OS_MAC
|
||||
/* The CLANG that ships with Mac OS doesn't have these builtins.
|
||||
but on x86 they are just normal reads/writes anyways */
|
||||
#define __atomic_load_4(ptr, csq) (*(reinterpret_cast<const volatile uint32_t*>(ptr)))
|
||||
#define __atomic_load_2(ptr, csq) (*(reinterpret_cast<const volatile uint16_t*>(ptr)))
|
||||
|
||||
#define __atomic_store_4(ptr, val, csq) (*(reinterpret_cast<volatile uint32_t*>(ptr)) = val)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/****************************************************
|
||||
*
|
||||
@@ -43,12 +57,28 @@
|
||||
****************************************************/
|
||||
|
||||
static_assert(sizeof(pid_t) <= sizeof(fastlock::m_pidOwner), "fastlock::m_pidOwner not large enough");
|
||||
uint64_t g_longwaits = 0;
|
||||
|
||||
uint64_t fastlock_getlongwaitcount()
|
||||
{
|
||||
return g_longwaits;
|
||||
}
|
||||
|
||||
|
||||
extern "C" pid_t gettid()
|
||||
{
|
||||
static thread_local int pidCache = -1;
|
||||
#ifdef __linux__
|
||||
if (pidCache == -1)
|
||||
pidCache = syscall(SYS_gettid);
|
||||
#else
|
||||
if (pidCache == -1) {
|
||||
uint64_t tidT;
|
||||
pthread_threadid_np(nullptr, &tidT);
|
||||
assert(tidT < UINT_MAX);
|
||||
pidCache = (int)tidT;
|
||||
}
|
||||
#endif
|
||||
return pidCache;
|
||||
}
|
||||
|
||||
@@ -75,7 +105,10 @@ extern "C" void fastlock_lock(struct fastlock *lock)
|
||||
while (__atomic_load_2(&lock->m_ticket.m_active, __ATOMIC_ACQUIRE) != myticket)
|
||||
{
|
||||
if ((++cloops % 1024*1024) == 0)
|
||||
{
|
||||
sched_yield();
|
||||
++g_longwaits;
|
||||
}
|
||||
#if defined(__i386__) || defined(__amd64__)
|
||||
__asm__ ("pause");
|
||||
#endif
|
||||
@@ -103,7 +136,7 @@ extern "C" int fastlock_trylock(struct fastlock *lock)
|
||||
|
||||
struct ticket ticket_expect { active, active };
|
||||
struct ticket ticket_setiflocked { active, next };
|
||||
if (__atomic_compare_exchange(&lock->m_ticket, &ticket_expect, &ticket_setiflocked, true /*strong*/, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE))
|
||||
if (__atomic_compare_exchange(&lock->m_ticket, &ticket_expect, &ticket_setiflocked, false /*weak*/, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE))
|
||||
{
|
||||
lock->m_depth = 1;
|
||||
__atomic_store_4(&lock->m_pidOwner, gettid(), __ATOMIC_RELEASE);
|
||||
@@ -137,4 +170,4 @@ extern "C" void fastlock_free(struct fastlock *lock)
|
||||
bool fastlock::fOwnLock()
|
||||
{
|
||||
return gettid() == m_pidOwner;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ int fastlock_trylock(struct fastlock *lock);
|
||||
void fastlock_unlock(struct fastlock *lock);
|
||||
void fastlock_free(struct fastlock *lock);
|
||||
|
||||
uint64_t fastlock_getlongwaitcount(); // this is a global value
|
||||
|
||||
/* End C API */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ section .text
|
||||
|
||||
extern gettid
|
||||
extern sched_yield
|
||||
extern g_longwaits
|
||||
|
||||
; This is the first use of assembly in this codebase, a valid question is WHY?
|
||||
; The spinlock we implement here is performance critical, and simply put GCC
|
||||
@@ -49,6 +50,8 @@ ALIGN 16
|
||||
syscall ; give up our timeslice we'll be here a while
|
||||
pop rax
|
||||
pop rsi
|
||||
mov rcx, g_longwaits
|
||||
inc qword [rcx] ; increment our long wait counter
|
||||
mov rdi, [rsp] ; our struct pointer is on the stack already
|
||||
xor ecx, ecx ; Reset our loop counter
|
||||
jmp .LLoop ; Get back in the game
|
||||
|
||||
@@ -35,7 +35,12 @@
|
||||
#if defined(__linux__)
|
||||
#define _GNU_SOURCE 1
|
||||
#define _DEFAULT_SOURCE 1
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,19,0)
|
||||
#define HAVE_SO_INCOMING_CPU 1
|
||||
#endif
|
||||
#endif // __linux__
|
||||
|
||||
#if defined(_AIX)
|
||||
#define _ALL_SOURCE
|
||||
|
||||
+18
-18
@@ -51,7 +51,7 @@ int zslValueLteMax(double value, zrangespec *spec);
|
||||
|
||||
/* Create a new array of geoPoints. */
|
||||
geoArray *geoArrayCreate(void) {
|
||||
geoArray *ga = zmalloc(sizeof(*ga), MALLOC_SHARED);
|
||||
geoArray *ga = (geoArray*)zmalloc(sizeof(*ga), MALLOC_SHARED);
|
||||
/* It gets allocated on first geoArrayAppend() call. */
|
||||
ga->array = NULL;
|
||||
ga->buckets = 0;
|
||||
@@ -64,7 +64,7 @@ geoArray *geoArrayCreate(void) {
|
||||
geoPoint *geoArrayAppend(geoArray *ga) {
|
||||
if (ga->used == ga->buckets) {
|
||||
ga->buckets = (ga->buckets == 0) ? 8 : ga->buckets*2;
|
||||
ga->array = zrealloc(ga->array,sizeof(geoPoint)*ga->buckets, MALLOC_SHARED);
|
||||
ga->array = (geoPoint*)zrealloc(ga->array,sizeof(geoPoint)*ga->buckets, MALLOC_SHARED);
|
||||
}
|
||||
geoPoint *gp = ga->array+ga->used;
|
||||
ga->used++;
|
||||
@@ -83,7 +83,7 @@ void geoArrayFree(geoArray *ga) {
|
||||
* Helpers
|
||||
* ==================================================================== */
|
||||
int decodeGeohash(double bits, double *xy) {
|
||||
GeoHashBits hash = { .bits = (uint64_t)bits, .step = GEO_STEP_MAX };
|
||||
GeoHashBits hash = { (uint64_t)bits, GEO_STEP_MAX };
|
||||
return geohashDecodeToLongLatWGS84(hash, xy);
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ int extractLongLatOrReply(client *c, robj **argv, double *xy) {
|
||||
int longLatFromMember(robj *zobj, robj *member, double *xy) {
|
||||
double score = 0;
|
||||
|
||||
if (zsetScore(zobj, ptrFromObj(member), &score) == C_ERR) return C_ERR;
|
||||
if (zsetScore(zobj, szFromObj(member), &score) == C_ERR) return C_ERR;
|
||||
if (!decodeGeohash(score, xy)) return C_ERR;
|
||||
return C_OK;
|
||||
}
|
||||
@@ -125,7 +125,7 @@ int longLatFromMember(robj *zobj, robj *member, double *xy) {
|
||||
* If the unit is not valid, an error is reported to the client, and a value
|
||||
* less than zero is returned. */
|
||||
double extractUnitOrReply(client *c, robj *unit) {
|
||||
char *u = ptrFromObj(unit);
|
||||
char *u = szFromObj(unit);
|
||||
|
||||
if (!strcmp(u, "m")) {
|
||||
return 1;
|
||||
@@ -225,12 +225,12 @@ int geoAppendIfWithinRadius(geoArray *ga, double lon, double lat, double radius,
|
||||
int geoGetPointsInRange(robj *zobj, double min, double max, double lon, double lat, double radius, geoArray *ga) {
|
||||
/* minex 0 = include min in range; maxex 1 = exclude max in range */
|
||||
/* That's: min <= val < max */
|
||||
zrangespec range = { .min = min, .max = max, .minex = 0, .maxex = 1 };
|
||||
zrangespec range = { min, max, 0, 1 };
|
||||
size_t origincount = ga->used;
|
||||
sds member;
|
||||
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = zobj->m_ptr;
|
||||
unsigned char *zl = (unsigned char*)zobj->m_ptr;
|
||||
unsigned char *eptr, *sptr;
|
||||
unsigned char *vstr = NULL;
|
||||
unsigned int vlen = 0;
|
||||
@@ -259,7 +259,7 @@ int geoGetPointsInRange(robj *zobj, double min, double max, double lon, double l
|
||||
zzlNext(zl, &eptr, &sptr);
|
||||
}
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
zskiplist *zsl = zs->zsl;
|
||||
zskiplistNode *ln;
|
||||
|
||||
@@ -277,7 +277,7 @@ int geoGetPointsInRange(robj *zobj, double min, double max, double lon, double l
|
||||
ele = sdsdup(ele);
|
||||
if (geoAppendIfWithinRadius(ga,lon,lat,radius,ln->score,ele)
|
||||
== C_ERR) sdsfree(ele);
|
||||
ln = ln->level[0].forward;
|
||||
ln = ln->level(0)->forward;
|
||||
}
|
||||
}
|
||||
return ga->used - origincount;
|
||||
@@ -382,7 +382,7 @@ int membersOfAllNeighbors(robj *zobj, GeoHashRadius n, double lon, double lat, d
|
||||
|
||||
/* Sort comparators for qsort() */
|
||||
static int sort_gp_asc(const void *a, const void *b) {
|
||||
const struct geoPoint *gpa = a, *gpb = b;
|
||||
const struct geoPoint *gpa = (geoPoint*)a, *gpb = (geoPoint*)b;
|
||||
/* We can't do adist - bdist because they are doubles and
|
||||
* the comparator returns an int. */
|
||||
if (gpa->dist > gpb->dist)
|
||||
@@ -413,7 +413,7 @@ void geoaddCommand(client *c) {
|
||||
|
||||
int elements = (c->argc - 2) / 3;
|
||||
int argc = 2+elements*2; /* ZADD key score ele ... */
|
||||
robj **argv = zcalloc(argc*sizeof(robj*), MALLOC_LOCAL);
|
||||
robj **argv = (robj**)zcalloc(argc*sizeof(robj*), MALLOC_LOCAL);
|
||||
argv[0] = createRawStringObject("zadd",4);
|
||||
argv[1] = c->argv[1]; /* key */
|
||||
incrRefCount(argv[1]);
|
||||
@@ -504,7 +504,7 @@ void georadiusGeneric(client *c, int flags) {
|
||||
if (c->argc > base_args) {
|
||||
int remaining = c->argc - base_args;
|
||||
for (int i = 0; i < remaining; i++) {
|
||||
char *arg = ptrFromObj(c->argv[base_args + i]);
|
||||
char *arg = szFromObj(c->argv[base_args + i]);
|
||||
if (!strcasecmp(arg, "withdist")) {
|
||||
withdist = 1;
|
||||
} else if (!strcasecmp(arg, "withhash")) {
|
||||
@@ -639,7 +639,7 @@ void georadiusGeneric(client *c, int flags) {
|
||||
|
||||
if (returned_items) {
|
||||
zobj = createZsetObject();
|
||||
zs = zobj->m_ptr;
|
||||
zs = (zset*)zobj->m_ptr;
|
||||
}
|
||||
|
||||
for (i = 0; i < returned_items; i++) {
|
||||
@@ -697,7 +697,7 @@ void georadiusbymemberroCommand(client *c) {
|
||||
* Returns an array with an 11 characters geohash representation of the
|
||||
* position of the specified elements. */
|
||||
void geohashCommand(client *c) {
|
||||
char *geoalphabet= "0123456789bcdefghjkmnpqrstuvwxyz";
|
||||
const char *geoalphabet= "0123456789bcdefghjkmnpqrstuvwxyz";
|
||||
int j;
|
||||
|
||||
/* Look up the requested zset */
|
||||
@@ -709,7 +709,7 @@ void geohashCommand(client *c) {
|
||||
addReplyArrayLen(c,c->argc-2);
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
double score;
|
||||
if (!zobj || zsetScore(zobj, ptrFromObj(c->argv[j]), &score) == C_ERR) {
|
||||
if (!zobj || zsetScore(zobj, szFromObj(c->argv[j]), &score) == C_ERR) {
|
||||
addReplyNull(c);
|
||||
} else {
|
||||
/* The internal format we use for geocoding is a bit different
|
||||
@@ -762,7 +762,7 @@ void geoposCommand(client *c) {
|
||||
addReplyArrayLen(c,c->argc-2);
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
double score;
|
||||
if (!zobj || zsetScore(zobj, ptrFromObj(c->argv[j]), &score) == C_ERR) {
|
||||
if (!zobj || zsetScore(zobj, szFromObj(c->argv[j]), &score) == C_ERR) {
|
||||
addReplyNullArray(c);
|
||||
} else {
|
||||
/* Decode... */
|
||||
@@ -802,8 +802,8 @@ void geodistCommand(client *c) {
|
||||
|
||||
/* Get the scores. We need both otherwise NULL is returned. */
|
||||
double score1, score2, xyxy[4];
|
||||
if (zsetScore(zobj, ptrFromObj(c->argv[2]), &score1) == C_ERR ||
|
||||
zsetScore(zobj, ptrFromObj(c->argv[3]), &score2) == C_ERR)
|
||||
if (zsetScore(zobj, szFromObj(c->argv[2]), &score1) == C_ERR ||
|
||||
zsetScore(zobj, szFromObj(c->argv[3]), &score2) == C_ERR)
|
||||
{
|
||||
addReplyNull(c);
|
||||
return;
|
||||
File renamed without changes.
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "server.h"
|
||||
|
||||
/* Emit an item in Gopher directory listing format:
|
||||
* <type><descr><TAB><selector><TAB><hostname><TAB><port>
|
||||
* If descr or selector are NULL, then the "(NULL)" string is used instead. */
|
||||
void addReplyGopherItem(client *c, const char *type, const char *descr,
|
||||
const char *selector, const char *hostname, int port)
|
||||
{
|
||||
sds item = sdscatfmt(sdsempty(),"%s%s\t%s\t%s\t%i\r\n",
|
||||
type, descr,
|
||||
selector ? selector : "(NULL)",
|
||||
hostname ? hostname : "(NULL)",
|
||||
port);
|
||||
addReplyProto(c,item,sdslen(item));
|
||||
sdsfree(item);
|
||||
}
|
||||
|
||||
/* This is called by processInputBuffer() when an inline request is processed
|
||||
* with Gopher mode enabled, and the request happens to have zero or just one
|
||||
* argument. In such case we get the relevant key and reply using the Gopher
|
||||
* protocol. */
|
||||
void processGopherRequest(client *c) {
|
||||
robj *keyname = c->argc == 0 ? createStringObject("/",1) : c->argv[0];
|
||||
robj *o = lookupKeyRead(c->db,keyname);
|
||||
|
||||
/* If there is no such key, return with a Gopher error. */
|
||||
if (o == NULL || o->type != OBJ_STRING) {
|
||||
char *errstr;
|
||||
if (o == NULL)
|
||||
errstr = "Error: no content at the specified key";
|
||||
else
|
||||
errstr = "Error: selected key type is invalid "
|
||||
"for Gopher output";
|
||||
addReplyGopherItem(c,"i",errstr,NULL,NULL,0);
|
||||
addReplyGopherItem(c,"i","Redis Gopher server",NULL,NULL,0);
|
||||
} else {
|
||||
addReply(c,o);
|
||||
}
|
||||
|
||||
/* Cleanup, also make sure to emit the final ".CRLF" line. Note that
|
||||
* the connection will be closed immediately after this because the client
|
||||
* will be flagged with CLIENT_CLOSE_AFTER_REPLY, in accordance with the
|
||||
* Gopher protocol. */
|
||||
if (c->argc == 0) decrRefCount(keyname);
|
||||
|
||||
/* Note that in theory we should terminate the Gopher request with
|
||||
* ".<CR><LF>" (called Lastline in the RFC) like that:
|
||||
*
|
||||
* addReplyProto(c,".\r\n",3);
|
||||
*
|
||||
* However after examining the current clients landscape, it's probably
|
||||
* going to do more harm than good for several reasons:
|
||||
*
|
||||
* 1. Clients should not have any issue with missing .<CR><LF> as for
|
||||
* specification, and in the real world indeed certain servers
|
||||
* implementations never used to send the terminator.
|
||||
*
|
||||
* 2. Redis does not know if it's serving a text file or a binary file:
|
||||
* at the same time clients will not remove the ".<CR><LF>" bytes at
|
||||
* tne end when downloading a binary file from the server, so adding
|
||||
* the "Lastline" terminator without knowing the content is just
|
||||
* dangerous.
|
||||
*
|
||||
* 3. The utility gopher2redis.rb that we provide for Redis, and any
|
||||
* other similar tool you may use as Gopher authoring system for
|
||||
* Redis, can just add the "Lastline" when needed.
|
||||
*/
|
||||
}
|
||||
@@ -184,7 +184,9 @@ struct hllhdr {
|
||||
uint8_t encoding; /* HLL_DENSE or HLL_SPARSE. */
|
||||
uint8_t notused[3]; /* Reserved for future use, must be zero. */
|
||||
uint8_t card[8]; /* Cached cardinality, little endian. */
|
||||
uint8_t registers[]; /* Data bytes. */
|
||||
uint8_t *registers() { /* Data bytes. */
|
||||
return reinterpret_cast<uint8_t*>(this+1);
|
||||
}
|
||||
};
|
||||
|
||||
/* The cached cardinality MSB is used to signal validity of the cached value. */
|
||||
@@ -205,7 +207,7 @@ struct hllhdr {
|
||||
#define HLL_RAW 255 /* Only used internally, never exposed. */
|
||||
#define HLL_MAX_ENCODING 1
|
||||
|
||||
static char *invalid_hll_err = "-INVALIDOBJ Corrupted HLL object detected\r\n";
|
||||
static const char *invalid_hll_err = "-INVALIDOBJ Corrupted HLL object detected\r\n";
|
||||
|
||||
/* =========================== Low level bit macros ========================= */
|
||||
|
||||
@@ -582,7 +584,7 @@ void hllDenseRegHisto(uint8_t *registers, int* reghisto) {
|
||||
* The function returns C_OK if the sparse representation was valid,
|
||||
* otherwise C_ERR is returned if the representation was corrupted. */
|
||||
int hllSparseToDense(robj *o) {
|
||||
sds sparse = ptrFromObj(o), dense;
|
||||
sds sparse = szFromObj(o), dense;
|
||||
struct hllhdr *hdr, *oldhdr = (struct hllhdr*)sparse;
|
||||
int idx = 0, runlen, regval;
|
||||
uint8_t *p = (uint8_t*)sparse, *end = p+sdslen(sparse);
|
||||
@@ -616,7 +618,7 @@ int hllSparseToDense(robj *o) {
|
||||
regval = HLL_SPARSE_VAL_VALUE(p);
|
||||
if ((runlen + idx) > HLL_REGISTERS) break; /* Overflow. */
|
||||
while(runlen--) {
|
||||
HLL_DENSE_SET_REGISTER(hdr->registers,idx,regval);
|
||||
HLL_DENSE_SET_REGISTER(hdr->registers(),idx,regval);
|
||||
idx++;
|
||||
}
|
||||
p++;
|
||||
@@ -631,7 +633,7 @@ int hllSparseToDense(robj *o) {
|
||||
}
|
||||
|
||||
/* Free the old representation and set the new one. */
|
||||
sdsfree(ptrFromObj(o));
|
||||
sdsfree(szFromObj(o));
|
||||
o->m_ptr = dense;
|
||||
return C_OK;
|
||||
}
|
||||
@@ -656,6 +658,13 @@ int hllSparseSet(robj *o, long index, uint8_t count) {
|
||||
uint8_t oldcount, *sparse, *end, *p, *prev, *next;
|
||||
long first, span;
|
||||
long is_zero = 0, is_xzero = 0, is_val = 0, runlen = 0;
|
||||
uint8_t seq[5], *n = nullptr;
|
||||
int last;
|
||||
int len;
|
||||
int seqlen = 0;
|
||||
int oldlen = 0;
|
||||
int deltalen = 0;
|
||||
int scanlen = 0;
|
||||
|
||||
/* If the count is too big to be representable by the sparse representation
|
||||
* switch to dense representation. */
|
||||
@@ -666,12 +675,12 @@ int hllSparseSet(robj *o, long index, uint8_t count) {
|
||||
* into XZERO-VAL-XZERO). Make sure there is enough space right now
|
||||
* so that the pointers we take during the execution of the function
|
||||
* will be valid all the time. */
|
||||
o->m_ptr = sdsMakeRoomFor(ptrFromObj(o),3);
|
||||
o->m_ptr = sdsMakeRoomFor(szFromObj(o),3);
|
||||
|
||||
/* Step 1: we need to locate the opcode we need to modify to check
|
||||
* if a value update is actually needed. */
|
||||
sparse = p = ((uint8_t*)ptrFromObj(o)) + HLL_HDR_SIZE;
|
||||
end = p + sdslen(ptrFromObj(o)) - HLL_HDR_SIZE;
|
||||
end = p + sdslen(szFromObj(o)) - HLL_HDR_SIZE;
|
||||
|
||||
first = 0;
|
||||
prev = NULL; /* Points to previous opcode at the end of the loop. */
|
||||
@@ -774,9 +783,8 @@ int hllSparseSet(robj *o, long index, uint8_t count) {
|
||||
* with 'newlen' as length. Later the new sequence is inserted in place
|
||||
* of the old one, possibly moving what is on the right a few bytes
|
||||
* if the new sequence is longer than the older one. */
|
||||
uint8_t seq[5], *n = seq;
|
||||
int last = first+span-1; /* Last register covered by the sequence. */
|
||||
int len;
|
||||
n = seq;
|
||||
last = first+span-1; /* Last register covered by the sequence. */
|
||||
|
||||
if (is_zero || is_xzero) {
|
||||
/* Handle splitting of ZERO / XZERO. */
|
||||
@@ -824,14 +832,14 @@ int hllSparseSet(robj *o, long index, uint8_t count) {
|
||||
*
|
||||
* Note that we already allocated space on the sds string
|
||||
* calling sdsMakeRoomFor(). */
|
||||
int seqlen = n-seq;
|
||||
int oldlen = is_xzero ? 2 : 1;
|
||||
int deltalen = seqlen-oldlen;
|
||||
seqlen = n-seq;
|
||||
oldlen = is_xzero ? 2 : 1;
|
||||
deltalen = seqlen-oldlen;
|
||||
|
||||
if (deltalen > 0 &&
|
||||
sdslen(ptrFromObj(o))+deltalen > server.hll_sparse_max_bytes) goto promote;
|
||||
sdslen(szFromObj(o))+deltalen > server.hll_sparse_max_bytes) goto promote;
|
||||
if (deltalen && next) memmove(next+deltalen,next,end-next);
|
||||
sdsIncrLen(ptrFromObj(o),deltalen);
|
||||
sdsIncrLen(szFromObj(o),deltalen);
|
||||
memcpy(p,seq,seqlen);
|
||||
end += deltalen;
|
||||
|
||||
@@ -842,7 +850,7 @@ updated:
|
||||
* may not be optimal: adjacent VAL opcodes can sometimes be merged into
|
||||
* a single one. */
|
||||
p = prev ? prev : sparse;
|
||||
int scanlen = 5; /* Scan up to 5 upcodes starting from prev. */
|
||||
scanlen = 5; /* Scan up to 5 upcodes starting from prev. */
|
||||
while (p < end && scanlen--) {
|
||||
if (HLL_SPARSE_IS_XZERO(p)) {
|
||||
p += 2;
|
||||
@@ -861,7 +869,7 @@ updated:
|
||||
if (len <= HLL_SPARSE_VAL_MAX_LEN) {
|
||||
HLL_SPARSE_VAL_SET(p+1,v1,len);
|
||||
memmove(p,p+1,end-p);
|
||||
sdsIncrLen(ptrFromObj(o),-1);
|
||||
sdsIncrLen(szFromObj(o),-1);
|
||||
end--;
|
||||
/* After a merge we reiterate without incrementing 'p'
|
||||
* in order to try to merge the just merged value with
|
||||
@@ -874,13 +882,13 @@ updated:
|
||||
}
|
||||
|
||||
/* Invalidate the cached cardinality. */
|
||||
hdr = ptrFromObj(o);
|
||||
hdr = (hllhdr*)ptrFromObj(o);
|
||||
HLL_INVALIDATE_CACHE(hdr);
|
||||
return 1;
|
||||
|
||||
promote: /* Promote to dense representation. */
|
||||
if (hllSparseToDense(o) == C_ERR) return -1; /* Corrupted HLL. */
|
||||
hdr = ptrFromObj(o);
|
||||
hdr = (hllhdr*)ptrFromObj(o);
|
||||
|
||||
/* We need to call hllDenseAdd() to perform the operation after the
|
||||
* conversion. However the result must be 1, since if we need to
|
||||
@@ -889,7 +897,7 @@ promote: /* Promote to dense representation. */
|
||||
* Note that this in turn means that PFADD will make sure the command
|
||||
* is propagated to slaves / AOF, so if there is a sparse -> dense
|
||||
* conversion, it will be performed in all the slaves as well. */
|
||||
int dense_retval = hllDenseSet(hdr->registers,index,count);
|
||||
int dense_retval = hllDenseSet(hdr->registers(),index,count);
|
||||
serverAssert(dense_retval == 1);
|
||||
return dense_retval;
|
||||
}
|
||||
@@ -1007,7 +1015,7 @@ double hllTau(double x) {
|
||||
* pointed by 'invalid' is set to non-zero, otherwise it is left untouched.
|
||||
*
|
||||
* hllCount() supports a special internal-only encoding of HLL_RAW, that
|
||||
* is, hdr->registers will point to an uint8_t array of HLL_REGISTERS element.
|
||||
* is, hdr->registers() will point to an uint8_t array of HLL_REGISTERS element.
|
||||
* This is useful in order to speedup PFCOUNT when called against multiple
|
||||
* keys (no need to work with 6-bit integers encoding). */
|
||||
uint64_t hllCount(struct hllhdr *hdr, int *invalid) {
|
||||
@@ -1023,12 +1031,12 @@ uint64_t hllCount(struct hllhdr *hdr, int *invalid) {
|
||||
|
||||
/* Compute register histogram */
|
||||
if (hdr->encoding == HLL_DENSE) {
|
||||
hllDenseRegHisto(hdr->registers,reghisto);
|
||||
hllDenseRegHisto(hdr->registers(),reghisto);
|
||||
} else if (hdr->encoding == HLL_SPARSE) {
|
||||
hllSparseRegHisto(hdr->registers,
|
||||
hllSparseRegHisto(hdr->registers(),
|
||||
sdslen((sds)hdr)-HLL_HDR_SIZE,invalid,reghisto);
|
||||
} else if (hdr->encoding == HLL_RAW) {
|
||||
hllRawRegHisto(hdr->registers,reghisto);
|
||||
hllRawRegHisto(hdr->registers(),reghisto);
|
||||
} else {
|
||||
serverPanic("Unknown HyperLogLog encoding in hllCount()");
|
||||
}
|
||||
@@ -1049,9 +1057,9 @@ uint64_t hllCount(struct hllhdr *hdr, int *invalid) {
|
||||
|
||||
/* Call hllDenseAdd() or hllSparseAdd() according to the HLL encoding. */
|
||||
int hllAdd(robj *o, unsigned char *ele, size_t elesize) {
|
||||
struct hllhdr *hdr = ptrFromObj(o);
|
||||
struct hllhdr *hdr = (hllhdr*)ptrFromObj(o);
|
||||
switch(hdr->encoding) {
|
||||
case HLL_DENSE: return hllDenseAdd(hdr->registers,ele,elesize);
|
||||
case HLL_DENSE: return hllDenseAdd(hdr->registers(),ele,elesize);
|
||||
case HLL_SPARSE: return hllSparseAdd(o,ele,elesize);
|
||||
default: return -1; /* Invalid representation. */
|
||||
}
|
||||
@@ -1066,18 +1074,18 @@ int hllAdd(robj *o, unsigned char *ele, size_t elesize) {
|
||||
* If the HyperLogLog is sparse and is found to be invalid, C_ERR
|
||||
* is returned, otherwise the function always succeeds. */
|
||||
int hllMerge(uint8_t *max, size_t cmax, robj *hll) {
|
||||
struct hllhdr *hdr = ptrFromObj(hll);
|
||||
struct hllhdr *hdr = (hllhdr*)ptrFromObj(hll);
|
||||
int i;
|
||||
|
||||
if (hdr->encoding == HLL_DENSE) {
|
||||
uint8_t val;
|
||||
|
||||
for (i = 0; i < HLL_REGISTERS; i++) {
|
||||
HLL_DENSE_GET_REGISTER(val,hdr->registers,i);
|
||||
HLL_DENSE_GET_REGISTER(val,hdr->registers(),i);
|
||||
if (val > max[i]) max[i] = val;
|
||||
}
|
||||
} else {
|
||||
uint8_t *p = ptrFromObj(hll), *end = p + sdslen(ptrFromObj(hll));
|
||||
uint8_t *p = (uint8_t*)ptrFromObj(hll), *end = p + sdslen(szFromObj(hll));
|
||||
long runlen, regval;
|
||||
|
||||
p += HLL_HDR_SIZE;
|
||||
@@ -1139,7 +1147,7 @@ robj *createHLLObject(void) {
|
||||
|
||||
/* Create the actual object. */
|
||||
o = createObject(OBJ_STRING,s);
|
||||
hdr = ptrFromObj(o);
|
||||
hdr = (hllhdr*)ptrFromObj(o);
|
||||
memcpy(hdr->magic,"HYLL",4);
|
||||
hdr->encoding = HLL_SPARSE;
|
||||
return o;
|
||||
@@ -1157,7 +1165,7 @@ int isHLLObjectOrReply(client *c, robj *o) {
|
||||
|
||||
if (!sdsEncodedObject(o)) goto invalid;
|
||||
if (stringObjectLen(o) < sizeof(*hdr)) goto invalid;
|
||||
hdr = ptrFromObj(o);
|
||||
hdr = (hllhdr*)ptrFromObj(o);
|
||||
|
||||
/* Magic should be "HYLL". */
|
||||
if (hdr->magic[0] != 'H' || hdr->magic[1] != 'Y' ||
|
||||
@@ -1199,7 +1207,7 @@ void pfaddCommand(client *c) {
|
||||
/* Perform the low level ADD operation for every element. */
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
int retval = hllAdd(o, (unsigned char*)ptrFromObj(c->argv[j]),
|
||||
sdslen(ptrFromObj(c->argv[j])));
|
||||
sdslen(szFromObj(c->argv[j])));
|
||||
switch(retval) {
|
||||
case 1:
|
||||
updated++;
|
||||
@@ -1209,7 +1217,7 @@ void pfaddCommand(client *c) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
hdr = ptrFromObj(o);
|
||||
hdr = (hllhdr*)ptrFromObj(o);
|
||||
if (updated) {
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_STRING,"pfadd",c->argv[1],c->db->id);
|
||||
@@ -1271,7 +1279,7 @@ void pfcountCommand(client *c) {
|
||||
o = dbUnshareStringValue(c->db,c->argv[1],o);
|
||||
|
||||
/* Check if the cached cardinality is valid. */
|
||||
hdr = ptrFromObj(o);
|
||||
hdr = (hllhdr*)ptrFromObj(o);
|
||||
if (HLL_VALID_CACHE(hdr)) {
|
||||
/* Just return the cached value. */
|
||||
card = (uint64_t)hdr->card[0];
|
||||
@@ -1328,7 +1336,7 @@ void pfmergeCommand(client *c) {
|
||||
|
||||
/* If at least one involved HLL is dense, use the dense representation
|
||||
* as target ASAP to save time and avoid the conversion step. */
|
||||
hdr = ptrFromObj(o);
|
||||
hdr = (hllhdr*)ptrFromObj(o);
|
||||
if (hdr->encoding == HLL_DENSE) use_dense = 1;
|
||||
|
||||
/* Merge with this HLL with our 'max' HHL by setting max[i]
|
||||
@@ -1365,13 +1373,13 @@ void pfmergeCommand(client *c) {
|
||||
* invalidate the cached value. */
|
||||
for (j = 0; j < HLL_REGISTERS; j++) {
|
||||
if (max[j] == 0) continue;
|
||||
hdr = ptrFromObj(o);
|
||||
hdr = (hllhdr*)ptrFromObj(o);
|
||||
switch(hdr->encoding) {
|
||||
case HLL_DENSE: hllDenseSet(hdr->registers,j,max[j]); break;
|
||||
case HLL_DENSE: hllDenseSet(hdr->registers(),j,max[j]); break;
|
||||
case HLL_SPARSE: hllSparseSet(o,j,max[j]); break;
|
||||
}
|
||||
}
|
||||
hdr = ptrFromObj(o); /* ptrFromObj(o) may be different now, as a side effect of
|
||||
hdr = (hllhdr*)ptrFromObj(o); /* ptrFromObj(o) may be different now, as a side effect of
|
||||
last hllSparseSet() call. */
|
||||
HLL_INVALIDATE_CACHE(hdr);
|
||||
|
||||
@@ -1395,6 +1403,10 @@ void pfselftestCommand(client *c) {
|
||||
struct hllhdr *hdr = (struct hllhdr*) bitcounters, *hdr2;
|
||||
robj *o = NULL;
|
||||
uint8_t bytecounters[HLL_REGISTERS];
|
||||
int64_t checkpoint = 1;
|
||||
uint64_t seed = 0;
|
||||
uint64_t ele;
|
||||
double relerr = 0;
|
||||
|
||||
/* Test 1: access registers.
|
||||
* The test is conceived to test that the different counters of our data
|
||||
@@ -1407,13 +1419,13 @@ void pfselftestCommand(client *c) {
|
||||
unsigned int r = rand() & HLL_REGISTER_MAX;
|
||||
|
||||
bytecounters[i] = r;
|
||||
HLL_DENSE_SET_REGISTER(hdr->registers,i,r);
|
||||
HLL_DENSE_SET_REGISTER(hdr->registers(),i,r);
|
||||
}
|
||||
/* Check that we are able to retrieve the same values. */
|
||||
for (i = 0; i < HLL_REGISTERS; i++) {
|
||||
unsigned int val;
|
||||
|
||||
HLL_DENSE_GET_REGISTER(val,hdr->registers,i);
|
||||
HLL_DENSE_GET_REGISTER(val,hdr->registers(),i);
|
||||
if (val != bytecounters[i]) {
|
||||
addReplyErrorFormat(c,
|
||||
"TESTFAILED Register %d should be %d but is %d",
|
||||
@@ -1433,21 +1445,20 @@ void pfselftestCommand(client *c) {
|
||||
*
|
||||
* The test is performed with both dense and sparse HLLs at the same
|
||||
* time also verifying that the computed cardinality is the same. */
|
||||
memset(hdr->registers,0,HLL_DENSE_SIZE-HLL_HDR_SIZE);
|
||||
memset(hdr->registers(),0,HLL_DENSE_SIZE-HLL_HDR_SIZE);
|
||||
o = createHLLObject();
|
||||
double relerr = 1.04/sqrt(HLL_REGISTERS);
|
||||
int64_t checkpoint = 1;
|
||||
uint64_t seed = (uint64_t)rand() | (uint64_t)rand() << 32;
|
||||
uint64_t ele;
|
||||
relerr = 1.04/sqrt(HLL_REGISTERS);
|
||||
checkpoint = 1;
|
||||
seed = (uint64_t)rand() | (uint64_t)rand() << 32;
|
||||
for (j = 1; j <= 10000000; j++) {
|
||||
ele = j ^ seed;
|
||||
hllDenseAdd(hdr->registers,(unsigned char*)&ele,sizeof(ele));
|
||||
hllDenseAdd(hdr->registers(),(unsigned char*)&ele,sizeof(ele));
|
||||
hllAdd(o,(unsigned char*)&ele,sizeof(ele));
|
||||
|
||||
/* Make sure that for small cardinalities we use sparse
|
||||
* encoding. */
|
||||
if (j == checkpoint && j < server.hll_sparse_max_bytes/2) {
|
||||
hdr2 = ptrFromObj(o);
|
||||
hdr2 = (hllhdr*)ptrFromObj(o);
|
||||
if (hdr2->encoding != HLL_SPARSE) {
|
||||
addReplyError(c, "TESTFAILED sparse encoding not used");
|
||||
goto cleanup;
|
||||
@@ -1455,7 +1466,7 @@ void pfselftestCommand(client *c) {
|
||||
}
|
||||
|
||||
/* Check that dense and sparse representations agree. */
|
||||
if (j == checkpoint && hllCount(hdr,NULL) != hllCount(ptrFromObj(o),NULL)) {
|
||||
if (j == checkpoint && hllCount(hdr,NULL) != hllCount((hllhdr*)ptrFromObj(o),NULL)) {
|
||||
addReplyError(c, "TESTFAILED dense/sparse disagree");
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -1494,7 +1505,7 @@ cleanup:
|
||||
/* PFDEBUG <subcommand> <key> ... args ...
|
||||
* Different debugging related operations about the HLL implementation. */
|
||||
void pfdebugCommand(client *c) {
|
||||
char *cmd = ptrFromObj(c->argv[1]);
|
||||
char *cmd = szFromObj(c->argv[1]);
|
||||
struct hllhdr *hdr;
|
||||
robj *o;
|
||||
int j;
|
||||
@@ -1506,7 +1517,7 @@ void pfdebugCommand(client *c) {
|
||||
}
|
||||
if (isHLLObjectOrReply(c,o) != C_OK) return;
|
||||
o = dbUnshareStringValue(c->db,c->argv[2],o);
|
||||
hdr = ptrFromObj(o);
|
||||
hdr = (hllhdr*)ptrFromObj(o);
|
||||
|
||||
/* PFDEBUG GETREG <key> */
|
||||
if (!strcasecmp(cmd,"getreg")) {
|
||||
@@ -1520,12 +1531,12 @@ void pfdebugCommand(client *c) {
|
||||
server.dirty++; /* Force propagation on encoding change. */
|
||||
}
|
||||
|
||||
hdr = ptrFromObj(o);
|
||||
hdr = (hllhdr*)ptrFromObj(o);
|
||||
addReplyArrayLen(c,HLL_REGISTERS);
|
||||
for (j = 0; j < HLL_REGISTERS; j++) {
|
||||
uint8_t val;
|
||||
|
||||
HLL_DENSE_GET_REGISTER(val,hdr->registers,j);
|
||||
HLL_DENSE_GET_REGISTER(val,hdr->registers(),j);
|
||||
addReplyLongLong(c,val);
|
||||
}
|
||||
}
|
||||
@@ -1533,7 +1544,7 @@ void pfdebugCommand(client *c) {
|
||||
else if (!strcasecmp(cmd,"decode")) {
|
||||
if (c->argc != 3) goto arityerr;
|
||||
|
||||
uint8_t *p = ptrFromObj(o), *end = p+sdslen(ptrFromObj(o));
|
||||
uint8_t *p = (uint8_t*)ptrFromObj(o), *end = p+sdslen(szFromObj(o));
|
||||
sds decoded = sdsempty();
|
||||
|
||||
if (hdr->encoding != HLL_SPARSE) {
|
||||
@@ -1566,7 +1577,7 @@ void pfdebugCommand(client *c) {
|
||||
}
|
||||
/* PFDEBUG ENCODING <key> */
|
||||
else if (!strcasecmp(cmd,"encoding")) {
|
||||
char *encodingstr[2] = {"dense","sparse"};
|
||||
const char *encodingstr[2] = {"dense","sparse"};
|
||||
if (c->argc != 3) goto arityerr;
|
||||
|
||||
addReplyStatus(c,encodingstr[hdr->encoding]);
|
||||
@@ -46,6 +46,10 @@ typedef struct intset {
|
||||
#endif
|
||||
} intset;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
intset *intsetNew(void);
|
||||
intset *intsetAdd(intset *is, int64_t value, uint8_t *success);
|
||||
intset *intsetRemove(intset *is, int64_t value, int *success);
|
||||
@@ -59,4 +63,8 @@ size_t intsetBlobLen(intset *is);
|
||||
int intsetTest(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __INTSET_H
|
||||
@@ -38,11 +38,11 @@
|
||||
/* Dictionary type for latency events. */
|
||||
int dictStringKeyCompare(void *privdata, const void *key1, const void *key2) {
|
||||
UNUSED(privdata);
|
||||
return strcmp(key1,key2) == 0;
|
||||
return strcmp((const char*)key1,(const char*)key2) == 0;
|
||||
}
|
||||
|
||||
uint64_t dictStringHash(const void *key) {
|
||||
return dictGenHashFunction(key, strlen(key));
|
||||
return dictGenHashFunction(key, strlen((const char*)key));
|
||||
}
|
||||
|
||||
void dictVanillaFree(void *privdata, void *val);
|
||||
@@ -96,13 +96,13 @@ void latencyMonitorInit(void) {
|
||||
* is a macro that only adds the sample if the latency is higher than
|
||||
* server.latency_monitor_threshold. */
|
||||
void latencyAddSample(const char *event, mstime_t latency) {
|
||||
struct latencyTimeSeries *ts = dictFetchValue(server.latency_events,event);
|
||||
struct latencyTimeSeries *ts = (latencyTimeSeries*)dictFetchValue(server.latency_events,event);
|
||||
time_t now = time(NULL);
|
||||
int prev;
|
||||
|
||||
/* Create the time series if it does not exist. */
|
||||
if (ts == NULL) {
|
||||
ts = zmalloc(sizeof(*ts), MALLOC_SHARED);
|
||||
ts = (latencyTimeSeries*)zmalloc(sizeof(*ts), MALLOC_SHARED);
|
||||
ts->idx = 0;
|
||||
ts->max = 0;
|
||||
memset(ts->samples,0,sizeof(ts->samples));
|
||||
@@ -139,7 +139,7 @@ int latencyResetEvent(char *event_to_reset) {
|
||||
|
||||
di = dictGetSafeIterator(server.latency_events);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
char *event = dictGetKey(de);
|
||||
char *event = (char*)dictGetKey(de);
|
||||
|
||||
if (event_to_reset == NULL || strcasecmp(event,event_to_reset) == 0) {
|
||||
dictDelete(server.latency_events, event);
|
||||
@@ -158,7 +158,7 @@ int latencyResetEvent(char *event_to_reset) {
|
||||
* If the specified event has no elements the structure is populate with
|
||||
* zero values. */
|
||||
void analyzeLatencyForEvent(char *event, struct latencyStats *ls) {
|
||||
struct latencyTimeSeries *ts = dictFetchValue(server.latency_events,event);
|
||||
struct latencyTimeSeries *ts = (latencyTimeSeries*)dictFetchValue(server.latency_events,event);
|
||||
int j;
|
||||
uint64_t sum;
|
||||
|
||||
@@ -251,8 +251,8 @@ sds createLatencyReport(void) {
|
||||
|
||||
di = dictGetSafeIterator(server.latency_events);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
char *event = dictGetKey(de);
|
||||
struct latencyTimeSeries *ts = dictGetVal(de);
|
||||
char *event = (char*)dictGetKey(de);
|
||||
struct latencyTimeSeries *ts = (latencyTimeSeries*)dictGetVal(de);
|
||||
struct latencyStats ls;
|
||||
|
||||
if (ts == NULL) continue;
|
||||
@@ -273,7 +273,7 @@ sds createLatencyReport(void) {
|
||||
|
||||
/* Fork */
|
||||
if (!strcasecmp(event,"fork")) {
|
||||
char *fork_quality;
|
||||
const char *fork_quality;
|
||||
if (server.stat_fork_rate < 10) {
|
||||
fork_quality = "terrible";
|
||||
advise_better_vm = 1;
|
||||
@@ -500,8 +500,8 @@ void latencyCommandReplyWithLatestEvents(client *c) {
|
||||
addReplyArrayLen(c,dictSize(server.latency_events));
|
||||
di = dictGetIterator(server.latency_events);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
char *event = dictGetKey(de);
|
||||
struct latencyTimeSeries *ts = dictGetVal(de);
|
||||
char *event = (char*)dictGetKey(de);
|
||||
struct latencyTimeSeries *ts = (latencyTimeSeries*)dictGetVal(de);
|
||||
int last = (ts->idx + LATENCY_TS_LEN - 1) % LATENCY_TS_LEN;
|
||||
|
||||
addReplyArrayLen(c,4);
|
||||
@@ -579,15 +579,15 @@ NULL
|
||||
};
|
||||
struct latencyTimeSeries *ts;
|
||||
|
||||
if (!strcasecmp(ptrFromObj(c->argv[1]),"history") && c->argc == 3) {
|
||||
if (!strcasecmp(szFromObj(c->argv[1]),"history") && c->argc == 3) {
|
||||
/* LATENCY HISTORY <event> */
|
||||
ts = dictFetchValue(server.latency_events,ptrFromObj(c->argv[2]));
|
||||
ts = (latencyTimeSeries*)dictFetchValue(server.latency_events,ptrFromObj(c->argv[2]));
|
||||
if (ts == NULL) {
|
||||
addReplyArrayLen(c,0);
|
||||
} else {
|
||||
latencyCommandReplyWithSamples(c,ts);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"graph") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"graph") && c->argc == 3) {
|
||||
/* LATENCY GRAPH <event> */
|
||||
sds graph;
|
||||
dictEntry *de;
|
||||
@@ -595,22 +595,22 @@ NULL
|
||||
|
||||
de = dictFind(server.latency_events,ptrFromObj(c->argv[2]));
|
||||
if (de == NULL) goto nodataerr;
|
||||
ts = dictGetVal(de);
|
||||
event = dictGetKey(de);
|
||||
ts = (latencyTimeSeries*)dictGetVal(de);
|
||||
event = (char*)dictGetKey(de);
|
||||
|
||||
graph = latencyCommandGenSparkeline(event,ts);
|
||||
addReplyBulkCString(c,graph);
|
||||
sdsfree(graph);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"latest") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"latest") && c->argc == 2) {
|
||||
/* LATENCY LATEST */
|
||||
latencyCommandReplyWithLatestEvents(c);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"doctor") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"doctor") && c->argc == 2) {
|
||||
/* LATENCY DOCTOR */
|
||||
sds report = createLatencyReport();
|
||||
|
||||
addReplyBulkCBuffer(c,report,sdslen(report));
|
||||
sdsfree(report);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"reset") && c->argc >= 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"reset") && c->argc >= 2) {
|
||||
/* LATENCY RESET */
|
||||
if (c->argc == 2) {
|
||||
addReplyLongLong(c,latencyResetEvent(NULL));
|
||||
@@ -618,10 +618,10 @@ NULL
|
||||
int j, resets = 0;
|
||||
|
||||
for (j = 2; j < c->argc; j++)
|
||||
resets += latencyResetEvent(ptrFromObj(c->argv[j]));
|
||||
resets += latencyResetEvent(szFromObj(c->argv[j]));
|
||||
addReplyLongLong(c,resets);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"help") && c->argc >= 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"help") && c->argc >= 2) {
|
||||
addReplyHelp(c, help);
|
||||
} else {
|
||||
addReplySubcommandSyntaxError(c);
|
||||
@@ -30,16 +30,16 @@ size_t lazyfreeGetPendingObjectsCount(void) {
|
||||
* representing the list. */
|
||||
size_t lazyfreeGetFreeEffort(robj *obj) {
|
||||
if (obj->type == OBJ_LIST) {
|
||||
quicklist *ql = ptrFromObj(obj);
|
||||
quicklist *ql = (quicklist*)ptrFromObj(obj);
|
||||
return ql->len;
|
||||
} else if (obj->type == OBJ_SET && obj->encoding == OBJ_ENCODING_HT) {
|
||||
dict *ht = ptrFromObj(obj);
|
||||
dict *ht = (dict*)ptrFromObj(obj);
|
||||
return dictSize(ht);
|
||||
} else if (obj->type == OBJ_ZSET && obj->encoding == OBJ_ENCODING_SKIPLIST){
|
||||
zset *zs = ptrFromObj(obj);
|
||||
zset *zs = (zset*)ptrFromObj(obj);
|
||||
return zs->zsl->length;
|
||||
} else if (obj->type == OBJ_HASH && obj->encoding == OBJ_ENCODING_HT) {
|
||||
dict *ht = ptrFromObj(obj);
|
||||
dict *ht = (dict*)ptrFromObj(obj);
|
||||
return dictSize(ht);
|
||||
} else {
|
||||
return 1; /* Everything else is a single allocation. */
|
||||
@@ -61,7 +61,7 @@ int dbAsyncDelete(redisDb *db, robj *key) {
|
||||
* the object synchronously. */
|
||||
dictEntry *de = dictUnlink(db->pdict,ptrFromObj(key));
|
||||
if (de) {
|
||||
robj *val = dictGetVal(de);
|
||||
robj *val = (robj*)dictGetVal(de);
|
||||
size_t free_effort = lazyfreeGetFreeEffort(val);
|
||||
|
||||
/* If releasing the object is too much work, do it in the background
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* This file implements the LOLWUT command. The command should do something
|
||||
* fun and interesting, and should be replaced by a new implementation at
|
||||
* each new version of Redis.
|
||||
*/
|
||||
|
||||
#include "server.h"
|
||||
|
||||
void lolwut5Command(client *c);
|
||||
|
||||
/* The default target for LOLWUT if no matching version was found.
|
||||
* This is what unstable versions of Redis will display. */
|
||||
void lolwutUnstableCommand(client *c) {
|
||||
sds rendered = sdsnew("Redis ver. ");
|
||||
rendered = sdscat(rendered,REDIS_VERSION);
|
||||
rendered = sdscatlen(rendered,"\n",1);
|
||||
addReplyBulkSds(c,rendered);
|
||||
}
|
||||
|
||||
void lolwutCommand(client *c) {
|
||||
char *v = REDIS_VERSION;
|
||||
if ((v[0] == '5' && v[1] == '.') ||
|
||||
(v[0] == '4' && v[1] == '.' && v[2] == '9'))
|
||||
lolwut5Command(c);
|
||||
else
|
||||
lolwutUnstableCommand(c);
|
||||
}
|
||||
-282
@@ -1,282 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* This file implements the LOLWUT command. The command should do something
|
||||
* fun and interesting, and should be replaced by a new implementation at
|
||||
* each new version of Redis.
|
||||
*/
|
||||
|
||||
#include "server.h"
|
||||
#include <math.h>
|
||||
|
||||
/* This structure represents our canvas. Drawing functions will take a pointer
|
||||
* to a canvas to write to it. Later the canvas can be rendered to a string
|
||||
* suitable to be printed on the screen, using unicode Braille characters. */
|
||||
typedef struct lwCanvas {
|
||||
int width;
|
||||
int height;
|
||||
char *pixels;
|
||||
} lwCanvas;
|
||||
|
||||
/* Translate a group of 8 pixels (2x4 vertical rectangle) to the corresponding
|
||||
* braille character. The byte should correspond to the pixels arranged as
|
||||
* follows, where 0 is the least significant bit, and 7 the most significant
|
||||
* bit:
|
||||
*
|
||||
* 0 3
|
||||
* 1 4
|
||||
* 2 5
|
||||
* 6 7
|
||||
*
|
||||
* The corresponding utf8 encoded character is set into the three bytes
|
||||
* pointed by 'output'.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
void lwTranslatePixelsGroup(int byte, char *output) {
|
||||
int code = 0x2800 + byte;
|
||||
/* Convert to unicode. This is in the U0800-UFFFF range, so we need to
|
||||
* emit it like this in three bytes:
|
||||
* 1110xxxx 10xxxxxx 10xxxxxx. */
|
||||
output[0] = 0xE0 | (code >> 12); /* 1110-xxxx */
|
||||
output[1] = 0x80 | ((code >> 6) & 0x3F); /* 10-xxxxxx */
|
||||
output[2] = 0x80 | (code & 0x3F); /* 10-xxxxxx */
|
||||
}
|
||||
|
||||
/* Allocate and return a new canvas of the specified size. */
|
||||
lwCanvas *lwCreateCanvas(int width, int height) {
|
||||
lwCanvas *canvas = zmalloc(sizeof(*canvas), MALLOC_SHARED);
|
||||
canvas->width = width;
|
||||
canvas->height = height;
|
||||
canvas->pixels = zmalloc(width*height, MALLOC_SHARED);
|
||||
memset(canvas->pixels,0,width*height);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
/* Free the canvas created by lwCreateCanvas(). */
|
||||
void lwFreeCanvas(lwCanvas *canvas) {
|
||||
zfree(canvas->pixels);
|
||||
zfree(canvas);
|
||||
}
|
||||
|
||||
/* Set a pixel to the specified color. Color is 0 or 1, where zero means no
|
||||
* dot will be displyed, and 1 means dot will be displayed.
|
||||
* Coordinates are arranged so that left-top corner is 0,0. You can write
|
||||
* out of the size of the canvas without issues. */
|
||||
void lwDrawPixel(lwCanvas *canvas, int x, int y, int color) {
|
||||
if (x < 0 || x >= canvas->width ||
|
||||
y < 0 || y >= canvas->height) return;
|
||||
canvas->pixels[x+y*canvas->width] = color;
|
||||
}
|
||||
|
||||
/* Return the value of the specified pixel on the canvas. */
|
||||
int lwGetPixel(lwCanvas *canvas, int x, int y) {
|
||||
if (x < 0 || x >= canvas->width ||
|
||||
y < 0 || y >= canvas->height) return 0;
|
||||
return canvas->pixels[x+y*canvas->width];
|
||||
}
|
||||
|
||||
/* Draw a line from x1,y1 to x2,y2 using the Bresenham algorithm. */
|
||||
void lwDrawLine(lwCanvas *canvas, int x1, int y1, int x2, int y2, int color) {
|
||||
int dx = abs(x2-x1);
|
||||
int dy = abs(y2-y1);
|
||||
int sx = (x1 < x2) ? 1 : -1;
|
||||
int sy = (y1 < y2) ? 1 : -1;
|
||||
int err = dx-dy, e2;
|
||||
|
||||
while(1) {
|
||||
lwDrawPixel(canvas,x1,y1,color);
|
||||
if (x1 == x2 && y1 == y2) break;
|
||||
e2 = err*2;
|
||||
if (e2 > -dy) {
|
||||
err -= dy;
|
||||
x1 += sx;
|
||||
}
|
||||
if (e2 < dx) {
|
||||
err += dx;
|
||||
y1 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw a square centered at the specified x,y coordinates, with the specified
|
||||
* rotation angle and size. In order to write a rotated square, we use the
|
||||
* trivial fact that the parametric equation:
|
||||
*
|
||||
* x = sin(k)
|
||||
* y = cos(k)
|
||||
*
|
||||
* Describes a circle for values going from 0 to 2*PI. So basically if we start
|
||||
* at 45 degrees, that is k = PI/4, with the first point, and then we find
|
||||
* the other three points incrementing K by PI/2 (90 degrees), we'll have the
|
||||
* points of the square. In order to rotate the square, we just start with
|
||||
* k = PI/4 + rotation_angle, and we are done.
|
||||
*
|
||||
* Of course the vanilla equations above will describe the square inside a
|
||||
* circle of radius 1, so in order to draw larger squares we'll have to
|
||||
* multiply the obtained coordinates, and then translate them. However this
|
||||
* is much simpler than implementing the abstract concept of 2D shape and then
|
||||
* performing the rotation/translation transformation, so for LOLWUT it's
|
||||
* a good approach. */
|
||||
void lwDrawSquare(lwCanvas *canvas, int x, int y, float size, float angle) {
|
||||
int px[4], py[4];
|
||||
|
||||
/* Adjust the desired size according to the fact that the square inscribed
|
||||
* into a circle of radius 1 has the side of length SQRT(2). This way
|
||||
* size becomes a simple multiplication factor we can use with our
|
||||
* coordinates to magnify them. */
|
||||
size /= 1.4142135623;
|
||||
size = round(size);
|
||||
|
||||
/* Compute the four points. */
|
||||
float k = M_PI/4 + angle;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
px[j] = round(sin(k) * size + x);
|
||||
py[j] = round(cos(k) * size + y);
|
||||
k += M_PI/2;
|
||||
}
|
||||
|
||||
/* Draw the square. */
|
||||
for (int j = 0; j < 4; j++)
|
||||
lwDrawLine(canvas,px[j],py[j],px[(j+1)%4],py[(j+1)%4],1);
|
||||
}
|
||||
|
||||
/* Schotter, the output of LOLWUT of Redis 5, is a computer graphic art piece
|
||||
* generated by Georg Nees in the 60s. It explores the relationship between
|
||||
* caos and order.
|
||||
*
|
||||
* The function creates the canvas itself, depending on the columns available
|
||||
* in the output display and the number of squares per row and per column
|
||||
* requested by the caller. */
|
||||
lwCanvas *lwDrawSchotter(int console_cols, int squares_per_row, int squares_per_col) {
|
||||
/* Calculate the canvas size. */
|
||||
int canvas_width = console_cols*2;
|
||||
int padding = canvas_width > 4 ? 2 : 0;
|
||||
float square_side = (float)(canvas_width-padding*2) / squares_per_row;
|
||||
int canvas_height = square_side * squares_per_col + padding*2;
|
||||
lwCanvas *canvas = lwCreateCanvas(canvas_width, canvas_height);
|
||||
|
||||
for (int y = 0; y < squares_per_col; y++) {
|
||||
for (int x = 0; x < squares_per_row; x++) {
|
||||
int sx = x * square_side + square_side/2 + padding;
|
||||
int sy = y * square_side + square_side/2 + padding;
|
||||
/* Rotate and translate randomly as we go down to lower
|
||||
* rows. */
|
||||
float angle = 0;
|
||||
if (y > 1) {
|
||||
float r1 = (float)rand() / RAND_MAX / squares_per_col * y;
|
||||
float r2 = (float)rand() / RAND_MAX / squares_per_col * y;
|
||||
float r3 = (float)rand() / RAND_MAX / squares_per_col * y;
|
||||
if (rand() % 2) r1 = -r1;
|
||||
if (rand() % 2) r2 = -r2;
|
||||
if (rand() % 2) r3 = -r3;
|
||||
angle = r1;
|
||||
sx += r2*square_side/3;
|
||||
sy += r3*square_side/3;
|
||||
}
|
||||
lwDrawSquare(canvas,sx,sy,square_side,angle);
|
||||
}
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
/* Converts the canvas to an SDS string representing the UTF8 characters to
|
||||
* print to the terminal in order to obtain a graphical representaiton of the
|
||||
* logical canvas. The actual returned string will require a terminal that is
|
||||
* width/2 large and height/4 tall in order to hold the whole image without
|
||||
* overflowing or scrolling, since each Barille character is 2x4. */
|
||||
sds lwRenderCanvas(lwCanvas *canvas) {
|
||||
sds text = sdsempty();
|
||||
for (int y = 0; y < canvas->height; y += 4) {
|
||||
for (int x = 0; x < canvas->width; x += 2) {
|
||||
/* We need to emit groups of 8 bits according to a specific
|
||||
* arrangement. See lwTranslatePixelsGroup() for more info. */
|
||||
int byte = 0;
|
||||
if (lwGetPixel(canvas,x,y)) byte |= (1<<0);
|
||||
if (lwGetPixel(canvas,x,y+1)) byte |= (1<<1);
|
||||
if (lwGetPixel(canvas,x,y+2)) byte |= (1<<2);
|
||||
if (lwGetPixel(canvas,x+1,y)) byte |= (1<<3);
|
||||
if (lwGetPixel(canvas,x+1,y+1)) byte |= (1<<4);
|
||||
if (lwGetPixel(canvas,x+1,y+2)) byte |= (1<<5);
|
||||
if (lwGetPixel(canvas,x,y+3)) byte |= (1<<6);
|
||||
if (lwGetPixel(canvas,x+1,y+3)) byte |= (1<<7);
|
||||
char unicode[3];
|
||||
lwTranslatePixelsGroup(byte,unicode);
|
||||
text = sdscatlen(text,unicode,3);
|
||||
}
|
||||
if (y != canvas->height-1) text = sdscatlen(text,"\n",1);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/* The LOLWUT command:
|
||||
*
|
||||
* LOLWUT [terminal columns] [squares-per-row] [squares-per-col]
|
||||
*
|
||||
* By default the command uses 66 columns, 8 squares per row, 12 squares
|
||||
* per column.
|
||||
*/
|
||||
void lolwut5Command(client *c) {
|
||||
long cols = 66;
|
||||
long squares_per_row = 8;
|
||||
long squares_per_col = 12;
|
||||
|
||||
/* Parse the optional arguments if any. */
|
||||
if (c->argc > 1 &&
|
||||
getLongFromObjectOrReply(c,c->argv[1],&cols,NULL) != C_OK)
|
||||
return;
|
||||
|
||||
if (c->argc > 2 &&
|
||||
getLongFromObjectOrReply(c,c->argv[2],&squares_per_row,NULL) != C_OK)
|
||||
return;
|
||||
|
||||
if (c->argc > 3 &&
|
||||
getLongFromObjectOrReply(c,c->argv[3],&squares_per_col,NULL) != C_OK)
|
||||
return;
|
||||
|
||||
/* Limits. We want LOLWUT to be always reasonably fast and cheap to execute
|
||||
* so we have maximum number of columns, rows, and output resulution. */
|
||||
if (cols < 1) cols = 1;
|
||||
if (cols > 1000) cols = 1000;
|
||||
if (squares_per_row < 1) squares_per_row = 1;
|
||||
if (squares_per_row > 200) squares_per_row = 200;
|
||||
if (squares_per_col < 1) squares_per_col = 1;
|
||||
if (squares_per_col > 200) squares_per_col = 200;
|
||||
|
||||
/* Generate some computer art and reply. */
|
||||
lwCanvas *canvas = lwDrawSchotter(cols,squares_per_row,squares_per_col);
|
||||
sds rendered = lwRenderCanvas(canvas);
|
||||
rendered = sdscat(rendered,
|
||||
"\nGeorg Nees - schotter, plotter on paper, 1968. Redis ver. ");
|
||||
rendered = sdscat(rendered,REDIS_VERSION);
|
||||
rendered = sdscatlen(rendered,"\n",1);
|
||||
addReplyBulkSds(c,rendered);
|
||||
lwFreeCanvas(canvas);
|
||||
}
|
||||
@@ -48,6 +48,10 @@
|
||||
|
||||
#define LZF_VERSION 0x0105 /* 1.5, API version */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compress in_len bytes stored at the memory block starting at
|
||||
* in_data and write the result to out_data, up to a maximum length
|
||||
@@ -96,5 +100,9 @@ unsigned int
|
||||
lzf_decompress (const void *const in_data, unsigned int in_len,
|
||||
void *out_data, unsigned int out_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+415
-150
File diff suppressed because it is too large.
Load diff
@@ -13,7 +13,7 @@ endif
|
||||
|
||||
.SUFFIXES: .c .so .xo .o
|
||||
|
||||
all: helloworld.so hellotype.so helloblock.so testmodule.so hellocluster.so hellotimer.so hellodict.so
|
||||
all: helloworld.so hellotype.so helloblock.so testmodule.so hellocluster.so hellotimer.so hellodict.so hellofilter.so
|
||||
|
||||
.c.xo:
|
||||
$(CC) -I. $(CFLAGS) $(SHOBJ_CFLAGS) -fPIC -c $< -o $@
|
||||
@@ -46,6 +46,10 @@ hellotimer.so: hellotimer.xo
|
||||
hellodict.xo: ../redismodule.h
|
||||
|
||||
hellodict.so: hellodict.xo
|
||||
|
||||
hellofilter.xo: ../redismodule.h
|
||||
|
||||
hellofilter.so: hellofilter.xo
|
||||
$(LD) -o $@ $< $(SHOBJ_LDFLAGS) $(LIBS) -lc
|
||||
|
||||
testmodule.xo: ../redismodule.h
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
#define REDISMODULE_EXPERIMENTAL_API
|
||||
#include "../redismodule.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static RedisModuleString *log_key_name;
|
||||
|
||||
static const char log_command_name[] = "hellofilter.log";
|
||||
static const char ping_command_name[] = "hellofilter.ping";
|
||||
static const char unregister_command_name[] = "hellofilter.unregister";
|
||||
static int in_log_command = 0;
|
||||
|
||||
static RedisModuleCommandFilter *filter = NULL;
|
||||
|
||||
int HelloFilter_UnregisterCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
RedisModule_ReplyWithLongLong(ctx,
|
||||
RedisModule_UnregisterCommandFilter(ctx, filter));
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
int HelloFilter_PingCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
RedisModuleCallReply *reply = RedisModule_Call(ctx, "ping", "c", "@log");
|
||||
if (reply) {
|
||||
RedisModule_ReplyWithCallReply(ctx, reply);
|
||||
RedisModule_FreeCallReply(reply);
|
||||
} else {
|
||||
RedisModule_ReplyWithSimpleString(ctx, "Unknown command or invalid arguments");
|
||||
}
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
int HelloFilter_LogCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
{
|
||||
RedisModuleString *s = RedisModule_CreateString(ctx, "", 0);
|
||||
|
||||
int i;
|
||||
for (i = 1; i < argc; i++) {
|
||||
size_t arglen;
|
||||
const char *arg = RedisModule_StringPtrLen(argv[i], &arglen);
|
||||
|
||||
if (i > 1) RedisModule_StringAppendBuffer(ctx, s, " ", 1);
|
||||
RedisModule_StringAppendBuffer(ctx, s, arg, arglen);
|
||||
}
|
||||
|
||||
RedisModuleKey *log = RedisModule_OpenKey(ctx, log_key_name, REDISMODULE_WRITE|REDISMODULE_READ);
|
||||
RedisModule_ListPush(log, REDISMODULE_LIST_HEAD, s);
|
||||
RedisModule_CloseKey(log);
|
||||
RedisModule_FreeString(ctx, s);
|
||||
|
||||
in_log_command = 1;
|
||||
|
||||
size_t cmdlen;
|
||||
const char *cmdname = RedisModule_StringPtrLen(argv[1], &cmdlen);
|
||||
RedisModuleCallReply *reply = RedisModule_Call(ctx, cmdname, "v", &argv[2], argc - 2);
|
||||
if (reply) {
|
||||
RedisModule_ReplyWithCallReply(ctx, reply);
|
||||
RedisModule_FreeCallReply(reply);
|
||||
} else {
|
||||
RedisModule_ReplyWithSimpleString(ctx, "Unknown command or invalid arguments");
|
||||
}
|
||||
|
||||
in_log_command = 0;
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
void HelloFilter_CommandFilter(RedisModuleCommandFilterCtx *filter)
|
||||
{
|
||||
if (in_log_command) return; /* don't process our own RM_Call() from HelloFilter_LogCommand() */
|
||||
|
||||
/* Fun manipulations:
|
||||
* - Remove @delme
|
||||
* - Replace @replaceme
|
||||
* - Append @insertbefore or @insertafter
|
||||
* - Prefix with Log command if @log encounterd
|
||||
*/
|
||||
int log = 0;
|
||||
int pos = 0;
|
||||
while (pos < RedisModule_CommandFilterArgsCount(filter)) {
|
||||
const RedisModuleString *arg = RedisModule_CommandFilterArgGet(filter, pos);
|
||||
size_t arg_len;
|
||||
const char *arg_str = RedisModule_StringPtrLen(arg, &arg_len);
|
||||
|
||||
if (arg_len == 6 && !memcmp(arg_str, "@delme", 6)) {
|
||||
RedisModule_CommandFilterArgDelete(filter, pos);
|
||||
continue;
|
||||
}
|
||||
if (arg_len == 10 && !memcmp(arg_str, "@replaceme", 10)) {
|
||||
RedisModule_CommandFilterArgReplace(filter, pos,
|
||||
RedisModule_CreateString(NULL, "--replaced--", 12));
|
||||
} else if (arg_len == 13 && !memcmp(arg_str, "@insertbefore", 13)) {
|
||||
RedisModule_CommandFilterArgInsert(filter, pos,
|
||||
RedisModule_CreateString(NULL, "--inserted-before--", 19));
|
||||
pos++;
|
||||
} else if (arg_len == 12 && !memcmp(arg_str, "@insertafter", 12)) {
|
||||
RedisModule_CommandFilterArgInsert(filter, pos + 1,
|
||||
RedisModule_CreateString(NULL, "--inserted-after--", 18));
|
||||
pos++;
|
||||
} else if (arg_len == 4 && !memcmp(arg_str, "@log", 4)) {
|
||||
log = 1;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (log) RedisModule_CommandFilterArgInsert(filter, 0,
|
||||
RedisModule_CreateString(NULL, log_command_name, sizeof(log_command_name)-1));
|
||||
}
|
||||
|
||||
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (RedisModule_Init(ctx,"hellofilter",1,REDISMODULE_APIVER_1)
|
||||
== REDISMODULE_ERR) return REDISMODULE_ERR;
|
||||
|
||||
if (argc != 2) {
|
||||
RedisModule_Log(ctx, "warning", "Log key name not specified");
|
||||
return REDISMODULE_ERR;
|
||||
}
|
||||
|
||||
long long noself = 0;
|
||||
log_key_name = RedisModule_CreateStringFromString(ctx, argv[0]);
|
||||
RedisModule_StringToLongLong(argv[1], &noself);
|
||||
|
||||
if (RedisModule_CreateCommand(ctx,log_command_name,
|
||||
HelloFilter_LogCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
if (RedisModule_CreateCommand(ctx,ping_command_name,
|
||||
HelloFilter_PingCommand,"deny-oom",1,1,1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
if (RedisModule_CreateCommand(ctx,unregister_command_name,
|
||||
HelloFilter_UnregisterCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
if ((filter = RedisModule_RegisterCommandFilter(ctx, HelloFilter_CommandFilter,
|
||||
noself ? REDISMODULE_CMDFILTER_NOSELF : 0))
|
||||
== NULL) return REDISMODULE_ERR;
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
@@ -109,9 +109,9 @@ int TestStringPrintf(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (argc < 3) {
|
||||
return RedisModule_WrongArity(ctx);
|
||||
}
|
||||
RedisModuleString *s = RedisModule_CreateStringPrintf(ctx,
|
||||
"Got %d args. argv[1]: %s, argv[2]: %s",
|
||||
argc,
|
||||
RedisModuleString *s = RedisModule_CreateStringPrintf(ctx,
|
||||
"Got %d args. argv[1]: %s, argv[2]: %s",
|
||||
argc,
|
||||
RedisModule_StringPtrLen(argv[1], NULL),
|
||||
RedisModule_StringPtrLen(argv[2], NULL)
|
||||
);
|
||||
@@ -133,7 +133,7 @@ int TestUnlink(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
|
||||
RedisModuleKey *k = RedisModule_OpenKey(ctx, RedisModule_CreateStringPrintf(ctx, "unlinked"), REDISMODULE_WRITE | REDISMODULE_READ);
|
||||
if (!k) return failTest(ctx, "Could not create key");
|
||||
|
||||
|
||||
if (REDISMODULE_ERR == RedisModule_StringSet(k, RedisModule_CreateStringPrintf(ctx, "Foobar"))) {
|
||||
return failTest(ctx, "Could not set string value");
|
||||
}
|
||||
@@ -152,7 +152,7 @@ int TestUnlink(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
return failTest(ctx, "Could not verify key to be unlinked");
|
||||
}
|
||||
return RedisModule_ReplyWithSimpleString(ctx, "OK");
|
||||
|
||||
|
||||
}
|
||||
|
||||
int NotifyCallback(RedisModuleCtx *ctx, int type, const char *event,
|
||||
@@ -188,6 +188,10 @@ int TestNotifications(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
RedisModule_Call(ctx, "LPUSH", "cc", "l", "y");
|
||||
RedisModule_Call(ctx, "LPUSH", "cc", "l", "y");
|
||||
|
||||
/* Miss some keys intentionally so we will get a "keymiss" notification. */
|
||||
RedisModule_Call(ctx, "GET", "c", "nosuchkey");
|
||||
RedisModule_Call(ctx, "SMEMBERS", "c", "nosuchkey");
|
||||
|
||||
size_t sz;
|
||||
const char *rep;
|
||||
RedisModuleCallReply *r = RedisModule_Call(ctx, "HGET", "cc", "notifications", "foo");
|
||||
@@ -225,6 +229,16 @@ int TestNotifications(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
FAIL("Wrong reply for l");
|
||||
}
|
||||
|
||||
r = RedisModule_Call(ctx, "HGET", "cc", "notifications", "nosuchkey");
|
||||
if (r == NULL || RedisModule_CallReplyType(r) != REDISMODULE_REPLY_STRING) {
|
||||
FAIL("Wrong or no reply for nosuchkey");
|
||||
} else {
|
||||
rep = RedisModule_CallReplyStringPtr(r, &sz);
|
||||
if (sz != 1 || *rep != '2') {
|
||||
FAIL("Got reply '%.*s'. expected '2'", sz, rep);
|
||||
}
|
||||
}
|
||||
|
||||
RedisModule_Call(ctx, "FLUSHDB", "");
|
||||
|
||||
return RedisModule_ReplyWithSimpleString(ctx, "OK");
|
||||
@@ -423,7 +437,7 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
if (RedisModule_CreateCommand(ctx,"test.ctxflags",
|
||||
TestCtxFlags,"readonly",1,1,1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
|
||||
if (RedisModule_CreateCommand(ctx,"test.unlink",
|
||||
TestUnlink,"write deny-oom",1,1,1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
@@ -435,7 +449,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
RedisModule_SubscribeToKeyspaceEvents(ctx,
|
||||
REDISMODULE_NOTIFY_HASH |
|
||||
REDISMODULE_NOTIFY_SET |
|
||||
REDISMODULE_NOTIFY_STRING,
|
||||
REDISMODULE_NOTIFY_STRING |
|
||||
REDISMODULE_NOTIFY_KEY_MISS,
|
||||
NotifyCallback);
|
||||
if (RedisModule_CreateCommand(ctx,"test.notify",
|
||||
TestNotifications,"write deny-oom",1,1,1) == REDISMODULE_ERR)
|
||||
|
||||
+15
-15
@@ -58,12 +58,12 @@ void queueMultiCommand(client *c) {
|
||||
multiCmd *mc;
|
||||
int j;
|
||||
|
||||
c->mstate.commands = zrealloc(c->mstate.commands,
|
||||
c->mstate.commands = (multiCmd*)zrealloc(c->mstate.commands,
|
||||
sizeof(multiCmd)*(c->mstate.count+1), MALLOC_LOCAL);
|
||||
mc = c->mstate.commands+c->mstate.count;
|
||||
mc->cmd = c->cmd;
|
||||
mc->argc = c->argc;
|
||||
mc->argv = zmalloc(sizeof(robj*)*c->argc, MALLOC_LOCAL);
|
||||
mc->argv = (robj**)zmalloc(sizeof(robj*)*c->argc, MALLOC_LOCAL);
|
||||
memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc);
|
||||
for (j = 0; j < c->argc; j++)
|
||||
incrRefCount(mc->argv[j]);
|
||||
@@ -122,7 +122,7 @@ void execCommand(client *c) {
|
||||
int orig_argc;
|
||||
struct redisCommand *orig_cmd;
|
||||
int must_propagate = 0; /* Need to propagate MULTI/EXEC to AOF / slaves? */
|
||||
int was_master = server.masterhost == NULL;
|
||||
int was_master = listLength(server.masters) == 0;
|
||||
|
||||
if (!(c->flags & CLIENT_MULTI)) {
|
||||
addReplyError(c,"EXEC without MULTI");
|
||||
@@ -147,7 +147,7 @@ void execCommand(client *c) {
|
||||
* was initiated when the instance was a master or a writable replica and
|
||||
* then the configuration changed (for example instance was turned into
|
||||
* a replica). */
|
||||
if (!server.loading && server.masterhost && server.repl_slave_ro &&
|
||||
if (!server.loading && listLength(server.masters) && server.repl_slave_ro &&
|
||||
!(c->flags & CLIENT_MASTER) && c->mstate.cmd_flags & CMD_WRITE)
|
||||
{
|
||||
addReplyError(c,
|
||||
@@ -193,7 +193,7 @@ void execCommand(client *c) {
|
||||
/* Make sure the EXEC command will be propagated as well if MULTI
|
||||
* was already propagated. */
|
||||
if (must_propagate) {
|
||||
int is_master = server.masterhost == NULL;
|
||||
int is_master = listLength(server.masters) == 0;
|
||||
server.dirty++;
|
||||
/* If inside the MULTI/EXEC block this instance was suddenly
|
||||
* switched from master to slave (using the SLAVEOF command), the
|
||||
@@ -201,7 +201,7 @@ void execCommand(client *c) {
|
||||
* rest was not. We need to make sure to at least terminate the
|
||||
* backlog with the final EXEC. */
|
||||
if (server.repl_backlog && was_master && !is_master) {
|
||||
char *execcmd = "*1\r\n$4\r\nEXEC\r\n";
|
||||
const char *execcmd = "*1\r\n$4\r\nEXEC\r\n";
|
||||
feedReplicationBacklog(execcmd,strlen(execcmd));
|
||||
}
|
||||
}
|
||||
@@ -243,12 +243,12 @@ void watchForKey(client *c, robj *key) {
|
||||
/* Check if we are already watching for this key */
|
||||
listRewind(c->watched_keys,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
wk = listNodeValue(ln);
|
||||
wk = (watchedKey*)listNodeValue(ln);
|
||||
if (wk->db == c->db && equalStringObjects(key,wk->key))
|
||||
return; /* Key already watched */
|
||||
}
|
||||
/* This key is not already watched in this DB. Let's add it */
|
||||
clients = dictFetchValue(c->db->watched_keys,key);
|
||||
clients = (decltype(clients)) dictFetchValue(c->db->watched_keys,key);
|
||||
if (!clients) {
|
||||
clients = listCreate();
|
||||
dictAdd(c->db->watched_keys,key,clients);
|
||||
@@ -256,7 +256,7 @@ void watchForKey(client *c, robj *key) {
|
||||
}
|
||||
listAddNodeTail(clients,c);
|
||||
/* Add the new key to the list of keys watched by this client */
|
||||
wk = zmalloc(sizeof(*wk), MALLOC_SHARED);
|
||||
wk = (watchedKey*)zmalloc(sizeof(*wk), MALLOC_SHARED);
|
||||
wk->key = key;
|
||||
wk->db = c->db;
|
||||
incrRefCount(key);
|
||||
@@ -277,8 +277,8 @@ void unwatchAllKeys(client *c) {
|
||||
|
||||
/* Lookup the watched key -> clients list and remove the client
|
||||
* from the list */
|
||||
wk = listNodeValue(ln);
|
||||
clients = dictFetchValue(wk->db->watched_keys, wk->key);
|
||||
wk = (watchedKey*)listNodeValue(ln);
|
||||
clients = (decltype(clients))dictFetchValue(wk->db->watched_keys, wk->key);
|
||||
serverAssertWithInfo(c,NULL,clients != NULL);
|
||||
listDelNode(clients,listSearchKey(clients,c));
|
||||
/* Kill the entry at all if this was the only client */
|
||||
@@ -300,14 +300,14 @@ void touchWatchedKey(redisDb *db, robj *key) {
|
||||
listNode *ln;
|
||||
|
||||
if (dictSize(db->watched_keys) == 0) return;
|
||||
clients = dictFetchValue(db->watched_keys, key);
|
||||
clients = (list*)dictFetchValue(db->watched_keys, key);
|
||||
if (!clients) return;
|
||||
|
||||
/* Mark all the clients watching this key as CLIENT_DIRTY_CAS */
|
||||
/* Check if we are already watching for this key */
|
||||
listRewind(clients,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
client *c = listNodeValue(ln);
|
||||
client *c = (client*)listNodeValue(ln);
|
||||
|
||||
c->flags |= CLIENT_DIRTY_CAS;
|
||||
}
|
||||
@@ -325,10 +325,10 @@ void touchWatchedKeysOnFlush(int dbid) {
|
||||
/* For every client, check all the waited keys */
|
||||
listRewind(server.clients,&li1);
|
||||
while((ln = listNext(&li1))) {
|
||||
client *c = listNodeValue(ln);
|
||||
client *c = (client*)listNodeValue(ln);
|
||||
listRewind(c->watched_keys,&li2);
|
||||
while((ln = listNext(&li2))) {
|
||||
watchedKey *wk = listNodeValue(ln);
|
||||
watchedKey *wk = (watchedKey*)listNodeValue(ln);
|
||||
|
||||
/* For every watched key matching the specified DB, if the
|
||||
* key exists, mark the client as dirty, as the key will be
|
||||
+53
-33
@@ -138,6 +138,7 @@ void linkClient(client *c) {
|
||||
* this way removing the client in unlinkClient() will not require
|
||||
* a linear scan, but just a constant time operation. */
|
||||
c->client_list_node = listLast(server.clients);
|
||||
if (c->fd != -1) atomicIncr(server.rgthreadvar[c->iel].cclients, 1);
|
||||
uint64_t id = htonu64(c->id);
|
||||
raxInsert(server.clients_index,(unsigned char*)&id,sizeof(id),c,NULL);
|
||||
}
|
||||
@@ -225,6 +226,7 @@ client *createClient(int fd, int iel) {
|
||||
c->bufAsync = NULL;
|
||||
c->buflenAsync = 0;
|
||||
c->bufposAsync = 0;
|
||||
memset(c->uuid, 0, UUID_BINARY_LEN);
|
||||
|
||||
listSetFreeMethod(c->pubsub_patterns,decrRefCountVoid);
|
||||
listSetMatchMethod(c->pubsub_patterns,listMatchObjects);
|
||||
@@ -298,6 +300,9 @@ int prepareClientToWrite(client *c, bool fAsync) {
|
||||
serverAssert(!fAsync || GlobalLocksAcquired());
|
||||
serverAssert(c->fd <= 0 || c->lock.fOwnLock());
|
||||
|
||||
if (c->flags & CLIENT_FORCE_REPLY) return C_OK; // FORCE REPLY means we're doing something else with the buffer.
|
||||
// do not install a write handler
|
||||
|
||||
/* If it's the Lua client we always return ok without installing any
|
||||
* handler since there is no socket at all. */
|
||||
if (c->flags & (CLIENT_LUA|CLIENT_MODULE)) return C_OK;
|
||||
@@ -1035,6 +1040,7 @@ static void acceptCommonHandler(int fd, int flags, char *ip, int iel) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SO_INCOMING_CPU
|
||||
// Set thread affinity
|
||||
if (server.fThreadAffinity)
|
||||
{
|
||||
@@ -1044,6 +1050,7 @@ static void acceptCommonHandler(int fd, int flags, char *ip, int iel) {
|
||||
serverLog(LL_WARNING, "Failed to set socket affinity");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If maxclient directive is set and this is one client more... close the
|
||||
* connection. Note that we create the client instead to check before
|
||||
@@ -1162,10 +1169,8 @@ static void freeClientArgv(client *c) {
|
||||
c->cmd = NULL;
|
||||
}
|
||||
|
||||
/* Close all the slaves connections. This is useful in chained replication
|
||||
* when we resync with our own master and want to force all our slaves to
|
||||
* resync with us as well. */
|
||||
void disconnectSlaves(void) {
|
||||
void disconnectSlavesExcept(unsigned char *uuid)
|
||||
{
|
||||
serverAssert(GlobalLocksAcquired());
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
@@ -1173,8 +1178,16 @@ void disconnectSlaves(void) {
|
||||
listRewind(server.slaves, &li);
|
||||
while ((ln = listNext(&li))) {
|
||||
client *c = (client*)listNodeValue(ln);
|
||||
freeClientAsync(c);
|
||||
}
|
||||
if (uuid == nullptr || !FUuidEqual(c->uuid, uuid))
|
||||
freeClientAsync(c);
|
||||
}
|
||||
}
|
||||
|
||||
/* Close all the slaves connections. This is useful in chained replication
|
||||
* when we resync with our own master and want to force all our slaves to
|
||||
* resync with us as well. */
|
||||
void disconnectSlaves(void) {
|
||||
disconnectSlavesExcept(nullptr);
|
||||
}
|
||||
|
||||
/* Remove the specified client from global lists where the client could
|
||||
@@ -1201,11 +1214,23 @@ void unlinkClient(client *c) {
|
||||
c->client_list_node = NULL;
|
||||
}
|
||||
|
||||
/* In the case of diskless replication the fork is writing to the
|
||||
* sockets and just closing the fd isn't enough, if we don't also
|
||||
* shutdown the socket the fork will continue to write to the slave
|
||||
* and the salve will only find out that it was disconnected when
|
||||
* it will finish reading the rdb. */
|
||||
if ((c->flags & CLIENT_SLAVE) &&
|
||||
(c->replstate == SLAVE_STATE_WAIT_BGSAVE_END)) {
|
||||
shutdown(c->fd, SHUT_RDWR);
|
||||
}
|
||||
|
||||
/* Unregister async I/O handlers and close the socket. */
|
||||
aeDeleteFileEvent(server.rgthreadvar[c->iel].el,c->fd,AE_READABLE);
|
||||
aeDeleteFileEvent(server.rgthreadvar[c->iel].el,c->fd,AE_WRITABLE);
|
||||
close(c->fd);
|
||||
c->fd = -1;
|
||||
|
||||
atomicDecr(server.rgthreadvar[c->iel].cclients, 1);
|
||||
}
|
||||
|
||||
/* Remove from the list of pending writes if needed. */
|
||||
@@ -1261,13 +1286,13 @@ void freeClient(client *c) {
|
||||
*
|
||||
* Note that before doing this we make sure that the client is not in
|
||||
* some unexpected state, by checking its flags. */
|
||||
if (server.master && c->flags & CLIENT_MASTER) {
|
||||
if (FActiveMaster(c)) {
|
||||
serverLog(LL_WARNING,"Connection with master lost.");
|
||||
if (!(c->flags & (CLIENT_CLOSE_AFTER_REPLY|
|
||||
CLIENT_CLOSE_ASAP|
|
||||
CLIENT_BLOCKED)))
|
||||
CLIENT_CLOSE_ASAP|
|
||||
CLIENT_BLOCKED)))
|
||||
{
|
||||
replicationCacheMaster(c);
|
||||
replicationCacheMaster(MasterInfoFromClient(c), c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1327,7 +1352,7 @@ void freeClient(client *c) {
|
||||
|
||||
/* Master/slave cleanup Case 2:
|
||||
* we lost the connection with the master. */
|
||||
if (c->flags & CLIENT_MASTER) replicationHandleMasterDisconnection();
|
||||
if (c->flags & CLIENT_MASTER) replicationHandleMasterDisconnection(MasterInfoFromClient(c));
|
||||
|
||||
/* If this client was scheduled for async freeing we need to remove it
|
||||
* from the queue. */
|
||||
@@ -1930,7 +1955,7 @@ int processMultibulkBuffer(client *c) {
|
||||
* more query buffer to process, because we read more data from the socket
|
||||
* or because a client was blocked and later reactivated, so there could be
|
||||
* pending query buffer, already representing a full command, to process. */
|
||||
void processInputBuffer(client *c) {
|
||||
void processInputBuffer(client *c, int callFlags) {
|
||||
AssertCorrectThread(c);
|
||||
bool fFreed = false;
|
||||
|
||||
@@ -1966,17 +1991,6 @@ void processInputBuffer(client *c) {
|
||||
|
||||
if (c->reqtype == PROTO_REQ_INLINE) {
|
||||
if (processInlineBuffer(c) != C_OK) break;
|
||||
/* If the Gopher mode and we got zero or one argument, process
|
||||
* the request in Gopher mode. */
|
||||
if (server.gopher_enabled &&
|
||||
((c->argc == 1 && ((char*)(ptrFromObj(c->argv[0])))[0] == '/') ||
|
||||
c->argc == 0))
|
||||
{
|
||||
processGopherRequest(c);
|
||||
resetClient(c);
|
||||
c->flags |= CLIENT_CLOSE_AFTER_REPLY;
|
||||
break;
|
||||
}
|
||||
} else if (c->reqtype == PROTO_REQ_MULTIBULK) {
|
||||
if (processMultibulkBuffer(c) != C_OK) break;
|
||||
} else {
|
||||
@@ -1992,7 +2006,7 @@ void processInputBuffer(client *c) {
|
||||
server.current_client = c;
|
||||
|
||||
/* Only reset the client when the command was executed. */
|
||||
if (processCommand(c) == C_OK) {
|
||||
if (processCommand(c, callFlags) == C_OK) {
|
||||
if (c->flags & CLIENT_MASTER && !(c->flags & CLIENT_MULTI)) {
|
||||
/* Update the applied replication offset of our master. */
|
||||
c->reploff = c->read_reploff - sdslen(c->querybuf) + c->qb_pos;
|
||||
@@ -2029,16 +2043,19 @@ void processInputBuffer(client *c) {
|
||||
* raw processInputBuffer(). */
|
||||
void processInputBufferAndReplicate(client *c) {
|
||||
if (!(c->flags & CLIENT_MASTER)) {
|
||||
processInputBuffer(c);
|
||||
processInputBuffer(c, CMD_CALL_FULL);
|
||||
} else {
|
||||
size_t prev_offset = c->reploff;
|
||||
processInputBuffer(c);
|
||||
processInputBuffer(c, CMD_CALL_FULL);
|
||||
size_t applied = c->reploff - prev_offset;
|
||||
if (applied) {
|
||||
aeAcquireLock();
|
||||
replicationFeedSlavesFromMasterStream(server.slaves,
|
||||
c->pending_querybuf, applied);
|
||||
aeReleaseLock();
|
||||
if (!server.fActiveReplica)
|
||||
{
|
||||
aeAcquireLock();
|
||||
replicationFeedSlavesFromMasterStream(server.slaves,
|
||||
c->pending_querybuf, applied);
|
||||
aeReleaseLock();
|
||||
}
|
||||
sdsrange(c->pending_querybuf,applied,-1);
|
||||
}
|
||||
}
|
||||
@@ -2130,7 +2147,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
* corresponding part of the replication stream, will be propagated to
|
||||
* the sub-slaves and to the replication backlog. */
|
||||
processInputBufferAndReplicate(c);
|
||||
aelock.arm(nullptr);
|
||||
aelock.arm(c);
|
||||
ProcessPendingAsyncWrites();
|
||||
}
|
||||
|
||||
@@ -2421,7 +2438,10 @@ NULL
|
||||
if (c == client) {
|
||||
close_this_client = 1;
|
||||
} else {
|
||||
freeClientAsync(client);
|
||||
if (FCorrectThread(client))
|
||||
freeClient(client);
|
||||
else
|
||||
freeClientAsync(client);
|
||||
}
|
||||
killed++;
|
||||
}
|
||||
@@ -2552,7 +2572,7 @@ void helloCommand(client *c) {
|
||||
|
||||
if (!server.sentinel_mode) {
|
||||
addReplyBulkCString(c,"role");
|
||||
addReplyBulkCString(c,server.masterhost ? "replica" : "master");
|
||||
addReplyBulkCString(c,listLength(server.masters) ? "replica" : "master");
|
||||
}
|
||||
|
||||
addReplyBulkCString(c,"modules");
|
||||
|
||||
@@ -55,6 +55,7 @@ int keyspaceEventsStringToFlags(char *classes) {
|
||||
case 'K': flags |= NOTIFY_KEYSPACE; break;
|
||||
case 'E': flags |= NOTIFY_KEYEVENT; break;
|
||||
case 't': flags |= NOTIFY_STREAM; break;
|
||||
case 'm': flags |= NOTIFY_KEY_MISS; break;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
@@ -81,6 +82,7 @@ sds keyspaceEventsFlagsToString(int flags) {
|
||||
if (flags & NOTIFY_EXPIRED) res = sdscatlen(res,"x",1);
|
||||
if (flags & NOTIFY_EVICTED) res = sdscatlen(res,"e",1);
|
||||
if (flags & NOTIFY_STREAM) res = sdscatlen(res,"t",1);
|
||||
if (flags & NOTIFY_KEY_MISS) res = sdscatlen(res,"m",1);
|
||||
}
|
||||
if (flags & NOTIFY_KEYSPACE) res = sdscatlen(res,"K",1);
|
||||
if (flags & NOTIFY_KEYEVENT) res = sdscatlen(res,"E",1);
|
||||
@@ -94,18 +96,18 @@ sds keyspaceEventsFlagsToString(int flags) {
|
||||
* 'event' is a C string representing the event name.
|
||||
* 'key' is a Redis object representing the key name.
|
||||
* 'dbid' is the database ID where the key lives. */
|
||||
void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) {
|
||||
void notifyKeyspaceEvent(int type, const char *event, robj *key, int dbid) {
|
||||
sds chan;
|
||||
robj *chanobj, *eventobj;
|
||||
int len = -1;
|
||||
char buf[24];
|
||||
|
||||
/* If any modules are interested in events, notify the module system now.
|
||||
/* If any modules are interested in events, notify the module system now.
|
||||
* This bypasses the notifications configuration, but the module engine
|
||||
* will only call event subscribers if the event type matches the types
|
||||
* they are interested in. */
|
||||
moduleNotifyKeyspaceEvent(type, event, key, dbid);
|
||||
|
||||
|
||||
/* If notifications for this class of events are off, return ASAP. */
|
||||
if (!(server.notify_keyspace_events & type)) return;
|
||||
|
||||
@@ -117,7 +119,7 @@ void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) {
|
||||
len = ll2string(buf,sizeof(buf),dbid);
|
||||
chan = sdscatlen(chan, buf, len);
|
||||
chan = sdscatlen(chan, "__:", 3);
|
||||
chan = sdscatsds(chan, ptrFromObj(key));
|
||||
chan = sdscatsds(chan, szFromObj(key));
|
||||
chanobj = createObject(OBJ_STRING, chan);
|
||||
pubsubPublishMessage(chanobj, eventobj);
|
||||
decrRefCount(chanobj);
|
||||
@@ -129,7 +131,7 @@ void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) {
|
||||
if (len == -1) len = ll2string(buf,sizeof(buf),dbid);
|
||||
chan = sdscatlen(chan, buf, len);
|
||||
chan = sdscatlen(chan, "__:", 3);
|
||||
chan = sdscatsds(chan, ptrFromObj(eventobj));
|
||||
chan = sdscatsds(chan, szFromObj(eventobj));
|
||||
chanobj = createObject(OBJ_STRING, chan);
|
||||
pubsubPublishMessage(chanobj, key);
|
||||
decrRefCount(chanobj);
|
||||
@@ -39,7 +39,7 @@
|
||||
/* ===================== Creation and parsing of objects ==================== */
|
||||
|
||||
robj *createObject(int type, void *ptr) {
|
||||
robj *o = zmalloc(sizeof(*o), MALLOC_SHARED);
|
||||
robj *o = (robj*)zmalloc(sizeof(*o), MALLOC_SHARED);
|
||||
o->type = type;
|
||||
o->encoding = OBJ_ENCODING_RAW;
|
||||
o->m_ptr = ptr;
|
||||
@@ -85,8 +85,8 @@ robj *createEmbeddedStringObject(const char *ptr, size_t len) {
|
||||
size_t allocsize = sizeof(struct sdshdr8)+len+1;
|
||||
if (allocsize < sizeof(void*))
|
||||
allocsize = sizeof(void*);
|
||||
robj *o = zmalloc(sizeof(robj)+allocsize-sizeof(o->m_ptr), MALLOC_SHARED);
|
||||
struct sdshdr8 *sh = (void*)(&o->m_ptr);
|
||||
robj *o = (robj*)zmalloc(sizeof(robj)+allocsize-sizeof(o->m_ptr), MALLOC_SHARED);
|
||||
struct sdshdr8 *sh = (sdshdr8*)(&o->m_ptr);
|
||||
|
||||
o->type = OBJ_STRING;
|
||||
o->encoding = OBJ_ENCODING_EMBSTR;
|
||||
@@ -101,12 +101,12 @@ robj *createEmbeddedStringObject(const char *ptr, size_t len) {
|
||||
sh->alloc = len;
|
||||
sh->flags = SDS_TYPE_8;
|
||||
if (ptr == SDS_NOINIT)
|
||||
sh->buf[len] = '\0';
|
||||
sh->buf()[len] = '\0';
|
||||
else if (ptr) {
|
||||
memcpy(sh->buf,ptr,len);
|
||||
sh->buf[len] = '\0';
|
||||
memcpy(sh->buf(),ptr,len);
|
||||
sh->buf()[len] = '\0';
|
||||
} else {
|
||||
memset(sh->buf,0,len+1);
|
||||
memset(sh->buf(),0,len+1);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
@@ -199,9 +199,9 @@ robj *dupStringObject(const robj *o) {
|
||||
|
||||
switch(o->encoding) {
|
||||
case OBJ_ENCODING_RAW:
|
||||
return createRawStringObject(ptrFromObj(o),sdslen(ptrFromObj(o)));
|
||||
return createRawStringObject(szFromObj(o),sdslen(szFromObj(o)));
|
||||
case OBJ_ENCODING_EMBSTR:
|
||||
return createEmbeddedStringObject(ptrFromObj(o),sdslen(ptrFromObj(o)));
|
||||
return createEmbeddedStringObject(szFromObj(o),sdslen(szFromObj(o)));
|
||||
case OBJ_ENCODING_INT:
|
||||
d = createObject(OBJ_STRING, NULL);
|
||||
d->encoding = OBJ_ENCODING_INT;
|
||||
@@ -249,7 +249,7 @@ robj *createHashObject(void) {
|
||||
}
|
||||
|
||||
robj *createZsetObject(void) {
|
||||
zset *zs = zmalloc(sizeof(*zs), MALLOC_SHARED);
|
||||
zset *zs = (zset*)zmalloc(sizeof(*zs), MALLOC_SHARED);
|
||||
robj *o;
|
||||
|
||||
zs->pdict = dictCreate(&zsetDictType,NULL);
|
||||
@@ -274,7 +274,7 @@ robj *createStreamObject(void) {
|
||||
}
|
||||
|
||||
robj *createModuleObject(moduleType *mt, void *value) {
|
||||
moduleValue *mv = zmalloc(sizeof(*mv), MALLOC_SHARED);
|
||||
moduleValue *mv = (moduleValue*)zmalloc(sizeof(*mv), MALLOC_SHARED);
|
||||
mv->type = mt;
|
||||
mv->value = value;
|
||||
return createObject(OBJ_MODULE,mv);
|
||||
@@ -282,13 +282,13 @@ robj *createModuleObject(moduleType *mt, void *value) {
|
||||
|
||||
void freeStringObject(robj *o) {
|
||||
if (o->encoding == OBJ_ENCODING_RAW) {
|
||||
sdsfree(ptrFromObj(o));
|
||||
sdsfree(szFromObj(o));
|
||||
}
|
||||
}
|
||||
|
||||
void freeListObject(robj *o) {
|
||||
if (o->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
quicklistRelease(ptrFromObj(o));
|
||||
quicklistRelease((quicklist*)ptrFromObj(o));
|
||||
} else {
|
||||
serverPanic("Unknown list encoding type");
|
||||
}
|
||||
@@ -311,7 +311,7 @@ void freeZsetObject(robj *o) {
|
||||
zset *zs;
|
||||
switch (o->encoding) {
|
||||
case OBJ_ENCODING_SKIPLIST:
|
||||
zs = ptrFromObj(o);
|
||||
zs = (zset*)ptrFromObj(o);
|
||||
dictRelease(zs->pdict);
|
||||
zslFree(zs->zsl);
|
||||
zfree(zs);
|
||||
@@ -339,13 +339,13 @@ void freeHashObject(robj *o) {
|
||||
}
|
||||
|
||||
void freeModuleObject(robj *o) {
|
||||
moduleValue *mv = ptrFromObj(o);
|
||||
moduleValue *mv = (moduleValue*)ptrFromObj(o);
|
||||
mv->type->free(mv->value);
|
||||
zfree(mv);
|
||||
}
|
||||
|
||||
void freeStreamObject(robj *o) {
|
||||
freeStream(ptrFromObj(o));
|
||||
freeStream((stream*)ptrFromObj(o));
|
||||
}
|
||||
|
||||
void incrRefCount(robj *o) {
|
||||
@@ -375,7 +375,7 @@ void decrRefCount(robj *o) {
|
||||
* as free method in data structures that expect a 'void free_object(void*)'
|
||||
* prototype for the free method. */
|
||||
void decrRefCountVoid(void *o) {
|
||||
decrRefCount(o);
|
||||
decrRefCount((robj*)o);
|
||||
}
|
||||
|
||||
/* This function set the ref count to zero without freeing the object.
|
||||
@@ -413,7 +413,7 @@ int isObjectRepresentableAsLongLong(robj *o, long long *llval) {
|
||||
if (llval) *llval = (long) ptrFromObj(o);
|
||||
return C_OK;
|
||||
} else {
|
||||
return isSdsRepresentableAsLongLong(ptrFromObj(o),llval);
|
||||
return isSdsRepresentableAsLongLong(szFromObj(o),llval);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,16 +423,16 @@ int isObjectRepresentableAsLongLong(robj *o, long long *llval) {
|
||||
* wasting too much time in allocations when appending to the string. */
|
||||
void trimStringObjectIfNeeded(robj *o) {
|
||||
if (o->encoding == OBJ_ENCODING_RAW &&
|
||||
sdsavail(ptrFromObj(o)) > sdslen(ptrFromObj(o))/10)
|
||||
sdsavail(szFromObj(o)) > sdslen(szFromObj(o))/10)
|
||||
{
|
||||
o->m_ptr = sdsRemoveFreeSpace(ptrFromObj(o));
|
||||
o->m_ptr = sdsRemoveFreeSpace(szFromObj(o));
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to encode a string object in order to save space */
|
||||
robj *tryObjectEncoding(robj *o) {
|
||||
long value;
|
||||
sds s = ptrFromObj(o);
|
||||
sds s = szFromObj(o);
|
||||
size_t len;
|
||||
|
||||
/* Make sure this is a string object, the only type we encode
|
||||
@@ -469,7 +469,7 @@ robj *tryObjectEncoding(robj *o) {
|
||||
incrRefCount(shared.integers[value]);
|
||||
return shared.integers[value];
|
||||
} else {
|
||||
if (o->encoding == OBJ_ENCODING_RAW) sdsfree(ptrFromObj(o));
|
||||
if (o->encoding == OBJ_ENCODING_RAW) sdsfree(szFromObj(o));
|
||||
o->encoding = OBJ_ENCODING_INT;
|
||||
o->m_ptr = (void*) value;
|
||||
return o;
|
||||
@@ -542,14 +542,14 @@ int compareStringObjectsWithFlags(robj *a, robj *b, int flags) {
|
||||
|
||||
if (a == b) return 0;
|
||||
if (sdsEncodedObject(a)) {
|
||||
astr = ptrFromObj(a);
|
||||
astr = szFromObj(a);
|
||||
alen = sdslen(astr);
|
||||
} else {
|
||||
alen = ll2string(bufa,sizeof(bufa),(long) ptrFromObj(a));
|
||||
astr = bufa;
|
||||
}
|
||||
if (sdsEncodedObject(b)) {
|
||||
bstr = ptrFromObj(b);
|
||||
bstr = szFromObj(b);
|
||||
blen = sdslen(bstr);
|
||||
} else {
|
||||
blen = ll2string(bufb,sizeof(bufb),(long) ptrFromObj(b));
|
||||
@@ -595,7 +595,7 @@ int equalStringObjects(robj *a, robj *b) {
|
||||
size_t stringObjectLen(robj *o) {
|
||||
serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);
|
||||
if (sdsEncodedObject(o)) {
|
||||
return sdslen(ptrFromObj(o));
|
||||
return sdslen(szFromObj(o));
|
||||
} else {
|
||||
return sdigits10((long)ptrFromObj(o));
|
||||
}
|
||||
@@ -611,10 +611,10 @@ int getDoubleFromObject(const robj *o, double *target) {
|
||||
serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);
|
||||
if (sdsEncodedObject(o)) {
|
||||
errno = 0;
|
||||
value = strtod(ptrFromObj(o), &eptr);
|
||||
if (sdslen(ptrFromObj(o)) == 0 ||
|
||||
isspace(((const char*)ptrFromObj(o))[0]) ||
|
||||
(size_t)(eptr-(char*)ptrFromObj(o)) != sdslen(ptrFromObj(o)) ||
|
||||
value = strtod(szFromObj(o), &eptr);
|
||||
if (sdslen(szFromObj(o)) == 0 ||
|
||||
isspace(((const char*)szFromObj(o))[0]) ||
|
||||
(size_t)(eptr-(char*)szFromObj(o)) != sdslen(szFromObj(o)) ||
|
||||
(errno == ERANGE &&
|
||||
(value == HUGE_VAL || value == -HUGE_VAL || value == 0)) ||
|
||||
isnan(value))
|
||||
@@ -653,16 +653,16 @@ int getLongDoubleFromObject(robj *o, long double *target) {
|
||||
serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);
|
||||
if (sdsEncodedObject(o)) {
|
||||
errno = 0;
|
||||
value = strtold(ptrFromObj(o), &eptr);
|
||||
if (sdslen(ptrFromObj(o)) == 0 ||
|
||||
isspace(((const char*)ptrFromObj(o))[0]) ||
|
||||
(size_t)(eptr-(char*)ptrFromObj(o)) != sdslen(ptrFromObj(o)) ||
|
||||
value = strtold(szFromObj(o), &eptr);
|
||||
if (sdslen(szFromObj(o)) == 0 ||
|
||||
isspace(((const char*)szFromObj(o))[0]) ||
|
||||
(size_t)(eptr-(char*)szFromObj(o)) != sdslen(szFromObj(o)) ||
|
||||
(errno == ERANGE &&
|
||||
(value == HUGE_VAL || value == -HUGE_VAL || value == 0)) ||
|
||||
isnan(value))
|
||||
return C_ERR;
|
||||
} else if (o->encoding == OBJ_ENCODING_INT) {
|
||||
value = (long)ptrFromObj(o);
|
||||
value = (long)szFromObj(o);
|
||||
} else {
|
||||
serverPanic("Unknown string encoding");
|
||||
}
|
||||
@@ -693,7 +693,7 @@ int getLongLongFromObject(robj *o, long long *target) {
|
||||
} else {
|
||||
serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);
|
||||
if (sdsEncodedObject(o)) {
|
||||
if (string2ll(ptrFromObj(o),sdslen(ptrFromObj(o)),&value) == 0) return C_ERR;
|
||||
if (string2ll(szFromObj(o),sdslen(szFromObj(o)),&value) == 0) return C_ERR;
|
||||
} else if (o->encoding == OBJ_ENCODING_INT) {
|
||||
value = (long)ptrFromObj(o);
|
||||
} else {
|
||||
@@ -734,7 +734,7 @@ int getLongFromObjectOrReply(client *c, robj *o, long *target, const char *msg)
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
char *strEncoding(int encoding) {
|
||||
const char *strEncoding(int encoding) {
|
||||
switch(encoding) {
|
||||
case OBJ_ENCODING_RAW: return "raw";
|
||||
case OBJ_ENCODING_INT: return "int";
|
||||
@@ -790,15 +790,15 @@ size_t objectComputeSize(robj *o, size_t sample_size) {
|
||||
if(o->encoding == OBJ_ENCODING_INT) {
|
||||
asize = sizeof(*o);
|
||||
} else if(o->encoding == OBJ_ENCODING_RAW) {
|
||||
asize = sdsAllocSize(ptrFromObj(o))+sizeof(*o);
|
||||
asize = sdsAllocSize(szFromObj(o))+sizeof(*o);
|
||||
} else if(o->encoding == OBJ_ENCODING_EMBSTR) {
|
||||
asize = sdslen(ptrFromObj(o))+2+sizeof(*o);
|
||||
asize = sdslen(szFromObj(o))+2+sizeof(*o);
|
||||
} else {
|
||||
serverPanic("Unknown string encoding");
|
||||
}
|
||||
} else if (o->type == OBJ_LIST) {
|
||||
if (o->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
quicklist *ql = ptrFromObj(o);
|
||||
quicklist *ql = (quicklist*)ptrFromObj(o);
|
||||
quicklistNode *node = ql->head;
|
||||
asize = sizeof(*o)+sizeof(quicklist);
|
||||
do {
|
||||
@@ -807,41 +807,41 @@ size_t objectComputeSize(robj *o, size_t sample_size) {
|
||||
} while ((node = node->next) && samples < sample_size);
|
||||
asize += (double)elesize/samples*ql->len;
|
||||
} else if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
asize = sizeof(*o)+ziplistBlobLen(ptrFromObj(o));
|
||||
asize = sizeof(*o)+ziplistBlobLen((unsigned char*)ptrFromObj(o));
|
||||
} else {
|
||||
serverPanic("Unknown list encoding");
|
||||
}
|
||||
} else if (o->type == OBJ_SET) {
|
||||
if (o->encoding == OBJ_ENCODING_HT) {
|
||||
d = ptrFromObj(o);
|
||||
d = (dict*)ptrFromObj(o);
|
||||
di = dictGetIterator(d);
|
||||
asize = sizeof(*o)+sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
|
||||
while((de = dictNext(di)) != NULL && samples < sample_size) {
|
||||
ele = dictGetKey(de);
|
||||
ele = (sds)dictGetKey(de);
|
||||
elesize += sizeof(struct dictEntry) + sdsAllocSize(ele);
|
||||
samples++;
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
if (samples) asize += (double)elesize/samples*dictSize(d);
|
||||
} else if (o->encoding == OBJ_ENCODING_INTSET) {
|
||||
intset *is = ptrFromObj(o);
|
||||
intset *is = (intset*)ptrFromObj(o);
|
||||
asize = sizeof(*o)+sizeof(*is)+is->encoding*is->length;
|
||||
} else {
|
||||
serverPanic("Unknown set encoding");
|
||||
}
|
||||
} else if (o->type == OBJ_ZSET) {
|
||||
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
asize = sizeof(*o)+(ziplistBlobLen(ptrFromObj(o)));
|
||||
asize = sizeof(*o)+(ziplistBlobLen((unsigned char*)ptrFromObj(o)));
|
||||
} else if (o->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
d = ((zset*)ptrFromObj(o))->pdict;
|
||||
zskiplist *zsl = ((zset*)ptrFromObj(o))->zsl;
|
||||
zskiplistNode *znode = zsl->header->level[0].forward;
|
||||
zskiplistNode *znode = zsl->header->level(0)->forward;
|
||||
asize = sizeof(*o)+sizeof(zset)+(sizeof(struct dictEntry*)*dictSlots(d));
|
||||
while(znode != NULL && samples < sample_size) {
|
||||
elesize += sdsAllocSize(znode->ele);
|
||||
elesize += sizeof(struct dictEntry) + zmalloc_size(znode);
|
||||
samples++;
|
||||
znode = znode->level[0].forward;
|
||||
znode = znode->level(0)->forward;
|
||||
}
|
||||
if (samples) asize += (double)elesize/samples*dictSize(d);
|
||||
} else {
|
||||
@@ -849,14 +849,14 @@ size_t objectComputeSize(robj *o, size_t sample_size) {
|
||||
}
|
||||
} else if (o->type == OBJ_HASH) {
|
||||
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
asize = sizeof(*o)+(ziplistBlobLen(ptrFromObj(o)));
|
||||
asize = sizeof(*o)+(ziplistBlobLen((unsigned char*)ptrFromObj(o)));
|
||||
} else if (o->encoding == OBJ_ENCODING_HT) {
|
||||
d = ptrFromObj(o);
|
||||
d = (dict*)ptrFromObj(o);
|
||||
di = dictGetIterator(d);
|
||||
asize = sizeof(*o)+sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
|
||||
while((de = dictNext(di)) != NULL && samples < sample_size) {
|
||||
ele = dictGetKey(de);
|
||||
ele2 = dictGetVal(de);
|
||||
ele = (sds)dictGetKey(de);
|
||||
ele2 = (sds)dictGetVal(de);
|
||||
elesize += sdsAllocSize(ele) + sdsAllocSize(ele2);
|
||||
elesize += sizeof(struct dictEntry);
|
||||
samples++;
|
||||
@@ -867,7 +867,7 @@ size_t objectComputeSize(robj *o, size_t sample_size) {
|
||||
serverPanic("Unknown hash encoding");
|
||||
}
|
||||
} else if (o->type == OBJ_STREAM) {
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
asize = sizeof(*o);
|
||||
asize += streamRadixTreeMemoryUsage(s->prax);
|
||||
|
||||
@@ -880,7 +880,7 @@ size_t objectComputeSize(robj *o, size_t sample_size) {
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
size_t lpsize = 0, samples = 0;
|
||||
while(samples < sample_size && raxNext(&ri)) {
|
||||
unsigned char *lp = ri.data;
|
||||
unsigned char *lp = (unsigned char*)ri.data;
|
||||
lpsize += lpBytes(lp);
|
||||
samples++;
|
||||
}
|
||||
@@ -893,7 +893,7 @@ size_t objectComputeSize(robj *o, size_t sample_size) {
|
||||
* if there are a few elements in the radix tree. */
|
||||
raxSeek(&ri,"$",NULL,0);
|
||||
raxNext(&ri);
|
||||
asize += lpBytes(ri.data);
|
||||
asize += lpBytes((unsigned char*)ri.data);
|
||||
}
|
||||
raxStop(&ri);
|
||||
|
||||
@@ -905,7 +905,7 @@ size_t objectComputeSize(robj *o, size_t sample_size) {
|
||||
raxStart(&ri,s->cgroups);
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
while(raxNext(&ri)) {
|
||||
streamCG *cg = ri.data;
|
||||
streamCG *cg = (streamCG*)ri.data;
|
||||
asize += sizeof(*cg);
|
||||
asize += streamRadixTreeMemoryUsage(cg->pel);
|
||||
asize += sizeof(streamNACK)*raxSize(cg->pel);
|
||||
@@ -916,7 +916,7 @@ size_t objectComputeSize(robj *o, size_t sample_size) {
|
||||
raxStart(&cri,cg->consumers);
|
||||
raxSeek(&cri,"^",NULL,0);
|
||||
while(raxNext(&cri)) {
|
||||
streamConsumer *consumer = cri.data;
|
||||
streamConsumer *consumer = (streamConsumer*)cri.data;
|
||||
asize += sizeof(*consumer);
|
||||
asize += sdslen(consumer->name);
|
||||
asize += streamRadixTreeMemoryUsage(consumer->pel);
|
||||
@@ -928,7 +928,7 @@ size_t objectComputeSize(robj *o, size_t sample_size) {
|
||||
raxStop(&ri);
|
||||
}
|
||||
} else if (o->type == OBJ_MODULE) {
|
||||
moduleValue *mv = ptrFromObj(o);
|
||||
moduleValue *mv = (moduleValue*)ptrFromObj(o);
|
||||
moduleType *mt = mv->type;
|
||||
if (mt->mem_usage != NULL) {
|
||||
asize = mt->mem_usage(mv->value);
|
||||
@@ -956,7 +956,7 @@ struct redisMemOverhead *getMemoryOverheadData(void) {
|
||||
size_t mem_total = 0;
|
||||
size_t mem = 0;
|
||||
size_t zmalloc_used = zmalloc_used_memory();
|
||||
struct redisMemOverhead *mh = zcalloc(sizeof(*mh), MALLOC_LOCAL);
|
||||
struct redisMemOverhead *mh = (redisMemOverhead*)zcalloc(sizeof(*mh), MALLOC_LOCAL);
|
||||
|
||||
mh->total_allocated = zmalloc_used;
|
||||
mh->startup_allocated = server.initial_memory_usage;
|
||||
@@ -993,7 +993,7 @@ struct redisMemOverhead *getMemoryOverheadData(void) {
|
||||
|
||||
listRewind(server.slaves,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
client *c = listNodeValue(ln);
|
||||
client *c = (client*)listNodeValue(ln);
|
||||
if (c->flags & CLIENT_CLOSE_ASAP)
|
||||
continue;
|
||||
mem += getClientOutputBufferMemoryUsage(c);
|
||||
@@ -1011,7 +1011,7 @@ struct redisMemOverhead *getMemoryOverheadData(void) {
|
||||
|
||||
listRewind(server.clients,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
client *c = listNodeValue(ln);
|
||||
client *c = (client*)listNodeValue(ln);
|
||||
if (c->flags & CLIENT_SLAVE && !(c->flags & CLIENT_MONITOR))
|
||||
continue;
|
||||
mem += getClientOutputBufferMemoryUsage(c);
|
||||
@@ -1037,7 +1037,7 @@ struct redisMemOverhead *getMemoryOverheadData(void) {
|
||||
dictSlots(server.repl_scriptcache_dict) * sizeof(dictEntry*);
|
||||
if (listLength(server.repl_scriptcache_fifo) > 0) {
|
||||
mem += listLength(server.repl_scriptcache_fifo) * (sizeof(listNode) +
|
||||
sdsZmallocSize(listNodeValue(listFirst(server.repl_scriptcache_fifo))));
|
||||
sdsZmallocSize((sds)listNodeValue(listFirst(server.repl_scriptcache_fifo))));
|
||||
}
|
||||
mh->lua_caches = mem;
|
||||
mem_total+=mem;
|
||||
@@ -1048,7 +1048,7 @@ struct redisMemOverhead *getMemoryOverheadData(void) {
|
||||
if (keyscount==0) continue;
|
||||
|
||||
mh->total_keys += keyscount;
|
||||
mh->db = zrealloc(mh->db,sizeof(mh->db[0])*(mh->num_dbs+1), MALLOC_LOCAL);
|
||||
mh->db = (decltype(mh->db))zrealloc(mh->db,sizeof(mh->db[0])*(mh->num_dbs+1), MALLOC_LOCAL);
|
||||
mh->db[mh->num_dbs].dbid = j;
|
||||
|
||||
mem = dictSize(db->pdict) * sizeof(dictEntry) +
|
||||
@@ -1256,7 +1256,7 @@ robj *objectCommandLookupOrReply(client *c, robj *key, robj *reply) {
|
||||
void objectCommand(client *c) {
|
||||
robj *o;
|
||||
|
||||
if (c->argc == 2 && !strcasecmp(ptrFromObj(c->argv[1]),"help")) {
|
||||
if (c->argc == 2 && !strcasecmp(szFromObj(c->argv[1]),"help")) {
|
||||
const char *help[] = {
|
||||
"ENCODING <key> -- Return the kind of internal representation used in order to store the value associated with a key.",
|
||||
"FREQ <key> -- Return the access frequency index of the key. The returned integer is proportional to the logarithm of the recent access frequency of the key.",
|
||||
@@ -1265,15 +1265,15 @@ void objectCommand(client *c) {
|
||||
NULL
|
||||
};
|
||||
addReplyHelp(c, help);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"refcount") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"refcount") && c->argc == 3) {
|
||||
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.null[c->resp]))
|
||||
== NULL) return;
|
||||
addReplyLongLong(c,o->refcount);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"encoding") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"encoding") && c->argc == 3) {
|
||||
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.null[c->resp]))
|
||||
== NULL) return;
|
||||
addReplyBulkCString(c,strEncoding(o->encoding));
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"idletime") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"idletime") && c->argc == 3) {
|
||||
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.null[c->resp]))
|
||||
== NULL) return;
|
||||
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
|
||||
@@ -1281,7 +1281,7 @@ NULL
|
||||
return;
|
||||
}
|
||||
addReplyLongLong(c,estimateObjectIdleTime(o)/1000);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"freq") && c->argc == 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"freq") && c->argc == 3) {
|
||||
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.null[c->resp]))
|
||||
== NULL) return;
|
||||
if (!(server.maxmemory_policy & MAXMEMORY_FLAG_LFU)) {
|
||||
@@ -1303,7 +1303,7 @@ NULL
|
||||
*
|
||||
* Usage: MEMORY usage <key> */
|
||||
void memoryCommand(client *c) {
|
||||
if (!strcasecmp(ptrFromObj(c->argv[1]),"help") && c->argc == 2) {
|
||||
if (!strcasecmp(szFromObj(c->argv[1]),"help") && c->argc == 2) {
|
||||
const char *help[] = {
|
||||
"DOCTOR - Return memory problems reports.",
|
||||
"MALLOC-STATS -- Return internal statistics report from the memory allocator.",
|
||||
@@ -1313,11 +1313,11 @@ void memoryCommand(client *c) {
|
||||
NULL
|
||||
};
|
||||
addReplyHelp(c, help);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"usage") && c->argc >= 3) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"usage") && c->argc >= 3) {
|
||||
dictEntry *de;
|
||||
long long samples = OBJ_COMPUTE_SIZE_DEF_SAMPLES;
|
||||
for (int j = 3; j < c->argc; j++) {
|
||||
if (!strcasecmp(ptrFromObj(c->argv[j]),"samples") &&
|
||||
if (!strcasecmp(szFromObj(c->argv[j]),"samples") &&
|
||||
j+1 < c->argc)
|
||||
{
|
||||
if (getLongLongFromObjectOrReply(c,c->argv[j+1],&samples,NULL)
|
||||
@@ -1337,11 +1337,11 @@ NULL
|
||||
addReplyNull(c);
|
||||
return;
|
||||
}
|
||||
size_t usage = objectComputeSize(dictGetVal(de),samples);
|
||||
usage += sdsAllocSize(dictGetKey(de));
|
||||
size_t usage = objectComputeSize((robj*)dictGetVal(de),samples);
|
||||
usage += sdsAllocSize((sds)dictGetKey(de));
|
||||
usage += sizeof(dictEntry);
|
||||
addReplyLongLong(c,usage);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"stats") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"stats") && c->argc == 2) {
|
||||
struct redisMemOverhead *mh = getMemoryOverheadData();
|
||||
|
||||
addReplyMapLen(c,25+mh->num_dbs);
|
||||
@@ -1435,7 +1435,7 @@ NULL
|
||||
addReplyLongLong(c,mh->total_frag_bytes);
|
||||
|
||||
freeMemoryOverheadData(mh);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"malloc-stats") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"malloc-stats") && c->argc == 2) {
|
||||
#if defined(USE_JEMALLOC)
|
||||
sds info = sdsempty();
|
||||
je_malloc_stats_print(inputCatSds, &info, NULL);
|
||||
@@ -1443,10 +1443,10 @@ NULL
|
||||
#else
|
||||
addReplyBulkCString(c,"Stats not supported for the current allocator");
|
||||
#endif
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"doctor") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"doctor") && c->argc == 2) {
|
||||
sds report = getMemoryDoctorReport();
|
||||
addReplyBulkSds(c,report);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"purge") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"purge") && c->argc == 2) {
|
||||
#if defined(USE_JEMALLOC)
|
||||
char tmp[32];
|
||||
unsigned narenas = 0;
|
||||
+1
-1
@@ -33,7 +33,7 @@
|
||||
#ifndef __PQSORT_H
|
||||
#define __PQSORT_H
|
||||
|
||||
void
|
||||
extern "C" void
|
||||
pqsort(void *a, size_t n, size_t es,
|
||||
int (*cmp) (const void *, const void *), size_t lrange, size_t rrange);
|
||||
|
||||
|
||||
@@ -121,14 +121,14 @@ void addReplyPubsubPatUnsubscribed(client *c, robj *pattern) {
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
void freePubsubPattern(void *p) {
|
||||
pubsubPattern *pat = p;
|
||||
pubsubPattern *pat = (pubsubPattern *)p;
|
||||
|
||||
decrRefCount(pat->pattern);
|
||||
zfree(pat);
|
||||
}
|
||||
|
||||
int listMatchPubsubPattern(void *a, void *b) {
|
||||
pubsubPattern *pa = a, *pb = b;
|
||||
pubsubPattern *pa = (pubsubPattern*)a, *pb = (pubsubPattern*)b;
|
||||
|
||||
return (pa->pclient == pb->pclient) &&
|
||||
(equalStringObjects(pa->pattern,pb->pattern));
|
||||
@@ -158,7 +158,7 @@ int pubsubSubscribeChannel(client *c, robj *channel) {
|
||||
dictAdd(server.pubsub_channels,channel,clients);
|
||||
incrRefCount(channel);
|
||||
} else {
|
||||
clients = dictGetVal(de);
|
||||
clients = (list*)dictGetVal(de);
|
||||
}
|
||||
listAddNodeTail(clients,c);
|
||||
}
|
||||
@@ -183,7 +183,7 @@ int pubsubUnsubscribeChannel(client *c, robj *channel, int notify) {
|
||||
/* Remove the client from the channel -> clients list hash table */
|
||||
de = dictFind(server.pubsub_channels,channel);
|
||||
serverAssertWithInfo(c,NULL,de != NULL);
|
||||
clients = dictGetVal(de);
|
||||
clients = (list*)dictGetVal(de);
|
||||
ln = listSearchKey(clients,c);
|
||||
serverAssertWithInfo(c,NULL,ln != NULL);
|
||||
listDelNode(clients,ln);
|
||||
@@ -209,7 +209,7 @@ int pubsubSubscribePattern(client *c, robj *pattern) {
|
||||
pubsubPattern *pat;
|
||||
listAddNodeTail(c->pubsub_patterns,pattern);
|
||||
incrRefCount(pattern);
|
||||
pat = zmalloc(sizeof(*pat), MALLOC_LOCAL);
|
||||
pat = (pubsubPattern*)zmalloc(sizeof(*pat), MALLOC_LOCAL);
|
||||
pat->pattern = getDecodedObject(pattern);
|
||||
pat->pclient = c;
|
||||
listAddNodeTail(server.pubsub_patterns,pat);
|
||||
@@ -249,7 +249,7 @@ int pubsubUnsubscribeAllChannels(client *c, int notify) {
|
||||
int count = 0;
|
||||
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
robj *channel = dictGetKey(de);
|
||||
robj *channel = (robj*)dictGetKey(de);
|
||||
|
||||
count += pubsubUnsubscribeChannel(c,channel,notify);
|
||||
}
|
||||
@@ -268,7 +268,7 @@ int pubsubUnsubscribeAllPatterns(client *c, int notify) {
|
||||
|
||||
listRewind(c->pubsub_patterns,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
robj *pattern = ln->value;
|
||||
robj *pattern = (robj*)ln->value;
|
||||
|
||||
count += pubsubUnsubscribePattern(c,pattern,notify);
|
||||
}
|
||||
@@ -286,13 +286,13 @@ int pubsubPublishMessage(robj *channel, robj *message) {
|
||||
/* Send to clients listening for that channel */
|
||||
de = dictFind(server.pubsub_channels,channel);
|
||||
if (de) {
|
||||
list *list = dictGetVal(de);
|
||||
list *list = reinterpret_cast<::list*>(dictGetVal(de));
|
||||
listNode *ln;
|
||||
listIter li;
|
||||
|
||||
listRewind(list,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
client *c = ln->value;
|
||||
client *c = reinterpret_cast<client*>(ln->value);
|
||||
fastlock_lock(&c->lock);
|
||||
addReplyPubsubMessage(c,channel,message);
|
||||
fastlock_unlock(&c->lock);
|
||||
@@ -304,12 +304,12 @@ int pubsubPublishMessage(robj *channel, robj *message) {
|
||||
listRewind(server.pubsub_patterns,&li);
|
||||
channel = getDecodedObject(channel);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
pubsubPattern *pat = ln->value;
|
||||
pubsubPattern *pat = (pubsubPattern*)ln->value;
|
||||
|
||||
if (stringmatchlen((char*)ptrFromObj(pat->pattern),
|
||||
sdslen(ptrFromObj(pat->pattern)),
|
||||
sdslen(szFromObj(pat->pattern)),
|
||||
(char*)ptrFromObj(channel),
|
||||
sdslen(ptrFromObj(channel)),0))
|
||||
sdslen(szFromObj(channel)),0))
|
||||
{
|
||||
fastlock_lock(&pat->pclient->lock);
|
||||
addReplyPubsubPatMessage(pat->pclient,
|
||||
@@ -380,7 +380,7 @@ void publishCommand(client *c) {
|
||||
|
||||
/* PUBSUB command for Pub/Sub introspection. */
|
||||
void pubsubCommand(client *c) {
|
||||
if (c->argc == 2 && !strcasecmp(ptrFromObj(c->argv[1]),"help")) {
|
||||
if (c->argc == 2 && !strcasecmp(szFromObj(c->argv[1]),"help")) {
|
||||
const char *help[] = {
|
||||
"CHANNELS [<pattern>] -- Return the currently active channels matching a pattern (default: all).",
|
||||
"NUMPAT -- Return number of subscriptions to patterns.",
|
||||
@@ -388,11 +388,11 @@ void pubsubCommand(client *c) {
|
||||
NULL
|
||||
};
|
||||
addReplyHelp(c, help);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"channels") &&
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"channels") &&
|
||||
(c->argc == 2 || c->argc == 3))
|
||||
{
|
||||
/* PUBSUB CHANNELS [<pattern>] */
|
||||
sds pat = (c->argc == 2) ? NULL : ptrFromObj(c->argv[2]);
|
||||
sds pat = (c->argc == 2) ? NULL : szFromObj(c->argv[2]);
|
||||
dictIterator *di = dictGetIterator(server.pubsub_channels);
|
||||
dictEntry *de;
|
||||
long mblen = 0;
|
||||
@@ -400,8 +400,8 @@ NULL
|
||||
|
||||
replylen = addReplyDeferredLen(c);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
robj *cobj = dictGetKey(de);
|
||||
sds channel = ptrFromObj(cobj);
|
||||
robj *cobj = (robj*)dictGetKey(de);
|
||||
sds channel = szFromObj(cobj);
|
||||
|
||||
if (!pat || stringmatchlen(pat, sdslen(pat),
|
||||
channel, sdslen(channel),0))
|
||||
@@ -412,18 +412,18 @@ NULL
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
setDeferredArrayLen(c,replylen,mblen);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"numsub") && c->argc >= 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"numsub") && c->argc >= 2) {
|
||||
/* PUBSUB NUMSUB [Channel_1 ... Channel_N] */
|
||||
int j;
|
||||
|
||||
addReplyArrayLen(c,(c->argc-2)*2);
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
list *l = dictFetchValue(server.pubsub_channels,c->argv[j]);
|
||||
list *l = (list*)dictFetchValue(server.pubsub_channels,c->argv[j]);
|
||||
|
||||
addReplyBulk(c,c->argv[j]);
|
||||
addReplyLongLong(c,l ? listLength(l) : 0);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"numpat") && c->argc == 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"numpat") && c->argc == 2) {
|
||||
/* PUBSUB NUMPAT */
|
||||
addReplyLongLong(c,listLength(server.pubsub_patterns));
|
||||
} else {
|
||||
@@ -122,6 +122,10 @@ typedef struct quicklistEntry {
|
||||
#define quicklistNodeIsCompressed(node) \
|
||||
((node)->encoding == QUICKLIST_NODE_ENCODING_LZF)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Prototypes */
|
||||
quicklist *quicklistCreate(void);
|
||||
quicklist *quicklistNew(int fill, int compress);
|
||||
@@ -174,4 +178,8 @@ int quicklistTest(int argc, char *argv[]);
|
||||
#define AL_START_HEAD 0
|
||||
#define AL_START_TAIL 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __QUICKLIST_H__ */
|
||||
+141
-117
@@ -49,7 +49,7 @@ extern int rdbCheckMode;
|
||||
void rdbCheckError(const char *fmt, ...);
|
||||
void rdbCheckSetError(const char *fmt, ...);
|
||||
|
||||
void rdbCheckThenExit(int linenum, char *reason, ...) {
|
||||
void rdbCheckThenExit(int linenum, const char *reason, ...) {
|
||||
va_list ap;
|
||||
char msg[1024];
|
||||
int len;
|
||||
@@ -62,7 +62,7 @@ void rdbCheckThenExit(int linenum, char *reason, ...) {
|
||||
|
||||
if (!rdbCheckMode) {
|
||||
serverLog(LL_WARNING, "%s", msg);
|
||||
char *argv[2] = {"",server.rdb_filename};
|
||||
const char * argv[2] = {"",server.rdb_filename};
|
||||
redis_check_rdb_main(2,argv,NULL);
|
||||
} else {
|
||||
rdbCheckError("%s",msg);
|
||||
@@ -285,7 +285,7 @@ void *rdbLoadIntegerObject(rio *rdb, int enctype, int flags, size_t *lenptr) {
|
||||
char buf[LONG_STR_SIZE], *p;
|
||||
int len = ll2string(buf,sizeof(buf),val);
|
||||
if (lenptr) *lenptr = len;
|
||||
p = plain ? zmalloc(len, MALLOC_SHARED) : sdsnewlen(SDS_NOINIT,len);
|
||||
p = (char*)(plain ? zmalloc(len, MALLOC_SHARED) : sdsnewlen(SDS_NOINIT,len));
|
||||
memcpy(p,buf,len);
|
||||
return p;
|
||||
} else if (encode) {
|
||||
@@ -339,7 +339,7 @@ writeerr:
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t rdbSaveLzfStringObject(rio *rdb, unsigned char *s, size_t len) {
|
||||
ssize_t rdbSaveLzfStringObject(rio *rdb, const unsigned char *s, size_t len) {
|
||||
size_t comprlen, outlen;
|
||||
void *out;
|
||||
|
||||
@@ -369,11 +369,11 @@ void *rdbLoadLzfStringObject(rio *rdb, int flags, size_t *lenptr) {
|
||||
|
||||
if ((clen = rdbLoadLen(rdb,NULL)) == RDB_LENERR) return NULL;
|
||||
if ((len = rdbLoadLen(rdb,NULL)) == RDB_LENERR) return NULL;
|
||||
if ((c = zmalloc(clen, MALLOC_SHARED)) == NULL) goto err;
|
||||
if ((c = (unsigned char*)zmalloc(clen, MALLOC_SHARED)) == NULL) goto err;
|
||||
|
||||
/* Allocate our target according to the uncompressed size. */
|
||||
if (plain) {
|
||||
val = zmalloc(len, MALLOC_SHARED);
|
||||
val = (char*)zmalloc(len, MALLOC_SHARED);
|
||||
} else {
|
||||
val = sdsnewlen(SDS_NOINIT,len);
|
||||
}
|
||||
@@ -403,7 +403,7 @@ err:
|
||||
|
||||
/* Save a string object as [len][data] on disk. If the object is a string
|
||||
* representation of an integer value we try to save it in a special form */
|
||||
ssize_t rdbSaveRawString(rio *rdb, unsigned char *s, size_t len) {
|
||||
ssize_t rdbSaveRawString(rio *rdb, const unsigned char *s, size_t len) {
|
||||
int enclen;
|
||||
ssize_t n, nwritten = 0;
|
||||
|
||||
@@ -419,7 +419,7 @@ ssize_t rdbSaveRawString(rio *rdb, unsigned char *s, size_t len) {
|
||||
/* Try LZF compression - under 20 bytes it's unable to compress even
|
||||
* aaaaaaaaaaaaaaaaaa so skip it */
|
||||
if (server.rdb_compression && len > 20) {
|
||||
n = rdbSaveLzfStringObject(rdb,s,len);
|
||||
n = rdbSaveLzfStringObject(rdb,(const unsigned char*)s,len);
|
||||
if (n == -1) return -1;
|
||||
if (n > 0) return n;
|
||||
/* Return value of 0 means data can't be compressed, save the old way */
|
||||
@@ -429,7 +429,7 @@ ssize_t rdbSaveRawString(rio *rdb, unsigned char *s, size_t len) {
|
||||
if ((n = rdbSaveLen(rdb,len)) == -1) return -1;
|
||||
nwritten += n;
|
||||
if (len > 0) {
|
||||
if (rdbWriteRaw(rdb,s,len) == -1) return -1;
|
||||
if (rdbWriteRaw(rdb,(unsigned char*)s,len) == -1) return -1;
|
||||
nwritten += len;
|
||||
}
|
||||
return nwritten;
|
||||
@@ -462,7 +462,7 @@ ssize_t rdbSaveStringObject(rio *rdb, robj *obj) {
|
||||
return rdbSaveLongLongAsStringObject(rdb,(long)ptrFromObj(obj));
|
||||
} else {
|
||||
serverAssertWithInfo(NULL,obj,sdsEncodedObject(obj));
|
||||
return rdbSaveRawString(rdb,ptrFromObj(obj),sdslen(ptrFromObj(obj)));
|
||||
return rdbSaveRawString(rdb,(unsigned char*)szFromObj(obj),sdslen(szFromObj(obj)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,7 +508,7 @@ void *rdbGenericLoadStringObject(rio *rdb, int flags, size_t *lenptr) {
|
||||
if (plain)
|
||||
zfree(buf);
|
||||
else
|
||||
sdsfree(buf);
|
||||
sdsfree((char*)buf);
|
||||
return NULL;
|
||||
}
|
||||
return buf;
|
||||
@@ -524,11 +524,11 @@ void *rdbGenericLoadStringObject(rio *rdb, int flags, size_t *lenptr) {
|
||||
}
|
||||
|
||||
robj *rdbLoadStringObject(rio *rdb) {
|
||||
return rdbGenericLoadStringObject(rdb,RDB_LOAD_NONE,NULL);
|
||||
return (robj*)rdbGenericLoadStringObject(rdb,RDB_LOAD_NONE,NULL);
|
||||
}
|
||||
|
||||
robj *rdbLoadEncodedStringObject(rio *rdb) {
|
||||
return rdbGenericLoadStringObject(rdb,RDB_LOAD_ENC,NULL);
|
||||
return (robj*)rdbGenericLoadStringObject(rdb,RDB_LOAD_ENC,NULL);
|
||||
}
|
||||
|
||||
/* Save a double value. Doubles are saved as strings prefixed by an unsigned
|
||||
@@ -697,7 +697,7 @@ ssize_t rdbSaveStreamPEL(rio *rdb, rax *pel, int nacks) {
|
||||
nwritten += n;
|
||||
|
||||
if (nacks) {
|
||||
streamNACK *nack = ri.data;
|
||||
streamNACK *nack = (streamNACK*)ri.data;
|
||||
if ((n = rdbSaveMillisecondTime(rdb,nack->delivery_time)) == -1)
|
||||
return -1;
|
||||
nwritten += n;
|
||||
@@ -727,7 +727,7 @@ size_t rdbSaveStreamConsumers(rio *rdb, streamCG *cg) {
|
||||
raxStart(&ri,cg->consumers);
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
while(raxNext(&ri)) {
|
||||
streamConsumer *consumer = ri.data;
|
||||
streamConsumer *consumer = (streamConsumer*)ri.data;
|
||||
|
||||
/* Consumer name. */
|
||||
if ((n = rdbSaveRawString(rdb,ri.key,ri.key_len)) == -1) return -1;
|
||||
@@ -752,7 +752,7 @@ size_t rdbSaveStreamConsumers(rio *rdb, streamCG *cg) {
|
||||
|
||||
/* Save a Redis object.
|
||||
* Returns -1 on error, number of bytes written on success. */
|
||||
ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key) {
|
||||
ssize_t n = 0, nwritten = 0;
|
||||
|
||||
if (o->type == OBJ_STRING) {
|
||||
@@ -762,7 +762,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
} else if (o->type == OBJ_LIST) {
|
||||
/* Save a list value */
|
||||
if (o->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
quicklist *ql = ptrFromObj(o);
|
||||
quicklist *ql = (quicklist*)ptrFromObj(o);
|
||||
quicklistNode *node = ql->head;
|
||||
|
||||
if ((n = rdbSaveLen(rdb,ql->len)) == -1) return -1;
|
||||
@@ -786,7 +786,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
} else if (o->type == OBJ_SET) {
|
||||
/* Save a set value */
|
||||
if (o->encoding == OBJ_ENCODING_HT) {
|
||||
dict *set = ptrFromObj(o);
|
||||
dict *set = (dict*)ptrFromObj(o);
|
||||
dictIterator *di = dictGetIterator(set);
|
||||
dictEntry *de;
|
||||
|
||||
@@ -797,7 +797,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
nwritten += n;
|
||||
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sds ele = dictGetKey(de);
|
||||
sds ele = (sds)dictGetKey(de);
|
||||
if ((n = rdbSaveRawString(rdb,(unsigned char*)ele,sdslen(ele)))
|
||||
== -1)
|
||||
{
|
||||
@@ -810,7 +810,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
} else if (o->encoding == OBJ_ENCODING_INTSET) {
|
||||
size_t l = intsetBlobLen((intset*)ptrFromObj(o));
|
||||
|
||||
if ((n = rdbSaveRawString(rdb,ptrFromObj(o),l)) == -1) return -1;
|
||||
if ((n = rdbSaveRawString(rdb,(unsigned char*)szFromObj(o),l)) == -1) return -1;
|
||||
nwritten += n;
|
||||
} else {
|
||||
serverPanic("Unknown set encoding");
|
||||
@@ -820,10 +820,10 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
size_t l = ziplistBlobLen((unsigned char*)ptrFromObj(o));
|
||||
|
||||
if ((n = rdbSaveRawString(rdb,ptrFromObj(o),l)) == -1) return -1;
|
||||
if ((n = rdbSaveRawString(rdb,(unsigned char*)ptrFromObj(o),l)) == -1) return -1;
|
||||
nwritten += n;
|
||||
} else if (o->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = ptrFromObj(o);
|
||||
zset *zs = (zset*)ptrFromObj(o);
|
||||
zskiplist *zsl = zs->zsl;
|
||||
|
||||
if ((n = rdbSaveLen(rdb,zsl->length)) == -1) return -1;
|
||||
@@ -856,11 +856,11 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
size_t l = ziplistBlobLen((unsigned char*)ptrFromObj(o));
|
||||
|
||||
if ((n = rdbSaveRawString(rdb,ptrFromObj(o),l)) == -1) return -1;
|
||||
if ((n = rdbSaveRawString(rdb,(unsigned char*)ptrFromObj(o),l)) == -1) return -1;
|
||||
nwritten += n;
|
||||
|
||||
} else if (o->encoding == OBJ_ENCODING_HT) {
|
||||
dictIterator *di = dictGetIterator(ptrFromObj(o));
|
||||
dictIterator *di = dictGetIterator((dict*)ptrFromObj(o));
|
||||
dictEntry *de;
|
||||
|
||||
if ((n = rdbSaveLen(rdb,dictSize((dict*)ptrFromObj(o)))) == -1) {
|
||||
@@ -870,8 +870,8 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
nwritten += n;
|
||||
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sds field = dictGetKey(de);
|
||||
sds value = dictGetVal(de);
|
||||
sds field = (sds)dictGetKey(de);
|
||||
sds value = (sds)dictGetVal(de);
|
||||
|
||||
if ((n = rdbSaveRawString(rdb,(unsigned char*)field,
|
||||
sdslen(field))) == -1)
|
||||
@@ -894,7 +894,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
}
|
||||
} else if (o->type == OBJ_STREAM) {
|
||||
/* Store how many listpacks we have inside the radix tree. */
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
rax *rax = s->prax;
|
||||
if ((n = rdbSaveLen(rdb,raxSize(rax))) == -1) return -1;
|
||||
nwritten += n;
|
||||
@@ -906,7 +906,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
raxStart(&ri,rax);
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
while (raxNext(&ri)) {
|
||||
unsigned char *lp = ri.data;
|
||||
unsigned char *lp = (unsigned char*)ri.data;
|
||||
size_t lp_bytes = lpBytes(lp);
|
||||
if ((n = rdbSaveRawString(rdb,ri.key,ri.key_len)) == -1) return -1;
|
||||
nwritten += n;
|
||||
@@ -939,7 +939,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
raxStart(&ri,s->cgroups);
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
while(raxNext(&ri)) {
|
||||
streamCG *cg = ri.data;
|
||||
streamCG *cg = (streamCG*)ri.data;
|
||||
|
||||
/* Save the group name. */
|
||||
if ((n = rdbSaveRawString(rdb,ri.key,ri.key_len)) == -1)
|
||||
@@ -965,9 +965,9 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
} else if (o->type == OBJ_MODULE) {
|
||||
/* Save a module-specific value. */
|
||||
RedisModuleIO io;
|
||||
moduleValue *mv = ptrFromObj(o);
|
||||
moduleValue *mv = (moduleValue*)ptrFromObj(o);
|
||||
moduleType *mt = mv->type;
|
||||
moduleInitIOContext(io,mt,rdb);
|
||||
moduleInitIOContext(io,mt,rdb,key);
|
||||
|
||||
/* Write the "module" identifier as prefix, so that we'll be able
|
||||
* to call the right module during loading. */
|
||||
@@ -997,7 +997,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
||||
* this length with very little changes to the code. In the future
|
||||
* we could switch to a faster solution. */
|
||||
size_t rdbSavedObjectLen(robj *o) {
|
||||
ssize_t len = rdbSaveObject(NULL,o);
|
||||
ssize_t len = rdbSaveObject(NULL,o,NULL);
|
||||
serverAssertWithInfo(NULL,o,len != -1);
|
||||
return len;
|
||||
}
|
||||
@@ -1039,30 +1039,30 @@ int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val, long long expiretime) {
|
||||
/* Save type, key, value */
|
||||
if (rdbSaveObjectType(rdb,val) == -1) return -1;
|
||||
if (rdbSaveStringObject(rdb,key) == -1) return -1;
|
||||
if (rdbSaveObject(rdb,val) == -1) return -1;
|
||||
if (rdbSaveObject(rdb,val,key) == -1) return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Save an AUX field. */
|
||||
ssize_t rdbSaveAuxField(rio *rdb, void *key, size_t keylen, void *val, size_t vallen) {
|
||||
ssize_t rdbSaveAuxField(rio *rdb, const void *key, size_t keylen, const void *val, size_t vallen) {
|
||||
ssize_t ret, len = 0;
|
||||
if ((ret = rdbSaveType(rdb,RDB_OPCODE_AUX)) == -1) return -1;
|
||||
len += ret;
|
||||
if ((ret = rdbSaveRawString(rdb,key,keylen)) == -1) return -1;
|
||||
if ((ret = rdbSaveRawString(rdb,(const unsigned char*)key,keylen)) == -1) return -1;
|
||||
len += ret;
|
||||
if ((ret = rdbSaveRawString(rdb,val,vallen)) == -1) return -1;
|
||||
if ((ret = rdbSaveRawString(rdb,(const unsigned char*)val,vallen)) == -1) return -1;
|
||||
len += ret;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Wrapper for rdbSaveAuxField() used when key/val length can be obtained
|
||||
* with strlen(). */
|
||||
ssize_t rdbSaveAuxFieldStrStr(rio *rdb, char *key, char *val) {
|
||||
ssize_t rdbSaveAuxFieldStrStr(rio *rdb, const char *key, const char *val) {
|
||||
return rdbSaveAuxField(rdb,key,strlen(key),val,strlen(val));
|
||||
}
|
||||
|
||||
/* Wrapper for strlen(key) + integer type (up to long long range). */
|
||||
ssize_t rdbSaveAuxFieldStrInt(rio *rdb, char *key, long long val) {
|
||||
ssize_t rdbSaveAuxFieldStrInt(rio *rdb, const char *key, long long val) {
|
||||
char buf[LONG_STR_SIZE];
|
||||
int vlen = ll2string(buf,sizeof(buf),val);
|
||||
return rdbSaveAuxField(rdb,key,strlen(key),buf,vlen);
|
||||
@@ -1137,8 +1137,8 @@ int rdbSaveRio(rio *rdb, int *error, int flags, rdbSaveInfo *rsi) {
|
||||
|
||||
/* Iterate this DB writing every entry */
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sds keystr = dictGetKey(de);
|
||||
robj key, *o = dictGetVal(de);
|
||||
sds keystr = (sds)dictGetKey(de);
|
||||
robj key, *o = (robj*)dictGetVal(de);
|
||||
long long expire;
|
||||
|
||||
initStaticStringObject(key,keystr);
|
||||
@@ -1166,8 +1166,8 @@ int rdbSaveRio(rio *rdb, int *error, int flags, rdbSaveInfo *rsi) {
|
||||
if (rsi && dictSize(server.lua_scripts)) {
|
||||
di = dictGetIterator(server.lua_scripts);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
robj *body = dictGetVal(de);
|
||||
if (rdbSaveAuxField(rdb,"lua",3,ptrFromObj(body),sdslen(ptrFromObj(body))) == -1)
|
||||
robj *body = (robj*)dictGetVal(de);
|
||||
if (rdbSaveAuxField(rdb,"lua",3,szFromObj(body),sdslen(szFromObj(body))) == -1)
|
||||
goto werr;
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
@@ -1376,7 +1376,7 @@ robj *rdbLoadCheckModuleValue(rio *rdb, char *modulename) {
|
||||
"Error reading integer from module %s value", modulename);
|
||||
}
|
||||
} else if (opcode == RDB_MODULE_OPCODE_STRING) {
|
||||
robj *o = rdbGenericLoadStringObject(rdb,RDB_LOAD_NONE,NULL);
|
||||
robj *o = (robj*)rdbGenericLoadStringObject(rdb,RDB_LOAD_NONE,NULL);
|
||||
if (o == NULL) {
|
||||
rdbExitReportCorruptRDB(
|
||||
"Error reading string from module %s value", modulename);
|
||||
@@ -1401,7 +1401,7 @@ robj *rdbLoadCheckModuleValue(rio *rdb, char *modulename) {
|
||||
|
||||
/* Load a Redis object of the specified type from the specified file.
|
||||
* On success a newly allocated object is returned, otherwise NULL. */
|
||||
robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
robj *rdbLoadObject(int rdbtype, rio *rdb, robj *key) {
|
||||
robj *o = NULL, *ele, *dec;
|
||||
uint64_t len;
|
||||
unsigned int i;
|
||||
@@ -1415,15 +1415,15 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
if ((len = rdbLoadLen(rdb,NULL)) == RDB_LENERR) return NULL;
|
||||
|
||||
o = createQuicklistObject();
|
||||
quicklistSetOptions(ptrFromObj(o), server.list_max_ziplist_size,
|
||||
quicklistSetOptions((quicklist*)ptrFromObj(o), server.list_max_ziplist_size,
|
||||
server.list_compress_depth);
|
||||
|
||||
/* Load every single element of the list */
|
||||
while(len--) {
|
||||
if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL;
|
||||
dec = getDecodedObject(ele);
|
||||
size_t len = sdslen(ptrFromObj(dec));
|
||||
quicklistPushTail(ptrFromObj(o), ptrFromObj(dec), len);
|
||||
size_t len = sdslen(szFromObj(dec));
|
||||
quicklistPushTail((quicklist*)ptrFromObj(o), ptrFromObj(dec), len);
|
||||
decrRefCount(dec);
|
||||
decrRefCount(ele);
|
||||
}
|
||||
@@ -1437,7 +1437,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
/* It's faster to expand the dict to the right size asap in order
|
||||
* to avoid rehashing */
|
||||
if (len > DICT_HT_INITIAL_SIZE)
|
||||
dictExpand(ptrFromObj(o),len);
|
||||
dictExpand((dict*)ptrFromObj(o),len);
|
||||
} else {
|
||||
o = createIntsetObject();
|
||||
}
|
||||
@@ -1447,16 +1447,16 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
long long llval;
|
||||
sds sdsele;
|
||||
|
||||
if ((sdsele = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
if ((sdsele = (sds)rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
== NULL) return NULL;
|
||||
|
||||
if (o->encoding == OBJ_ENCODING_INTSET) {
|
||||
/* Fetch integer value from element. */
|
||||
if (isSdsRepresentableAsLongLong(sdsele,&llval) == C_OK) {
|
||||
o->m_ptr = intsetAdd(ptrFromObj(o),llval,NULL);
|
||||
o->m_ptr = intsetAdd((intset*)ptrFromObj(o),llval,NULL);
|
||||
} else {
|
||||
setTypeConvert(o,OBJ_ENCODING_HT);
|
||||
dictExpand(ptrFromObj(o),len);
|
||||
dictExpand((dict*)ptrFromObj(o),len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1476,7 +1476,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
|
||||
if ((zsetlen = rdbLoadLen(rdb,NULL)) == RDB_LENERR) return NULL;
|
||||
o = createZsetObject();
|
||||
zs = ptrFromObj(o);
|
||||
zs = (zset*)ptrFromObj(o);
|
||||
|
||||
if (zsetlen > DICT_HT_INITIAL_SIZE)
|
||||
dictExpand(zs->pdict,zsetlen);
|
||||
@@ -1487,7 +1487,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
double score;
|
||||
zskiplistNode *znode;
|
||||
|
||||
if ((sdsele = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
if ((sdsele = (sds)rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
== NULL) return NULL;
|
||||
|
||||
if (rdbtype == RDB_TYPE_ZSET_2) {
|
||||
@@ -1525,15 +1525,15 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
while (o->encoding == OBJ_ENCODING_ZIPLIST && len > 0) {
|
||||
len--;
|
||||
/* Load raw strings */
|
||||
if ((field = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
if ((field = (sds)rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
== NULL) return NULL;
|
||||
if ((value = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
if ((value = (sds)rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
== NULL) return NULL;
|
||||
|
||||
/* Add pair to ziplist */
|
||||
o->m_ptr = ziplistPush(ptrFromObj(o), (unsigned char*)field,
|
||||
o->m_ptr = ziplistPush((unsigned char*)ptrFromObj(o), (unsigned char*)field,
|
||||
sdslen(field), ZIPLIST_TAIL);
|
||||
o->m_ptr = ziplistPush(ptrFromObj(o), (unsigned char*)value,
|
||||
o->m_ptr = ziplistPush((unsigned char*)ptrFromObj(o), (unsigned char*)value,
|
||||
sdslen(value), ZIPLIST_TAIL);
|
||||
|
||||
/* Convert to hash table if size threshold is exceeded */
|
||||
@@ -1550,15 +1550,15 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
}
|
||||
|
||||
if (o->encoding == OBJ_ENCODING_HT && len > DICT_HT_INITIAL_SIZE)
|
||||
dictExpand(ptrFromObj(o),len);
|
||||
dictExpand((dict*)ptrFromObj(o),len);
|
||||
|
||||
/* Load remaining fields and values into the hash table */
|
||||
while (o->encoding == OBJ_ENCODING_HT && len > 0) {
|
||||
len--;
|
||||
/* Load encoded strings */
|
||||
if ((field = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
if ((field = (sds)rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
== NULL) return NULL;
|
||||
if ((value = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
if ((value = (sds)rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL))
|
||||
== NULL) return NULL;
|
||||
|
||||
/* Add pair to hash table */
|
||||
@@ -1573,14 +1573,14 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
} else if (rdbtype == RDB_TYPE_LIST_QUICKLIST) {
|
||||
if ((len = rdbLoadLen(rdb,NULL)) == RDB_LENERR) return NULL;
|
||||
o = createQuicklistObject();
|
||||
quicklistSetOptions(ptrFromObj(o), server.list_max_ziplist_size,
|
||||
quicklistSetOptions((quicklist*)ptrFromObj(o), server.list_max_ziplist_size,
|
||||
server.list_compress_depth);
|
||||
|
||||
while (len--) {
|
||||
unsigned char *zl =
|
||||
unsigned char *zl = (unsigned char*)
|
||||
rdbGenericLoadStringObject(rdb,RDB_LOAD_PLAIN,NULL);
|
||||
if (zl == NULL) return NULL;
|
||||
quicklistAppendZiplist(ptrFromObj(o), zl);
|
||||
quicklistAppendZiplist((quicklist*)ptrFromObj(o), zl);
|
||||
}
|
||||
} else if (rdbtype == RDB_TYPE_HASH_ZIPMAP ||
|
||||
rdbtype == RDB_TYPE_LIST_ZIPLIST ||
|
||||
@@ -1588,7 +1588,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
rdbtype == RDB_TYPE_ZSET_ZIPLIST ||
|
||||
rdbtype == RDB_TYPE_HASH_ZIPLIST)
|
||||
{
|
||||
unsigned char *encoded =
|
||||
unsigned char *encoded = (unsigned char*)
|
||||
rdbGenericLoadStringObject(rdb,RDB_LOAD_PLAIN,NULL);
|
||||
if (encoded == NULL) return NULL;
|
||||
o = createObject(OBJ_STRING,encoded); /* Obj type fixed below. */
|
||||
@@ -1605,7 +1605,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
* when loading dumps created by Redis 2.4 gets deprecated. */
|
||||
{
|
||||
unsigned char *zl = ziplistNew();
|
||||
unsigned char *zi = zipmapRewind(ptrFromObj(o));
|
||||
unsigned char *zi = zipmapRewind((unsigned char*)ptrFromObj(o));
|
||||
unsigned char *fstr, *vstr;
|
||||
unsigned int flen, vlen;
|
||||
unsigned int maxlen = 0;
|
||||
@@ -1637,7 +1637,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
case RDB_TYPE_SET_INTSET:
|
||||
o->type = OBJ_SET;
|
||||
o->encoding = OBJ_ENCODING_INTSET;
|
||||
if (intsetLen(ptrFromObj(o)) > server.set_max_intset_entries)
|
||||
if (intsetLen((intset*)ptrFromObj(o)) > server.set_max_intset_entries)
|
||||
setTypeConvert(o,OBJ_ENCODING_HT);
|
||||
break;
|
||||
case RDB_TYPE_ZSET_ZIPLIST:
|
||||
@@ -1658,14 +1658,14 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
}
|
||||
} else if (rdbtype == RDB_TYPE_STREAM_LISTPACKS) {
|
||||
o = createStreamObject();
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
uint64_t listpacks = rdbLoadLen(rdb,NULL);
|
||||
|
||||
while(listpacks--) {
|
||||
/* Get the master ID, the one we'll use as key of the radix tree
|
||||
* node: the entries inside the listpack itself are delta-encoded
|
||||
* relatively to this ID. */
|
||||
sds nodekey = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL);
|
||||
sds nodekey = (sds)rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL);
|
||||
if (nodekey == NULL) {
|
||||
rdbExitReportCorruptRDB("Stream master ID loading failed: invalid encoding or I/O error.");
|
||||
}
|
||||
@@ -1675,7 +1675,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
}
|
||||
|
||||
/* Load the listpack. */
|
||||
unsigned char *lp =
|
||||
unsigned char *lp = (unsigned char*)
|
||||
rdbGenericLoadStringObject(rdb,RDB_LOAD_PLAIN,NULL);
|
||||
if (lp == NULL) return NULL;
|
||||
unsigned char *first = lpFirst(lp);
|
||||
@@ -1706,7 +1706,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
* consumer group ASAP and populate its structure as
|
||||
* we read more data. */
|
||||
streamID cg_id;
|
||||
sds cgname = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL);
|
||||
sds cgname = (sds)rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL);
|
||||
if (cgname == NULL) {
|
||||
rdbExitReportCorruptRDB(
|
||||
"Error reading the consumer group name from Stream");
|
||||
@@ -1740,7 +1740,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
* consumers and their local PELs. */
|
||||
size_t consumers_num = rdbLoadLen(rdb,NULL);
|
||||
while(consumers_num--) {
|
||||
sds cname = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL);
|
||||
sds cname = (sds)rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL);
|
||||
if (cname == NULL) {
|
||||
rdbExitReportCorruptRDB(
|
||||
"Error reading the consumer name from Stream group");
|
||||
@@ -1756,7 +1756,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
while(pel_size--) {
|
||||
unsigned char rawid[sizeof(streamID)];
|
||||
rdbLoadRaw(rdb,rawid,sizeof(rawid));
|
||||
streamNACK *nack = raxFind(cgroup->pel,rawid,sizeof(rawid));
|
||||
streamNACK *nack = (streamNACK*)raxFind(cgroup->pel,rawid,sizeof(rawid));
|
||||
if (nack == raxNotFound)
|
||||
rdbExitReportCorruptRDB("Consumer entry not found in "
|
||||
"group global PEL");
|
||||
@@ -1788,7 +1788,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
||||
exit(1);
|
||||
}
|
||||
RedisModuleIO io;
|
||||
moduleInitIOContext(io,mt,rdb);
|
||||
moduleInitIOContext(io,mt,rdb,key);
|
||||
io.ver = (rdbtype == RDB_TYPE_MODULE) ? 1 : 2;
|
||||
/* Call the rdb_load method of the module providing the 10 bit
|
||||
* encoding version in the lower 10 bits of the module ID. */
|
||||
@@ -1859,8 +1859,15 @@ void rdbLoadProgressCallback(rio *r, const void *buf, size_t len) {
|
||||
* our cached time since it is used to create and update the last
|
||||
* interaction time with clients and for other important things. */
|
||||
updateCachedTime();
|
||||
if (server.masterhost && server.repl_state == REPL_STATE_TRANSFER)
|
||||
replicationSendNewlineToMaster();
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(server.masters, &li);
|
||||
while ((ln = listNext(&li)))
|
||||
{
|
||||
struct redisMaster *mi = (struct redisMaster*)listNodeValue(ln);
|
||||
if (mi->repl_state == REPL_STATE_TRANSFER)
|
||||
replicationSendNewlineToMaster(mi);
|
||||
}
|
||||
loadingProgress(r->processed_bytes);
|
||||
processEventsWhileBlocked(serverTL - server.rgthreadvar);
|
||||
}
|
||||
@@ -1873,6 +1880,9 @@ int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi, int loading_aof) {
|
||||
int type, rdbver;
|
||||
redisDb *db = server.db+0;
|
||||
char buf[1024];
|
||||
/* Key-specific attributes, set by opcodes before the key type. */
|
||||
long long lru_idle = -1, lfu_freq = -1, expiretime = -1, now = mstime();
|
||||
long long lru_clock = LRU_CLOCK();
|
||||
|
||||
rdb->update_cksum = rdbLoadProgressCallback;
|
||||
rdb->max_processing_chunk = server.loading_process_events_interval_bytes;
|
||||
@@ -1890,9 +1900,8 @@ int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi, int loading_aof) {
|
||||
return C_ERR;
|
||||
}
|
||||
|
||||
/* Key-specific attributes, set by opcodes before the key type. */
|
||||
long long lru_idle = -1, lfu_freq = -1, expiretime = -1, now = mstime();
|
||||
long long lru_clock = LRU_CLOCK();
|
||||
now = mstime();
|
||||
lru_clock = LRU_CLOCK();
|
||||
|
||||
while(1) {
|
||||
robj *key, *val;
|
||||
@@ -1968,38 +1977,38 @@ int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi, int loading_aof) {
|
||||
serverLog(LL_NOTICE,"RDB '%s': %s",
|
||||
(char*)ptrFromObj(auxkey),
|
||||
(char*)ptrFromObj(auxval));
|
||||
} else if (!strcasecmp(ptrFromObj(auxkey),"repl-stream-db")) {
|
||||
if (rsi) rsi->repl_stream_db = atoi(ptrFromObj(auxval));
|
||||
} else if (!strcasecmp(ptrFromObj(auxkey),"repl-id")) {
|
||||
if (rsi && sdslen(ptrFromObj(auxval)) == CONFIG_RUN_ID_SIZE) {
|
||||
} else if (!strcasecmp(szFromObj(auxkey),"repl-stream-db")) {
|
||||
if (rsi) rsi->repl_stream_db = atoi(szFromObj(auxval));
|
||||
} else if (!strcasecmp(szFromObj(auxkey),"repl-id")) {
|
||||
if (rsi && sdslen(szFromObj(auxval)) == CONFIG_RUN_ID_SIZE) {
|
||||
memcpy(rsi->repl_id,ptrFromObj(auxval),CONFIG_RUN_ID_SIZE+1);
|
||||
rsi->repl_id_is_set = 1;
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(auxkey),"repl-offset")) {
|
||||
if (rsi) rsi->repl_offset = strtoll(ptrFromObj(auxval),NULL,10);
|
||||
} else if (!strcasecmp(ptrFromObj(auxkey),"lua")) {
|
||||
} else if (!strcasecmp(szFromObj(auxkey),"repl-offset")) {
|
||||
if (rsi) rsi->repl_offset = strtoll(szFromObj(auxval),NULL,10);
|
||||
} else if (!strcasecmp(szFromObj(auxkey),"lua")) {
|
||||
/* Load the script back in memory. */
|
||||
if (luaCreateFunction(NULL,server.lua,auxval) == NULL) {
|
||||
rdbExitReportCorruptRDB(
|
||||
"Can't load Lua script from RDB file! "
|
||||
"BODY: %s", ptrFromObj(auxval));
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(auxkey),"redis-ver")) {
|
||||
} else if (!strcasecmp(szFromObj(auxkey),"redis-ver")) {
|
||||
serverLog(LL_NOTICE,"Loading RDB produced by version %s",
|
||||
(const char*)ptrFromObj(auxval));
|
||||
} else if (!strcasecmp(ptrFromObj(auxkey),"ctime")) {
|
||||
time_t age = time(NULL)-strtol(ptrFromObj(auxval),NULL,10);
|
||||
} else if (!strcasecmp(szFromObj(auxkey),"ctime")) {
|
||||
time_t age = time(NULL)-strtol(szFromObj(auxval),NULL,10);
|
||||
if (age < 0) age = 0;
|
||||
serverLog(LL_NOTICE,"RDB age %ld seconds",
|
||||
(unsigned long) age);
|
||||
} else if (!strcasecmp(ptrFromObj(auxkey),"used-mem")) {
|
||||
long long usedmem = strtoll(ptrFromObj(auxval),NULL,10);
|
||||
} else if (!strcasecmp(szFromObj(auxkey),"used-mem")) {
|
||||
long long usedmem = strtoll(szFromObj(auxval),NULL,10);
|
||||
serverLog(LL_NOTICE,"RDB memory usage when created %.2f Mb",
|
||||
(double) usedmem / (1024*1024));
|
||||
} else if (!strcasecmp(ptrFromObj(auxkey),"aof-preamble")) {
|
||||
long long haspreamble = strtoll(ptrFromObj(auxval),NULL,10);
|
||||
} else if (!strcasecmp(szFromObj(auxkey),"aof-preamble")) {
|
||||
long long haspreamble = strtoll(szFromObj(auxval),NULL,10);
|
||||
if (haspreamble) serverLog(LL_NOTICE,"RDB has an AOF tail");
|
||||
} else if (!strcasecmp(ptrFromObj(auxkey),"redis-bits")) {
|
||||
} else if (!strcasecmp(szFromObj(auxkey),"redis-bits")) {
|
||||
/* Just ignored. */
|
||||
} else {
|
||||
/* We ignore fields we don't understand, as by AUX field
|
||||
@@ -2044,28 +2053,36 @@ int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi, int loading_aof) {
|
||||
/* Read key */
|
||||
if ((key = rdbLoadStringObject(rdb)) == NULL) goto eoferr;
|
||||
/* Read value */
|
||||
if ((val = rdbLoadObject(type,rdb)) == NULL) goto eoferr;
|
||||
if ((val = rdbLoadObject(type,rdb,key)) == NULL) goto eoferr;
|
||||
/* Check if the key already expired. This function is used when loading
|
||||
* an RDB file from disk, either at startup, or when an RDB was
|
||||
* received from the master. In the latter case, the master is
|
||||
* responsible for key expiry. If we would expire keys here, the
|
||||
* snapshot taken by the master may not be reflected on the slave. */
|
||||
if (server.masterhost == NULL && !loading_aof && expiretime != -1 && expiretime < now) {
|
||||
if (listLength(server.masters) == 0 && !loading_aof && expiretime != -1 && expiretime < now) {
|
||||
decrRefCount(key);
|
||||
decrRefCount(val);
|
||||
} else {
|
||||
/* Add the new object in the hash table */
|
||||
dbAdd(db,key,val);
|
||||
int fInserted = dbMerge(db, key, val, rsi->fForceSetKey);
|
||||
|
||||
/* Set the expire time if needed */
|
||||
if (expiretime != -1) setExpire(NULL,db,key,expiretime);
|
||||
if (fInserted)
|
||||
{
|
||||
/* Set the expire time if needed */
|
||||
if (expiretime != -1) setExpire(NULL,db,key,expiretime);
|
||||
|
||||
/* Set usage information (for eviction). */
|
||||
objectSetLRUOrLFU(val,lfu_freq,lru_idle,lru_clock);
|
||||
/* Set usage information (for eviction). */
|
||||
objectSetLRUOrLFU(val,lfu_freq,lru_idle,lru_clock);
|
||||
|
||||
/* Decrement the key refcount since dbAdd() will take its
|
||||
* own reference. */
|
||||
decrRefCount(key);
|
||||
/* Decrement the key refcount since dbMerge() will take its
|
||||
* own reference. */
|
||||
decrRefCount(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
decrRefCount(key);
|
||||
decrRefCount(val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the state that is key-specified and is populated by
|
||||
@@ -2193,7 +2210,7 @@ void backgroundSaveDoneHandlerSocket(int exitcode, int bysignal) {
|
||||
* If the process returned an error, consider the list of slaves that
|
||||
* can continue to be empty, so that it's just a special case of the
|
||||
* normal code path. */
|
||||
ok_slaves = zmalloc(sizeof(uint64_t), MALLOC_LOCAL); /* Make space for the count. */
|
||||
ok_slaves = (uint64_t*)zmalloc(sizeof(uint64_t), MALLOC_LOCAL); /* Make space for the count. */
|
||||
ok_slaves[0] = 0;
|
||||
if (!bysignal && exitcode == 0) {
|
||||
int readlen = sizeof(uint64_t);
|
||||
@@ -2205,7 +2222,7 @@ void backgroundSaveDoneHandlerSocket(int exitcode, int bysignal) {
|
||||
|
||||
/* Make space for enough elements as specified by the first
|
||||
* uint64_t element in the array. */
|
||||
ok_slaves = zrealloc(ok_slaves,sizeof(uint64_t)+readlen, MALLOC_LOCAL);
|
||||
ok_slaves = (uint64_t*)zrealloc(ok_slaves,sizeof(uint64_t)+readlen, MALLOC_LOCAL);
|
||||
if (readlen &&
|
||||
read(server.rdb_pipe_read_result_from_child, ok_slaves+1,
|
||||
readlen) != readlen)
|
||||
@@ -2225,7 +2242,7 @@ void backgroundSaveDoneHandlerSocket(int exitcode, int bysignal) {
|
||||
|
||||
listRewind(server.slaves,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
client *slave = ln->value;
|
||||
client *slave = (client*)ln->value;
|
||||
|
||||
if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_END) {
|
||||
uint64_t j;
|
||||
@@ -2311,16 +2328,16 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) {
|
||||
|
||||
/* Collect the file descriptors of the slaves we want to transfer
|
||||
* the RDB to, which are i WAIT_BGSAVE_START state. */
|
||||
fds = zmalloc(sizeof(int)*listLength(server.slaves), MALLOC_LOCAL);
|
||||
fds = (int*)zmalloc(sizeof(int)*listLength(server.slaves), MALLOC_LOCAL);
|
||||
/* We also allocate an array of corresponding client IDs. This will
|
||||
* be useful for the child process in order to build the report
|
||||
* (sent via unix pipe) that will be sent to the parent. */
|
||||
clientids = zmalloc(sizeof(uint64_t)*listLength(server.slaves), MALLOC_LOCAL);
|
||||
clientids = (uint64_t*)zmalloc(sizeof(uint64_t)*listLength(server.slaves), MALLOC_LOCAL);
|
||||
numfds = 0;
|
||||
|
||||
listRewind(server.slaves,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
client *slave = ln->value;
|
||||
client *slave = (client*)ln->value;
|
||||
|
||||
if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START) {
|
||||
clientids[numfds] = slave->id;
|
||||
@@ -2380,7 +2397,7 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) {
|
||||
* set to 0 if the replication process terminated with a success
|
||||
* or the error code if an error occurred. */
|
||||
void *msg = zmalloc(sizeof(uint64_t)*(1+2*numfds), MALLOC_LOCAL);
|
||||
uint64_t *len = msg;
|
||||
uint64_t *len = (uint64_t*)msg;
|
||||
uint64_t *ids = len+1;
|
||||
int j, msglen;
|
||||
|
||||
@@ -2417,7 +2434,7 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) {
|
||||
* replicationSetupSlaveForFullResync() turned it into BGSAVE_END */
|
||||
listRewind(server.slaves,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
client *slave = ln->value;
|
||||
client *slave = (client*)ln->value;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < numfds; j++) {
|
||||
@@ -2470,7 +2487,7 @@ void bgsaveCommand(client *c) {
|
||||
/* The SCHEDULE option changes the behavior of BGSAVE when an AOF rewrite
|
||||
* is in progress. Instead of returning an error a BGSAVE gets scheduled. */
|
||||
if (c->argc > 1) {
|
||||
if (c->argc == 2 && !strcasecmp(ptrFromObj(c->argv[1]),"schedule")) {
|
||||
if (c->argc == 2 && !strcasecmp(szFromObj(c->argv[1]),"schedule")) {
|
||||
schedule = 1;
|
||||
} else {
|
||||
addReply(c,shared.syntaxerr);
|
||||
@@ -2520,7 +2537,7 @@ rdbSaveInfo *rdbPopulateSaveInfo(rdbSaveInfo *rsi) {
|
||||
* connects to us, the NULL repl_backlog will trigger a full
|
||||
* synchronization, at the same time we will use a new replid and clear
|
||||
* replid2. */
|
||||
if (!server.masterhost && server.repl_backlog) {
|
||||
if (!listLength(server.masters) && server.repl_backlog) {
|
||||
/* Note that when server.slaveseldb is -1, it means that this master
|
||||
* didn't apply any write commands after a full synchronization.
|
||||
* So we can let repl_stream_db be 0, this allows a restarted slave
|
||||
@@ -2530,10 +2547,17 @@ rdbSaveInfo *rdbPopulateSaveInfo(rdbSaveInfo *rsi) {
|
||||
return rsi;
|
||||
}
|
||||
|
||||
if (listLength(server.masters) > 1)
|
||||
{
|
||||
// BUGBUG, warn user about this incomplete implementation
|
||||
serverLog(LL_WARNING, "Warning: Only backing up first master's information in RDB");
|
||||
}
|
||||
struct redisMaster *miFirst = (redisMaster*)(listLength(server.masters) ? listNodeValue(listFirst(server.masters)) : NULL);
|
||||
|
||||
/* If the instance is a slave we need a connected master
|
||||
* in order to fetch the currently selected DB. */
|
||||
if (server.master) {
|
||||
rsi->repl_stream_db = server.master->db->id;
|
||||
if (miFirst && miFirst->master) {
|
||||
rsi->repl_stream_db = miFirst->master->db->id;
|
||||
return rsi;
|
||||
}
|
||||
|
||||
@@ -2542,8 +2566,8 @@ rdbSaveInfo *rdbPopulateSaveInfo(rdbSaveInfo *rsi) {
|
||||
* increment the master_repl_offset only from data arriving from the
|
||||
* master, so if we are disconnected the offset in the cached master
|
||||
* is valid. */
|
||||
if (server.cached_master) {
|
||||
rsi->repl_stream_db = server.cached_master->db->id;
|
||||
if (miFirst && miFirst->cached_master) {
|
||||
rsi->repl_stream_db = miFirst->cached_master->db->id;
|
||||
return rsi;
|
||||
}
|
||||
return NULL;
|
||||
@@ -144,14 +144,14 @@ int rdbSaveFile(char *filename, rdbSaveInfo *rsi);
|
||||
int rdbSaveFd(int fd, rdbSaveInfo *rsi);
|
||||
int rdbSaveS3(char *path, rdbSaveInfo *rsi);
|
||||
int rdbLoadS3(char *path, rdbSaveInfo *rsi);
|
||||
ssize_t rdbSaveObject(rio *rdb, robj *o);
|
||||
ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key);
|
||||
size_t rdbSavedObjectLen(robj *o);
|
||||
robj *rdbLoadObject(int type, rio *rdb);
|
||||
robj *rdbLoadObject(int type, rio *rdb, robj *key);
|
||||
void backgroundSaveDoneHandler(int exitcode, int bysignal);
|
||||
int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val, long long expiretime);
|
||||
robj *rdbLoadStringObject(rio *rdb);
|
||||
ssize_t rdbSaveStringObject(rio *rdb, robj *obj);
|
||||
ssize_t rdbSaveRawString(rio *rdb, unsigned char *s, size_t len);
|
||||
ssize_t rdbSaveRawString(rio *rdb, const unsigned char *s, size_t len);
|
||||
void *rdbGenericLoadStringObject(rio *rdb, int flags, size_t *lenptr);
|
||||
int rdbSaveBinaryDoubleValue(rio *rdb, double val);
|
||||
int rdbLoadBinaryDoubleValue(rio *rdb, double *val);
|
||||
|
||||
@@ -41,10 +41,11 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
|
||||
extern "C" {
|
||||
#include <sds.h> /* Use hiredis sds. */
|
||||
#include "ae.h"
|
||||
#include "hiredis.h"
|
||||
}
|
||||
#include "ae.h"
|
||||
#include "adlist.h"
|
||||
#include "dict.h"
|
||||
#include "zmalloc.h"
|
||||
@@ -231,7 +232,7 @@ static int dictSdsKeyCompare(void *privdata, const void *key1,
|
||||
}
|
||||
|
||||
/* _serverAssert is needed by dict */
|
||||
void _serverAssert(const char *estr, const char *file, int line) {
|
||||
extern "C" void _serverAssert(const char *estr, const char *file, int line) {
|
||||
fprintf(stderr, "=== ASSERTION FAILED ===");
|
||||
fprintf(stderr, "==> %s:%d '%s' is not true",file,line,estr);
|
||||
*((char*)-1) = 'x';
|
||||
@@ -240,7 +241,9 @@ void _serverAssert(const char *estr, const char *file, int line) {
|
||||
static redisConfig *getRedisConfig(const char *ip, int port,
|
||||
const char *hostsocket)
|
||||
{
|
||||
redisConfig *cfg = zcalloc(sizeof(*cfg), MALLOC_LOCAL);
|
||||
redisConfig *cfg = (redisConfig*)zcalloc(sizeof(*cfg), MALLOC_LOCAL);
|
||||
int i = 0;
|
||||
void *r = NULL;
|
||||
if (!cfg) return NULL;
|
||||
redisContext *c = NULL;
|
||||
redisReply *reply = NULL, *sub_reply = NULL;
|
||||
@@ -250,15 +253,14 @@ static redisConfig *getRedisConfig(const char *ip, int port,
|
||||
c = redisConnectUnix(hostsocket);
|
||||
if (c == NULL || c->err) {
|
||||
fprintf(stderr,"Could not connect to Redis at ");
|
||||
char *err = (c != NULL ? c->errstr : "");
|
||||
const char *err = (c != NULL ? c->errstr : "");
|
||||
if (hostsocket == NULL) fprintf(stderr,"%s:%d: %s\n",ip,port,err);
|
||||
else fprintf(stderr,"%s: %s\n",hostsocket,err);
|
||||
goto fail;
|
||||
}
|
||||
redisAppendCommand(c, "CONFIG GET %s", "save");
|
||||
redisAppendCommand(c, "CONFIG GET %s", "appendonly");
|
||||
int i = 0;
|
||||
void *r = NULL;
|
||||
|
||||
for (; i < 2; i++) {
|
||||
int res = redisGetReply(c, &r);
|
||||
if (reply) freeReplyObject(reply);
|
||||
@@ -270,7 +272,7 @@ static redisConfig *getRedisConfig(const char *ip, int port,
|
||||
}
|
||||
if (reply->type != REDIS_REPLY_ARRAY || reply->elements < 2) goto fail;
|
||||
sub_reply = reply->element[1];
|
||||
char *value = sub_reply->str;
|
||||
const char *value = sub_reply->str;
|
||||
if (!value) value = "";
|
||||
switch (i) {
|
||||
case 0: cfg->save = sdsnew(value); break;
|
||||
@@ -325,7 +327,7 @@ static void freeAllClients(void) {
|
||||
|
||||
while(ln) {
|
||||
next = ln->next;
|
||||
freeClient(ln->value);
|
||||
freeClient((client)ln->value);
|
||||
ln = next;
|
||||
}
|
||||
}
|
||||
@@ -405,7 +407,7 @@ static void clientDone(client c) {
|
||||
}
|
||||
|
||||
static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
client c = privdata;
|
||||
client c = (client)privdata;
|
||||
void *reply = NULL;
|
||||
UNUSED(el);
|
||||
UNUSED(fd);
|
||||
@@ -430,7 +432,7 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
fprintf(stderr,"Unexpected error reply, exiting...\n");
|
||||
exit(1);
|
||||
}
|
||||
redisReply *r = reply;
|
||||
redisReply *r = (redisReply*)reply;
|
||||
int is_err = (r->type == REDIS_REPLY_ERROR);
|
||||
|
||||
if (is_err && config.showerrors) {
|
||||
@@ -505,7 +507,7 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
}
|
||||
|
||||
static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
client c = privdata;
|
||||
client c = (client)privdata;
|
||||
UNUSED(el);
|
||||
UNUSED(fd);
|
||||
UNUSED(mask);
|
||||
@@ -565,10 +567,10 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
* for arguments randomization.
|
||||
*
|
||||
* Even when cloning another client, prefix commands are applied if needed.*/
|
||||
static client createClient(char *cmd, size_t len, client from, int thread_id) {
|
||||
static client createClient(const char *cmd, size_t len, client from, int thread_id) {
|
||||
int j;
|
||||
int is_cluster_client = (config.cluster_mode && thread_id >= 0);
|
||||
client c = zmalloc(sizeof(struct _client), MALLOC_LOCAL);
|
||||
client c = (client)zmalloc(sizeof(struct _client), MALLOC_LOCAL);
|
||||
|
||||
const char *ip = NULL;
|
||||
int port = 0;
|
||||
@@ -653,7 +655,7 @@ static client createClient(char *cmd, size_t len, client from, int thread_id) {
|
||||
if (from) {
|
||||
c->randlen = from->randlen;
|
||||
c->randfree = 0;
|
||||
c->randptr = zmalloc(sizeof(char*)*c->randlen, MALLOC_LOCAL);
|
||||
c->randptr = (char**)zmalloc(sizeof(char*)*c->randlen, MALLOC_LOCAL);
|
||||
/* copy the offsets. */
|
||||
for (j = 0; j < (int)c->randlen; j++) {
|
||||
c->randptr[j] = c->obuf + (from->randptr[j]-from->obuf);
|
||||
@@ -665,10 +667,10 @@ static client createClient(char *cmd, size_t len, client from, int thread_id) {
|
||||
|
||||
c->randlen = 0;
|
||||
c->randfree = RANDPTR_INITIAL_SIZE;
|
||||
c->randptr = zmalloc(sizeof(char*)*c->randfree, MALLOC_LOCAL);
|
||||
c->randptr = (char**)zmalloc(sizeof(char*)*c->randfree, MALLOC_LOCAL);
|
||||
while ((p = strstr(p,"__rand_int__")) != NULL) {
|
||||
if (c->randfree == 0) {
|
||||
c->randptr = zrealloc(c->randptr,sizeof(char*)*c->randlen*2, MALLOC_LOCAL);
|
||||
c->randptr = (char**)zrealloc(c->randptr,sizeof(char*)*c->randlen*2, MALLOC_LOCAL);
|
||||
c->randfree += c->randlen;
|
||||
}
|
||||
c->randptr[c->randlen++] = p;
|
||||
@@ -682,7 +684,7 @@ static client createClient(char *cmd, size_t len, client from, int thread_id) {
|
||||
if (from) {
|
||||
c->staglen = from->staglen;
|
||||
c->stagfree = 0;
|
||||
c->stagptr = zmalloc(sizeof(char*)*c->staglen, MALLOC_LOCAL);
|
||||
c->stagptr = (char**)zmalloc(sizeof(char*)*c->staglen, MALLOC_LOCAL);
|
||||
/* copy the offsets. */
|
||||
for (j = 0; j < (int)c->staglen; j++) {
|
||||
c->stagptr[j] = c->obuf + (from->stagptr[j]-from->obuf);
|
||||
@@ -694,10 +696,10 @@ static client createClient(char *cmd, size_t len, client from, int thread_id) {
|
||||
|
||||
c->staglen = 0;
|
||||
c->stagfree = RANDPTR_INITIAL_SIZE;
|
||||
c->stagptr = zmalloc(sizeof(char*)*c->stagfree, MALLOC_LOCAL);
|
||||
c->stagptr = (char**)zmalloc(sizeof(char*)*c->stagfree, MALLOC_LOCAL);
|
||||
while ((p = strstr(p,"{tag}")) != NULL) {
|
||||
if (c->stagfree == 0) {
|
||||
c->stagptr = zrealloc(c->stagptr,
|
||||
c->stagptr = (char**)zrealloc(c->stagptr,
|
||||
sizeof(char*) * c->staglen*2, MALLOC_LOCAL);
|
||||
c->stagfree += c->staglen;
|
||||
}
|
||||
@@ -821,7 +823,7 @@ static void showLatencyReport(void) {
|
||||
static void initBenchmarkThreads() {
|
||||
int i;
|
||||
if (config.threads) freeBenchmarkThreads();
|
||||
config.threads = zmalloc(config.num_threads * sizeof(benchmarkThread*), MALLOC_LOCAL);
|
||||
config.threads = (benchmarkThread**)zmalloc(config.num_threads * sizeof(benchmarkThread*), MALLOC_LOCAL);
|
||||
for (i = 0; i < config.num_threads; i++) {
|
||||
benchmarkThread *thread = createBenchmarkThread(i);
|
||||
config.threads[i] = thread;
|
||||
@@ -841,7 +843,7 @@ static void startBenchmarkThreads() {
|
||||
pthread_join(config.threads[i]->thread, NULL);
|
||||
}
|
||||
|
||||
static void benchmark(char *title, char *cmd, int len) {
|
||||
static void benchmark(const char *title, const char *cmd, int len) {
|
||||
client c;
|
||||
|
||||
config.title = title;
|
||||
@@ -867,7 +869,7 @@ static void benchmark(char *title, char *cmd, int len) {
|
||||
/* Thread functions. */
|
||||
|
||||
static benchmarkThread *createBenchmarkThread(int index) {
|
||||
benchmarkThread *thread = zmalloc(sizeof(*thread), MALLOC_LOCAL);
|
||||
benchmarkThread *thread = (benchmarkThread*)zmalloc(sizeof(*thread), MALLOC_LOCAL);
|
||||
if (thread == NULL) return NULL;
|
||||
thread->index = index;
|
||||
thread->el = aeCreateEventLoop(1024*10);
|
||||
@@ -899,7 +901,7 @@ static void *execBenchmarkThread(void *ptr) {
|
||||
/* Cluster helper functions. */
|
||||
|
||||
static clusterNode *createClusterNode(char *ip, int port) {
|
||||
clusterNode *node = zmalloc(sizeof(*node), MALLOC_LOCAL);
|
||||
clusterNode *node = (clusterNode*)zmalloc(sizeof(*node), MALLOC_LOCAL);
|
||||
if (!node) return NULL;
|
||||
node->ip = ip;
|
||||
node->port = port;
|
||||
@@ -907,7 +909,7 @@ static clusterNode *createClusterNode(char *ip, int port) {
|
||||
node->flags = 0;
|
||||
node->replicate = NULL;
|
||||
node->replicas_count = 0;
|
||||
node->slots = zmalloc(CLUSTER_SLOTS * sizeof(int), MALLOC_LOCAL);
|
||||
node->slots = (int*)zmalloc(CLUSTER_SLOTS * sizeof(int), MALLOC_LOCAL);
|
||||
node->slots_count = 0;
|
||||
node->current_slot_index = 0;
|
||||
node->updated_slots = NULL;
|
||||
@@ -953,7 +955,7 @@ static void freeClusterNodes() {
|
||||
|
||||
static clusterNode **addClusterNode(clusterNode *node) {
|
||||
int count = config.cluster_node_count + 1;
|
||||
config.cluster_nodes = zrealloc(config.cluster_nodes,
|
||||
config.cluster_nodes = (clusterNode**)zrealloc(config.cluster_nodes,
|
||||
count * sizeof(*node), MALLOC_LOCAL);
|
||||
if (!config.cluster_nodes) return NULL;
|
||||
config.cluster_nodes[config.cluster_node_count++] = node;
|
||||
@@ -964,6 +966,7 @@ static int fetchClusterConfiguration() {
|
||||
int success = 1;
|
||||
redisContext *ctx = NULL;
|
||||
redisReply *reply = NULL;
|
||||
char *lines = reply->str, *p, *line;
|
||||
if (config.hostsocket == NULL)
|
||||
ctx = redisConnect(config.hostip,config.hostport);
|
||||
else
|
||||
@@ -979,7 +982,7 @@ static int fetchClusterConfiguration() {
|
||||
clusterNode *firstNode = createClusterNode((char *) config.hostip,
|
||||
config.hostport);
|
||||
if (!firstNode) {success = 0; goto cleanup;}
|
||||
reply = redisCommand(ctx, "CLUSTER NODES");
|
||||
reply = (redisReply*)redisCommand(ctx, "CLUSTER NODES");
|
||||
success = (reply != NULL);
|
||||
if (!success) goto cleanup;
|
||||
success = (reply->type != REDIS_REPLY_ERROR);
|
||||
@@ -993,7 +996,7 @@ static int fetchClusterConfiguration() {
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
char *lines = reply->str, *p, *line;
|
||||
lines = reply->str;
|
||||
while ((p = strstr(lines, "\n")) != NULL) {
|
||||
*p = '\0';
|
||||
line = lines;
|
||||
@@ -1077,7 +1080,7 @@ static int fetchClusterConfiguration() {
|
||||
sds dst = sdsnew(p);
|
||||
node->migrating_count += 2;
|
||||
node->migrating =
|
||||
zrealloc(node->migrating,
|
||||
(char**)zrealloc(node->migrating,
|
||||
(node->migrating_count * sizeof(sds)), MALLOC_LOCAL);
|
||||
node->migrating[node->migrating_count - 2] =
|
||||
slot;
|
||||
@@ -1091,7 +1094,7 @@ static int fetchClusterConfiguration() {
|
||||
sds slot = sdsnew(slotsdef);
|
||||
sds src = sdsnew(p);
|
||||
node->importing_count += 2;
|
||||
node->importing = zrealloc(node->importing,
|
||||
node->importing = (char**)zrealloc(node->importing,
|
||||
(node->importing_count * sizeof(sds)), MALLOC_LOCAL);
|
||||
node->importing[node->importing_count - 2] =
|
||||
slot;
|
||||
@@ -1183,7 +1186,7 @@ static int fetchClusterSlotsConfiguration(client c) {
|
||||
node->updated_slots_count = 0;
|
||||
dictReplace(masters, node->name, node) ;
|
||||
}
|
||||
reply = redisCommand(ctx, "CLUSTER SLOTS");
|
||||
reply = (redisReply*)redisCommand(ctx, "CLUSTER SLOTS");
|
||||
if (reply == NULL || reply->type == REDIS_REPLY_ERROR) {
|
||||
success = 0;
|
||||
if (reply)
|
||||
@@ -1211,9 +1214,9 @@ static int fetchClusterSlotsConfiguration(client c) {
|
||||
goto cleanup;
|
||||
}
|
||||
sdsfree(name);
|
||||
clusterNode *node = dictGetVal(entry);
|
||||
clusterNode *node = (clusterNode*)dictGetVal(entry);
|
||||
if (node->updated_slots == NULL)
|
||||
node->updated_slots = zcalloc(CLUSTER_SLOTS * sizeof(int), MALLOC_LOCAL);
|
||||
node->updated_slots = (int*)zcalloc(CLUSTER_SLOTS * sizeof(int), MALLOC_LOCAL);
|
||||
for (slot = from; slot <= to; slot++)
|
||||
node->updated_slots[node->updated_slots_count++] = slot;
|
||||
}
|
||||
@@ -1436,7 +1439,7 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData
|
||||
|
||||
/* Return true if the named test was selected using the -t command line
|
||||
* switch, or if all the tests are selected (no -t passed by user). */
|
||||
int test_is_selected(char *name) {
|
||||
int test_is_selected(const char *name) {
|
||||
char buf[256];
|
||||
int l = strlen(name);
|
||||
|
||||
@@ -1499,7 +1502,7 @@ int main(int argc, const char **argv) {
|
||||
argc -= i;
|
||||
argv += i;
|
||||
|
||||
config.latency = zmalloc(sizeof(long long)*config.requests, MALLOC_LOCAL);
|
||||
config.latency = (long long*)zmalloc(sizeof(long long)*config.requests, MALLOC_LOCAL);
|
||||
|
||||
if (config.cluster_mode) {
|
||||
/* Fetch cluster configuration. */
|
||||
@@ -1596,7 +1599,7 @@ int main(int argc, const char **argv) {
|
||||
}
|
||||
|
||||
/* Run default benchmark suite. */
|
||||
data = zmalloc(config.datasize+1, MALLOC_LOCAL);
|
||||
data = (char*)zmalloc(config.datasize+1, MALLOC_LOCAL);
|
||||
do {
|
||||
memset(data,'x',config.datasize);
|
||||
data[config.datasize] = '\0';
|
||||
@@ -190,7 +190,7 @@ int redis_check_aof_main(int argc, char **argv) {
|
||||
if (has_preamble) {
|
||||
printf("The AOF appears to start with an RDB preamble.\n"
|
||||
"Checking the RDB preamble to start:\n");
|
||||
if (redis_check_rdb_main(argc,argv,fp) == C_ERR) {
|
||||
if (redis_check_rdb_main(argc,(const char**)argv,fp) == C_ERR) {
|
||||
printf("RDB preamble of AOF file is not sane, aborting.\n");
|
||||
exit(1);
|
||||
} else {
|
||||
@@ -37,7 +37,7 @@ void rdbLoadProgressCallback(rio *r, const void *buf, size_t len);
|
||||
int rdbCheckMode = 0;
|
||||
|
||||
struct {
|
||||
rio *rio;
|
||||
::rio *rio;
|
||||
robj *key; /* Current key we are reading. */
|
||||
int key_type; /* Current key type if != -1. */
|
||||
unsigned long keys; /* Number of keys processed. */
|
||||
@@ -59,7 +59,7 @@ struct {
|
||||
#define RDB_CHECK_DOING_READ_LEN 6
|
||||
#define RDB_CHECK_DOING_READ_AUX 7
|
||||
|
||||
char *rdb_check_doing_string[] = {
|
||||
const char *rdb_check_doing_string[] = {
|
||||
"start",
|
||||
"read-type",
|
||||
"read-expire",
|
||||
@@ -70,7 +70,7 @@ char *rdb_check_doing_string[] = {
|
||||
"read-aux"
|
||||
};
|
||||
|
||||
char *rdb_type_string[] = {
|
||||
const char *rdb_type_string[] = {
|
||||
"string",
|
||||
"list-linked",
|
||||
"set-hashtable",
|
||||
@@ -176,7 +176,7 @@ void rdbCheckSetupSignals(void) {
|
||||
* 1 is returned.
|
||||
* The file is specified as a filename in 'rdbfilename' if 'fp' is not NULL,
|
||||
* otherwise the already open file 'fp' is checked. */
|
||||
int redis_check_rdb(char *rdbfilename, FILE *fp) {
|
||||
int redis_check_rdb(const char *rdbfilename, FILE *fp) {
|
||||
uint64_t dbid;
|
||||
int type, rdbver;
|
||||
char buf[1024];
|
||||
@@ -285,7 +285,7 @@ int redis_check_rdb(char *rdbfilename, FILE *fp) {
|
||||
rdbstate.keys++;
|
||||
/* Read value */
|
||||
rdbstate.doing = RDB_CHECK_DOING_READ_OBJECT_VALUE;
|
||||
if ((val = rdbLoadObject(type,&rdb)) == NULL) goto eoferr;
|
||||
if ((val = rdbLoadObject(type,&rdb,key)) == NULL) goto eoferr;
|
||||
/* Check if the key already expired. */
|
||||
if (expiretime != -1 && expiretime < now)
|
||||
rdbstate.already_expired++;
|
||||
@@ -339,7 +339,7 @@ err:
|
||||
* status code according to success (RDB is sane) or error (RDB is corrupted).
|
||||
* Otherwise if called with a non NULL fp, the function returns C_OK or
|
||||
* C_ERR depending on the success or failure. */
|
||||
int redis_check_rdb_main(int argc, char **argv, FILE *fp) {
|
||||
int redis_check_rdb_main(int argc, const char **argv, FILE *fp) {
|
||||
if (argc != 2 && fp == NULL) {
|
||||
fprintf(stderr, "Usage: %s <rdb-file-name>\n", argv[0]);
|
||||
exit(1);
|
||||
@@ -0,0 +1,933 @@
|
||||
#include "fmacros.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
extern "C" {
|
||||
#include <hiredis.h>
|
||||
#include <sds.h> /* use sds.h from hiredis, so that only one set of sds functions will be present in the binary */
|
||||
}
|
||||
#include "dict.h"
|
||||
#include "adlist.h"
|
||||
#include "zmalloc.h"
|
||||
#include "storage.h"
|
||||
|
||||
#include "redis-cli.h"
|
||||
|
||||
static dict *clusterManagerGetLinkStatus(void);
|
||||
|
||||
/* The Cluster Manager global structure */
|
||||
struct clusterManager cluster_manager;
|
||||
|
||||
extern "C" uint64_t dictSdsHash(const void *key) {
|
||||
return dictGenHashFunction((unsigned char*)key, sdslen((char*)key));
|
||||
}
|
||||
|
||||
extern "C" int dictSdsKeyCompare(void *privdata, const void *key1,
|
||||
const void *key2)
|
||||
{
|
||||
int l1,l2;
|
||||
DICT_NOTUSED(privdata);
|
||||
|
||||
l1 = sdslen((sds)key1);
|
||||
l2 = sdslen((sds)key2);
|
||||
if (l1 != l2) return 0;
|
||||
return memcmp(key1, key2, l1) == 0;
|
||||
}
|
||||
|
||||
extern "C" void dictSdsDestructor(void *privdata, void *val)
|
||||
{
|
||||
DICT_NOTUSED(privdata);
|
||||
sdsfree((sds)val);
|
||||
}
|
||||
|
||||
extern "C" void dictListDestructor(void *privdata, void *val)
|
||||
{
|
||||
DICT_NOTUSED(privdata);
|
||||
listRelease((list*)val);
|
||||
}
|
||||
|
||||
/* Used by clusterManagerFixSlotsCoverage */
|
||||
dict *clusterManagerUncoveredSlots = NULL;
|
||||
|
||||
/* Info about a cluster internal link. */
|
||||
|
||||
typedef struct clusterManagerLink {
|
||||
sds node_name;
|
||||
sds node_addr;
|
||||
int connected;
|
||||
int handshaking;
|
||||
} clusterManagerLink;
|
||||
|
||||
static dictType clusterManagerDictType = {
|
||||
dictSdsHash, /* hash function */
|
||||
NULL, /* key dup */
|
||||
NULL, /* val dup */
|
||||
dictSdsKeyCompare, /* key compare */
|
||||
NULL, /* key destructor */
|
||||
dictSdsDestructor /* val destructor */
|
||||
};
|
||||
|
||||
static dictType clusterManagerLinkDictType = {
|
||||
dictSdsHash, /* hash function */
|
||||
NULL, /* key dup */
|
||||
NULL, /* val dup */
|
||||
dictSdsKeyCompare, /* key compare */
|
||||
dictSdsDestructor, /* key destructor */
|
||||
dictListDestructor /* val destructor */
|
||||
};
|
||||
|
||||
|
||||
extern "C" void freeClusterManager(void) {
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
if (cluster_manager.nodes != NULL) {
|
||||
listRewind(cluster_manager.nodes,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
clusterManagerNode *n = (clusterManagerNode*)ln->value;
|
||||
freeClusterManagerNode(n);
|
||||
}
|
||||
listRelease(cluster_manager.nodes);
|
||||
cluster_manager.nodes = NULL;
|
||||
}
|
||||
if (cluster_manager.errors != NULL) {
|
||||
listRewind(cluster_manager.errors,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
sds err = (sds)ln->value;
|
||||
sdsfree(err);
|
||||
}
|
||||
listRelease(cluster_manager.errors);
|
||||
cluster_manager.errors = NULL;
|
||||
}
|
||||
if (clusterManagerUncoveredSlots != NULL)
|
||||
dictRelease(clusterManagerUncoveredSlots);
|
||||
}
|
||||
|
||||
/* Return the anti-affinity score, which is a measure of the amount of
|
||||
* violations of anti-affinity in the current cluster layout, that is, how
|
||||
* badly the masters and slaves are distributed in the different IP
|
||||
* addresses so that slaves of the same master are not in the master
|
||||
* host and are also in different hosts.
|
||||
*
|
||||
* The score is calculated as follows:
|
||||
*
|
||||
* SAME_AS_MASTER = 10000 * each slave in the same IP of its master.
|
||||
* SAME_AS_SLAVE = 1 * each slave having the same IP as another slave
|
||||
of the same master.
|
||||
* FINAL_SCORE = SAME_AS_MASTER + SAME_AS_SLAVE
|
||||
*
|
||||
* So a greater score means a worse anti-affinity level, while zero
|
||||
* means perfect anti-affinity.
|
||||
*
|
||||
* The anti affinity optimizator will try to get a score as low as
|
||||
* possible. Since we do not want to sacrifice the fact that slaves should
|
||||
* not be in the same host as the master, we assign 10000 times the score
|
||||
* to this violation, so that we'll optimize for the second factor only
|
||||
* if it does not impact the first one.
|
||||
*
|
||||
* The ipnodes argument is an array of clusterManagerNodeArray, one for
|
||||
* each IP, while ip_count is the total number of IPs in the configuration.
|
||||
*
|
||||
* The function returns the above score, and the list of
|
||||
* offending slaves can be stored into the 'offending' argument,
|
||||
* so that the optimizer can try changing the configuration of the
|
||||
* slaves violating the anti-affinity goals. */
|
||||
int clusterManagerGetAntiAffinityScore(clusterManagerNodeArray *ipnodes,
|
||||
int ip_count, clusterManagerNode ***offending, int *offending_len)
|
||||
{
|
||||
int score = 0, i, j;
|
||||
int node_len = cluster_manager.nodes->len;
|
||||
clusterManagerNode **offending_p = NULL;
|
||||
if (offending != NULL) {
|
||||
*offending = (clusterManagerNode**)zcalloc(node_len * sizeof(clusterManagerNode*), MALLOC_LOCAL);
|
||||
offending_p = *offending;
|
||||
}
|
||||
/* For each set of nodes in the same host, split by
|
||||
* related nodes (masters and slaves which are involved in
|
||||
* replication of each other) */
|
||||
for (i = 0; i < ip_count; i++) {
|
||||
clusterManagerNodeArray *node_array = &(ipnodes[i]);
|
||||
dict *related = dictCreate(&clusterManagerDictType, NULL);
|
||||
char *ip = NULL;
|
||||
for (j = 0; j < node_array->len; j++) {
|
||||
clusterManagerNode *node = node_array->nodes[j];
|
||||
if (node == NULL) continue;
|
||||
if (!ip) ip = node->ip;
|
||||
sds types;
|
||||
/* We always use the Master ID as key. */
|
||||
sds key = (!node->replicate ? node->name : node->replicate);
|
||||
assert(key != NULL);
|
||||
dictEntry *entry = dictFind(related, key);
|
||||
if (entry) types = sdsdup((sds) dictGetVal(entry));
|
||||
else types = sdsempty();
|
||||
/* Master type 'm' is always set as the first character of the
|
||||
* types string. */
|
||||
if (!node->replicate) types = sdscatprintf(types, "m%s", types);
|
||||
else types = sdscat(types, "s");
|
||||
dictReplace(related, key, types);
|
||||
}
|
||||
/* Now it's trivial to check, for each related group having the
|
||||
* same host, what is their local score. */
|
||||
dictIterator *iter = dictGetIterator(related);
|
||||
dictEntry *entry;
|
||||
while ((entry = dictNext(iter)) != NULL) {
|
||||
sds types = (sds) dictGetVal(entry);
|
||||
sds name = (sds) dictGetKey(entry);
|
||||
int typeslen = sdslen(types);
|
||||
if (typeslen < 2) continue;
|
||||
if (types[0] == 'm') score += (10000 * (typeslen - 1));
|
||||
else score += (1 * typeslen);
|
||||
if (offending == NULL) continue;
|
||||
/* Populate the list of offending nodes. */
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(cluster_manager.nodes, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
clusterManagerNode *n = (clusterManagerNode*)ln->value;
|
||||
if (n->replicate == NULL) continue;
|
||||
if (!strcmp(n->replicate, name) && !strcmp(n->ip, ip)) {
|
||||
*(offending_p++) = n;
|
||||
if (offending_len != NULL) (*offending_len)++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//if (offending_len != NULL) *offending_len = offending_p - *offending;
|
||||
dictReleaseIterator(iter);
|
||||
dictRelease(related);
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
|
||||
/* Wait until the cluster configuration is consistent. */
|
||||
extern "C" void clusterManagerWaitForClusterJoin(void) {
|
||||
printf("Waiting for the cluster to join\n");
|
||||
int counter = 0,
|
||||
check_after = CLUSTER_JOIN_CHECK_AFTER +
|
||||
(int)(listLength(cluster_manager.nodes) * 0.15f);
|
||||
while(!clusterManagerIsConfigConsistent()) {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
if (++counter > check_after) {
|
||||
dict *status = clusterManagerGetLinkStatus();
|
||||
dictIterator *iter = NULL;
|
||||
if (status != NULL && dictSize(status) > 0) {
|
||||
printf("\n");
|
||||
clusterManagerLogErr("Warning: %d node(s) may "
|
||||
"be unreachable\n", dictSize(status));
|
||||
iter = dictGetIterator(status);
|
||||
dictEntry *entry;
|
||||
while ((entry = dictNext(iter)) != NULL) {
|
||||
sds nodeaddr = (sds) dictGetKey(entry);
|
||||
char *node_ip = NULL;
|
||||
int node_port = 0, node_bus_port = 0;
|
||||
list *from = (list *) dictGetVal(entry);
|
||||
if (parseClusterNodeAddress(nodeaddr, &node_ip,
|
||||
&node_port, &node_bus_port) && node_bus_port) {
|
||||
clusterManagerLogErr(" - The port %d of node %s may "
|
||||
"be unreachable from:\n",
|
||||
node_bus_port, node_ip);
|
||||
} else {
|
||||
clusterManagerLogErr(" - Node %s may be unreachable "
|
||||
"from:\n", nodeaddr);
|
||||
}
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(from, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
sds from_addr = (sds)ln->value;
|
||||
clusterManagerLogErr(" %s\n", from_addr);
|
||||
sdsfree(from_addr);
|
||||
}
|
||||
clusterManagerLogErr("Cluster bus ports must be reachable "
|
||||
"by every node.\nRemember that "
|
||||
"cluster bus ports are different "
|
||||
"from standard instance ports.\n");
|
||||
listEmpty(from);
|
||||
}
|
||||
}
|
||||
if (iter != NULL) dictReleaseIterator(iter);
|
||||
if (status != NULL) dictRelease(status);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
list *clusterManagerGetDisconnectedLinks(clusterManagerNode *node) {
|
||||
list *links = NULL;
|
||||
char *lines = NULL, *p, *line;
|
||||
redisReply *reply = (redisReply*)CLUSTER_MANAGER_COMMAND(node, "CLUSTER NODES");
|
||||
if (!clusterManagerCheckRedisReply(node, reply, NULL)) goto cleanup;
|
||||
links = listCreate();
|
||||
lines = reply->str;
|
||||
while ((p = strstr(lines, "\n")) != NULL) {
|
||||
int i = 0;
|
||||
*p = '\0';
|
||||
line = lines;
|
||||
lines = p + 1;
|
||||
char *nodename = NULL, *addr = NULL, *flags = NULL, *link_status = NULL;
|
||||
while ((p = strchr(line, ' ')) != NULL) {
|
||||
*p = '\0';
|
||||
char *token = line;
|
||||
line = p + 1;
|
||||
if (i == 0) nodename = token;
|
||||
else if (i == 1) addr = token;
|
||||
else if (i == 2) flags = token;
|
||||
else if (i == 7) link_status = token;
|
||||
else if (i == 8) break;
|
||||
i++;
|
||||
}
|
||||
if (i == 7) link_status = line;
|
||||
if (nodename == NULL || addr == NULL || flags == NULL ||
|
||||
link_status == NULL) continue;
|
||||
if (strstr(flags, "myself") != NULL) continue;
|
||||
int disconnected = ((strstr(flags, "disconnected") != NULL) ||
|
||||
(strstr(link_status, "disconnected")));
|
||||
int handshaking = (strstr(flags, "handshake") != NULL);
|
||||
if (disconnected || handshaking) {
|
||||
clusterManagerLink *link = (clusterManagerLink*)zmalloc(sizeof(*link), MALLOC_LOCAL);
|
||||
link->node_name = sdsnew(nodename);
|
||||
link->node_addr = sdsnew(addr);
|
||||
link->connected = 0;
|
||||
link->handshaking = handshaking;
|
||||
listAddNodeTail(links, link);
|
||||
}
|
||||
}
|
||||
cleanup:
|
||||
if (reply != NULL) freeReplyObject(reply);
|
||||
return links;
|
||||
}
|
||||
|
||||
/* Check for disconnected cluster links. It returns a dict whose keys
|
||||
* are the unreachable node addresses and the values are lists of
|
||||
* node addresses that cannot reach the unreachable node. */
|
||||
dict *clusterManagerGetLinkStatus(void) {
|
||||
if (cluster_manager.nodes == NULL) return NULL;
|
||||
dict *status = dictCreate(&clusterManagerLinkDictType, NULL);
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(cluster_manager.nodes, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
clusterManagerNode *node = (clusterManagerNode*)ln->value;
|
||||
list *links = clusterManagerGetDisconnectedLinks(node);
|
||||
if (links) {
|
||||
listIter lli;
|
||||
listNode *lln;
|
||||
listRewind(links, &lli);
|
||||
while ((lln = listNext(&lli)) != NULL) {
|
||||
clusterManagerLink *link = (clusterManagerLink*)lln->value;
|
||||
list *from = NULL;
|
||||
dictEntry *entry = dictFind(status, link->node_addr);
|
||||
if (entry) from = (list*)dictGetVal(entry);
|
||||
else {
|
||||
from = listCreate();
|
||||
dictAdd(status, sdsdup(link->node_addr), from);
|
||||
}
|
||||
sds myaddr = sdsempty();
|
||||
myaddr = sdscatfmt(myaddr, "%s:%u", node->ip, node->port);
|
||||
listAddNodeTail(from, myaddr);
|
||||
sdsfree(link->node_name);
|
||||
sdsfree(link->node_addr);
|
||||
zfree(link);
|
||||
}
|
||||
listRelease(links);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* This function returns a random master node, return NULL if none */
|
||||
|
||||
static clusterManagerNode *clusterManagerNodeMasterRandom() {
|
||||
int master_count = 0;
|
||||
int idx;
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(cluster_manager.nodes, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
clusterManagerNode *n = (clusterManagerNode*)ln->value;
|
||||
if (n->flags & CLUSTER_MANAGER_FLAG_SLAVE) continue;
|
||||
master_count++;
|
||||
}
|
||||
|
||||
srand(time(NULL));
|
||||
idx = rand() % master_count;
|
||||
listRewind(cluster_manager.nodes, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
clusterManagerNode *n = (clusterManagerNode*)ln->value;
|
||||
if (n->flags & CLUSTER_MANAGER_FLAG_SLAVE) continue;
|
||||
if (!idx--) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
/* Can not be reached */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int clusterManagerFixSlotsCoverage(char *all_slots) {
|
||||
int i, fixed = 0;
|
||||
dictIterator *iter = nullptr;
|
||||
dictEntry *entry = nullptr;
|
||||
list *none = NULL, *single = NULL, *multi = NULL;
|
||||
clusterManagerLogInfo(">>> Fixing slots coverage...\n");
|
||||
printf("List of not covered slots: \n");
|
||||
int uncovered_count = 0;
|
||||
sds log = sdsempty();
|
||||
for (i = 0; i < CLUSTER_MANAGER_SLOTS; i++) {
|
||||
int covered = all_slots[i];
|
||||
if (!covered) {
|
||||
sds key = sdsfromlonglong((long long) i);
|
||||
if (uncovered_count++ > 0) printf(",");
|
||||
printf("%s", (char *) key);
|
||||
list *slot_nodes = listCreate();
|
||||
sds slot_nodes_str = sdsempty();
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(cluster_manager.nodes, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
clusterManagerNode *n = (clusterManagerNode*)ln->value;
|
||||
if (n->flags & CLUSTER_MANAGER_FLAG_SLAVE || n->replicate)
|
||||
continue;
|
||||
redisReply *reply = (redisReply*)CLUSTER_MANAGER_COMMAND(n,
|
||||
"CLUSTER GETKEYSINSLOT %d %d", i, 1);
|
||||
if (!clusterManagerCheckRedisReply(n, reply, NULL)) {
|
||||
fixed = -1;
|
||||
if (reply) freeReplyObject(reply);
|
||||
goto cleanup;
|
||||
}
|
||||
assert(reply->type == REDIS_REPLY_ARRAY);
|
||||
if (reply->elements > 0) {
|
||||
listAddNodeTail(slot_nodes, n);
|
||||
if (listLength(slot_nodes) > 1)
|
||||
slot_nodes_str = sdscat(slot_nodes_str, ", ");
|
||||
slot_nodes_str = sdscatfmt(slot_nodes_str,
|
||||
"%s:%u", n->ip, n->port);
|
||||
}
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
log = sdscatfmt(log, "\nSlot %S has keys in %u nodes: %S",
|
||||
key, listLength(slot_nodes), slot_nodes_str);
|
||||
sdsfree(slot_nodes_str);
|
||||
dictAdd(clusterManagerUncoveredSlots, key, slot_nodes);
|
||||
}
|
||||
}
|
||||
printf("\n%s\n", log);
|
||||
/* For every slot, take action depending on the actual condition:
|
||||
* 1) No node has keys for this slot.
|
||||
* 2) A single node has keys for this slot.
|
||||
* 3) Multiple nodes have keys for this slot. */
|
||||
none = listCreate();
|
||||
single = listCreate();
|
||||
multi = listCreate();
|
||||
iter = dictGetIterator(clusterManagerUncoveredSlots);
|
||||
while ((entry = dictNext(iter)) != NULL) {
|
||||
sds slot = (sds) dictGetKey(entry);
|
||||
list *nodes = (list *) dictGetVal(entry);
|
||||
switch (listLength(nodes)){
|
||||
case 0: listAddNodeTail(none, slot); break;
|
||||
case 1: listAddNodeTail(single, slot); break;
|
||||
default: listAddNodeTail(multi, slot); break;
|
||||
}
|
||||
}
|
||||
dictReleaseIterator(iter);
|
||||
|
||||
/* Handle case "1": keys in no node. */
|
||||
if (listLength(none) > 0) {
|
||||
printf("The following uncovered slots have no keys "
|
||||
"across the cluster:\n");
|
||||
clusterManagerPrintSlotsList(none);
|
||||
if (confirmWithYes("Fix these slots by covering with a random node?")){
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(none, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
sds slot = (sds)ln->value;
|
||||
int s = atoi(slot);
|
||||
clusterManagerNode *n = clusterManagerNodeMasterRandom();
|
||||
clusterManagerLogInfo(">>> Covering slot %s with %s:%d\n",
|
||||
slot, n->ip, n->port);
|
||||
if (!clusterManagerSetSlotOwner(n, s, 0)) {
|
||||
fixed = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Since CLUSTER ADDSLOTS succeeded, we also update the slot
|
||||
* info into the node struct, in order to keep it synced */
|
||||
n->slots[s] = 1;
|
||||
fixed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle case "2": keys only in one node. */
|
||||
if (listLength(single) > 0) {
|
||||
printf("The following uncovered slots have keys in just one node:\n");
|
||||
clusterManagerPrintSlotsList(single);
|
||||
if (confirmWithYes("Fix these slots by covering with those nodes?")){
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(single, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
sds slot = (sds)ln->value;
|
||||
int s = atoi(slot);
|
||||
dictEntry *entry = dictFind(clusterManagerUncoveredSlots, slot);
|
||||
assert(entry != NULL);
|
||||
list *nodes = (list *) dictGetVal(entry);
|
||||
listNode *fn = listFirst(nodes);
|
||||
assert(fn != NULL);
|
||||
clusterManagerNode *n = (clusterManagerNode*)fn->value;
|
||||
clusterManagerLogInfo(">>> Covering slot %s with %s:%d\n",
|
||||
slot, n->ip, n->port);
|
||||
if (!clusterManagerSetSlotOwner(n, s, 0)) {
|
||||
fixed = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Since CLUSTER ADDSLOTS succeeded, we also update the slot
|
||||
* info into the node struct, in order to keep it synced */
|
||||
n->slots[atoi(slot)] = 1;
|
||||
fixed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle case "3": keys in multiple nodes. */
|
||||
if (listLength(multi) > 0) {
|
||||
printf("The following uncovered slots have keys in multiple nodes:\n");
|
||||
clusterManagerPrintSlotsList(multi);
|
||||
if (confirmWithYes("Fix these slots by moving keys "
|
||||
"into a single node?")) {
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(multi, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
sds slot = (sds)ln->value;
|
||||
dictEntry *entry = dictFind(clusterManagerUncoveredSlots, slot);
|
||||
assert(entry != NULL);
|
||||
list *nodes = (list *) dictGetVal(entry);
|
||||
int s = atoi(slot);
|
||||
clusterManagerNode *target =
|
||||
clusterManagerGetNodeWithMostKeysInSlot(nodes, s, NULL);
|
||||
if (target == NULL) {
|
||||
fixed = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
clusterManagerLogInfo(">>> Covering slot %s moving keys "
|
||||
"to %s:%d\n", slot,
|
||||
target->ip, target->port);
|
||||
if (!clusterManagerSetSlotOwner(target, s, 1)) {
|
||||
fixed = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Since CLUSTER ADDSLOTS succeeded, we also update the slot
|
||||
* info into the node struct, in order to keep it synced */
|
||||
target->slots[atoi(slot)] = 1;
|
||||
listIter nli;
|
||||
listNode *nln;
|
||||
listRewind(nodes, &nli);
|
||||
while ((nln = listNext(&nli)) != NULL) {
|
||||
clusterManagerNode *src = (clusterManagerNode*)nln->value;
|
||||
if (src == target) continue;
|
||||
/* Assign the slot to target node in the source node. */
|
||||
if (!clusterManagerSetSlot(src, target, s, "NODE", NULL))
|
||||
fixed = -1;
|
||||
if (fixed < 0) goto cleanup;
|
||||
/* Set the source node in 'importing' state
|
||||
* (even if we will actually migrate keys away)
|
||||
* in order to avoid receiving redirections
|
||||
* for MIGRATE. */
|
||||
if (!clusterManagerSetSlot(src, target, s,
|
||||
"IMPORTING", NULL)) fixed = -1;
|
||||
if (fixed < 0) goto cleanup;
|
||||
int opts = CLUSTER_MANAGER_OPT_VERBOSE |
|
||||
CLUSTER_MANAGER_OPT_COLD;
|
||||
if (!clusterManagerMoveSlot(src, target, s, opts, NULL)) {
|
||||
fixed = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (!clusterManagerClearSlotStatus(src, s))
|
||||
fixed = -1;
|
||||
if (fixed < 0) goto cleanup;
|
||||
}
|
||||
fixed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanup:
|
||||
sdsfree(log);
|
||||
if (none) listRelease(none);
|
||||
if (single) listRelease(single);
|
||||
if (multi) listRelease(multi);
|
||||
return fixed;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int clusterManagerCheckCluster(int quiet) {
|
||||
listNode *ln = listFirst(cluster_manager.nodes);
|
||||
if (!ln) return 0;
|
||||
clusterManagerNode *node = (clusterManagerNode*)ln->value;
|
||||
clusterManagerLogInfo(">>> Performing Cluster Check (using node %s:%d)\n",
|
||||
node->ip, node->port);
|
||||
int result = 1, consistent = 0;
|
||||
int do_fix = config.cluster_manager_command.flags &
|
||||
CLUSTER_MANAGER_CMD_FLAG_FIX;
|
||||
if (!quiet) clusterManagerShowNodes();
|
||||
consistent = clusterManagerIsConfigConsistent();
|
||||
if (!consistent) {
|
||||
sds err = sdsnew("[ERR] Nodes don't agree about configuration!");
|
||||
clusterManagerOnError(err);
|
||||
result = 0;
|
||||
} else {
|
||||
clusterManagerLogOk("[OK] All nodes agree about slots "
|
||||
"configuration.\n");
|
||||
}
|
||||
/* Check open slots */
|
||||
clusterManagerLogInfo(">>> Check for open slots...\n");
|
||||
listIter li;
|
||||
listRewind(cluster_manager.nodes, &li);
|
||||
int i;
|
||||
dict *open_slots = NULL;
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
clusterManagerNode *n = (clusterManagerNode*)ln->value;
|
||||
if (n->migrating != NULL) {
|
||||
if (open_slots == NULL)
|
||||
open_slots = dictCreate(&clusterManagerDictType, NULL);
|
||||
sds errstr = sdsempty();
|
||||
errstr = sdscatprintf(errstr,
|
||||
"[WARNING] Node %s:%d has slots in "
|
||||
"migrating state ",
|
||||
n->ip,
|
||||
n->port);
|
||||
for (i = 0; i < n->migrating_count; i += 2) {
|
||||
sds slot = n->migrating[i];
|
||||
dictReplace(open_slots, slot, sdsdup(n->migrating[i + 1]));
|
||||
const char *fmt = (i > 0 ? ",%S" : "%S");
|
||||
errstr = sdscatfmt(errstr, fmt, slot);
|
||||
}
|
||||
errstr = sdscat(errstr, ".");
|
||||
clusterManagerOnError(errstr);
|
||||
}
|
||||
if (n->importing != NULL) {
|
||||
if (open_slots == NULL)
|
||||
open_slots = dictCreate(&clusterManagerDictType, NULL);
|
||||
sds errstr = sdsempty();
|
||||
errstr = sdscatprintf(errstr,
|
||||
"[WARNING] Node %s:%d has slots in "
|
||||
"importing state ",
|
||||
n->ip,
|
||||
n->port);
|
||||
for (i = 0; i < n->importing_count; i += 2) {
|
||||
sds slot = n->importing[i];
|
||||
dictReplace(open_slots, slot, sdsdup(n->importing[i + 1]));
|
||||
const char *fmt = (i > 0 ? ",%S" : "%S");
|
||||
errstr = sdscatfmt(errstr, fmt, slot);
|
||||
}
|
||||
errstr = sdscat(errstr, ".");
|
||||
clusterManagerOnError(errstr);
|
||||
}
|
||||
}
|
||||
if (open_slots != NULL) {
|
||||
result = 0;
|
||||
dictIterator *iter = dictGetIterator(open_slots);
|
||||
dictEntry *entry;
|
||||
sds errstr = sdsnew("[WARNING] The following slots are open: ");
|
||||
i = 0;
|
||||
while ((entry = dictNext(iter)) != NULL) {
|
||||
sds slot = (sds) dictGetKey(entry);
|
||||
const char *fmt = (i++ > 0 ? ",%S" : "%S");
|
||||
errstr = sdscatfmt(errstr, fmt, slot);
|
||||
}
|
||||
clusterManagerLogErr("%s.\n", (char *) errstr);
|
||||
sdsfree(errstr);
|
||||
if (do_fix) {
|
||||
/* Fix open slots. */
|
||||
dictReleaseIterator(iter);
|
||||
iter = dictGetIterator(open_slots);
|
||||
while ((entry = dictNext(iter)) != NULL) {
|
||||
sds slot = (sds) dictGetKey(entry);
|
||||
result = clusterManagerFixOpenSlot(atoi(slot));
|
||||
if (!result) break;
|
||||
}
|
||||
}
|
||||
dictReleaseIterator(iter);
|
||||
dictRelease(open_slots);
|
||||
}
|
||||
clusterManagerLogInfo(">>> Check slots coverage...\n");
|
||||
char slots[CLUSTER_MANAGER_SLOTS];
|
||||
memset(slots, 0, CLUSTER_MANAGER_SLOTS);
|
||||
int coverage = clusterManagerGetCoveredSlots(slots);
|
||||
if (coverage == CLUSTER_MANAGER_SLOTS) {
|
||||
clusterManagerLogOk("[OK] All %d slots covered.\n",
|
||||
CLUSTER_MANAGER_SLOTS);
|
||||
} else {
|
||||
sds err = sdsempty();
|
||||
err = sdscatprintf(err, "[ERR] Not all %d slots are "
|
||||
"covered by nodes.\n",
|
||||
CLUSTER_MANAGER_SLOTS);
|
||||
clusterManagerOnError(err);
|
||||
result = 0;
|
||||
if (do_fix/* && result*/) {
|
||||
dictType dtype = clusterManagerDictType;
|
||||
dtype.keyDestructor = dictSdsDestructor;
|
||||
dtype.valDestructor = dictListDestructor;
|
||||
clusterManagerUncoveredSlots = dictCreate(&dtype, NULL);
|
||||
int fixed = clusterManagerFixSlotsCoverage(slots);
|
||||
if (fixed > 0) result = 1;
|
||||
}
|
||||
}
|
||||
int search_multiple_owners = config.cluster_manager_command.flags &
|
||||
CLUSTER_MANAGER_CMD_FLAG_CHECK_OWNERS;
|
||||
if (search_multiple_owners) {
|
||||
/* Check whether there are multiple owners, even when slots are
|
||||
* fully covered and there are no open slots. */
|
||||
clusterManagerLogInfo(">>> Check for multiple slot owners...\n");
|
||||
int slot = 0, slots_with_multiple_owners = 0;
|
||||
for (; slot < CLUSTER_MANAGER_SLOTS; slot++) {
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(cluster_manager.nodes, &li);
|
||||
list *owners = listCreate();
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
clusterManagerNode *n = (clusterManagerNode*)ln->value;
|
||||
if (n->flags & CLUSTER_MANAGER_FLAG_SLAVE) continue;
|
||||
if (n->slots[slot]) listAddNodeTail(owners, n);
|
||||
else {
|
||||
/* Nodes having keys for the slot will be considered
|
||||
* owners too. */
|
||||
int count = clusterManagerCountKeysInSlot(n, slot);
|
||||
if (count > 0) listAddNodeTail(owners, n);
|
||||
}
|
||||
}
|
||||
if (listLength(owners) > 1) {
|
||||
result = 0;
|
||||
clusterManagerLogErr("[WARNING] Slot %d has %d owners:\n",
|
||||
slot, listLength(owners));
|
||||
listRewind(owners, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
clusterManagerNode *n = (clusterManagerNode*)ln->value;
|
||||
clusterManagerLogErr(" %s:%d\n", n->ip, n->port);
|
||||
}
|
||||
slots_with_multiple_owners++;
|
||||
if (do_fix) {
|
||||
result = clusterManagerFixMultipleSlotOwners(slot, owners);
|
||||
if (!result) {
|
||||
clusterManagerLogErr("Failed to fix multiple owners "
|
||||
"for slot %d\n", slot);
|
||||
listRelease(owners);
|
||||
break;
|
||||
} else slots_with_multiple_owners--;
|
||||
}
|
||||
}
|
||||
listRelease(owners);
|
||||
}
|
||||
if (slots_with_multiple_owners == 0)
|
||||
clusterManagerLogOk("[OK] No multiple owners found.\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static typeinfo* typeinfo_add(dict *types, const char* name, typeinfo* type_template) {
|
||||
typeinfo *info = (typeinfo*)zmalloc(sizeof(typeinfo), MALLOC_LOCAL);
|
||||
*info = *type_template;
|
||||
info->name = sdsnew(name);
|
||||
dictAdd(types, info->name, info);
|
||||
return info;
|
||||
}
|
||||
|
||||
static dictType typeinfoDictType = {
|
||||
dictSdsHash, /* hash function */
|
||||
NULL, /* key dup */
|
||||
NULL, /* val dup */
|
||||
dictSdsKeyCompare, /* key compare */
|
||||
NULL, /* key destructor (owned by the value)*/
|
||||
type_free /* val destructor */
|
||||
};
|
||||
|
||||
static void getKeyTypes(dict *types_dict, redisReply *keys, typeinfo **types) {
|
||||
redisReply *reply;
|
||||
unsigned int i;
|
||||
|
||||
/* Pipeline TYPE commands */
|
||||
for(i=0;i<keys->elements;i++) {
|
||||
redisAppendCommand(context, "TYPE %s", keys->element[i]->str);
|
||||
}
|
||||
|
||||
/* Retrieve types */
|
||||
for(i=0;i<keys->elements;i++) {
|
||||
if(redisGetReply(context, (void**)&reply)!=REDIS_OK) {
|
||||
fprintf(stderr, "Error getting type for key '%s' (%d: %s)\n",
|
||||
keys->element[i]->str, context->err, context->errstr);
|
||||
exit(1);
|
||||
} else if(reply->type != REDIS_REPLY_STATUS) {
|
||||
if(reply->type == REDIS_REPLY_ERROR) {
|
||||
fprintf(stderr, "TYPE returned an error: %s\n", reply->str);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Invalid reply type (%d) for TYPE on key '%s'!\n",
|
||||
reply->type, keys->element[i]->str);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sds typereply = sdsnew(reply->str);
|
||||
dictEntry *de = dictFind(types_dict, typereply);
|
||||
sdsfree(typereply);
|
||||
typeinfo *type = NULL;
|
||||
if (de)
|
||||
type = (typeinfo*)dictGetVal(de);
|
||||
else if (strcmp(reply->str, "none")) /* create new types for modules, (but not for deleted keys) */
|
||||
type = typeinfo_add(types_dict, reply->str, &type_other);
|
||||
types[i] = type;
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
}
|
||||
|
||||
void findBigKeys(int memkeys, unsigned memkeys_samples) {
|
||||
unsigned long long sampled = 0, total_keys, totlen=0, *sizes=NULL, it=0;
|
||||
redisReply *reply, *keys;
|
||||
unsigned int arrsize=0, i;
|
||||
dictIterator *di;
|
||||
dictEntry *de;
|
||||
typeinfo **types = NULL;
|
||||
double pct;
|
||||
|
||||
dict *types_dict = dictCreate(&typeinfoDictType, NULL);
|
||||
typeinfo_add(types_dict, "string", &type_string);
|
||||
typeinfo_add(types_dict, "list", &type_list);
|
||||
typeinfo_add(types_dict, "set", &type_set);
|
||||
typeinfo_add(types_dict, "hash", &type_hash);
|
||||
typeinfo_add(types_dict, "zset", &type_zset);
|
||||
typeinfo_add(types_dict, "stream", &type_stream);
|
||||
|
||||
/* Total keys pre scanning */
|
||||
total_keys = getDbSize();
|
||||
|
||||
/* Status message */
|
||||
printf("\n# Scanning the entire keyspace to find biggest keys as well as\n");
|
||||
printf("# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec\n");
|
||||
printf("# per 100 SCAN commands (not usually needed).\n\n");
|
||||
|
||||
/* SCAN loop */
|
||||
do {
|
||||
/* Calculate approximate percentage completion */
|
||||
pct = 100 * (double)sampled/total_keys;
|
||||
|
||||
/* Grab some keys and point to the keys array */
|
||||
reply = sendScan(&it);
|
||||
keys = reply->element[1];
|
||||
|
||||
/* Reallocate our type and size array if we need to */
|
||||
if(keys->elements > arrsize) {
|
||||
types = (typeinfo**)zrealloc(types, sizeof(int)*keys->elements, MALLOC_LOCAL);
|
||||
sizes = (unsigned long long*)zrealloc(sizes, sizeof(unsigned long long)*keys->elements, MALLOC_LOCAL);
|
||||
|
||||
if(!types || !sizes) {
|
||||
fprintf(stderr, "Failed to allocate storage for keys!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
arrsize = keys->elements;
|
||||
}
|
||||
|
||||
/* Retrieve types and then sizes */
|
||||
getKeyTypes(types_dict, keys, types);
|
||||
getKeySizes(keys, types, sizes, memkeys, memkeys_samples);
|
||||
|
||||
/* Now update our stats */
|
||||
for(i=0;i<keys->elements;i++) {
|
||||
typeinfo *type = types[i];
|
||||
/* Skip keys that disappeared between SCAN and TYPE */
|
||||
if(!type)
|
||||
continue;
|
||||
|
||||
type->totalsize += sizes[i];
|
||||
type->count++;
|
||||
totlen += keys->element[i]->len;
|
||||
sampled++;
|
||||
|
||||
if(type->biggest<sizes[i]) {
|
||||
printf(
|
||||
"[%05.2f%%] Biggest %-6s found so far '%s' with %llu %s\n",
|
||||
pct, type->name, keys->element[i]->str, sizes[i],
|
||||
!memkeys? type->sizeunit: "bytes");
|
||||
|
||||
/* Keep track of biggest key name for this type */
|
||||
if (type->biggest_key)
|
||||
sdsfree(type->biggest_key);
|
||||
type->biggest_key = sdsnew(keys->element[i]->str);
|
||||
if(!type->biggest_key) {
|
||||
fprintf(stderr, "Failed to allocate memory for key!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Keep track of the biggest size for this type */
|
||||
type->biggest = sizes[i];
|
||||
}
|
||||
|
||||
/* Update overall progress */
|
||||
if(sampled % 1000000 == 0) {
|
||||
printf("[%05.2f%%] Sampled %llu keys so far\n", pct, sampled);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sleep if we've been directed to do so */
|
||||
if(sampled && (sampled %100) == 0 && config.interval) {
|
||||
usleep(config.interval);
|
||||
}
|
||||
|
||||
freeReplyObject(reply);
|
||||
} while(it != 0);
|
||||
|
||||
if(types) zfree(types);
|
||||
if(sizes) zfree(sizes);
|
||||
|
||||
/* We're done */
|
||||
printf("\n-------- summary -------\n\n");
|
||||
|
||||
printf("Sampled %llu keys in the keyspace!\n", sampled);
|
||||
printf("Total key length in bytes is %llu (avg len %.2f)\n\n",
|
||||
totlen, totlen ? (double)totlen/sampled : 0);
|
||||
|
||||
/* Output the biggest keys we found, for types we did find */
|
||||
di = dictGetIterator(types_dict);
|
||||
while ((de = dictNext(di))) {
|
||||
typeinfo *type = (typeinfo*)dictGetVal(de);
|
||||
if(type->biggest_key) {
|
||||
printf("Biggest %6s found '%s' has %llu %s\n", type->name, type->biggest_key,
|
||||
type->biggest, !memkeys? type->sizeunit: "bytes");
|
||||
}
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
|
||||
printf("\n");
|
||||
|
||||
di = dictGetIterator(types_dict);
|
||||
while ((de = dictNext(di))) {
|
||||
typeinfo *type = (typeinfo*)dictGetVal(de);
|
||||
printf("%llu %ss with %llu %s (%05.2f%% of keys, avg size %.2f)\n",
|
||||
type->count, type->name, type->totalsize, !memkeys? type->sizeunit: "bytes",
|
||||
sampled ? 100 * (double)type->count/sampled : 0,
|
||||
type->count ? (double)type->totalsize/type->count : 0);
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
|
||||
dictRelease(types_dict);
|
||||
|
||||
/* Success! */
|
||||
exit(0);
|
||||
}
|
||||
+47
-1151
File diff suppressed because it is too large.
Load diff
+279
@@ -0,0 +1,279 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define UNUSED(V) ((void) V)
|
||||
|
||||
#define OUTPUT_STANDARD 0
|
||||
#define OUTPUT_RAW 1
|
||||
#define OUTPUT_CSV 2
|
||||
#define REDIS_CLI_KEEPALIVE_INTERVAL 15 /* seconds */
|
||||
#define REDIS_CLI_DEFAULT_PIPE_TIMEOUT 30 /* seconds */
|
||||
#define REDIS_CLI_HISTFILE_ENV "REDISCLI_HISTFILE"
|
||||
#define REDIS_CLI_HISTFILE_DEFAULT ".rediscli_history"
|
||||
#define REDIS_CLI_RCFILE_ENV "REDISCLI_RCFILE"
|
||||
#define REDIS_CLI_RCFILE_DEFAULT ".redisclirc"
|
||||
#define REDIS_CLI_AUTH_ENV "REDISCLI_AUTH"
|
||||
|
||||
#define CLUSTER_MANAGER_SLOTS 16384
|
||||
#define CLUSTER_MANAGER_MIGRATE_TIMEOUT 60000
|
||||
#define CLUSTER_MANAGER_MIGRATE_PIPELINE 10
|
||||
#define CLUSTER_MANAGER_REBALANCE_THRESHOLD 2
|
||||
|
||||
#define CLUSTER_MANAGER_INVALID_HOST_ARG \
|
||||
"[ERR] Invalid arguments: you need to pass either a valid " \
|
||||
"address (ie. 120.0.0.1:7000) or space separated IP " \
|
||||
"and port (ie. 120.0.0.1 7000)\n"
|
||||
#define CLUSTER_MANAGER_MODE() (config.cluster_manager_command.name != NULL)
|
||||
#define CLUSTER_MANAGER_MASTERS_COUNT(nodes, replicas) (nodes/(replicas + 1))
|
||||
#define CLUSTER_MANAGER_COMMAND(n,...) \
|
||||
(redisCommand(n->context, __VA_ARGS__))
|
||||
|
||||
#define CLUSTER_MANAGER_NODE_ARRAY_FREE(array) zfree(array->alloc)
|
||||
|
||||
#define CLUSTER_MANAGER_PRINT_REPLY_ERROR(n, err) \
|
||||
clusterManagerLogErr("Node %s:%d replied with error:\n%s\n", \
|
||||
n->ip, n->port, err);
|
||||
|
||||
#define clusterManagerLogInfo(...) \
|
||||
clusterManagerLog(CLUSTER_MANAGER_LOG_LVL_INFO,__VA_ARGS__)
|
||||
|
||||
#define clusterManagerLogErr(...) \
|
||||
clusterManagerLog(CLUSTER_MANAGER_LOG_LVL_ERR,__VA_ARGS__)
|
||||
|
||||
#define clusterManagerLogWarn(...) \
|
||||
clusterManagerLog(CLUSTER_MANAGER_LOG_LVL_WARN,__VA_ARGS__)
|
||||
|
||||
#define clusterManagerLogOk(...) \
|
||||
clusterManagerLog(CLUSTER_MANAGER_LOG_LVL_SUCCESS,__VA_ARGS__)
|
||||
|
||||
#define CLUSTER_MANAGER_FLAG_MYSELF 1 << 0
|
||||
#define CLUSTER_MANAGER_FLAG_SLAVE 1 << 1
|
||||
#define CLUSTER_MANAGER_FLAG_FRIEND 1 << 2
|
||||
#define CLUSTER_MANAGER_FLAG_NOADDR 1 << 3
|
||||
#define CLUSTER_MANAGER_FLAG_DISCONNECT 1 << 4
|
||||
#define CLUSTER_MANAGER_FLAG_FAIL 1 << 5
|
||||
|
||||
#define CLUSTER_MANAGER_CMD_FLAG_FIX 1 << 0
|
||||
#define CLUSTER_MANAGER_CMD_FLAG_SLAVE 1 << 1
|
||||
#define CLUSTER_MANAGER_CMD_FLAG_YES 1 << 2
|
||||
#define CLUSTER_MANAGER_CMD_FLAG_AUTOWEIGHTS 1 << 3
|
||||
#define CLUSTER_MANAGER_CMD_FLAG_EMPTYMASTER 1 << 4
|
||||
#define CLUSTER_MANAGER_CMD_FLAG_SIMULATE 1 << 5
|
||||
#define CLUSTER_MANAGER_CMD_FLAG_REPLACE 1 << 6
|
||||
#define CLUSTER_MANAGER_CMD_FLAG_COPY 1 << 7
|
||||
#define CLUSTER_MANAGER_CMD_FLAG_COLOR 1 << 8
|
||||
#define CLUSTER_MANAGER_CMD_FLAG_CHECK_OWNERS 1 << 9
|
||||
|
||||
#define CLUSTER_MANAGER_OPT_GETFRIENDS 1 << 0
|
||||
#define CLUSTER_MANAGER_OPT_COLD 1 << 1
|
||||
#define CLUSTER_MANAGER_OPT_UPDATE 1 << 2
|
||||
#define CLUSTER_MANAGER_OPT_QUIET 1 << 6
|
||||
#define CLUSTER_MANAGER_OPT_VERBOSE 1 << 7
|
||||
|
||||
#define CLUSTER_MANAGER_LOG_LVL_INFO 1
|
||||
#define CLUSTER_MANAGER_LOG_LVL_WARN 2
|
||||
#define CLUSTER_MANAGER_LOG_LVL_ERR 3
|
||||
#define CLUSTER_MANAGER_LOG_LVL_SUCCESS 4
|
||||
|
||||
#define CLUSTER_JOIN_CHECK_AFTER 20
|
||||
|
||||
#define LOG_COLOR_BOLD "29;1m"
|
||||
#define LOG_COLOR_RED "31;1m"
|
||||
#define LOG_COLOR_GREEN "32;1m"
|
||||
#define LOG_COLOR_YELLOW "33;1m"
|
||||
#define LOG_COLOR_RESET "0m"
|
||||
|
||||
/* cliConnect() flags. */
|
||||
#define CC_FORCE (1<<0) /* Re-connect if already connected. */
|
||||
#define CC_QUIET (1<<1) /* Don't log connecting errors. */
|
||||
|
||||
struct clusterManagerLink;
|
||||
typedef struct clusterManagerLink clusterManagerLink;
|
||||
|
||||
/* Dict Helpers */
|
||||
|
||||
uint64_t dictSdsHash(const void *key);
|
||||
int dictSdsKeyCompare(void *privdata, const void *key1,
|
||||
const void *key2);
|
||||
void dictSdsDestructor(void *privdata, void *val);
|
||||
void dictListDestructor(void *privdata, void *val);
|
||||
|
||||
/* Cluster Manager Command Info */
|
||||
typedef struct clusterManagerCommand {
|
||||
char *name;
|
||||
int argc;
|
||||
char **argv;
|
||||
int flags;
|
||||
int replicas;
|
||||
char *from;
|
||||
char *to;
|
||||
char **weight;
|
||||
int weight_argc;
|
||||
char *master_id;
|
||||
int slots;
|
||||
int timeout;
|
||||
int pipeline;
|
||||
float threshold;
|
||||
char *backup_dir;
|
||||
} clusterManagerCommand;
|
||||
|
||||
void createClusterManagerCommand(char *cmdname, int argc, char **argv);
|
||||
|
||||
extern redisContext *context;
|
||||
extern struct config {
|
||||
char *hostip;
|
||||
int hostport;
|
||||
char *hostsocket;
|
||||
long repeat;
|
||||
long interval;
|
||||
int dbnum;
|
||||
int interactive;
|
||||
int shutdown;
|
||||
int monitor_mode;
|
||||
int pubsub_mode;
|
||||
int latency_mode;
|
||||
int latency_dist_mode;
|
||||
int latency_history;
|
||||
int lru_test_mode;
|
||||
long long lru_test_sample_size;
|
||||
int cluster_mode;
|
||||
int cluster_reissue_command;
|
||||
int slave_mode;
|
||||
int pipe_mode;
|
||||
int pipe_timeout;
|
||||
int getrdb_mode;
|
||||
int stat_mode;
|
||||
int scan_mode;
|
||||
int intrinsic_latency_mode;
|
||||
int intrinsic_latency_duration;
|
||||
char *pattern;
|
||||
char *rdb_filename;
|
||||
int bigkeys;
|
||||
int memkeys;
|
||||
unsigned memkeys_samples;
|
||||
int hotkeys;
|
||||
int stdinarg; /* get last arg from stdin. (-x option) */
|
||||
char *auth;
|
||||
int output; /* output mode, see OUTPUT_* defines */
|
||||
sds mb_delim;
|
||||
char prompt[128];
|
||||
char *eval;
|
||||
int eval_ldb;
|
||||
int eval_ldb_sync; /* Ask for synchronous mode of the Lua debugger. */
|
||||
int eval_ldb_end; /* Lua debugging session ended. */
|
||||
int enable_ldb_on_eval; /* Handle manual SCRIPT DEBUG + EVAL commands. */
|
||||
int last_cmd_type;
|
||||
int verbose;
|
||||
clusterManagerCommand cluster_manager_command;
|
||||
int no_auth_warning;
|
||||
} config;
|
||||
|
||||
/* The Cluster Manager global structure */
|
||||
extern struct clusterManager {
|
||||
list *nodes; /* List of nodes in the configuration. */
|
||||
list *errors;
|
||||
} cluster_manager;
|
||||
|
||||
typedef struct clusterManagerNode {
|
||||
redisContext *context;
|
||||
sds name;
|
||||
char *ip;
|
||||
int port;
|
||||
uint64_t current_epoch;
|
||||
time_t ping_sent;
|
||||
time_t ping_recv;
|
||||
int flags;
|
||||
list *flags_str; /* Flags string representations */
|
||||
sds replicate; /* Master ID if node is a slave */
|
||||
int dirty; /* Node has changes that can be flushed */
|
||||
uint8_t slots[CLUSTER_MANAGER_SLOTS];
|
||||
int slots_count;
|
||||
int replicas_count;
|
||||
list *friends;
|
||||
sds *migrating; /* An array of sds where even strings are slots and odd
|
||||
* strings are the destination node IDs. */
|
||||
sds *importing; /* An array of sds where even strings are slots and odd
|
||||
* strings are the source node IDs. */
|
||||
int migrating_count; /* Length of the migrating array (migrating slots*2) */
|
||||
int importing_count; /* Length of the importing array (importing slots*2) */
|
||||
float weight; /* Weight used by rebalance */
|
||||
int balance; /* Used by rebalance */
|
||||
} clusterManagerNode;
|
||||
|
||||
/* Data structure used to represent a sequence of cluster nodes. */
|
||||
typedef struct clusterManagerNodeArray {
|
||||
clusterManagerNode **nodes; /* Actual nodes array */
|
||||
clusterManagerNode **alloc; /* Pointer to the allocated memory */
|
||||
int len; /* Actual length of the array */
|
||||
int count; /* Non-NULL nodes count */
|
||||
} clusterManagerNodeArray;
|
||||
|
||||
/* Used for the reshard table. */
|
||||
typedef struct clusterManagerReshardTableItem {
|
||||
clusterManagerNode *source;
|
||||
int slot;
|
||||
} clusterManagerReshardTableItem;
|
||||
|
||||
typedef struct typeinfo {
|
||||
char *name;
|
||||
char *sizecmd;
|
||||
char *sizeunit;
|
||||
unsigned long long biggest;
|
||||
unsigned long long count;
|
||||
unsigned long long totalsize;
|
||||
sds biggest_key;
|
||||
} typeinfo;
|
||||
|
||||
extern typeinfo type_string;
|
||||
extern typeinfo type_list;
|
||||
extern typeinfo type_set;
|
||||
extern typeinfo type_hash;
|
||||
extern typeinfo type_zset;
|
||||
extern typeinfo type_stream;
|
||||
extern typeinfo type_other;
|
||||
|
||||
void findBigKeys(int memkeys, unsigned memkeys_samples);
|
||||
int clusterManagerGetAntiAffinityScore(clusterManagerNodeArray *ipnodes,
|
||||
int ip_count, clusterManagerNode ***offending, int *offending_len);
|
||||
int clusterManagerFixMultipleSlotOwners(int slot, list *owners);
|
||||
void getKeySizes(redisReply *keys, struct typeinfo **types,
|
||||
unsigned long long *sizes, int memkeys,
|
||||
unsigned memkeys_samples);
|
||||
int clusterManagerFixOpenSlot(int slot);
|
||||
void clusterManagerPrintSlotsList(list *slots);
|
||||
int clusterManagerGetCoveredSlots(char *all_slots);
|
||||
void clusterManagerOnError(sds err);
|
||||
int clusterManagerIsConfigConsistent(void);
|
||||
void freeClusterManagerNode(clusterManagerNode *node);
|
||||
void clusterManagerLog(int level, const char* fmt, ...);
|
||||
int parseClusterNodeAddress(char *addr, char **ip_ptr, int *port_ptr,
|
||||
int *bus_port_ptr);
|
||||
int clusterManagerCheckRedisReply(clusterManagerNode *n,
|
||||
redisReply *r, char **err);
|
||||
int confirmWithYes(const char *msg);
|
||||
int clusterManagerSetSlotOwner(clusterManagerNode *owner,
|
||||
int slot,
|
||||
int do_clear);
|
||||
clusterManagerNode * clusterManagerGetNodeWithMostKeysInSlot(list *nodes,
|
||||
int slot,
|
||||
char **err);
|
||||
int clusterManagerSetSlot(clusterManagerNode *node1,
|
||||
clusterManagerNode *node2,
|
||||
int slot, const char *status, char **err);
|
||||
int clusterManagerMoveSlot(clusterManagerNode *source,
|
||||
clusterManagerNode *target,
|
||||
int slot, int opts, char**err);
|
||||
int clusterManagerClearSlotStatus(clusterManagerNode *node, int slot);
|
||||
void clusterManagerShowNodes(void);
|
||||
signed int clusterManagerCountKeysInSlot(clusterManagerNode *node,
|
||||
int slot);
|
||||
void type_free(void* priv_data, void* val);
|
||||
int getDbSize(void);
|
||||
redisReply *sendScan(unsigned long long *it);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
+9
-1
@@ -40,10 +40,18 @@
|
||||
|
||||
#include <unistd.h> /* for _exit() */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define assert(_e) ((_e)?(void)0 : (_serverAssert(#_e,__FILE__,__LINE__),_exit(1)))
|
||||
#define panic(...) _serverPanic(__FILE__,__LINE__,__VA_ARGS__),_exit(1)
|
||||
|
||||
void _serverAssert(char *estr, char *file, int line);
|
||||
void _serverAssert(const char *estr, const char *file, int line);
|
||||
void _serverPanic(const char *file, int line, const char *msg, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+26
-1
@@ -98,7 +98,8 @@
|
||||
#define REDISMODULE_NOTIFY_EXPIRED (1<<8) /* x */
|
||||
#define REDISMODULE_NOTIFY_EVICTED (1<<9) /* e */
|
||||
#define REDISMODULE_NOTIFY_STREAM (1<<10) /* t */
|
||||
#define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED | REDISMODULE_NOTIFY_STREAM) /* A */
|
||||
#define REDISMODULE_NOTIFY_KEY_MISS (1<<11) /* m */
|
||||
#define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED | REDISMODULE_NOTIFY_STREAM | REDISMODULE_NOTIFY_KEY_MISS) /* A */
|
||||
|
||||
|
||||
/* A special pointer that we can use between the core and the module to signal
|
||||
@@ -132,6 +133,11 @@
|
||||
* of timers that are going to expire, sorted by expire time. */
|
||||
typedef uint64_t RedisModuleTimerID;
|
||||
|
||||
/* CommandFilter Flags */
|
||||
|
||||
/* Do filter RedisModule_Call() commands initiated by module itself. */
|
||||
#define REDISMODULE_CMDFILTER_NOSELF (1<<0)
|
||||
|
||||
/* ------------------------- End of common defines ------------------------ */
|
||||
|
||||
#ifndef REDISMODULE_CORE
|
||||
@@ -150,6 +156,8 @@ typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
|
||||
typedef struct RedisModuleClusterInfo RedisModuleClusterInfo;
|
||||
typedef struct RedisModuleDict RedisModuleDict;
|
||||
typedef struct RedisModuleDictIter RedisModuleDictIter;
|
||||
typedef struct RedisModuleCommandFilterCtx RedisModuleCommandFilterCtx;
|
||||
typedef struct RedisModuleCommandFilter RedisModuleCommandFilter;
|
||||
|
||||
typedef int (*RedisModuleCmdFunc)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
|
||||
typedef void (*RedisModuleDisconnectFunc)(RedisModuleCtx *ctx, RedisModuleBlockedClient *bc);
|
||||
@@ -162,6 +170,7 @@ typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value
|
||||
typedef void (*RedisModuleTypeFreeFunc)(void *value);
|
||||
typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const char *sender_id, uint8_t type, const unsigned char *payload, uint32_t len);
|
||||
typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data);
|
||||
typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCommandFilterCtx *filter);
|
||||
|
||||
#define REDISMODULE_TYPE_METHOD_VERSION 1
|
||||
typedef struct RedisModuleTypeMethods {
|
||||
@@ -278,6 +287,7 @@ int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, Re
|
||||
void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b);
|
||||
RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io);
|
||||
const RedisModuleString *REDISMODULE_API_FUNC(RedisModule_GetKeyNameFromIO)(RedisModuleIO *io);
|
||||
long long REDISMODULE_API_FUNC(RedisModule_Milliseconds)(void);
|
||||
void REDISMODULE_API_FUNC(RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele);
|
||||
@@ -337,6 +347,13 @@ void REDISMODULE_API_FUNC(RedisModule_SetDisconnectCallback)(RedisModuleBlockedC
|
||||
void REDISMODULE_API_FUNC(RedisModule_SetClusterFlags)(RedisModuleCtx *ctx, uint64_t flags);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ExportSharedAPI)(RedisModuleCtx *ctx, const char *apiname, void *func);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_GetSharedAPI)(RedisModuleCtx *ctx, const char *apiname);
|
||||
RedisModuleCommandFilter *REDISMODULE_API_FUNC(RedisModule_RegisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilterFunc cb, int flags);
|
||||
int REDISMODULE_API_FUNC(RedisModule_UnregisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilter *filter);
|
||||
int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgsCount)(RedisModuleCommandFilterCtx *fctx);
|
||||
const RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CommandFilterArgGet)(RedisModuleCommandFilterCtx *fctx, int pos);
|
||||
int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgInsert)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg);
|
||||
int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgReplace)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg);
|
||||
int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgDelete)(RedisModuleCommandFilterCtx *fctx, int pos);
|
||||
#endif
|
||||
|
||||
/* This is included inline inside each Redis module. */
|
||||
@@ -442,6 +459,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
|
||||
REDISMODULE_GET_API(RetainString);
|
||||
REDISMODULE_GET_API(StringCompare);
|
||||
REDISMODULE_GET_API(GetContextFromIO);
|
||||
REDISMODULE_GET_API(GetKeyNameFromIO);
|
||||
REDISMODULE_GET_API(Milliseconds);
|
||||
REDISMODULE_GET_API(DigestAddStringBuffer);
|
||||
REDISMODULE_GET_API(DigestAddLongLong);
|
||||
@@ -499,6 +517,13 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
|
||||
REDISMODULE_GET_API(SetClusterFlags);
|
||||
REDISMODULE_GET_API(ExportSharedAPI);
|
||||
REDISMODULE_GET_API(GetSharedAPI);
|
||||
REDISMODULE_GET_API(RegisterCommandFilter);
|
||||
REDISMODULE_GET_API(UnregisterCommandFilter);
|
||||
REDISMODULE_GET_API(CommandFilterArgsCount);
|
||||
REDISMODULE_GET_API(CommandFilterArgGet);
|
||||
REDISMODULE_GET_API(CommandFilterArgInsert);
|
||||
REDISMODULE_GET_API(CommandFilterArgReplace);
|
||||
REDISMODULE_GET_API(CommandFilterArgDelete);
|
||||
#endif
|
||||
|
||||
if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR;
|
||||
|
||||
+806
-435
File diff suppressed because it is too large.
Load diff
@@ -266,8 +266,8 @@ void rioInitWithFdset(rio *r, int *fds, int numfds) {
|
||||
int j;
|
||||
|
||||
*r = rioFdsetIO;
|
||||
r->io.fdset.fds = zmalloc(sizeof(int)*numfds, MALLOC_LOCAL);
|
||||
r->io.fdset.state = zmalloc(sizeof(int)*numfds, MALLOC_LOCAL);
|
||||
r->io.fdset.fds = (int*)zmalloc(sizeof(int)*numfds, MALLOC_LOCAL);
|
||||
r->io.fdset.state = (int*)zmalloc(sizeof(int)*numfds, MALLOC_LOCAL);
|
||||
memcpy(r->io.fdset.fds,fds,sizeof(int)*numfds);
|
||||
for (j = 0; j < numfds; j++) r->io.fdset.state[j] = 0;
|
||||
r->io.fdset.numfds = numfds;
|
||||
@@ -287,7 +287,7 @@ void rioFreeFdset(rio *r) {
|
||||
/* This function can be installed both in memory and file streams when checksum
|
||||
* computation is needed. */
|
||||
void rioGenericUpdateChecksum(rio *r, const void *buf, size_t len) {
|
||||
r->cksum = crc64(r->cksum,buf,len);
|
||||
r->cksum = crc64(r->cksum,(const unsigned char*)buf,len);
|
||||
}
|
||||
|
||||
/* Set the file-based rio object to auto-fsync every 'bytes' file written.
|
||||
@@ -36,6 +36,10 @@
|
||||
#include <stdint.h>
|
||||
#include "sds.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _rio {
|
||||
/* Backend functions.
|
||||
* Since this functions do not tolerate short writes or reads the return
|
||||
@@ -141,4 +145,8 @@ int rioWriteBulkObject(rio *r, struct redisObject *obj);
|
||||
void rioGenericUpdateChecksum(rio *r, const void *buf, size_t len);
|
||||
void rioSetAutoSync(rio *r, off_t bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+16
-4
@@ -474,6 +474,11 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
|
||||
c->argc = argc;
|
||||
c->puser = server.lua_caller->puser;
|
||||
|
||||
/* Process module hooks */
|
||||
moduleCallCommandFilters(c);
|
||||
argv = c->argv;
|
||||
argc = c->argc;
|
||||
|
||||
/* Log the command if debugging is active. */
|
||||
if (ldb.active && ldb.step) {
|
||||
sds cmdlog = sdsnew("<redis>");
|
||||
@@ -532,7 +537,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
|
||||
luaPushError(lua,
|
||||
"Write commands not allowed after non deterministic commands. Call redis.replicate_commands() at the start of your script in order to switch to single commands replication mode.");
|
||||
goto cleanup;
|
||||
} else if (server.masterhost && server.repl_slave_ro &&
|
||||
} else if (listLength(server.masters) && server.repl_slave_ro &&
|
||||
!server.loading &&
|
||||
!(server.lua_caller->flags & CLIENT_MASTER))
|
||||
{
|
||||
@@ -558,7 +563,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
|
||||
* in the middle. */
|
||||
if (server.maxmemory && /* Maxmemory is actually enabled. */
|
||||
!server.loading && /* Don't care about mem if loading. */
|
||||
!server.masterhost && /* Slave must execute the script. */
|
||||
!listLength(server.masters) && /* Slave must execute the script. */
|
||||
server.lua_write_dirty == 0 && /* Script had no side effects so far. */
|
||||
(cmd->flags & CMD_DENYOOM))
|
||||
{
|
||||
@@ -1420,8 +1425,15 @@ void evalGenericCommand(client *c, int evalsha) {
|
||||
/* Restore the client that was protected when the script timeout
|
||||
* was detected. */
|
||||
unprotectClient(c);
|
||||
if (server.masterhost && server.master)
|
||||
queueClientForReprocessing(server.master);
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(server.masters, &li);
|
||||
while ((ln = listNext(&li)))
|
||||
{
|
||||
struct redisMaster *mi = (struct redisMaster*)listNodeValue(ln);
|
||||
if (mi->master)
|
||||
queueClientForReprocessing(mi->master);
|
||||
}
|
||||
}
|
||||
server.lua_caller = NULL;
|
||||
|
||||
|
||||
@@ -1089,7 +1089,7 @@ sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
|
||||
|
||||
/* Join an array of C strings using the specified separator (also a C string).
|
||||
* Returns the result as an sds string. */
|
||||
sds sdsjoin(char **argv, int argc, char *sep) {
|
||||
sds sdsjoin(char **argv, int argc, const char *sep) {
|
||||
sds join = sdsempty();
|
||||
int j;
|
||||
|
||||
|
||||
@@ -60,6 +60,10 @@ struct __attribute__ ((__packed__)) sdshdr8 {
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
#ifndef __cplusplus
|
||||
char buf[];
|
||||
#else
|
||||
char *buf() {
|
||||
return reinterpret_cast<char*>(this+1);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr16 {
|
||||
@@ -98,7 +102,7 @@ struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
||||
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||
|
||||
inline size_t sdslen(const sds s) {
|
||||
static inline size_t sdslen(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
int type = flags & SDS_TYPE_MASK;
|
||||
|
||||
@@ -270,7 +274,7 @@ sds sdsfromlonglong(long long value);
|
||||
sds sdscatrepr(sds s, const char *p, size_t len);
|
||||
sds *sdssplitargs(const char *line, int *argc);
|
||||
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
|
||||
sds sdsjoin(char **argv, int argc, char *sep);
|
||||
sds sdsjoin(char **argv, int argc, const char *sep);
|
||||
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
|
||||
|
||||
/* Low level functions exposed to the user API */
|
||||
|
||||
+116
-116
@@ -375,7 +375,7 @@ sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master);
|
||||
void sentinelScheduleScriptExecution(char *path, ...);
|
||||
void sentinelStartFailover(sentinelRedisInstance *master);
|
||||
void sentinelDiscardReplyCallback(redisAsyncContext *c, void *reply, void *privdata);
|
||||
int sentinelSendSlaveOf(sentinelRedisInstance *ri, char *host, int port);
|
||||
int sentinelSendSlaveOf(sentinelRedisInstance *ri, const char *host, int port);
|
||||
char *sentinelVoteLeader(sentinelRedisInstance *master, uint64_t req_epoch, char *req_runid, uint64_t *leader_epoch);
|
||||
void sentinelFlushConfig(void);
|
||||
void sentinelGenerateInitialMonitorEvents(void);
|
||||
@@ -394,7 +394,7 @@ void releaseSentinelRedisInstance(sentinelRedisInstance *ri);
|
||||
|
||||
void dictInstancesValDestructor (void *privdata, void *obj) {
|
||||
UNUSED(privdata);
|
||||
releaseSentinelRedisInstance(obj);
|
||||
releaseSentinelRedisInstance((sentinelRedisInstance*)obj);
|
||||
}
|
||||
|
||||
/* Instance name (sds) -> instance (sentinelRedisInstance pointer)
|
||||
@@ -554,7 +554,7 @@ sentinelAddr *createSentinelAddr(char *hostname, int port) {
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
sa = zmalloc(sizeof(*sa), MALLOC_LOCAL);
|
||||
sa = (sentinelAddr*)zmalloc(sizeof(*sa), MALLOC_LOCAL);
|
||||
sa->ip = sdsnew(ip);
|
||||
sa->port = port;
|
||||
return sa;
|
||||
@@ -564,7 +564,7 @@ sentinelAddr *createSentinelAddr(char *hostname, int port) {
|
||||
sentinelAddr *dupSentinelAddr(sentinelAddr *src) {
|
||||
sentinelAddr *sa;
|
||||
|
||||
sa = zmalloc(sizeof(*sa), MALLOC_LOCAL);
|
||||
sa = (sentinelAddr*)zmalloc(sizeof(*sa), MALLOC_LOCAL);
|
||||
sa->ip = sdsnew(src->ip);
|
||||
sa->port = src->port;
|
||||
return sa;
|
||||
@@ -607,7 +607,7 @@ int sentinelAddrIsEqual(sentinelAddr *a, sentinelAddr *b) {
|
||||
*
|
||||
* Any other specifier after "%@" is processed by printf itself.
|
||||
*/
|
||||
void sentinelEvent(int level, char *type, sentinelRedisInstance *ri,
|
||||
void sentinelEvent(int level, const char *type, sentinelRedisInstance *ri,
|
||||
const char *fmt, ...) {
|
||||
va_list ap;
|
||||
char msg[LOG_MAX_LEN];
|
||||
@@ -674,7 +674,7 @@ void sentinelGenerateInitialMonitorEvents(void) {
|
||||
|
||||
di = dictGetIterator(sentinel.masters);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
sentinelEvent(LL_WARNING,"+monitor",ri,"%@ quorum %d",ri->quorum);
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
@@ -708,10 +708,10 @@ void sentinelScheduleScriptExecution(char *path, ...) {
|
||||
va_end(ap);
|
||||
argv[0] = sdsnew(path);
|
||||
|
||||
sj = zmalloc(sizeof(*sj), MALLOC_LOCAL);
|
||||
sj = (sentinelScriptJob*)zmalloc(sizeof(*sj), MALLOC_LOCAL);
|
||||
sj->flags = SENTINEL_SCRIPT_NONE;
|
||||
sj->retry_num = 0;
|
||||
sj->argv = zmalloc(sizeof(char*)*(argc+1), MALLOC_LOCAL);
|
||||
sj->argv = (char**)zmalloc(sizeof(char*)*(argc+1), MALLOC_LOCAL);
|
||||
sj->start_time = 0;
|
||||
sj->pid = 0;
|
||||
memcpy(sj->argv,argv,sizeof(char*)*(argc+1));
|
||||
@@ -725,7 +725,7 @@ void sentinelScheduleScriptExecution(char *path, ...) {
|
||||
|
||||
listRewind(sentinel.scripts_queue,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
sj = ln->value;
|
||||
sj = (sentinelScriptJob*)ln->value;
|
||||
|
||||
if (sj->flags & SENTINEL_SCRIPT_RUNNING) continue;
|
||||
/* The first node is the oldest as we add on tail. */
|
||||
@@ -746,7 +746,7 @@ listNode *sentinelGetScriptListNodeByPid(pid_t pid) {
|
||||
|
||||
listRewind(sentinel.scripts_queue,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
sentinelScriptJob *sj = ln->value;
|
||||
sentinelScriptJob *sj = (sentinelScriptJob*)ln->value;
|
||||
|
||||
if ((sj->flags & SENTINEL_SCRIPT_RUNNING) && sj->pid == pid)
|
||||
return ln;
|
||||
@@ -767,7 +767,7 @@ void sentinelRunPendingScripts(void) {
|
||||
while (sentinel.running_scripts < SENTINEL_SCRIPT_MAX_RUNNING &&
|
||||
(ln = listNext(&li)) != NULL)
|
||||
{
|
||||
sentinelScriptJob *sj = ln->value;
|
||||
sentinelScriptJob *sj = (sentinelScriptJob*)ln->value;
|
||||
pid_t pid;
|
||||
|
||||
/* Skip if already running. */
|
||||
@@ -839,7 +839,7 @@ void sentinelCollectTerminatedScripts(void) {
|
||||
serverLog(LL_WARNING,"wait3() returned a pid (%ld) we can't find in our scripts execution queue!", (long)pid);
|
||||
continue;
|
||||
}
|
||||
sj = ln->value;
|
||||
sj = (sentinelScriptJob*)ln->value;
|
||||
|
||||
/* If the script was terminated by a signal or returns an
|
||||
* exit code of "1" (that means: please retry), we reschedule it
|
||||
@@ -874,7 +874,7 @@ void sentinelKillTimedoutScripts(void) {
|
||||
|
||||
listRewind(sentinel.scripts_queue,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
sentinelScriptJob *sj = ln->value;
|
||||
sentinelScriptJob *sj = (sentinelScriptJob*)ln->value;
|
||||
|
||||
if (sj->flags & SENTINEL_SCRIPT_RUNNING &&
|
||||
(now - sj->start_time) > SENTINEL_SCRIPT_MAX_RUNTIME)
|
||||
@@ -894,7 +894,7 @@ void sentinelPendingScriptsCommand(client *c) {
|
||||
addReplyArrayLen(c,listLength(sentinel.scripts_queue));
|
||||
listRewind(sentinel.scripts_queue,&li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
sentinelScriptJob *sj = ln->value;
|
||||
sentinelScriptJob *sj = (sentinelScriptJob*)ln->value;
|
||||
int j = 0;
|
||||
|
||||
addReplyMapLen(c,5);
|
||||
@@ -939,7 +939,7 @@ void sentinelPendingScriptsCommand(client *c) {
|
||||
*
|
||||
* from/to fields are respectively master -> promoted slave addresses for
|
||||
* "start" and "end". */
|
||||
void sentinelCallClientReconfScript(sentinelRedisInstance *master, int role, char *state, sentinelAddr *from, sentinelAddr *to) {
|
||||
void sentinelCallClientReconfScript(sentinelRedisInstance *master, int role, const char *state, sentinelAddr *from, sentinelAddr *to) {
|
||||
char fromport[32], toport[32];
|
||||
|
||||
if (master->client_reconfig_script == NULL) return;
|
||||
@@ -955,7 +955,7 @@ void sentinelCallClientReconfScript(sentinelRedisInstance *master, int role, cha
|
||||
|
||||
/* Create a not yet connected link object. */
|
||||
instanceLink *createInstanceLink(void) {
|
||||
instanceLink *link = zmalloc(sizeof(*link), MALLOC_LOCAL);
|
||||
instanceLink *link = (instanceLink*)zmalloc(sizeof(*link), MALLOC_LOCAL);
|
||||
|
||||
link->refcount = 1;
|
||||
link->disconnected = 1;
|
||||
@@ -1053,7 +1053,7 @@ int sentinelTryConnectionSharing(sentinelRedisInstance *ri) {
|
||||
|
||||
di = dictGetIterator(sentinel.masters);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *master = dictGetVal(de), *match;
|
||||
sentinelRedisInstance *master = (sentinelRedisInstance*)dictGetVal(de), *match;
|
||||
/* We want to share with the same physical Sentinel referenced
|
||||
* in other masters, so skip our master. */
|
||||
if (master == ri->master) continue;
|
||||
@@ -1087,7 +1087,7 @@ int sentinelUpdateSentinelAddressInAllMasters(sentinelRedisInstance *ri) {
|
||||
|
||||
di = dictGetIterator(sentinel.masters);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *master = dictGetVal(de), *match;
|
||||
sentinelRedisInstance *master = (sentinelRedisInstance*)dictGetVal(de), *match;
|
||||
match = getSentinelRedisInstanceByAddrAndRunID(master->sentinels,
|
||||
NULL,0,ri->runid);
|
||||
/* If there is no match, this master does not know about this
|
||||
@@ -1122,7 +1122,7 @@ int sentinelUpdateSentinelAddressInAllMasters(sentinelRedisInstance *ri) {
|
||||
* Note: we don't free the hiredis context as hiredis will do it for us
|
||||
* for async connections. */
|
||||
void instanceLinkConnectionError(const redisAsyncContext *c) {
|
||||
instanceLink *link = c->data;
|
||||
instanceLink *link = (instanceLink*)c->data;
|
||||
int pubsub;
|
||||
|
||||
if (!link) return;
|
||||
@@ -1205,7 +1205,7 @@ sentinelRedisInstance *createSentinelRedisInstance(char *name, int flags, char *
|
||||
}
|
||||
|
||||
/* Create the instance object. */
|
||||
ri = zmalloc(sizeof(*ri), MALLOC_LOCAL);
|
||||
ri = (sentinelRedisInstance*)zmalloc(sizeof(*ri), MALLOC_LOCAL);
|
||||
/* Note that all the instances are started in the disconnected state,
|
||||
* the event loop will take care of connecting them. */
|
||||
ri->flags = flags;
|
||||
@@ -1303,7 +1303,7 @@ sentinelRedisInstance *sentinelRedisInstanceLookupSlave(
|
||||
serverAssert(ri->flags & SRI_MASTER);
|
||||
anetFormatAddr(buf,sizeof(buf),ip,port);
|
||||
key = sdsnew(buf);
|
||||
slave = dictFetchValue(ri->slaves,key);
|
||||
slave = (sentinelRedisInstance*)dictFetchValue(ri->slaves,key);
|
||||
sdsfree(key);
|
||||
return slave;
|
||||
}
|
||||
@@ -1336,7 +1336,7 @@ int removeMatchingSentinelFromMaster(sentinelRedisInstance *master, char *runid)
|
||||
|
||||
di = dictGetSafeIterator(master->sentinels);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
if (ri->runid && strcmp(ri->runid,runid) == 0) {
|
||||
dictDelete(master->sentinels,ri->name);
|
||||
@@ -1361,7 +1361,7 @@ sentinelRedisInstance *getSentinelRedisInstanceByAddrAndRunID(dict *instances, c
|
||||
serverAssert(ip || runid); /* User must pass at least one search param. */
|
||||
di = dictGetIterator(instances);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
if (runid && !ri->runid) continue;
|
||||
if ((runid == NULL || strcmp(ri->runid, runid) == 0) &&
|
||||
@@ -1381,7 +1381,7 @@ sentinelRedisInstance *sentinelGetMasterByName(char *name) {
|
||||
sentinelRedisInstance *ri;
|
||||
sds sdsname = sdsnew(name);
|
||||
|
||||
ri = dictFetchValue(sentinel.masters,sdsname);
|
||||
ri = (sentinelRedisInstance*)dictFetchValue(sentinel.masters,sdsname);
|
||||
sdsfree(sdsname);
|
||||
return ri;
|
||||
}
|
||||
@@ -1393,7 +1393,7 @@ void sentinelAddFlagsToDictOfRedisInstances(dict *instances, int flags) {
|
||||
|
||||
di = dictGetIterator(instances);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
ri->flags |= flags;
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
@@ -1407,7 +1407,7 @@ void sentinelDelFlagsToDictOfRedisInstances(dict *instances, int flags) {
|
||||
|
||||
di = dictGetIterator(instances);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
ri->flags &= ~flags;
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
@@ -1467,7 +1467,7 @@ int sentinelResetMastersByPattern(char *pattern, int flags) {
|
||||
|
||||
di = dictGetIterator(sentinel.masters);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
if (ri->name) {
|
||||
if (stringmatch(pattern,ri->name,0)) {
|
||||
@@ -1501,10 +1501,10 @@ int sentinelResetMasterAndChangeAddress(sentinelRedisInstance *master, char *ip,
|
||||
* Don't include the one having the address we are switching to. */
|
||||
di = dictGetIterator(master->slaves);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *slave = dictGetVal(de);
|
||||
sentinelRedisInstance *slave = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
if (sentinelAddrIsEqual(slave->addr,newaddr)) continue;
|
||||
slaves = zrealloc(slaves,sizeof(sentinelAddr*)*(numslaves+1), MALLOC_LOCAL);
|
||||
slaves = (sentinelAddr**)zrealloc(slaves,sizeof(sentinelAddr*)*(numslaves+1), MALLOC_LOCAL);
|
||||
slaves[numslaves++] = createSentinelAddr(slave->addr->ip,
|
||||
slave->addr->port);
|
||||
}
|
||||
@@ -1514,7 +1514,7 @@ int sentinelResetMasterAndChangeAddress(sentinelRedisInstance *master, char *ip,
|
||||
* as a slave as well, so that we'll be able to sense / reconfigure
|
||||
* the old master. */
|
||||
if (!sentinelAddrIsEqual(newaddr,master->addr)) {
|
||||
slaves = zrealloc(slaves,sizeof(sentinelAddr*)*(numslaves+1), MALLOC_LOCAL);
|
||||
slaves = (sentinelAddr**)zrealloc(slaves,sizeof(sentinelAddr*)*(numslaves+1), MALLOC_LOCAL);
|
||||
slaves[numslaves++] = createSentinelAddr(master->addr->ip,
|
||||
master->addr->port);
|
||||
}
|
||||
@@ -1584,14 +1584,14 @@ void sentinelPropagateDownAfterPeriod(sentinelRedisInstance *master) {
|
||||
for (j = 0; d[j]; j++) {
|
||||
di = dictGetIterator(d[j]);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
ri->down_after_period = master->down_after_period;
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
}
|
||||
}
|
||||
|
||||
char *sentinelGetInstanceTypeString(sentinelRedisInstance *ri) {
|
||||
const char *sentinelGetInstanceTypeString(sentinelRedisInstance *ri) {
|
||||
if (ri->flags & SRI_MASTER) return "master";
|
||||
else if (ri->flags & SRI_SLAVE) return "slave";
|
||||
else if (ri->flags & SRI_SENTINEL) return "sentinel";
|
||||
@@ -1605,16 +1605,16 @@ char *sentinelGetInstanceTypeString(sentinelRedisInstance *ri) {
|
||||
* we check the one of the master), and map the command that we should send
|
||||
* to the set of renamed commads. However, if the command was not renamed,
|
||||
* we just return "command" itself. */
|
||||
char *sentinelInstanceMapCommand(sentinelRedisInstance *ri, char *command) {
|
||||
const char *sentinelInstanceMapCommand(sentinelRedisInstance *ri, const char *command) {
|
||||
sds sc = sdsnew(command);
|
||||
if (ri->master) ri = ri->master;
|
||||
char *retval = dictFetchValue(ri->renamed_commands, sc);
|
||||
char *retval = (char*)dictFetchValue(ri->renamed_commands, sc);
|
||||
sdsfree(sc);
|
||||
return retval ? retval : command;
|
||||
}
|
||||
|
||||
/* ============================ Config handling ============================= */
|
||||
char *sentinelHandleConfiguration(char **argv, int argc) {
|
||||
const char *sentinelHandleConfiguration(char **argv, int argc) {
|
||||
sentinelRedisInstance *ri;
|
||||
|
||||
if (!strcasecmp(argv[0],"monitor") && argc == 5) {
|
||||
@@ -1781,7 +1781,7 @@ void rewriteConfigSentinelOption(struct rewriteConfigState *state) {
|
||||
sentinelAddr *master_addr;
|
||||
|
||||
/* sentinel monitor */
|
||||
master = dictGetVal(de);
|
||||
master = (sentinelRedisInstance*)dictGetVal(de);
|
||||
master_addr = sentinelGetCurrentMasterAddress(master);
|
||||
line = sdscatprintf(sdsempty(),"sentinel monitor %s %s %d %d",
|
||||
master->name, master_addr->ip, master_addr->port,
|
||||
@@ -1853,7 +1853,7 @@ void rewriteConfigSentinelOption(struct rewriteConfigState *state) {
|
||||
while((de = dictNext(di2)) != NULL) {
|
||||
sentinelAddr *slave_addr;
|
||||
|
||||
ri = dictGetVal(de);
|
||||
ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
slave_addr = ri->addr;
|
||||
|
||||
/* If master_addr (obtained using sentinelGetCurrentMasterAddress()
|
||||
@@ -1873,7 +1873,7 @@ void rewriteConfigSentinelOption(struct rewriteConfigState *state) {
|
||||
/* sentinel known-sentinel */
|
||||
di2 = dictGetIterator(master->sentinels);
|
||||
while((de = dictNext(di2)) != NULL) {
|
||||
ri = dictGetVal(de);
|
||||
ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
if (ri->runid == NULL) continue;
|
||||
line = sdscatprintf(sdsempty(),
|
||||
"sentinel known-sentinel %s %s %d %s",
|
||||
@@ -1885,8 +1885,8 @@ void rewriteConfigSentinelOption(struct rewriteConfigState *state) {
|
||||
/* sentinel rename-command */
|
||||
di2 = dictGetIterator(master->renamed_commands);
|
||||
while((de = dictNext(di2)) != NULL) {
|
||||
sds oldname = dictGetKey(de);
|
||||
sds newname = dictGetVal(de);
|
||||
sds oldname = (sds)dictGetKey(de);
|
||||
sds newname = (sds)dictGetVal(de);
|
||||
line = sdscatprintf(sdsempty(),
|
||||
"sentinel rename-command %s %s %s",
|
||||
master->name, oldname, newname);
|
||||
@@ -1982,7 +1982,7 @@ void sentinelSendAuthIfNeeded(sentinelRedisInstance *ri, redisAsyncContext *c) {
|
||||
*
|
||||
* This makes it possible to list all the sentinel instances connected
|
||||
* to a Redis servewr with CLIENT LIST, grepping for a specific name format. */
|
||||
void sentinelSetClientName(sentinelRedisInstance *ri, redisAsyncContext *c, char *type) {
|
||||
void sentinelSetClientName(sentinelRedisInstance *ri, redisAsyncContext *c, const char *type) {
|
||||
char name[64];
|
||||
|
||||
snprintf(name,sizeof(name),"sentinel-%.8s-%s",sentinel.myid,type);
|
||||
@@ -2337,13 +2337,13 @@ void sentinelRefreshInstanceInfo(sentinelRedisInstance *ri, const char *info) {
|
||||
}
|
||||
|
||||
void sentinelInfoReplyCallback(redisAsyncContext *c, void *reply, void *privdata) {
|
||||
sentinelRedisInstance *ri = privdata;
|
||||
instanceLink *link = c->data;
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)privdata;
|
||||
instanceLink *link = (instanceLink*)c->data;
|
||||
redisReply *r;
|
||||
|
||||
if (!reply || !link) return;
|
||||
link->pending_commands--;
|
||||
r = reply;
|
||||
r = (redisReply*)reply;
|
||||
|
||||
if (r->type == REDIS_REPLY_STRING)
|
||||
sentinelRefreshInstanceInfo(ri,r->str);
|
||||
@@ -2352,7 +2352,7 @@ void sentinelInfoReplyCallback(redisAsyncContext *c, void *reply, void *privdata
|
||||
/* Just discard the reply. We use this when we are not monitoring the return
|
||||
* value of the command but its effects directly. */
|
||||
void sentinelDiscardReplyCallback(redisAsyncContext *c, void *reply, void *privdata) {
|
||||
instanceLink *link = c->data;
|
||||
instanceLink *link = (instanceLink*)c->data;
|
||||
UNUSED(reply);
|
||||
UNUSED(privdata);
|
||||
|
||||
@@ -2360,13 +2360,13 @@ void sentinelDiscardReplyCallback(redisAsyncContext *c, void *reply, void *privd
|
||||
}
|
||||
|
||||
void sentinelPingReplyCallback(redisAsyncContext *c, void *reply, void *privdata) {
|
||||
sentinelRedisInstance *ri = privdata;
|
||||
instanceLink *link = c->data;
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)privdata;
|
||||
instanceLink *link = (instanceLink*)c->data;
|
||||
redisReply *r;
|
||||
|
||||
if (!reply || !link) return;
|
||||
link->pending_commands--;
|
||||
r = reply;
|
||||
r = (redisReply*)reply;
|
||||
|
||||
if (r->type == REDIS_REPLY_STATUS ||
|
||||
r->type == REDIS_REPLY_ERROR) {
|
||||
@@ -2402,13 +2402,13 @@ void sentinelPingReplyCallback(redisAsyncContext *c, void *reply, void *privdata
|
||||
/* This is called when we get the reply about the PUBLISH command we send
|
||||
* to the master to advertise this sentinel. */
|
||||
void sentinelPublishReplyCallback(redisAsyncContext *c, void *reply, void *privdata) {
|
||||
sentinelRedisInstance *ri = privdata;
|
||||
instanceLink *link = c->data;
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)privdata;
|
||||
instanceLink *link = (instanceLink*)c->data;
|
||||
redisReply *r;
|
||||
|
||||
if (!reply || !link) return;
|
||||
link->pending_commands--;
|
||||
r = reply;
|
||||
r = (redisReply*)reply;
|
||||
|
||||
/* Only update pub_time if we actually published our message. Otherwise
|
||||
* we'll retry again in 100 milliseconds. */
|
||||
@@ -2421,7 +2421,7 @@ void sentinelPublishReplyCallback(redisAsyncContext *c, void *reply, void *privd
|
||||
*
|
||||
* If the master name specified in the message is not known, the message is
|
||||
* discarded. */
|
||||
void sentinelProcessHelloMessage(char *hello, int hello_len) {
|
||||
void sentinelProcessHelloMessage(const char *hello, int hello_len) {
|
||||
/* Format is composed of 8 tokens:
|
||||
* 0=ip,1=port,2=runid,3=current_epoch,4=master_name,
|
||||
* 5=master_ip,6=master_port,7=master_config_epoch. */
|
||||
@@ -2526,12 +2526,12 @@ cleanup:
|
||||
/* This is our Pub/Sub callback for the Hello channel. It's useful in order
|
||||
* to discover other sentinels attached at the same master. */
|
||||
void sentinelReceiveHelloMessages(redisAsyncContext *c, void *reply, void *privdata) {
|
||||
sentinelRedisInstance *ri = privdata;
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)privdata;
|
||||
redisReply *r;
|
||||
UNUSED(c);
|
||||
|
||||
if (!reply || !ri) return;
|
||||
r = reply;
|
||||
r = (redisReply*)reply;
|
||||
|
||||
/* Update the last activity in the pubsub channel. Note that since we
|
||||
* receive our messages as well this timestamp can be used to detect
|
||||
@@ -2613,7 +2613,7 @@ void sentinelForceHelloUpdateDictOfRedisInstances(dict *instances) {
|
||||
|
||||
di = dictGetSafeIterator(instances);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
if (ri->last_pub_time >= (SENTINEL_PUBLISH_PERIOD+1))
|
||||
ri->last_pub_time -= (SENTINEL_PUBLISH_PERIOD+1);
|
||||
}
|
||||
@@ -2940,7 +2940,7 @@ void addReplyDictOfRedisInstances(client *c, dict *instances) {
|
||||
di = dictGetIterator(instances);
|
||||
addReplyArrayLen(c,dictSize(instances));
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
addReplySentinelRedisInstance(c,ri);
|
||||
}
|
||||
@@ -2955,7 +2955,7 @@ sentinelRedisInstance *sentinelGetMasterByNameOrReplyError(client *c,
|
||||
{
|
||||
sentinelRedisInstance *ri;
|
||||
|
||||
ri = dictFetchValue(sentinel.masters,ptrFromObj(name));
|
||||
ri = (sentinelRedisInstance*)dictFetchValue(sentinel.masters,ptrFromObj(name));
|
||||
if (!ri) {
|
||||
addReplyError(c,"No such master with that name");
|
||||
return NULL;
|
||||
@@ -2975,7 +2975,7 @@ int sentinelIsQuorumReachable(sentinelRedisInstance *master, int *usableptr) {
|
||||
|
||||
di = dictGetIterator(master->sentinels);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
if (ri->flags & (SRI_S_DOWN|SRI_O_DOWN)) continue;
|
||||
usable++;
|
||||
@@ -2989,11 +2989,11 @@ int sentinelIsQuorumReachable(sentinelRedisInstance *master, int *usableptr) {
|
||||
}
|
||||
|
||||
void sentinelCommand(client *c) {
|
||||
if (!strcasecmp(ptrFromObj(c->argv[1]),"masters")) {
|
||||
if (!strcasecmp(szFromObj(c->argv[1]),"masters")) {
|
||||
/* SENTINEL MASTERS */
|
||||
if (c->argc != 2) goto numargserr;
|
||||
addReplyDictOfRedisInstances(c,sentinel.masters);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"master")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"master")) {
|
||||
/* SENTINEL MASTER <name> */
|
||||
sentinelRedisInstance *ri;
|
||||
|
||||
@@ -3001,8 +3001,8 @@ void sentinelCommand(client *c) {
|
||||
if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2]))
|
||||
== NULL) return;
|
||||
addReplySentinelRedisInstance(c,ri);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"slaves") ||
|
||||
!strcasecmp(ptrFromObj(c->argv[1]),"replicas"))
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"slaves") ||
|
||||
!strcasecmp(szFromObj(c->argv[1]),"replicas"))
|
||||
{
|
||||
/* SENTINEL REPLICAS <master-name> */
|
||||
sentinelRedisInstance *ri;
|
||||
@@ -3011,7 +3011,7 @@ void sentinelCommand(client *c) {
|
||||
if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) == NULL)
|
||||
return;
|
||||
addReplyDictOfRedisInstances(c,ri->slaves);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"sentinels")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"sentinels")) {
|
||||
/* SENTINEL SENTINELS <master-name> */
|
||||
sentinelRedisInstance *ri;
|
||||
|
||||
@@ -3019,7 +3019,7 @@ void sentinelCommand(client *c) {
|
||||
if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) == NULL)
|
||||
return;
|
||||
addReplyDictOfRedisInstances(c,ri->sentinels);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"is-master-down-by-addr")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"is-master-down-by-addr")) {
|
||||
/* SENTINEL IS-MASTER-DOWN-BY-ADDR <ip> <port> <current-epoch> <runid>
|
||||
*
|
||||
* Arguments:
|
||||
@@ -3050,7 +3050,7 @@ void sentinelCommand(client *c) {
|
||||
!= C_OK)
|
||||
return;
|
||||
ri = getSentinelRedisInstanceByAddrAndRunID(sentinel.masters,
|
||||
ptrFromObj(c->argv[2]),port,NULL);
|
||||
szFromObj(c->argv[2]),port,NULL);
|
||||
|
||||
/* It exists? Is actually a master? Is subjectively down? It's down.
|
||||
* Note: if we are in tilt mode we always reply with "0". */
|
||||
@@ -3060,9 +3060,9 @@ void sentinelCommand(client *c) {
|
||||
|
||||
/* Vote for the master (or fetch the previous vote) if the request
|
||||
* includes a runid, otherwise the sender is not seeking for a vote. */
|
||||
if (ri && ri->flags & SRI_MASTER && strcasecmp(ptrFromObj(c->argv[5]),"*")) {
|
||||
if (ri && ri->flags & SRI_MASTER && strcasecmp(szFromObj(c->argv[5]),"*")) {
|
||||
leader = sentinelVoteLeader(ri,(uint64_t)req_epoch,
|
||||
ptrFromObj(c->argv[5]),
|
||||
szFromObj(c->argv[5]),
|
||||
&leader_epoch);
|
||||
}
|
||||
|
||||
@@ -3073,16 +3073,16 @@ void sentinelCommand(client *c) {
|
||||
addReplyBulkCString(c, leader ? leader : "*");
|
||||
addReplyLongLong(c, (long long)leader_epoch);
|
||||
if (leader) sdsfree(leader);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"reset")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"reset")) {
|
||||
/* SENTINEL RESET <pattern> */
|
||||
if (c->argc != 3) goto numargserr;
|
||||
addReplyLongLong(c,sentinelResetMastersByPattern(ptrFromObj(c->argv[2]),SENTINEL_GENERATE_EVENT));
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"get-master-addr-by-name")) {
|
||||
addReplyLongLong(c,sentinelResetMastersByPattern(szFromObj(c->argv[2]),SENTINEL_GENERATE_EVENT));
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"get-master-addr-by-name")) {
|
||||
/* SENTINEL GET-MASTER-ADDR-BY-NAME <master-name> */
|
||||
sentinelRedisInstance *ri;
|
||||
|
||||
if (c->argc != 3) goto numargserr;
|
||||
ri = sentinelGetMasterByName(ptrFromObj(c->argv[2]));
|
||||
ri = sentinelGetMasterByName(szFromObj(c->argv[2]));
|
||||
if (ri == NULL) {
|
||||
addReplyNullArray(c);
|
||||
} else {
|
||||
@@ -3092,7 +3092,7 @@ void sentinelCommand(client *c) {
|
||||
addReplyBulkCString(c,addr->ip);
|
||||
addReplyBulkLongLong(c,addr->port);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"failover")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"failover")) {
|
||||
/* SENTINEL FAILOVER <master-name> */
|
||||
sentinelRedisInstance *ri;
|
||||
|
||||
@@ -3112,12 +3112,12 @@ void sentinelCommand(client *c) {
|
||||
sentinelStartFailover(ri);
|
||||
ri->flags |= SRI_FORCE_FAILOVER;
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"pending-scripts")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"pending-scripts")) {
|
||||
/* SENTINEL PENDING-SCRIPTS */
|
||||
|
||||
if (c->argc != 2) goto numargserr;
|
||||
sentinelPendingScriptsCommand(c);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"monitor")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"monitor")) {
|
||||
/* SENTINEL MONITOR <name> <ip> <port> <quorum> */
|
||||
sentinelRedisInstance *ri;
|
||||
long quorum, port;
|
||||
@@ -3137,14 +3137,14 @@ void sentinelCommand(client *c) {
|
||||
/* Make sure the IP field is actually a valid IP before passing it
|
||||
* to createSentinelRedisInstance(), otherwise we may trigger a
|
||||
* DNS lookup at runtime. */
|
||||
if (anetResolveIP(NULL,ptrFromObj(c->argv[3]),ip,sizeof(ip)) == ANET_ERR) {
|
||||
if (anetResolveIP(NULL,szFromObj(c->argv[3]),ip,sizeof(ip)) == ANET_ERR) {
|
||||
addReplyError(c,"Invalid IP address specified");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parameters are valid. Try to create the master instance. */
|
||||
ri = createSentinelRedisInstance(ptrFromObj(c->argv[2]),SRI_MASTER,
|
||||
ptrFromObj(c->argv[3]),port,quorum,NULL);
|
||||
ri = createSentinelRedisInstance(szFromObj(c->argv[2]),SRI_MASTER,
|
||||
szFromObj(c->argv[3]),port,quorum,NULL);
|
||||
if (ri == NULL) {
|
||||
switch(errno) {
|
||||
case EBUSY:
|
||||
@@ -3162,12 +3162,12 @@ void sentinelCommand(client *c) {
|
||||
sentinelEvent(LL_WARNING,"+monitor",ri,"%@ quorum %d",ri->quorum);
|
||||
addReply(c,shared.ok);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"flushconfig")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"flushconfig")) {
|
||||
if (c->argc != 2) goto numargserr;
|
||||
sentinelFlushConfig();
|
||||
addReply(c,shared.ok);
|
||||
return;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"remove")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"remove")) {
|
||||
/* SENTINEL REMOVE <name> */
|
||||
sentinelRedisInstance *ri;
|
||||
|
||||
@@ -3178,7 +3178,7 @@ void sentinelCommand(client *c) {
|
||||
dictDelete(sentinel.masters,ptrFromObj(c->argv[2]));
|
||||
sentinelFlushConfig();
|
||||
addReply(c,shared.ok);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"ckquorum")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"ckquorum")) {
|
||||
/* SENTINEL CKQUORUM <name> */
|
||||
sentinelRedisInstance *ri;
|
||||
int usable;
|
||||
@@ -3205,10 +3205,10 @@ void sentinelCommand(client *c) {
|
||||
e = sdscat(e,"\r\n");
|
||||
addReplySds(c,e);
|
||||
}
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"set")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"set")) {
|
||||
if (c->argc < 3) goto numargserr;
|
||||
sentinelSetCommand(c);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"info-cache")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"info-cache")) {
|
||||
/* SENTINEL INFO-CACHE <name> */
|
||||
if (c->argc < 2) goto numargserr;
|
||||
mstime_t now = mstime();
|
||||
@@ -3224,7 +3224,7 @@ void sentinelCommand(client *c) {
|
||||
|
||||
for (int i = 2; i < c->argc; i++) {
|
||||
sentinelRedisInstance *ri;
|
||||
ri = sentinelGetMasterByName(ptrFromObj(c->argv[i]));
|
||||
ri = sentinelGetMasterByName(szFromObj(c->argv[i]));
|
||||
if (!ri) continue; /* ignore non-existing names */
|
||||
dictAdd(masters_local, ri->name, ri);
|
||||
}
|
||||
@@ -3244,7 +3244,7 @@ void sentinelCommand(client *c) {
|
||||
dictEntry *de;
|
||||
di = dictGetIterator(masters_local);
|
||||
while ((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
addReplyBulkCBuffer(c,ri->name,strlen(ri->name));
|
||||
addReplyArrayLen(c,dictSize(ri->slaves) + 1); /* +1 for self */
|
||||
addReplyArrayLen(c,2);
|
||||
@@ -3258,7 +3258,7 @@ void sentinelCommand(client *c) {
|
||||
dictEntry *sde;
|
||||
sdi = dictGetIterator(ri->slaves);
|
||||
while ((sde = dictNext(sdi)) != NULL) {
|
||||
sentinelRedisInstance *sri = dictGetVal(sde);
|
||||
sentinelRedisInstance *sri = (sentinelRedisInstance*)dictGetVal(sde);
|
||||
addReplyArrayLen(c,2);
|
||||
addReplyLongLong(c, now - sri->info_refresh);
|
||||
if (sri->info)
|
||||
@@ -3270,24 +3270,24 @@ void sentinelCommand(client *c) {
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
if (masters_local != sentinel.masters) dictRelease(masters_local);
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[1]),"simulate-failure")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[1]),"simulate-failure")) {
|
||||
/* SENTINEL SIMULATE-FAILURE <flag> <flag> ... <flag> */
|
||||
int j;
|
||||
|
||||
sentinel.simfailure_flags = SENTINEL_SIMFAILURE_NONE;
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
if (!strcasecmp(ptrFromObj(c->argv[j]),"crash-after-election")) {
|
||||
if (!strcasecmp(szFromObj(c->argv[j]),"crash-after-election")) {
|
||||
sentinel.simfailure_flags |=
|
||||
SENTINEL_SIMFAILURE_CRASH_AFTER_ELECTION;
|
||||
serverLog(LL_WARNING,"Failure simulation: this Sentinel "
|
||||
"will crash after being successfully elected as failover "
|
||||
"leader");
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"crash-after-promotion")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"crash-after-promotion")) {
|
||||
sentinel.simfailure_flags |=
|
||||
SENTINEL_SIMFAILURE_CRASH_AFTER_PROMOTION;
|
||||
serverLog(LL_WARNING,"Failure simulation: this Sentinel "
|
||||
"will crash after promoting the selected replica to master");
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"help")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"help")) {
|
||||
addReplyArrayLen(c,2);
|
||||
addReplyBulkCString(c,"crash-after-election");
|
||||
addReplyBulkCString(c,"crash-after-promotion");
|
||||
@@ -3326,7 +3326,7 @@ void sentinelInfoCommand(client *c) {
|
||||
}
|
||||
|
||||
int defsections = 0, allsections = 0;
|
||||
char *section = c->argc == 2 ? ptrFromObj(c->argv[1]) : NULL;
|
||||
char *section = c->argc == 2 ? szFromObj(c->argv[1]) : NULL;
|
||||
if (section) {
|
||||
allsections = !strcasecmp(section,"all");
|
||||
defsections = !strcasecmp(section,"default");
|
||||
@@ -3363,8 +3363,8 @@ void sentinelInfoCommand(client *c) {
|
||||
|
||||
di = dictGetIterator(sentinel.masters);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
char *status = "ok";
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
const char *status = "ok";
|
||||
|
||||
if (ri->flags & SRI_O_DOWN) status = "odown";
|
||||
else if (ri->flags & SRI_S_DOWN) status = "sdown";
|
||||
@@ -3394,7 +3394,7 @@ void sentinelRoleCommand(client *c) {
|
||||
|
||||
di = dictGetIterator(sentinel.masters);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
addReplyBulkCString(c,ri->name);
|
||||
}
|
||||
@@ -3414,7 +3414,7 @@ void sentinelSetCommand(client *c) {
|
||||
/* Process option - value pairs. */
|
||||
for (j = 3; j < c->argc; j++) {
|
||||
int moreargs = (c->argc-1) - j;
|
||||
option = ptrFromObj(c->argv[j]);
|
||||
option = szFromObj(c->argv[j]);
|
||||
long long ll;
|
||||
int old_j = j; /* Used to know what to log as an event. */
|
||||
|
||||
@@ -3448,7 +3448,7 @@ void sentinelSetCommand(client *c) {
|
||||
changes++;
|
||||
} else if (!strcasecmp(option,"notification-script") && moreargs > 0) {
|
||||
/* notification-script <path> */
|
||||
char *value = ptrFromObj(c->argv[++j]);
|
||||
char *value = szFromObj(c->argv[++j]);
|
||||
if (sentinel.deny_scripts_reconfig) {
|
||||
addReplyError(c,
|
||||
"Reconfiguration of scripts path is denied for "
|
||||
@@ -3468,7 +3468,7 @@ void sentinelSetCommand(client *c) {
|
||||
changes++;
|
||||
} else if (!strcasecmp(option,"client-reconfig-script") && moreargs > 0) {
|
||||
/* client-reconfig-script <path> */
|
||||
char *value = ptrFromObj(c->argv[++j]);
|
||||
char *value = szFromObj(c->argv[++j]);
|
||||
if (sentinel.deny_scripts_reconfig) {
|
||||
addReplyError(c,
|
||||
"Reconfiguration of scripts path is denied for "
|
||||
@@ -3489,7 +3489,7 @@ void sentinelSetCommand(client *c) {
|
||||
changes++;
|
||||
} else if (!strcasecmp(option,"auth-pass") && moreargs > 0) {
|
||||
/* auth-pass <password> */
|
||||
char *value = ptrFromObj(c->argv[++j]);
|
||||
char *value = szFromObj(c->argv[++j]);
|
||||
sdsfree(ri->auth_pass);
|
||||
ri->auth_pass = strlen(value) ? sdsnew(value) : NULL;
|
||||
changes++;
|
||||
@@ -3504,8 +3504,8 @@ void sentinelSetCommand(client *c) {
|
||||
changes++;
|
||||
} else if (!strcasecmp(option,"rename-command") && moreargs > 1) {
|
||||
/* rename-command <oldname> <newname> */
|
||||
sds oldname = ptrFromObj(c->argv[++j]);
|
||||
sds newname = ptrFromObj(c->argv[++j]);
|
||||
sds oldname = szFromObj(c->argv[++j]);
|
||||
sds newname = szFromObj(c->argv[++j]);
|
||||
|
||||
if ((sdslen(oldname) == 0) || (sdslen(newname) == 0)) {
|
||||
badarg = sdslen(newname) ? j-1 : j;
|
||||
@@ -3565,11 +3565,11 @@ badfmt: /* Bad format errors */
|
||||
* Because we have a Sentinel PUBLISH, the code to send hello messages is the same
|
||||
* for all the three kind of instances: masters, slaves, sentinels. */
|
||||
void sentinelPublishCommand(client *c) {
|
||||
if (strcmp(ptrFromObj(c->argv[1]),SENTINEL_HELLO_CHANNEL)) {
|
||||
if (strcmp(szFromObj(c->argv[1]),SENTINEL_HELLO_CHANNEL)) {
|
||||
addReplyError(c, "Only HELLO messages are accepted by Sentinel instances.");
|
||||
return;
|
||||
}
|
||||
sentinelProcessHelloMessage(ptrFromObj(c->argv[2]),sdslen(ptrFromObj(c->argv[2])));
|
||||
sentinelProcessHelloMessage(szFromObj(c->argv[2]),sdslen(szFromObj(c->argv[2])));
|
||||
addReplyLongLong(c,1);
|
||||
}
|
||||
|
||||
@@ -3659,7 +3659,7 @@ void sentinelCheckObjectivelyDown(sentinelRedisInstance *master) {
|
||||
/* Count all the other sentinels. */
|
||||
di = dictGetIterator(master->sentinels);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
if (ri->flags & SRI_MASTER_DOWN) quorum++;
|
||||
}
|
||||
@@ -3686,13 +3686,13 @@ void sentinelCheckObjectivelyDown(sentinelRedisInstance *master) {
|
||||
/* Receive the SENTINEL is-master-down-by-addr reply, see the
|
||||
* sentinelAskMasterStateToOtherSentinels() function for more information. */
|
||||
void sentinelReceiveIsMasterDownReply(redisAsyncContext *c, void *reply, void *privdata) {
|
||||
sentinelRedisInstance *ri = privdata;
|
||||
instanceLink *link = c->data;
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)privdata;
|
||||
instanceLink *link = (instanceLink*)c->data;
|
||||
redisReply *r;
|
||||
|
||||
if (!reply || !link) return;
|
||||
link->pending_commands--;
|
||||
r = reply;
|
||||
r = (redisReply*)reply;
|
||||
|
||||
/* Ignore every error or unexpected reply.
|
||||
* Note that if the command returns an error for any reason we'll
|
||||
@@ -3734,7 +3734,7 @@ void sentinelAskMasterStateToOtherSentinels(sentinelRedisInstance *master, int f
|
||||
|
||||
di = dictGetIterator(master->sentinels);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
mstime_t elapsed = mstime() - ri->last_master_down_reply_time;
|
||||
char port[32];
|
||||
int retval;
|
||||
@@ -3860,7 +3860,7 @@ char *sentinelGetLeader(sentinelRedisInstance *master, uint64_t epoch) {
|
||||
/* Count other sentinels votes */
|
||||
di = dictGetIterator(master->sentinels);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
if (ri->leader != NULL && ri->leader_epoch == sentinel.current_epoch)
|
||||
sentinelLeaderIncr(counters,ri->leader);
|
||||
}
|
||||
@@ -3875,7 +3875,7 @@ char *sentinelGetLeader(sentinelRedisInstance *master, uint64_t epoch) {
|
||||
|
||||
if (votes > max_votes) {
|
||||
max_votes = votes;
|
||||
winner = dictGetKey(de);
|
||||
winner = (char*)dictGetKey(de);
|
||||
}
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
@@ -3917,7 +3917,7 @@ char *sentinelGetLeader(sentinelRedisInstance *master, uint64_t epoch) {
|
||||
* The command returns C_OK if the SLAVEOF command was accepted for
|
||||
* (later) delivery otherwise C_ERR. The command replies are just
|
||||
* discarded. */
|
||||
int sentinelSendSlaveOf(sentinelRedisInstance *ri, char *host, int port) {
|
||||
int sentinelSendSlaveOf(sentinelRedisInstance *ri, const char *host, int port) {
|
||||
char portstr[32];
|
||||
int retval;
|
||||
|
||||
@@ -4096,7 +4096,7 @@ int compareSlavesForPromotion(const void *a, const void *b) {
|
||||
}
|
||||
|
||||
sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master) {
|
||||
sentinelRedisInstance **instance =
|
||||
sentinelRedisInstance **instance = (sentinelRedisInstance**)
|
||||
zmalloc(sizeof(instance[0])*dictSize(master->slaves), MALLOC_LOCAL);
|
||||
sentinelRedisInstance *selected = NULL;
|
||||
int instances = 0;
|
||||
@@ -4110,7 +4110,7 @@ sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master) {
|
||||
|
||||
di = dictGetIterator(master->slaves);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *slave = dictGetVal(de);
|
||||
sentinelRedisInstance *slave = (sentinelRedisInstance*)dictGetVal(de);
|
||||
mstime_t info_validity_time;
|
||||
|
||||
if (slave->flags & (SRI_S_DOWN|SRI_O_DOWN)) continue;
|
||||
@@ -4245,7 +4245,7 @@ void sentinelFailoverDetectEnd(sentinelRedisInstance *master) {
|
||||
* configured. */
|
||||
di = dictGetIterator(master->slaves);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *slave = dictGetVal(de);
|
||||
sentinelRedisInstance *slave = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
if (slave->flags & (SRI_PROMOTED|SRI_RECONF_DONE)) continue;
|
||||
if (slave->flags & SRI_S_DOWN) continue;
|
||||
@@ -4275,7 +4275,7 @@ void sentinelFailoverDetectEnd(sentinelRedisInstance *master) {
|
||||
|
||||
di = dictGetIterator(master->slaves);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *slave = dictGetVal(de);
|
||||
sentinelRedisInstance *slave = (sentinelRedisInstance*)dictGetVal(de);
|
||||
int retval;
|
||||
|
||||
if (slave->flags & (SRI_RECONF_DONE|SRI_RECONF_SENT)) continue;
|
||||
@@ -4303,7 +4303,7 @@ void sentinelFailoverReconfNextSlave(sentinelRedisInstance *master) {
|
||||
|
||||
di = dictGetIterator(master->slaves);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *slave = dictGetVal(de);
|
||||
sentinelRedisInstance *slave = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
if (slave->flags & (SRI_RECONF_SENT|SRI_RECONF_INPROG))
|
||||
in_progress++;
|
||||
@@ -4314,7 +4314,7 @@ void sentinelFailoverReconfNextSlave(sentinelRedisInstance *master) {
|
||||
while(in_progress < master->parallel_syncs &&
|
||||
(de = dictNext(di)) != NULL)
|
||||
{
|
||||
sentinelRedisInstance *slave = dictGetVal(de);
|
||||
sentinelRedisInstance *slave = (sentinelRedisInstance*)dictGetVal(de);
|
||||
int retval;
|
||||
|
||||
/* Skip the promoted slave, and already configured slaves. */
|
||||
@@ -4461,7 +4461,7 @@ void sentinelHandleDictOfRedisInstances(dict *instances) {
|
||||
/* There are a number of things we need to perform against every master. */
|
||||
di = dictGetIterator(instances);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sentinelRedisInstance *ri = dictGetVal(de);
|
||||
sentinelRedisInstance *ri = (sentinelRedisInstance*)dictGetVal(de);
|
||||
|
||||
sentinelHandleRedisInstance(ri);
|
||||
if (ri->flags & SRI_MASTER) {
|
||||
+159
-77
@@ -57,6 +57,8 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <locale.h>
|
||||
#include <sys/socket.h>
|
||||
#include <algorithm>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
/* Our shared "common" objects */
|
||||
|
||||
@@ -718,7 +720,7 @@ struct redisCommand redisCommandTable[] = {
|
||||
|
||||
{"touch",touchCommand,-2,
|
||||
"read-only fast @keyspace",
|
||||
0,NULL,1,1,1,0,0,0},
|
||||
0,NULL,1,-1,1,0,0,0},
|
||||
|
||||
{"pttl",pttlCommand,2,
|
||||
"read-only fast random @keyspace",
|
||||
@@ -866,7 +868,7 @@ struct redisCommand redisCommandTable[] = {
|
||||
"no-script @keyspace",
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
{"command",commandCommand,0,
|
||||
{"command",commandCommand,-1,
|
||||
"ok-loading ok-stale random @connection",
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
@@ -995,12 +997,12 @@ struct redisCommand redisCommandTable[] = {
|
||||
"admin no-script ok-loading ok-stale",
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
{"lolwut",lolwutCommand,-1,
|
||||
"read-only fast",
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
{"acl",aclCommand,-2,
|
||||
"admin no-script ok-loading ok-stale",
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
{"rreplay",replicaReplayCommand,3,
|
||||
"read-only fast noprop",
|
||||
0,NULL,0,0,0,0,0,0}
|
||||
};
|
||||
|
||||
@@ -1044,7 +1046,7 @@ void serverLogRaw(int level, const char *msg) {
|
||||
} else if (pid != server.pid) {
|
||||
role_char = 'C'; /* RDB / AOF writing child. */
|
||||
} else {
|
||||
role_char = (server.masterhost ? 'S':'M'); /* Slave or Master. */
|
||||
role_char = (listLength(server.masters) ? 'S':'M'); /* Slave or Master. */
|
||||
}
|
||||
fprintf(fp,"%d:%c %s %c %s\n",
|
||||
(int)getpid(),role_char, buf,c[level],msg);
|
||||
@@ -1133,13 +1135,13 @@ void exitFromChild(int retcode) {
|
||||
* keys and redis objects as values (objects can hold SDS strings,
|
||||
* lists, sets). */
|
||||
|
||||
extern "C" void dictVanillaFree(void *privdata, void *val)
|
||||
void dictVanillaFree(void *privdata, void *val)
|
||||
{
|
||||
DICT_NOTUSED(privdata);
|
||||
zfree(val);
|
||||
}
|
||||
|
||||
extern "C" void dictListDestructor(void *privdata, void *val)
|
||||
void dictListDestructor(void *privdata, void *val)
|
||||
{
|
||||
DICT_NOTUSED(privdata);
|
||||
listRelease((list*)val);
|
||||
@@ -1159,7 +1161,7 @@ int dictSdsKeyCompare(void *privdata, const void *key1,
|
||||
|
||||
/* A case insensitive version used for the command lookup table and other
|
||||
* places where case insensitive non binary-safe comparison is needed. */
|
||||
extern "C" int dictSdsKeyCaseCompare(void *privdata, const void *key1,
|
||||
int dictSdsKeyCaseCompare(void *privdata, const void *key1,
|
||||
const void *key2)
|
||||
{
|
||||
DICT_NOTUSED(privdata);
|
||||
@@ -1199,7 +1201,7 @@ uint64_t dictSdsHash(const void *key) {
|
||||
return dictGenHashFunction((unsigned char*)key, sdslen((char*)key));
|
||||
}
|
||||
|
||||
extern "C" uint64_t dictSdsCaseHash(const void *key) {
|
||||
uint64_t dictSdsCaseHash(const void *key) {
|
||||
return dictGenCaseHashFunction((unsigned char*)key, sdslen((char*)key));
|
||||
}
|
||||
|
||||
@@ -1685,9 +1687,9 @@ void clientsCron(int iel) {
|
||||
void databasesCron(void) {
|
||||
/* Expire keys by random sampling. Not required for slaves
|
||||
* as master will synthesize DELs for us. */
|
||||
if (server.active_expire_enabled && server.masterhost == NULL) {
|
||||
if (server.active_expire_enabled && listLength(server.masters) == 0) {
|
||||
activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);
|
||||
} else if (server.masterhost != NULL) {
|
||||
} else if (listLength(server.masters)) {
|
||||
expireSlaveKeys();
|
||||
}
|
||||
|
||||
@@ -2072,7 +2074,7 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
|
||||
|
||||
/* Run a fast expire cycle (the called function will return
|
||||
* ASAP if a fast cycle is not needed). */
|
||||
if (server.active_expire_enabled && server.masterhost == NULL)
|
||||
if (server.active_expire_enabled && listLength(server.masters) == 0)
|
||||
activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);
|
||||
|
||||
/* Send all the slaves an ACK request if at least one client blocked
|
||||
@@ -2149,7 +2151,7 @@ void afterSleep(struct aeEventLoop *eventLoop) {
|
||||
|
||||
/* =========================== Server initialization ======================== */
|
||||
|
||||
extern "C" void createSharedObjects(void) {
|
||||
void createSharedObjects(void) {
|
||||
int j;
|
||||
|
||||
shared.crlf = createObject(OBJ_STRING,sdsnew("\r\n"));
|
||||
@@ -2252,6 +2254,28 @@ extern "C" void createSharedObjects(void) {
|
||||
shared.maxstring = sdsnew("maxstring");
|
||||
}
|
||||
|
||||
void initMasterInfo(redisMaster *master)
|
||||
{
|
||||
if (server.default_masterauth)
|
||||
master->masterauth = zstrdup(server.default_masterauth);
|
||||
else
|
||||
master->masterauth = NULL;
|
||||
|
||||
if (server.default_masteruser)
|
||||
master->masteruser = zstrdup(server.default_masteruser);
|
||||
else
|
||||
master->masteruser = NULL;
|
||||
|
||||
master->masterport = 6379;
|
||||
master->master = NULL;
|
||||
master->cached_master = NULL;
|
||||
master->master_initial_offset = -1;
|
||||
|
||||
|
||||
master->repl_state = REPL_STATE_NONE;
|
||||
master->repl_down_since = 0; /* Never connected, repl is down since EVER. */
|
||||
}
|
||||
|
||||
void initServerConfig(void) {
|
||||
int j;
|
||||
|
||||
@@ -2264,6 +2288,9 @@ void initServerConfig(void) {
|
||||
server.runid[CONFIG_RUN_ID_SIZE] = '\0';
|
||||
changeReplicationId();
|
||||
clearReplicationId2();
|
||||
server.clients = listCreate();
|
||||
server.slaves = listCreate();
|
||||
server.monitors = listCreate();
|
||||
server.timezone = getTimeZone(); /* Initialized by tzset(). */
|
||||
server.configfile = NULL;
|
||||
server.executable = NULL;
|
||||
@@ -2277,7 +2304,6 @@ void initServerConfig(void) {
|
||||
server.unixsocketperm = CONFIG_DEFAULT_UNIX_SOCKET_PERM;
|
||||
server.sofd = -1;
|
||||
server.protected_mode = CONFIG_DEFAULT_PROTECTED_MODE;
|
||||
server.gopher_enabled = CONFIG_DEFAULT_GOPHER_ENABLED;
|
||||
server.dbnum = CONFIG_DEFAULT_DBNUM;
|
||||
server.verbosity = CONFIG_DEFAULT_VERBOSITY;
|
||||
server.maxidletime = CONFIG_DEFAULT_CLIENT_TIMEOUT;
|
||||
@@ -2370,6 +2396,7 @@ void initServerConfig(void) {
|
||||
server.lazyfree_lazy_server_del = CONFIG_DEFAULT_LAZYFREE_LAZY_SERVER_DEL;
|
||||
server.always_show_logo = CONFIG_DEFAULT_ALWAYS_SHOW_LOGO;
|
||||
server.lua_time_limit = LUA_SCRIPT_TIME_LIMIT;
|
||||
server.fActiveReplica = CONFIG_DEFAULT_ACTIVE_REPLICA;
|
||||
|
||||
unsigned int lruclock = getLRUClock();
|
||||
atomicSet(server.lruclock,lruclock);
|
||||
@@ -2380,19 +2407,13 @@ void initServerConfig(void) {
|
||||
appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
|
||||
|
||||
/* Replication related */
|
||||
server.masterauth = NULL;
|
||||
server.masterhost = NULL;
|
||||
server.masterport = 6379;
|
||||
server.master = NULL;
|
||||
server.cached_master = NULL;
|
||||
server.master_initial_offset = -1;
|
||||
server.repl_state = REPL_STATE_NONE;
|
||||
server.masters = listCreate();
|
||||
server.enable_multimaster = CONFIG_DEFAULT_ENABLE_MULTIMASTER;
|
||||
server.repl_syncio_timeout = CONFIG_REPL_SYNCIO_TIMEOUT;
|
||||
server.repl_serve_stale_data = CONFIG_DEFAULT_SLAVE_SERVE_STALE_DATA;
|
||||
server.repl_slave_ro = CONFIG_DEFAULT_SLAVE_READ_ONLY;
|
||||
server.repl_slave_ignore_maxmemory = CONFIG_DEFAULT_SLAVE_IGNORE_MAXMEMORY;
|
||||
server.repl_slave_lazy_flush = CONFIG_DEFAULT_SLAVE_LAZY_FLUSH;
|
||||
server.repl_down_since = 0; /* Never connected, repl is down since EVER. */
|
||||
server.repl_disable_tcp_nodelay = CONFIG_DEFAULT_REPL_DISABLE_TCP_NODELAY;
|
||||
server.repl_diskless_sync = CONFIG_DEFAULT_REPL_DISKLESS_SYNC;
|
||||
server.repl_diskless_sync_delay = CONFIG_DEFAULT_REPL_DISKLESS_SYNC_DELAY;
|
||||
@@ -2443,6 +2464,7 @@ void initServerConfig(void) {
|
||||
server.pexpireCommand = lookupCommandByCString("pexpire");
|
||||
server.xclaimCommand = lookupCommandByCString("xclaim");
|
||||
server.xgroupCommand = lookupCommandByCString("xgroup");
|
||||
server.rreplayCommand = lookupCommandByCString("rreplay");
|
||||
|
||||
/* Slow log */
|
||||
server.slowlog_log_slower_than = CONFIG_DEFAULT_SLOWLOG_LOG_SLOWER_THAN;
|
||||
@@ -2814,6 +2836,7 @@ static void initServerThread(struct redisServerThreadVars *pvar, int fMain)
|
||||
pvar->unblocked_clients = listCreate();
|
||||
pvar->clients_pending_asyncwrite = listCreate();
|
||||
pvar->ipfd_count = 0;
|
||||
pvar->cclients = 0;
|
||||
pvar->el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);
|
||||
if (pvar->el == NULL) {
|
||||
serverLog(LL_WARNING,
|
||||
@@ -2848,11 +2871,8 @@ void initServer(void) {
|
||||
server.hz = server.config_hz;
|
||||
server.pid = getpid();
|
||||
server.current_client = NULL;
|
||||
server.clients = listCreate();
|
||||
server.clients_index = raxNew();
|
||||
server.clients_to_close = listCreate();
|
||||
server.slaves = listCreate();
|
||||
server.monitors = listCreate();
|
||||
server.slaveseldb = -1; /* Force to emit the first SELECT command. */
|
||||
server.ready_keys = listCreate();
|
||||
server.clients_waiting_acks = listCreate();
|
||||
@@ -2960,6 +2980,10 @@ void initServer(void) {
|
||||
server.maxmemory_policy = MAXMEMORY_NO_EVICTION;
|
||||
}
|
||||
|
||||
/* Generate UUID */
|
||||
static_assert(sizeof(uuid_t) == sizeof(server.uuid), "UUIDs are standardized at 16-bytes");
|
||||
uuid_generate((unsigned char*)server.uuid);
|
||||
|
||||
if (server.cluster_enabled) clusterInit();
|
||||
replicationScriptCacheInit();
|
||||
scriptingInit(1);
|
||||
@@ -3008,6 +3032,8 @@ int populateCommandTableParseFlags(struct redisCommand *c, const char *strflags)
|
||||
c->flags |= CMD_ASKING;
|
||||
} else if (!strcasecmp(flag,"fast")) {
|
||||
c->flags |= CMD_FAST | CMD_CATEGORY_FAST;
|
||||
} else if (!strcasecmp(flag,"noprop")) {
|
||||
c->flags |= CMD_SKIP_PROPOGATE;
|
||||
} else {
|
||||
/* Parse ACL categories here if the flag name starts with @. */
|
||||
uint64_t catflag;
|
||||
@@ -3329,6 +3355,9 @@ void call(client *c, int flags) {
|
||||
!(flags & CMD_CALL_PROPAGATE_AOF))
|
||||
propagate_flags &= ~PROPAGATE_AOF;
|
||||
|
||||
if (c->cmd->flags & CMD_SKIP_PROPOGATE)
|
||||
propagate_flags &= ~PROPAGATE_REPL;
|
||||
|
||||
/* Call propagate() only if at least one of AOF / replication
|
||||
* propagation is needed. Note that modules commands handle replication
|
||||
* in an explicit way, so we never replicate them automatically. */
|
||||
@@ -3377,8 +3406,10 @@ void call(client *c, int flags) {
|
||||
* If C_OK is returned the client is still alive and valid and
|
||||
* other operations can be performed by the caller. Otherwise
|
||||
* if C_ERR is returned the client was destroyed (i.e. after QUIT). */
|
||||
int processCommand(client *c) {
|
||||
int processCommand(client *c, int callFlags) {
|
||||
serverAssert(GlobalLocksAcquired());
|
||||
moduleCallCommandFilters(c);
|
||||
|
||||
/* The QUIT command is handled separately. Normal command procs will
|
||||
* go through checking for replication and QUIT will cause trouble
|
||||
* when FORCE_REPLICATION is enabled and would be implemented in
|
||||
@@ -3496,7 +3527,7 @@ int processCommand(client *c) {
|
||||
* and if this is a master instance. */
|
||||
int deny_write_type = writeCommandsDeniedByDiskError();
|
||||
if (deny_write_type != DISK_ERROR_TYPE_NONE &&
|
||||
server.masterhost == NULL &&
|
||||
listLength(server.masters) == 0 &&
|
||||
(c->cmd->flags & CMD_WRITE ||
|
||||
c->cmd->proc == pingCommand))
|
||||
{
|
||||
@@ -3513,7 +3544,7 @@ int processCommand(client *c) {
|
||||
|
||||
/* Don't accept write commands if there are not enough good slaves and
|
||||
* user configured the min-slaves-to-write option. */
|
||||
if (server.masterhost == NULL &&
|
||||
if (listLength(server.masters) == 0 &&
|
||||
server.repl_min_slaves_to_write &&
|
||||
server.repl_min_slaves_max_lag &&
|
||||
c->cmd->flags & CMD_WRITE &&
|
||||
@@ -3526,7 +3557,7 @@ int processCommand(client *c) {
|
||||
|
||||
/* Don't accept write commands if this is a read only slave. But
|
||||
* accept write commands if this is our master. */
|
||||
if (server.masterhost && server.repl_slave_ro &&
|
||||
if (listLength(server.masters) && server.repl_slave_ro &&
|
||||
!(c->flags & CLIENT_MASTER) &&
|
||||
c->cmd->flags & CMD_WRITE)
|
||||
{
|
||||
@@ -3549,7 +3580,7 @@ int processCommand(client *c) {
|
||||
/* Only allow commands with flag "t", such as INFO, SLAVEOF and so on,
|
||||
* when slave-serve-stale-data is no and we are a slave with a broken
|
||||
* link with master. */
|
||||
if (server.masterhost && server.repl_state != REPL_STATE_CONNECTED &&
|
||||
if (FBrokenLinkToMaster() &&
|
||||
server.repl_serve_stale_data == 0 &&
|
||||
!(c->cmd->flags & CMD_STALE))
|
||||
{
|
||||
@@ -3590,7 +3621,7 @@ int processCommand(client *c) {
|
||||
queueMultiCommand(c);
|
||||
addReply(c,shared.queued);
|
||||
} else {
|
||||
call(c,CMD_CALL_FULL);
|
||||
call(c,callFlags);
|
||||
c->woff = server.master_repl_offset;
|
||||
if (listLength(server.ready_keys))
|
||||
handleClientsBlockedOnKeys();
|
||||
@@ -3996,6 +4027,12 @@ extern "C" sds genRedisInfoString(const char *section) {
|
||||
listLength(server.clients)-listLength(server.slaves),
|
||||
maxin, maxout,
|
||||
server.blocked_clients);
|
||||
for (int ithread = 0; ithread < server.cthreads; ++ithread)
|
||||
{
|
||||
info = sdscatprintf(info,
|
||||
"thread_%d_clients:%d\r\n",
|
||||
ithread, server.rgthreadvar[ithread].cclients);
|
||||
}
|
||||
}
|
||||
|
||||
/* Memory */
|
||||
@@ -4270,46 +4307,57 @@ extern "C" sds genRedisInfoString(const char *section) {
|
||||
info = sdscatprintf(info,
|
||||
"# Replication\r\n"
|
||||
"role:%s\r\n",
|
||||
server.masterhost == NULL ? "master" : "slave");
|
||||
if (server.masterhost) {
|
||||
long long slave_repl_offset = 1;
|
||||
listLength(server.masters) == 0 ? "master" : "slave");
|
||||
if (listLength(server.masters)) {
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(server.masters, &li);
|
||||
|
||||
if (server.master)
|
||||
slave_repl_offset = server.master->reploff;
|
||||
else if (server.cached_master)
|
||||
slave_repl_offset = server.cached_master->reploff;
|
||||
int cmasters = 0;
|
||||
while ((ln = listNext(&li)))
|
||||
{
|
||||
long long slave_repl_offset = 1;
|
||||
redisMaster *mi = (redisMaster*)listNodeValue(ln);
|
||||
info = sdscatprintf(info, "Master %d: \r\n", cmasters);
|
||||
++cmasters;
|
||||
|
||||
info = sdscatprintf(info,
|
||||
"master_host:%s\r\n"
|
||||
"master_port:%d\r\n"
|
||||
"master_link_status:%s\r\n"
|
||||
"master_last_io_seconds_ago:%d\r\n"
|
||||
"master_sync_in_progress:%d\r\n"
|
||||
"slave_repl_offset:%lld\r\n"
|
||||
,server.masterhost,
|
||||
server.masterport,
|
||||
(server.repl_state == REPL_STATE_CONNECTED) ?
|
||||
"up" : "down",
|
||||
server.master ?
|
||||
((int)(server.unixtime-server.master->lastinteraction)) : -1,
|
||||
server.repl_state == REPL_STATE_TRANSFER,
|
||||
slave_repl_offset
|
||||
);
|
||||
if (mi->master)
|
||||
slave_repl_offset = mi->master->reploff;
|
||||
else if (mi->cached_master)
|
||||
slave_repl_offset = mi->cached_master->reploff;
|
||||
|
||||
if (server.repl_state == REPL_STATE_TRANSFER) {
|
||||
info = sdscatprintf(info,
|
||||
"master_sync_left_bytes:%lld\r\n"
|
||||
"master_sync_last_io_seconds_ago:%d\r\n"
|
||||
, (long long)
|
||||
(server.repl_transfer_size - server.repl_transfer_read),
|
||||
(int)(server.unixtime-server.repl_transfer_lastio)
|
||||
"master_host:%s\r\n"
|
||||
"master_port:%d\r\n"
|
||||
"master_link_status:%s\r\n"
|
||||
"master_last_io_seconds_ago:%d\r\n"
|
||||
"master_sync_in_progress:%d\r\n"
|
||||
"slave_repl_offset:%lld\r\n"
|
||||
,mi->masterhost,
|
||||
mi->masterport,
|
||||
(mi->repl_state == REPL_STATE_CONNECTED) ?
|
||||
"up" : "down",
|
||||
mi->master ?
|
||||
((int)(server.unixtime-mi->master->lastinteraction)) : -1,
|
||||
mi->repl_state == REPL_STATE_TRANSFER,
|
||||
slave_repl_offset
|
||||
);
|
||||
}
|
||||
|
||||
if (server.repl_state != REPL_STATE_CONNECTED) {
|
||||
info = sdscatprintf(info,
|
||||
"master_link_down_since_seconds:%jd\r\n",
|
||||
(intmax_t)server.unixtime-server.repl_down_since);
|
||||
if (mi->repl_state == REPL_STATE_TRANSFER) {
|
||||
info = sdscatprintf(info,
|
||||
"master_sync_left_bytes:%lld\r\n"
|
||||
"master_sync_last_io_seconds_ago:%d\r\n"
|
||||
, (long long)
|
||||
(mi->repl_transfer_size - mi->repl_transfer_read),
|
||||
(int)(server.unixtime-mi->repl_transfer_lastio)
|
||||
);
|
||||
}
|
||||
|
||||
if (mi->repl_state != REPL_STATE_CONNECTED) {
|
||||
info = sdscatprintf(info,
|
||||
"master_link_down_since_seconds:%jd\r\n",
|
||||
(intmax_t)server.unixtime-mi->repl_down_since);
|
||||
}
|
||||
}
|
||||
info = sdscatprintf(info,
|
||||
"slave_priority:%d\r\n"
|
||||
@@ -4400,11 +4448,15 @@ extern "C" sds genRedisInfoString(const char *section) {
|
||||
"used_cpu_sys:%ld.%06ld\r\n"
|
||||
"used_cpu_user:%ld.%06ld\r\n"
|
||||
"used_cpu_sys_children:%ld.%06ld\r\n"
|
||||
"used_cpu_user_children:%ld.%06ld\r\n",
|
||||
"used_cpu_user_children:%ld.%06ld\r\n"
|
||||
"server_threads:%d\r\n"
|
||||
"long_lock_waits:%" PRIu64 "\r\n",
|
||||
(long)self_ru.ru_stime.tv_sec, (long)self_ru.ru_stime.tv_usec,
|
||||
(long)self_ru.ru_utime.tv_sec, (long)self_ru.ru_utime.tv_usec,
|
||||
(long)c_ru.ru_stime.tv_sec, (long)c_ru.ru_stime.tv_usec,
|
||||
(long)c_ru.ru_utime.tv_sec, (long)c_ru.ru_utime.tv_usec);
|
||||
(long)c_ru.ru_utime.tv_sec, (long)c_ru.ru_utime.tv_usec,
|
||||
server.cthreads,
|
||||
fastlock_getlongwaitcount());
|
||||
}
|
||||
|
||||
/* Command statistics */
|
||||
@@ -4619,6 +4671,7 @@ static void sigShutdownHandler(int sig) {
|
||||
rdbRemoveTempFile(getpid());
|
||||
exit(1); /* Exit with an error since this was not a clean shutdown. */
|
||||
} else if (server.loading) {
|
||||
serverLogFromHandler(LL_WARNING, "Received shutdown signal during loading, exiting now.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -4675,7 +4728,7 @@ void loadDataFromDisk(void) {
|
||||
(float)(ustime()-start)/1000000);
|
||||
|
||||
/* Restore the replication ID / offset from the RDB file. */
|
||||
if ((server.masterhost || (server.cluster_enabled && nodeIsSlave(server.cluster->myself)))&&
|
||||
if ((listLength(server.masters) || (server.cluster_enabled && nodeIsSlave(server.cluster->myself)))&&
|
||||
rsi.repl_id_is_set &&
|
||||
rsi.repl_offset != -1 &&
|
||||
/* Note that older implementations may save a repl_stream_db
|
||||
@@ -4685,11 +4738,19 @@ void loadDataFromDisk(void) {
|
||||
{
|
||||
memcpy(server.replid,rsi.repl_id,sizeof(server.replid));
|
||||
server.master_repl_offset = rsi.repl_offset;
|
||||
/* If we are a slave, create a cached master from this
|
||||
* information, in order to allow partial resynchronizations
|
||||
* with masters. */
|
||||
replicationCacheMasterUsingMyself();
|
||||
selectDb(server.cached_master,rsi.repl_stream_db);
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
|
||||
listRewind(server.masters, &li);
|
||||
while ((ln = listNext(&li)))
|
||||
{
|
||||
redisMaster *mi = (redisMaster*)listNodeValue(ln);
|
||||
/* If we are a slave, create a cached master from this
|
||||
* information, in order to allow partial resynchronizations
|
||||
* with masters. */
|
||||
replicationCacheMasterUsingMyself(mi);
|
||||
selectDb(mi->cached_master,rsi.repl_stream_db);
|
||||
}
|
||||
}
|
||||
} else if (errno != ENOENT) {
|
||||
serverLog(LL_WARNING,"Fatal error loading the DB: %s. Exiting.",strerror(errno));
|
||||
@@ -4704,7 +4765,7 @@ void redisOutOfMemoryHandler(size_t allocation_size) {
|
||||
serverPanic("Redis aborting for OUT OF MEMORY");
|
||||
}
|
||||
|
||||
void redisSetProcTitle(char *title) {
|
||||
void redisSetProcTitle(const char *title) {
|
||||
#ifdef USE_SETPROCTITLE
|
||||
const char *server_mode = "";
|
||||
if (server.cluster_enabled) server_mode = " [cluster]";
|
||||
@@ -4911,7 +4972,7 @@ int main(int argc, char **argv) {
|
||||
* the program main. However the program is part of the Redis executable
|
||||
* so that we can easily execute an RDB check on loading errors. */
|
||||
if (strstr(argv[0],"keydb-check-rdb") != NULL)
|
||||
redis_check_rdb_main(argc,argv,NULL);
|
||||
redis_check_rdb_main(argc,(const char**)argv,NULL);
|
||||
else if (strstr(argv[0],"keydb-check-aof") != NULL)
|
||||
redis_check_aof_main(argc,argv);
|
||||
|
||||
@@ -5039,6 +5100,14 @@ int main(int argc, char **argv) {
|
||||
sentinelIsRunning();
|
||||
}
|
||||
|
||||
if (server.rdb_filename == nullptr)
|
||||
{
|
||||
if (server.rdb_s3bucketpath == nullptr)
|
||||
server.rdb_filename = zstrdup(CONFIG_DEFAULT_RDB_FILENAME);
|
||||
else
|
||||
server.repl_diskless_sync = TRUE;
|
||||
}
|
||||
|
||||
if (server.cthreads > 4) {
|
||||
serverLog(LL_WARNING, "Warning: server-threads is set to %d. This is above the maximum recommend value of 4, please ensure you've verified this is actually faster on your machine.", server.cthreads);
|
||||
}
|
||||
@@ -5057,6 +5126,7 @@ int main(int argc, char **argv) {
|
||||
pthread_create(rgthread + iel, NULL, workerThreadMain, (void*)((int64_t)iel));
|
||||
if (server.fThreadAffinity)
|
||||
{
|
||||
#ifdef __linux__
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(iel, &cpuset);
|
||||
@@ -5064,8 +5134,20 @@ int main(int argc, char **argv) {
|
||||
{
|
||||
serverLog(LOG_INFO, "Binding thread %d to cpu %d", iel, iel);
|
||||
}
|
||||
#else
|
||||
serverLog(LL_WARNING, "CPU pinning not available on this platform");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Block SIGALRM from this thread, it should only be received on a server thread */
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGALRM);
|
||||
pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
|
||||
|
||||
/* The main thread sleeps until all the workers are done.
|
||||
this is so that all worker threads are orthogonal in their startup/shutdown */
|
||||
void *pvRet;
|
||||
pthread_join(rgthread[IDX_EVENT_LOOP_MAIN], &pvRet);
|
||||
return 0;
|
||||
|
||||
+114
-64
@@ -76,6 +76,7 @@ typedef long long mstime_t; /* millisecond time type. */
|
||||
#include "quicklist.h" /* Lists are encoded as linked lists of
|
||||
N-elements flat arrays */
|
||||
#include "rax.h" /* Radix tree */
|
||||
#include "uuid.h"
|
||||
|
||||
/* Following includes allow test functions to be called from Redis main() */
|
||||
#include "zipmap.h"
|
||||
@@ -135,7 +136,6 @@ extern "C" {
|
||||
#define CONFIG_DEFAULT_UNIX_SOCKET_PERM 0
|
||||
#define CONFIG_DEFAULT_TCP_KEEPALIVE 300
|
||||
#define CONFIG_DEFAULT_PROTECTED_MODE 1
|
||||
#define CONFIG_DEFAULT_GOPHER_ENABLED 0
|
||||
#define CONFIG_DEFAULT_LOGFILE ""
|
||||
#define CONFIG_DEFAULT_SYSLOG_ENABLED 0
|
||||
#define CONFIG_DEFAULT_STOP_WRITES_ON_BGSAVE_ERROR 1
|
||||
@@ -186,6 +186,9 @@ extern "C" {
|
||||
#define CONFIG_DEFAULT_THREADS 1
|
||||
#define CONFIG_DEFAULT_THREAD_AFFINITY 0
|
||||
|
||||
#define CONFIG_DEFAULT_ACTIVE_REPLICA 0
|
||||
#define CONFIG_DEFAULT_ENABLE_MULTIMASTER 0
|
||||
|
||||
#define ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 20 /* Loopkups per loop. */
|
||||
#define ACTIVE_EXPIRE_CYCLE_FAST_DURATION 1000 /* Microseconds */
|
||||
#define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* CPU max % for keys collection */
|
||||
@@ -262,6 +265,7 @@ extern "C" {
|
||||
#define CMD_CATEGORY_CONNECTION (1ULL<<34)
|
||||
#define CMD_CATEGORY_TRANSACTION (1ULL<<35)
|
||||
#define CMD_CATEGORY_SCRIPTING (1ULL<<36)
|
||||
#define CMD_SKIP_PROPOGATE (1ULL<<37) /* "noprop" flag */
|
||||
|
||||
/* AOF states */
|
||||
#define AOF_OFF 0 /* AOF is off */
|
||||
@@ -301,6 +305,7 @@ extern "C" {
|
||||
#define CLIENT_LUA_DEBUG_SYNC (1<<26) /* EVAL debugging without fork() */
|
||||
#define CLIENT_MODULE (1<<27) /* Non connected client used by some module. */
|
||||
#define CLIENT_PROTECTED (1<<28) /* Client should not be freed for now. */
|
||||
#define CLIENT_FORCE_REPLY (1<<29) /* Should addReply be forced to write the text? */
|
||||
|
||||
/* Client block type (btype field in client structure)
|
||||
* if CLIENT_BLOCKED flag is set. */
|
||||
@@ -335,17 +340,19 @@ extern "C" {
|
||||
#define REPL_STATE_RECEIVE_PONG 3 /* Wait for PING reply */
|
||||
#define REPL_STATE_SEND_AUTH 4 /* Send AUTH to master */
|
||||
#define REPL_STATE_RECEIVE_AUTH 5 /* Wait for AUTH reply */
|
||||
#define REPL_STATE_SEND_PORT 6 /* Send REPLCONF listening-port */
|
||||
#define REPL_STATE_RECEIVE_PORT 7 /* Wait for REPLCONF reply */
|
||||
#define REPL_STATE_SEND_IP 8 /* Send REPLCONF ip-address */
|
||||
#define REPL_STATE_RECEIVE_IP 9 /* Wait for REPLCONF reply */
|
||||
#define REPL_STATE_SEND_CAPA 10 /* Send REPLCONF capa */
|
||||
#define REPL_STATE_RECEIVE_CAPA 11 /* Wait for REPLCONF reply */
|
||||
#define REPL_STATE_SEND_PSYNC 12 /* Send PSYNC */
|
||||
#define REPL_STATE_RECEIVE_PSYNC 13 /* Wait for PSYNC reply */
|
||||
#define REPL_STATE_SEND_UUID 6 /* send our UUID */
|
||||
#define REPL_STATE_RECEIVE_UUID 7 /* they should ack with their UUID */
|
||||
#define REPL_STATE_SEND_PORT 8 /* Send REPLCONF listening-port */
|
||||
#define REPL_STATE_RECEIVE_PORT 9 /* Wait for REPLCONF reply */
|
||||
#define REPL_STATE_SEND_IP 10 /* Send REPLCONF ip-address */
|
||||
#define REPL_STATE_RECEIVE_IP 11 /* Wait for REPLCONF reply */
|
||||
#define REPL_STATE_SEND_CAPA 12 /* Send REPLCONF capa */
|
||||
#define REPL_STATE_RECEIVE_CAPA 13 /* Wait for REPLCONF reply */
|
||||
#define REPL_STATE_SEND_PSYNC 14 /* Send PSYNC */
|
||||
#define REPL_STATE_RECEIVE_PSYNC 15 /* Wait for PSYNC reply */
|
||||
/* --- End of handshake states --- */
|
||||
#define REPL_STATE_TRANSFER 14 /* Receiving .rdb from master */
|
||||
#define REPL_STATE_CONNECTED 15 /* Connected to master */
|
||||
#define REPL_STATE_TRANSFER 16 /* Receiving .rdb from master */
|
||||
#define REPL_STATE_CONNECTED 17 /* Connected to master */
|
||||
|
||||
/* State of slaves from the POV of the master. Used in client->replstate.
|
||||
* In SEND_BULK and ONLINE state the slave receives new updates
|
||||
@@ -485,7 +492,8 @@ extern "C" {
|
||||
#define NOTIFY_EXPIRED (1<<8) /* x */
|
||||
#define NOTIFY_EVICTED (1<<9) /* e */
|
||||
#define NOTIFY_STREAM (1<<10) /* t */
|
||||
#define NOTIFY_ALL (NOTIFY_GENERIC | NOTIFY_STRING | NOTIFY_LIST | NOTIFY_SET | NOTIFY_HASH | NOTIFY_ZSET | NOTIFY_EXPIRED | NOTIFY_EVICTED | NOTIFY_STREAM) /* A flag */
|
||||
#define NOTIFY_KEY_MISS (1<<11) /* m */
|
||||
#define NOTIFY_ALL (NOTIFY_GENERIC | NOTIFY_STRING | NOTIFY_LIST | NOTIFY_SET | NOTIFY_HASH | NOTIFY_ZSET | NOTIFY_EXPIRED | NOTIFY_EVICTED | NOTIFY_STREAM | NOTIFY_KEY_MISS) /* A flag */
|
||||
|
||||
/* Get the first bind addr or NULL */
|
||||
#define NET_FIRST_BIND_ADDR (server.bindaddr_count ? server.bindaddr[0] : NULL)
|
||||
@@ -595,16 +603,18 @@ typedef struct RedisModuleIO {
|
||||
int ver; /* Module serialization version: 1 (old),
|
||||
* 2 (current version with opcodes annotation). */
|
||||
struct RedisModuleCtx *ctx; /* Optional context, see RM_GetContextFromIO()*/
|
||||
struct redisObject *key; /* Optional name of key processed */
|
||||
} RedisModuleIO;
|
||||
|
||||
/* Macro to initialize an IO context. Note that the 'ver' field is populated
|
||||
* inside rdb.c according to the version of the value to load. */
|
||||
#define moduleInitIOContext(iovar,mtype,rioptr) do { \
|
||||
#define moduleInitIOContext(iovar,mtype,rioptr,keyptr) do { \
|
||||
iovar.prio = rioptr; \
|
||||
iovar.type = mtype; \
|
||||
iovar.bytes = 0; \
|
||||
iovar.error = 0; \
|
||||
iovar.ver = 0; \
|
||||
iovar.key = keyptr; \
|
||||
iovar.ctx = NULL; \
|
||||
} while(0);
|
||||
|
||||
@@ -661,6 +671,11 @@ __attribute__((always_inline)) inline void *ptrFromObj(const robj *o)
|
||||
return o->m_ptr;
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) inline char *szFromObj(const robj *o)
|
||||
{
|
||||
return (char*)ptrFromObj(o);
|
||||
}
|
||||
|
||||
/* Macro used to initialize a Redis object allocated on the stack.
|
||||
* Note that this macro is taken near the structure definition to make sure
|
||||
* we'll update it when the structure is changed, to avoid bugs like
|
||||
@@ -869,6 +884,11 @@ typedef struct client {
|
||||
sds peerid; /* Cached peer ID. */
|
||||
listNode *client_list_node; /* list node in client list */
|
||||
|
||||
/* UUID announced by the client (default nil) - used to detect multiple connections to/from the same peer */
|
||||
/* compliant servers will announce their UUIDs when a replica connection is started, and return when asked */
|
||||
/* UUIDs are transient and lost when the server is shut down */
|
||||
unsigned char uuid[UUID_BINARY_LEN];
|
||||
|
||||
/* Response buffer */
|
||||
int bufpos;
|
||||
char buf[PROTO_REPLY_CHUNK_BYTES];
|
||||
@@ -910,15 +930,21 @@ struct sharedObjectsStruct {
|
||||
};
|
||||
|
||||
/* ZSETs use a specialized version of Skiplists */
|
||||
struct zskiplistLevel {
|
||||
struct zskiplistNode *forward;
|
||||
unsigned long span;
|
||||
};
|
||||
typedef struct zskiplistNode {
|
||||
sds ele;
|
||||
double score;
|
||||
struct zskiplistNode *backward;
|
||||
#ifndef __cplusplus
|
||||
struct zskiplistLevel {
|
||||
struct zskiplistNode *forward;
|
||||
unsigned long span;
|
||||
} level[];
|
||||
|
||||
#ifdef __cplusplus
|
||||
zskiplistLevel *level(size_t idx) {
|
||||
return reinterpret_cast<zskiplistLevel*>(this+1) + idx;
|
||||
}
|
||||
#else
|
||||
struct zskiplistLevel level[];
|
||||
#endif
|
||||
} zskiplistNode;
|
||||
|
||||
@@ -1014,9 +1040,10 @@ typedef struct rdbSaveInfo {
|
||||
int repl_id_is_set; /* True if repl_id field is set. */
|
||||
char repl_id[CONFIG_RUN_ID_SIZE+1]; /* Replication ID. */
|
||||
long long repl_offset; /* Replication offset. */
|
||||
int fForceSetKey;
|
||||
} rdbSaveInfo;
|
||||
|
||||
#define RDB_SAVE_INFO_INIT {-1,0,"000000000000000000000000000000",-1}
|
||||
#define RDB_SAVE_INFO_INIT {-1,0,"000000000000000000000000000000",-1, TRUE}
|
||||
|
||||
struct malloc_stats {
|
||||
size_t zmalloc_used;
|
||||
@@ -1053,9 +1080,37 @@ struct redisServerThreadVars {
|
||||
list *clients_pending_write; /* There is to write or install handler. */
|
||||
list *unblocked_clients; /* list of clients to unblock before next loop NOT THREADSAFE */
|
||||
list *clients_pending_asyncwrite;
|
||||
int cclients;
|
||||
struct fastlock lockPendingWrite;
|
||||
};
|
||||
|
||||
struct redisMaster {
|
||||
char *masteruser; /* AUTH with this user and masterauth with master */
|
||||
char *masterauth; /* AUTH with this password with master */
|
||||
char *masterhost; /* Hostname of master */
|
||||
int masterport; /* Port of master */
|
||||
client *cached_master; /* Cached master to be reused for PSYNC. */
|
||||
client *master;
|
||||
/* The following two fields is where we store master PSYNC replid/offset
|
||||
* while the PSYNC is in progress. At the end we'll copy the fields into
|
||||
* the server->master client structure. */
|
||||
char master_replid[CONFIG_RUN_ID_SIZE+1]; /* Master PSYNC runid. */
|
||||
long long master_initial_offset; /* Master PSYNC offset. */
|
||||
|
||||
int repl_state; /* Replication status if the instance is a slave */
|
||||
off_t repl_transfer_size; /* Size of RDB to read from master during sync. */
|
||||
off_t repl_transfer_read; /* Amount of RDB read from master during sync. */
|
||||
off_t repl_transfer_last_fsync_off; /* Offset when we fsync-ed last time. */
|
||||
int repl_transfer_s; /* Slave -> Master SYNC socket */
|
||||
int repl_transfer_fd; /* Slave -> Master SYNC temp file descriptor */
|
||||
char *repl_transfer_tmpfile; /* Slave-> master SYNC temp file name */
|
||||
time_t repl_transfer_lastio; /* Unix time of the latest read, for timeout */
|
||||
time_t repl_down_since; /* Unix time at which link with master went down */
|
||||
|
||||
unsigned char master_uuid[UUID_BINARY_LEN]; /* Used during sync with master, this is our master's UUID */
|
||||
/* After we've connected with our master use the UUID in server.master */
|
||||
};
|
||||
|
||||
struct redisServer {
|
||||
/* General */
|
||||
pid_t pid; /* Main process pid. */
|
||||
@@ -1115,8 +1170,6 @@ struct redisServer {
|
||||
dict *migrate_cached_sockets;/* MIGRATE cached sockets */
|
||||
uint64_t next_client_id; /* Next client unique ID. Incremental. */
|
||||
int protected_mode; /* Don't accept external connections. */
|
||||
int gopher_enabled; /* If true the server will reply to gopher
|
||||
queries. Will still serve RESP2 queries. */
|
||||
/* RDB / AOF loading information */
|
||||
int loading; /* We are loading data from disk if true */
|
||||
off_t loading_total_bytes;
|
||||
@@ -1128,7 +1181,7 @@ struct redisServer {
|
||||
*lpopCommand, *rpopCommand, *zpopminCommand,
|
||||
*zpopmaxCommand, *sremCommand, *execCommand,
|
||||
*expireCommand, *pexpireCommand, *xclaimCommand,
|
||||
*xgroupCommand;
|
||||
*xgroupCommand, *rreplayCommand;
|
||||
/* Fields used only for stats */
|
||||
time_t stat_starttime; /* Server start time */
|
||||
long long stat_numcommands; /* Number of processed commands */
|
||||
@@ -1169,6 +1222,8 @@ struct redisServer {
|
||||
int idx;
|
||||
} inst_metric[STATS_METRIC_COUNT];
|
||||
/* Configuration */
|
||||
char *default_masteruser; /* AUTH with this user and masterauth with master */
|
||||
char *default_masterauth; /* AUTH with this password with master */
|
||||
int verbosity; /* Loglevel in redis.conf */
|
||||
int maxidletime; /* Client timeout in seconds */
|
||||
int tcpkeepalive; /* Set SO_KEEPALIVE if non-zero. */
|
||||
@@ -1282,35 +1337,17 @@ struct redisServer {
|
||||
int repl_diskless_sync; /* Send RDB to slaves sockets directly. */
|
||||
int repl_diskless_sync_delay; /* Delay to start a diskless repl BGSAVE. */
|
||||
/* Replication (slave) */
|
||||
char *masteruser; /* AUTH with this user and masterauth with master */
|
||||
char *masterauth; /* AUTH with this password with master */
|
||||
char *masterhost; /* Hostname of master */
|
||||
int masterport; /* Port of master */
|
||||
list *masters;
|
||||
int enable_multimaster;
|
||||
int repl_timeout; /* Timeout after N seconds of master idle */
|
||||
client *master; /* Client that is master for this slave */
|
||||
client *cached_master; /* Cached master to be reused for PSYNC. */
|
||||
int repl_syncio_timeout; /* Timeout for synchronous I/O calls */
|
||||
int repl_state; /* Replication status if the instance is a slave */
|
||||
off_t repl_transfer_size; /* Size of RDB to read from master during sync. */
|
||||
off_t repl_transfer_read; /* Amount of RDB read from master during sync. */
|
||||
off_t repl_transfer_last_fsync_off; /* Offset when we fsync-ed last time. */
|
||||
int repl_transfer_s; /* Slave -> Master SYNC socket */
|
||||
int repl_transfer_fd; /* Slave -> Master SYNC temp file descriptor */
|
||||
char *repl_transfer_tmpfile; /* Slave-> master SYNC temp file name */
|
||||
time_t repl_transfer_lastio; /* Unix time of the latest read, for timeout */
|
||||
int repl_disable_tcp_nodelay; /* Disable TCP_NODELAY after SYNC? */
|
||||
int repl_serve_stale_data; /* Serve stale data when link is down? */
|
||||
int repl_slave_ro; /* Slave is read only? */
|
||||
int repl_slave_ignore_maxmemory; /* If true slaves do not evict. */
|
||||
time_t repl_down_since; /* Unix time at which link with master went down */
|
||||
int repl_disable_tcp_nodelay; /* Disable TCP_NODELAY after SYNC? */
|
||||
int slave_priority; /* Reported in INFO and used by Sentinel. */
|
||||
int slave_announce_port; /* Give the master this listening port. */
|
||||
char *slave_announce_ip; /* Give the master this ip address. */
|
||||
/* The following two fields is where we store master PSYNC replid/offset
|
||||
* while the PSYNC is in progress. At the end we'll copy the fields into
|
||||
* the server->master client structure. */
|
||||
char master_replid[CONFIG_RUN_ID_SIZE+1]; /* Master PSYNC runid. */
|
||||
long long master_initial_offset; /* Master PSYNC offset. */
|
||||
int repl_slave_lazy_flush; /* Lazy FLUSHALL before loading DB? */
|
||||
/* Replication script cache. */
|
||||
dict *repl_scriptcache_dict; /* SHA1 all slaves are aware of. */
|
||||
@@ -1420,6 +1457,9 @@ struct redisServer {
|
||||
pthread_mutex_t next_client_id_mutex;
|
||||
pthread_mutex_t unixtime_mutex;
|
||||
|
||||
int fActiveReplica; /* Can this replica also be a master? */
|
||||
unsigned char uuid[UUID_BINARY_LEN]; /* This server's UUID - populated on boot */
|
||||
|
||||
struct fastlock flock;
|
||||
};
|
||||
|
||||
@@ -1551,6 +1591,7 @@ size_t moduleCount(void);
|
||||
void moduleAcquireGIL(int fServerThread);
|
||||
void moduleReleaseGIL(int fServerThread);
|
||||
void moduleNotifyKeyspaceEvent(int type, const char *event, robj *key, int dbid);
|
||||
void moduleCallCommandFilters(client *c);
|
||||
|
||||
/* Utils */
|
||||
long long ustime(void);
|
||||
@@ -1560,7 +1601,7 @@ void getRandomBytes(unsigned char *p, size_t len);
|
||||
uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l);
|
||||
void exitFromChild(int retcode);
|
||||
size_t redisPopcount(void *s, long count);
|
||||
void redisSetProcTitle(char *title);
|
||||
void redisSetProcTitle(const char *title);
|
||||
|
||||
/* networking.c -- Networking and Client related operations */
|
||||
client *createClient(int fd, int iel);
|
||||
@@ -1575,9 +1616,8 @@ void setDeferredMapLen(client *c, void *node, long length);
|
||||
void setDeferredSetLen(client *c, void *node, long length);
|
||||
void setDeferredAttributeLen(client *c, void *node, long length);
|
||||
void setDeferredPushLen(client *c, void *node, long length);
|
||||
void processInputBuffer(client *c);
|
||||
void processInputBuffer(client *c, int callFlags);
|
||||
void processInputBufferAndReplicate(client *c);
|
||||
void processGopherRequest(client *c);
|
||||
void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask);
|
||||
void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask);
|
||||
void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask);
|
||||
@@ -1599,6 +1639,9 @@ void addReplyStatus(client *c, const char *status);
|
||||
void addReplyDouble(client *c, double d);
|
||||
void addReplyHumanLongDouble(client *c, long double d);
|
||||
void addReplyLongLong(client *c, long long ll);
|
||||
#ifdef __cplusplus
|
||||
void addReplyLongLongWithPrefixCore(client *c, long long ll, char prefix, bool fAsync);
|
||||
#endif
|
||||
void addReplyArrayLen(client *c, long length);
|
||||
void addReplyMapLen(client *c, long length);
|
||||
void addReplySetLen(client *c, long length);
|
||||
@@ -1628,6 +1671,7 @@ int getClientTypeByName(const char *name);
|
||||
const char *getClientTypeName(int cclass);
|
||||
void flushSlavesOutputBuffers(void);
|
||||
void disconnectSlaves(void);
|
||||
void disconnectSlavesExcept(unsigned char *uuid);
|
||||
int listenToPort(int port, int *fds, int *count, int fReusePort);
|
||||
void pauseClients(mstime_t duration);
|
||||
int clientsArePaused(void);
|
||||
@@ -1737,7 +1781,7 @@ int getDoubleFromObject(const robj *o, double *target);
|
||||
int getLongLongFromObject(robj *o, long long *target);
|
||||
int getLongDoubleFromObject(robj *o, long double *target);
|
||||
int getLongDoubleFromObjectOrReply(client *c, robj *o, long double *target, const char *msg);
|
||||
char *strEncoding(int encoding);
|
||||
const char *strEncoding(int encoding);
|
||||
int compareStringObjects(robj *a, robj *b);
|
||||
int collateStringObjects(robj *a, robj *b);
|
||||
int equalStringObjects(robj *a, robj *b);
|
||||
@@ -1751,16 +1795,17 @@ ssize_t syncRead(int fd, char *ptr, ssize_t size, long long timeout);
|
||||
ssize_t syncReadLine(int fd, char *ptr, ssize_t size, long long timeout);
|
||||
|
||||
/* Replication */
|
||||
void initMasterInfo(struct redisMaster *master);
|
||||
void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc);
|
||||
void replicationFeedSlavesFromMasterStream(list *slaves, char *buf, size_t buflen);
|
||||
void replicationFeedMonitors(client *c, list *monitors, int dictid, robj **argv, int argc);
|
||||
void updateSlavesWaitingBgsave(int bgsaveerr, int type);
|
||||
void replicationCron(void);
|
||||
void replicationHandleMasterDisconnection(void);
|
||||
void replicationCacheMaster(client *c);
|
||||
void replicationHandleMasterDisconnection(struct redisMaster *mi);
|
||||
void replicationCacheMaster(struct redisMaster *mi, client *c);
|
||||
void resizeReplicationBacklog(long long newsize);
|
||||
void replicationSetMaster(char *ip, int port);
|
||||
void replicationUnsetMaster(void);
|
||||
struct redisMaster *replicationAddMaster(char *ip, int port);
|
||||
void replicationUnsetMaster(struct redisMaster *mi);
|
||||
void refreshGoodSlavesCount(void);
|
||||
void replicationScriptCacheInit(void);
|
||||
void replicationScriptCacheFlush(void);
|
||||
@@ -1769,16 +1814,16 @@ int replicationScriptCacheExists(sds sha1);
|
||||
void processClientsWaitingReplicas(void);
|
||||
void unblockClientWaitingReplicas(client *c);
|
||||
int replicationCountAcksByOffset(long long offset);
|
||||
void replicationSendNewlineToMaster(void);
|
||||
long long replicationGetSlaveOffset(void);
|
||||
void replicationSendNewlineToMaster(struct redisMaster *mi);
|
||||
long long replicationGetSlaveOffset(struct redisMaster *mi);
|
||||
char *replicationGetSlaveName(client *c);
|
||||
long long getPsyncInitialOffset(void);
|
||||
int replicationSetupSlaveForFullResync(client *slave, long long offset);
|
||||
void changeReplicationId(void);
|
||||
void clearReplicationId2(void);
|
||||
void chopReplicationBacklog(void);
|
||||
void replicationCacheMasterUsingMyself(void);
|
||||
void feedReplicationBacklog(void *ptr, size_t len);
|
||||
void replicationCacheMasterUsingMyself(struct redisMaster *mi);
|
||||
void feedReplicationBacklog(const void *ptr, size_t len);
|
||||
|
||||
/* Generic persistence functions */
|
||||
void startLoading(FILE *fp);
|
||||
@@ -1832,7 +1877,7 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen);
|
||||
sds ACLDefaultUserFirstPassword(void);
|
||||
uint64_t ACLGetCommandCategoryFlagByName(const char *name);
|
||||
int ACLAppendUserForLoading(sds *argv, int argc, int *argc_err);
|
||||
char *ACLSetUserStringError(void);
|
||||
const char *ACLSetUserStringError(void);
|
||||
int ACLLoadConfiguredUsers(void);
|
||||
sds ACLDescribeUser(user *u);
|
||||
void ACLLoadUsersAtStartup(void);
|
||||
@@ -1907,7 +1952,7 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev
|
||||
size_t freeMemoryGetNotCountedMemory();
|
||||
int freeMemoryIfNeeded(void);
|
||||
int freeMemoryIfNeededAndSafe(void);
|
||||
int processCommand(client *c);
|
||||
int processCommand(client *c, int callFlags);
|
||||
void setupSignalHandlers(void);
|
||||
struct redisCommand *lookupCommand(sds name);
|
||||
struct redisCommand *lookupCommandByCString(const char *s);
|
||||
@@ -1995,7 +2040,7 @@ int listMatchPubsubPattern(void *a, void *b);
|
||||
int pubsubPublishMessage(robj *channel, robj *message);
|
||||
|
||||
/* Keyspace events notification */
|
||||
void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid);
|
||||
void notifyKeyspaceEvent(int type, const char *event, robj *key, int dbid);
|
||||
int keyspaceEventsStringToFlags(char *classes);
|
||||
sds keyspaceEventsFlagsToString(int flags);
|
||||
|
||||
@@ -2027,6 +2072,7 @@ void objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle,
|
||||
#define LOOKUP_NOTOUCH (1<<0)
|
||||
void dbAdd(redisDb *db, robj *key, robj *val);
|
||||
void dbOverwrite(redisDb *db, robj *key, robj *val);
|
||||
int dbMerge(redisDb *db, robj *key, robj *val, int fReplace);
|
||||
void setKey(redisDb *db, robj *key, robj *val);
|
||||
int dbExists(redisDb *db, robj *key);
|
||||
robj *dbRandomKey(redisDb *db);
|
||||
@@ -2080,12 +2126,12 @@ int clusterSendModuleMessageToTarget(const char *target, uint64_t module_id, uin
|
||||
void initSentinelConfig(void);
|
||||
void initSentinel(void);
|
||||
void sentinelTimer(void);
|
||||
char *sentinelHandleConfiguration(char **argv, int argc);
|
||||
const char *sentinelHandleConfiguration(char **argv, int argc);
|
||||
void sentinelIsRunning(void);
|
||||
|
||||
/* keydb-check-rdb & aof */
|
||||
int redis_check_rdb(char *rdbfilename, FILE *fp);
|
||||
int redis_check_rdb_main(int argc, char **argv, FILE *fp);
|
||||
int redis_check_rdb(const char *rdbfilename, FILE *fp);
|
||||
int redis_check_rdb_main(int argc, const char **argv, FILE *fp);
|
||||
int redis_check_aof_main(int argc, char **argv);
|
||||
|
||||
/* Scripting */
|
||||
@@ -2326,8 +2372,12 @@ void xclaimCommand(client *c);
|
||||
void xinfoCommand(client *c);
|
||||
void xdelCommand(client *c);
|
||||
void xtrimCommand(client *c);
|
||||
void lolwutCommand(client *c);
|
||||
void aclCommand(client *c);
|
||||
void replicaReplayCommand(client *c);
|
||||
|
||||
int FBrokenLinkToMaster();
|
||||
int FActiveMaster(client *c);
|
||||
struct redisMaster *MasterInfoFromClient(client *c);
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#ifndef __cplusplus
|
||||
@@ -2349,10 +2399,10 @@ sds genRedisInfoString(const char *section);
|
||||
void enableWatchdog(int period);
|
||||
void disableWatchdog(void);
|
||||
void watchdogScheduleSignal(int period);
|
||||
void serverLogHexDump(int level, char *descr, void *value, size_t len);
|
||||
void serverLogHexDump(int level, const char *descr, void *value, size_t len);
|
||||
int memtest_preserving_test(unsigned long *m, size_t bytes, int passes);
|
||||
void mixDigest(unsigned char *digest, void *ptr, size_t len);
|
||||
void xorDigest(unsigned char *digest, void *ptr, size_t len);
|
||||
void xorDigest(unsigned char *digest, const void *ptr, size_t len);
|
||||
int populateCommandTableParseFlags(struct redisCommand *c, const char *strflags);
|
||||
|
||||
int moduleGILAcquiredByModule(void);
|
||||
|
||||
@@ -46,12 +46,12 @@
|
||||
* Incrementing the ref count of all the objects retained is up to
|
||||
* this function. */
|
||||
slowlogEntry *slowlogCreateEntry(client *c, robj **argv, int argc, long long duration) {
|
||||
slowlogEntry *se = zmalloc(sizeof(*se), MALLOC_LOCAL);
|
||||
slowlogEntry *se = (slowlogEntry*)zmalloc(sizeof(*se), MALLOC_LOCAL);
|
||||
int j, slargc = argc;
|
||||
|
||||
if (slargc > SLOWLOG_ENTRY_MAX_ARGC) slargc = SLOWLOG_ENTRY_MAX_ARGC;
|
||||
se->argc = slargc;
|
||||
se->argv = zmalloc(sizeof(robj*)*slargc, MALLOC_LOCAL);
|
||||
se->argv = (robj**)zmalloc(sizeof(robj*)*slargc, MALLOC_LOCAL);
|
||||
for (j = 0; j < slargc; j++) {
|
||||
/* Logging too many arguments is a useless memory waste, so we stop
|
||||
* at SLOWLOG_ENTRY_MAX_ARGC, but use the last argument to specify
|
||||
@@ -64,13 +64,13 @@ slowlogEntry *slowlogCreateEntry(client *c, robj **argv, int argc, long long dur
|
||||
/* Trim too long strings as well... */
|
||||
if (argv[j]->type == OBJ_STRING &&
|
||||
sdsEncodedObject(argv[j]) &&
|
||||
sdslen(ptrFromObj(argv[j])) > SLOWLOG_ENTRY_MAX_STRING)
|
||||
sdslen(szFromObj(argv[j])) > SLOWLOG_ENTRY_MAX_STRING)
|
||||
{
|
||||
sds s = sdsnewlen(ptrFromObj(argv[j]), SLOWLOG_ENTRY_MAX_STRING);
|
||||
|
||||
s = sdscatprintf(s,"... (%lu more bytes)",
|
||||
(unsigned long)
|
||||
sdslen(ptrFromObj(argv[j])) - SLOWLOG_ENTRY_MAX_STRING);
|
||||
sdslen(szFromObj(argv[j])) - SLOWLOG_ENTRY_MAX_STRING);
|
||||
se->argv[j] = createObject(OBJ_STRING,s);
|
||||
} else if (argv[j]->refcount == OBJ_SHARED_REFCOUNT) {
|
||||
se->argv[j] = argv[j];
|
||||
@@ -89,7 +89,7 @@ slowlogEntry *slowlogCreateEntry(client *c, robj **argv, int argc, long long dur
|
||||
se->duration = duration;
|
||||
se->id = server.slowlog_entry_id++;
|
||||
se->peerid = sdsnew(getClientPeerId(c));
|
||||
se->cname = c->name ? sdsnew(ptrFromObj(c->name)) : sdsempty();
|
||||
se->cname = c->name ? sdsnew(szFromObj(c->name)) : sdsempty();
|
||||
return se;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ slowlogEntry *slowlogCreateEntry(client *c, robj **argv, int argc, long long dur
|
||||
*
|
||||
* This function will take care to release all the retained object. */
|
||||
void slowlogFreeEntry(void *septr) {
|
||||
slowlogEntry *se = septr;
|
||||
slowlogEntry *se = (slowlogEntry*)septr;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < se->argc; j++)
|
||||
@@ -140,7 +140,7 @@ void slowlogReset(void) {
|
||||
/* The SLOWLOG command. Implements all the subcommands needed to handle the
|
||||
* Redis slow log. */
|
||||
void slowlogCommand(client *c) {
|
||||
if (c->argc == 2 && !strcasecmp(ptrFromObj(c->argv[1]),"help")) {
|
||||
if (c->argc == 2 && !strcasecmp(szFromObj(c->argv[1]),"help")) {
|
||||
const char *help[] = {
|
||||
"GET [count] -- Return top entries from the slowlog (default: 10)."
|
||||
" Entries are made of:",
|
||||
@@ -150,13 +150,13 @@ void slowlogCommand(client *c) {
|
||||
NULL
|
||||
};
|
||||
addReplyHelp(c, help);
|
||||
} else if (c->argc == 2 && !strcasecmp(ptrFromObj(c->argv[1]),"reset")) {
|
||||
} else if (c->argc == 2 && !strcasecmp(szFromObj(c->argv[1]),"reset")) {
|
||||
slowlogReset();
|
||||
addReply(c,shared.ok);
|
||||
} else if (c->argc == 2 && !strcasecmp(ptrFromObj(c->argv[1]),"len")) {
|
||||
} else if (c->argc == 2 && !strcasecmp(szFromObj(c->argv[1]),"len")) {
|
||||
addReplyLongLong(c,listLength(server.slowlog));
|
||||
} else if ((c->argc == 2 || c->argc == 3) &&
|
||||
!strcasecmp(ptrFromObj(c->argv[1]),"get"))
|
||||
!strcasecmp(szFromObj(c->argv[1]),"get"))
|
||||
{
|
||||
long count = 10, sent = 0;
|
||||
listIter li;
|
||||
@@ -173,7 +173,7 @@ NULL
|
||||
while(count-- && (ln = listNext(&li))) {
|
||||
int j;
|
||||
|
||||
se = ln->value;
|
||||
se = (slowlogEntry*)ln->value;
|
||||
addReplyArrayLen(c,6);
|
||||
addReplyLongLong(c,se->id);
|
||||
addReplyLongLong(c,se->time);
|
||||
+54
-47
@@ -36,7 +36,7 @@
|
||||
zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank);
|
||||
|
||||
redisSortOperation *createSortOperation(int type, robj *pattern) {
|
||||
redisSortOperation *so = zmalloc(sizeof(*so), MALLOC_LOCAL);
|
||||
redisSortOperation *so = (redisSortOperation*)zmalloc(sizeof(*so), MALLOC_LOCAL);
|
||||
so->type = type;
|
||||
so->pattern = pattern;
|
||||
return so;
|
||||
@@ -58,7 +58,7 @@ redisSortOperation *createSortOperation(int type, robj *pattern) {
|
||||
*
|
||||
* The returned object will always have its refcount increased by 1
|
||||
* when it is non-NULL. */
|
||||
robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
|
||||
robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst, int writeflag) {
|
||||
char *p, *f, *k;
|
||||
sds spat, ssub;
|
||||
robj *keyobj, *fieldobj = NULL, *o;
|
||||
@@ -66,7 +66,7 @@ robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
|
||||
|
||||
/* If the pattern is "#" return the substitution object itself in order
|
||||
* to implement the "SORT ... GET #" feature. */
|
||||
spat = ptrFromObj(pattern);
|
||||
spat = szFromObj(pattern);
|
||||
if (spat[0] == '#' && spat[1] == '\0') {
|
||||
incrRefCount(subst);
|
||||
return subst;
|
||||
@@ -76,7 +76,7 @@ robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
|
||||
* a decoded object on the fly. Otherwise getDecodedObject will just
|
||||
* increment the ref count, that we'll decrement later. */
|
||||
subst = getDecodedObject(subst);
|
||||
ssub = ptrFromObj(subst);
|
||||
ssub = szFromObj(subst);
|
||||
|
||||
/* If we can't find '*' in the pattern we return NULL as to GET a
|
||||
* fixed key does not make sense. */
|
||||
@@ -99,14 +99,17 @@ robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
|
||||
sublen = sdslen(ssub);
|
||||
postfixlen = sdslen(spat)-(prefixlen+1)-(fieldlen ? fieldlen+2 : 0);
|
||||
keyobj = createStringObject(NULL,prefixlen+sublen+postfixlen);
|
||||
k = ptrFromObj(keyobj);
|
||||
k = szFromObj(keyobj);
|
||||
memcpy(k,spat,prefixlen);
|
||||
memcpy(k+prefixlen,ssub,sublen);
|
||||
memcpy(k+prefixlen+sublen,p+1,postfixlen);
|
||||
decrRefCount(subst); /* Incremented by decodeObject() */
|
||||
|
||||
/* Lookup substituted key */
|
||||
o = lookupKeyRead(db,keyobj);
|
||||
if (!writeflag)
|
||||
o = lookupKeyRead(db,keyobj);
|
||||
else
|
||||
o = lookupKeyWrite(db,keyobj);
|
||||
if (o == NULL) goto noobj;
|
||||
|
||||
if (fieldobj) {
|
||||
@@ -114,7 +117,7 @@ robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
|
||||
|
||||
/* Retrieve value from hash by the field name. The returend object
|
||||
* is a new object with refcount already incremented. */
|
||||
o = hashTypeGetValueObject(o, ptrFromObj(fieldobj));
|
||||
o = hashTypeGetValueObject(o, szFromObj(fieldobj));
|
||||
} else {
|
||||
if (o->type != OBJ_STRING) goto noobj;
|
||||
|
||||
@@ -136,7 +139,7 @@ noobj:
|
||||
* the additional parameter is not standard but a BSD-specific we have to
|
||||
* pass sorting parameters via the global 'server' structure */
|
||||
int sortCompare(const void *s1, const void *s2) {
|
||||
const redisSortObject *so1 = s1, *so2 = s2;
|
||||
const redisSortObject *so1 = (redisSortObject*)s1, *so2 = (redisSortObject*)s2;
|
||||
int cmp;
|
||||
|
||||
if (!server.sort_alpha) {
|
||||
@@ -169,7 +172,7 @@ int sortCompare(const void *s1, const void *s2) {
|
||||
} else {
|
||||
/* Here we can use strcoll() directly as we are sure that
|
||||
* the objects are decoded string objects. */
|
||||
cmp = strcoll(ptrFromObj(so1->u.cmpobj),ptrFromObj(so2->u.cmpobj));
|
||||
cmp = strcoll(szFromObj(so1->u.cmpobj),szFromObj(so2->u.cmpobj));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -198,40 +201,22 @@ void sortCommand(client *c) {
|
||||
robj *sortval, *sortby = NULL, *storekey = NULL;
|
||||
redisSortObject *vector; /* Resulting vector to sort */
|
||||
|
||||
/* Lookup the key to sort. It must be of the right types */
|
||||
sortval = lookupKeyRead(c->db,c->argv[1]);
|
||||
if (sortval && sortval->type != OBJ_SET &&
|
||||
sortval->type != OBJ_LIST &&
|
||||
sortval->type != OBJ_ZSET)
|
||||
{
|
||||
addReply(c,shared.wrongtypeerr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a list of operations to perform for every sorted element.
|
||||
* Operations can be GET */
|
||||
operations = listCreate();
|
||||
listSetFreeMethod(operations,zfree);
|
||||
j = 2; /* options start at argv[2] */
|
||||
|
||||
/* Now we need to protect sortval incrementing its count, in the future
|
||||
* SORT may have options able to overwrite/delete keys during the sorting
|
||||
* and the sorted key itself may get destroyed */
|
||||
if (sortval)
|
||||
incrRefCount(sortval);
|
||||
else
|
||||
sortval = createQuicklistObject();
|
||||
|
||||
/* The SORT command has an SQL-alike syntax, parse it */
|
||||
while(j < c->argc) {
|
||||
int leftargs = c->argc-j-1;
|
||||
if (!strcasecmp(ptrFromObj(c->argv[j]),"asc")) {
|
||||
if (!strcasecmp(szFromObj(c->argv[j]),"asc")) {
|
||||
desc = 0;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"desc")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"desc")) {
|
||||
desc = 1;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"alpha")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"alpha")) {
|
||||
alpha = 1;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"limit") && leftargs >= 2) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"limit") && leftargs >= 2) {
|
||||
if ((getLongFromObjectOrReply(c, c->argv[j+1], &limit_start, NULL)
|
||||
!= C_OK) ||
|
||||
(getLongFromObjectOrReply(c, c->argv[j+2], &limit_count, NULL)
|
||||
@@ -241,14 +226,14 @@ void sortCommand(client *c) {
|
||||
break;
|
||||
}
|
||||
j+=2;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"store") && leftargs >= 1) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"store") && leftargs >= 1) {
|
||||
storekey = c->argv[j+1];
|
||||
j++;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"by") && leftargs >= 1) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"by") && leftargs >= 1) {
|
||||
sortby = c->argv[j+1];
|
||||
/* If the BY pattern does not contain '*', i.e. it is constant,
|
||||
* we don't need to sort nor to lookup the weight keys. */
|
||||
if (strchr(ptrFromObj(c->argv[j+1]),'*') == NULL) {
|
||||
if (strchr(szFromObj(c->argv[j+1]),'*') == NULL) {
|
||||
dontsort = 1;
|
||||
} else {
|
||||
/* If BY is specified with a real patter, we can't accept
|
||||
@@ -260,7 +245,7 @@ void sortCommand(client *c) {
|
||||
}
|
||||
}
|
||||
j++;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"get") && leftargs >= 1) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"get") && leftargs >= 1) {
|
||||
if (server.cluster_enabled) {
|
||||
addReplyError(c,"GET option of SORT denied in Cluster mode.");
|
||||
syntax_error++;
|
||||
@@ -280,11 +265,33 @@ void sortCommand(client *c) {
|
||||
|
||||
/* Handle syntax errors set during options parsing. */
|
||||
if (syntax_error) {
|
||||
decrRefCount(sortval);
|
||||
listRelease(operations);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Lookup the key to sort. It must be of the right types */
|
||||
if (storekey)
|
||||
sortval = lookupKeyRead(c->db,c->argv[1]);
|
||||
else
|
||||
sortval = lookupKeyWrite(c->db,c->argv[1]);
|
||||
if (sortval && sortval->type != OBJ_SET &&
|
||||
sortval->type != OBJ_LIST &&
|
||||
sortval->type != OBJ_ZSET)
|
||||
{
|
||||
listRelease(operations);
|
||||
addReply(c,shared.wrongtypeerr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we need to protect sortval incrementing its count, in the future
|
||||
* SORT may have options able to overwrite/delete keys during the sorting
|
||||
* and the sorted key itself may get destroyed */
|
||||
if (sortval)
|
||||
incrRefCount(sortval);
|
||||
else
|
||||
sortval = createQuicklistObject();
|
||||
|
||||
|
||||
/* When sorting a set with no sort specified, we must sort the output
|
||||
* so the result is consistent across scripting and replication.
|
||||
*
|
||||
@@ -340,7 +347,7 @@ void sortCommand(client *c) {
|
||||
}
|
||||
|
||||
/* Load the sorting vector with all the objects to sort */
|
||||
vector = zmalloc(sizeof(redisSortObject)*vectorlen, MALLOC_LOCAL);
|
||||
vector = (redisSortObject*)zmalloc(sizeof(redisSortObject)*vectorlen, MALLOC_LOCAL);
|
||||
j = 0;
|
||||
|
||||
if (sortval->type == OBJ_LIST && dontsort) {
|
||||
@@ -396,7 +403,7 @@ void sortCommand(client *c) {
|
||||
* Note that in this case we also handle LIMIT here in a direct
|
||||
* way, just getting the required range, as an optimization. */
|
||||
|
||||
zset *zs = ptrFromObj(sortval);
|
||||
zset *zs = (zset*)ptrFromObj(sortval);
|
||||
zskiplist *zsl = zs->zsl;
|
||||
zskiplistNode *ln;
|
||||
sds sdsele;
|
||||
@@ -410,7 +417,7 @@ void sortCommand(client *c) {
|
||||
if (start > 0)
|
||||
ln = zslGetElementByRank(zsl,zsetlen-start);
|
||||
} else {
|
||||
ln = zsl->header->level[0].forward;
|
||||
ln = zsl->header->level(0)->forward;
|
||||
if (start > 0)
|
||||
ln = zslGetElementByRank(zsl,start+1);
|
||||
}
|
||||
@@ -422,7 +429,7 @@ void sortCommand(client *c) {
|
||||
vector[j].u.score = 0;
|
||||
vector[j].u.cmpobj = NULL;
|
||||
j++;
|
||||
ln = desc ? ln->backward : ln->level[0].forward;
|
||||
ln = desc ? ln->backward : ln->level(0)->forward;
|
||||
}
|
||||
/* Fix start/end: output code is not aware of this optimization. */
|
||||
end -= start;
|
||||
@@ -434,7 +441,7 @@ void sortCommand(client *c) {
|
||||
sds sdsele;
|
||||
di = dictGetIterator(set);
|
||||
while((setele = dictNext(di)) != NULL) {
|
||||
sdsele = dictGetKey(setele);
|
||||
sdsele = (sds)dictGetKey(setele);
|
||||
vector[j].obj = createStringObject(sdsele,sdslen(sdsele));
|
||||
vector[j].u.score = 0;
|
||||
vector[j].u.cmpobj = NULL;
|
||||
@@ -452,7 +459,7 @@ void sortCommand(client *c) {
|
||||
robj *byval;
|
||||
if (sortby) {
|
||||
/* lookup value to sort by */
|
||||
byval = lookupKeyByPattern(c->db,sortby,vector[j].obj);
|
||||
byval = lookupKeyByPattern(c->db,sortby,vector[j].obj,storekey!=NULL);
|
||||
if (!byval) continue;
|
||||
} else {
|
||||
/* use object itself to sort by */
|
||||
@@ -465,7 +472,7 @@ void sortCommand(client *c) {
|
||||
if (sdsEncodedObject(byval)) {
|
||||
char *eptr;
|
||||
|
||||
vector[j].u.score = strtod(ptrFromObj(byval),&eptr);
|
||||
vector[j].u.score = strtod(szFromObj(byval),&eptr);
|
||||
if (eptr[0] != '\0' || errno == ERANGE ||
|
||||
isnan(vector[j].u.score))
|
||||
{
|
||||
@@ -513,9 +520,9 @@ void sortCommand(client *c) {
|
||||
if (!getop) addReplyBulk(c,vector[j].obj);
|
||||
listRewind(operations,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
redisSortOperation *sop = ln->value;
|
||||
redisSortOperation *sop = (redisSortOperation*)ln->value;
|
||||
robj *val = lookupKeyByPattern(c->db,sop->pattern,
|
||||
vector[j].obj);
|
||||
vector[j].obj,storekey!=NULL);
|
||||
|
||||
if (sop->type == SORT_OP_GET) {
|
||||
if (!val) {
|
||||
@@ -543,9 +550,9 @@ void sortCommand(client *c) {
|
||||
} else {
|
||||
listRewind(operations,&li);
|
||||
while((ln = listNext(&li))) {
|
||||
redisSortOperation *sop = ln->value;
|
||||
redisSortOperation *sop = (redisSortOperation*)ln->value;
|
||||
robj *val = lookupKeyByPattern(c->db,sop->pattern,
|
||||
vector[j].obj);
|
||||
vector[j].obj,storekey!=NULL);
|
||||
|
||||
if (sop->type == SORT_OP_GET) {
|
||||
if (!val) val = createStringObject("",0);
|
||||
@@ -55,7 +55,7 @@ static int label_margin_top = 1;
|
||||
|
||||
/* Create a new sequence. */
|
||||
struct sequence *createSparklineSequence(void) {
|
||||
struct sequence *seq = zmalloc(sizeof(*seq), MALLOC_LOCAL);
|
||||
struct sequence *seq = (sequence*)zmalloc(sizeof(*seq), MALLOC_LOCAL);
|
||||
seq->length = 0;
|
||||
seq->samples = NULL;
|
||||
return seq;
|
||||
@@ -70,7 +70,7 @@ void sparklineSequenceAddSample(struct sequence *seq, double value, char *label)
|
||||
if (value < seq->min) seq->min = value;
|
||||
else if (value > seq->max) seq->max = value;
|
||||
}
|
||||
seq->samples = zrealloc(seq->samples,sizeof(struct sample)*(seq->length+1), MALLOC_SHARED);
|
||||
seq->samples = (sample*)zrealloc(seq->samples,sizeof(struct sample)*(seq->length+1), MALLOC_SHARED);
|
||||
seq->samples[seq->length].value = value;
|
||||
seq->samples[seq->length].label = label;
|
||||
seq->length++;
|
||||
@@ -99,7 +99,7 @@ sds sparklineRenderRange(sds output, struct sequence *seq, int rows, int offset,
|
||||
double relmax = seq->max - seq->min;
|
||||
int steps = charset_len*rows;
|
||||
int row = 0;
|
||||
char *chars = zmalloc(len, MALLOC_LOCAL);
|
||||
char *chars = (char*)zmalloc(len, MALLOC_LOCAL);
|
||||
int loop = 1;
|
||||
int opt_fill = flags & SPARKLINE_FILL;
|
||||
int opt_log = flags & SPARKLINE_LOG_SCALE;
|
||||
@@ -47,10 +47,18 @@ struct sequence {
|
||||
#define SPARKLINE_FILL 1 /* Fill the area under the curve. */
|
||||
#define SPARKLINE_LOG_SCALE 2 /* Use logarithmic scale. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct sequence *createSparklineSequence(void);
|
||||
void sparklineSequenceAddSample(struct sequence *seq, double value, char *label);
|
||||
void freeSparklineSequence(struct sequence *seq);
|
||||
sds sparklineRenderRange(sds output, struct sequence *seq, int rows, int offset, int len, int flags);
|
||||
sds sparklineRender(sds output, struct sequence *seq, int columns, int rows, int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SPARKLINE_H */
|
||||
+4
-1
@@ -1,12 +1,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include "storage.h"
|
||||
#include <assert.h>
|
||||
#ifdef __linux__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
// initialize the memory subsystem.
|
||||
// NOTE: This may be called twice, first with NULL specifying we should use ram
|
||||
@@ -42,7 +43,9 @@ void *srealloc(void *pv, size_t cb, enum MALLOC_CLASS class)
|
||||
return realloc(pv, cb);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
size_t salloc_usable_size(void *ptr)
|
||||
{
|
||||
return malloc_usable_size(ptr);
|
||||
}
|
||||
#endif
|
||||
@@ -15,7 +15,7 @@
|
||||
struct memkind *mkdisk = NULL;
|
||||
static const char *PMEM_DIR = NULL;
|
||||
|
||||
int memkind_pmem_iskind(struct memkind *kind, const void *pv);
|
||||
extern "C" int memkind_pmem_iskind(struct memkind *kind, const void *pv);
|
||||
|
||||
void handle_prefork();
|
||||
void handle_postfork_parent();
|
||||
@@ -27,7 +27,10 @@ struct object_page
|
||||
{
|
||||
uint64_t allocmap[OBJECT_PAGE_BUFFER_SIZE/(8*sizeof(uint64_t))];
|
||||
struct object_page *pnext;
|
||||
char rgb[];
|
||||
char *rgb()
|
||||
{
|
||||
return reinterpret_cast<char*>(this+1);
|
||||
};
|
||||
};
|
||||
|
||||
struct alloc_pool
|
||||
@@ -40,7 +43,7 @@ struct alloc_pool
|
||||
struct object_page *pool_allocate_page(int cbObject)
|
||||
{
|
||||
size_t cb = (((size_t)cbObject) * OBJECT_PAGE_BUFFER_SIZE) + sizeof(struct object_page);
|
||||
return scalloc(cb, 1, MALLOC_SHARED);
|
||||
return (object_page*)scalloc(cb, 1, MALLOC_SHARED);
|
||||
}
|
||||
void pool_initialize(struct alloc_pool *ppool, int cbObject)
|
||||
{
|
||||
@@ -78,7 +81,7 @@ void *pool_alloc(struct alloc_pool *ppool)
|
||||
int idx = IdxAllocObject(cur);
|
||||
if (idx >= 0)
|
||||
{
|
||||
return cur->rgb + (((size_t)ppool->cbObject) * idx);
|
||||
return cur->rgb() + (((size_t)ppool->cbObject) * idx);
|
||||
}
|
||||
|
||||
if (cur->pnext == NULL)
|
||||
@@ -93,14 +96,14 @@ void *pool_alloc(struct alloc_pool *ppool)
|
||||
void pool_free(struct alloc_pool *ppool, void *pv)
|
||||
{
|
||||
struct object_page *cur = ppool->pobjpageHead;
|
||||
char *obj = pv;
|
||||
char *obj = (char*)pv;
|
||||
|
||||
for (;cur != NULL;)
|
||||
{
|
||||
if (obj >= cur->rgb && (obj < (cur->rgb + (OBJECT_PAGE_BUFFER_SIZE * ppool->cbObject))))
|
||||
if (obj >= cur->rgb() && (obj < (cur->rgb() + (OBJECT_PAGE_BUFFER_SIZE * ppool->cbObject))))
|
||||
{
|
||||
// Its on this page
|
||||
int idx = (obj - cur->rgb) / ppool->cbObject;
|
||||
int idx = (obj - cur->rgb()) / ppool->cbObject;
|
||||
cur->allocmap[idx / OBJ_PAGE_BITS_PER_WORD] &= ~(1ULL << (idx % OBJ_PAGE_BITS_PER_WORD));
|
||||
return;
|
||||
}
|
||||
@@ -143,7 +146,7 @@ void storage_init(const char *tmpfilePath, size_t cbFileReserve)
|
||||
{
|
||||
// First create the file
|
||||
serverAssert(mkdisk == MEMKIND_DEFAULT);
|
||||
PMEM_DIR = memkind_malloc(MEMKIND_DEFAULT, strlen(tmpfilePath));
|
||||
PMEM_DIR = (char*)memkind_malloc(MEMKIND_DEFAULT, strlen(tmpfilePath));
|
||||
strcpy((char*)PMEM_DIR, tmpfilePath);
|
||||
int errv = memkind_create_pmem(PMEM_DIR, 0, &mkdisk);
|
||||
if (errv == MEMKIND_ERROR_INVALID)
|
||||
@@ -181,7 +184,7 @@ void storage_init(const char *tmpfilePath, size_t cbFileReserve)
|
||||
|
||||
struct redisObject *salloc_obj()
|
||||
{
|
||||
return pool_alloc(&poolobj);
|
||||
return (redisObject*)pool_alloc(&poolobj);
|
||||
}
|
||||
void sfree_obj(struct redisObject *obj)
|
||||
{
|
||||
@@ -189,7 +192,7 @@ void sfree_obj(struct redisObject *obj)
|
||||
}
|
||||
struct redisObject *salloc_objembstr()
|
||||
{
|
||||
return pool_alloc(&poolembstrobj);
|
||||
return (redisObject*)pool_alloc(&poolembstrobj);
|
||||
}
|
||||
void sfree_objembstr(robj *obj)
|
||||
{
|
||||
@@ -211,9 +214,9 @@ size_t salloc_usable_size(void *ptr)
|
||||
return memkind_malloc_usable_size(kindFromPtr(ptr), ptr);
|
||||
}
|
||||
|
||||
static memkind_t kindFromClass(enum MALLOC_CLASS class)
|
||||
static memkind_t kindFromClass(enum MALLOC_CLASS mclass)
|
||||
{
|
||||
switch (class)
|
||||
switch (mclass)
|
||||
{
|
||||
case MALLOC_SHARED:
|
||||
return mkdisk;
|
||||
@@ -223,17 +226,17 @@ static memkind_t kindFromClass(enum MALLOC_CLASS class)
|
||||
return MEMKIND_DEFAULT;
|
||||
}
|
||||
|
||||
void *salloc(size_t cb, enum MALLOC_CLASS class)
|
||||
void *salloc(size_t cb, enum MALLOC_CLASS mclass)
|
||||
{
|
||||
if (cb == 0)
|
||||
cb = 1;
|
||||
|
||||
return memkind_malloc(kindFromClass(class), cb);
|
||||
return memkind_malloc(kindFromClass(mclass), cb);
|
||||
}
|
||||
|
||||
void *scalloc(size_t cb, size_t c, enum MALLOC_CLASS class)
|
||||
void *scalloc(size_t cb, size_t c, enum MALLOC_CLASS mclass)
|
||||
{
|
||||
return memkind_calloc(kindFromClass(class), cb, c);
|
||||
return memkind_calloc(kindFromClass(mclass), cb, c);
|
||||
}
|
||||
|
||||
void sfree(void *pv)
|
||||
@@ -241,9 +244,9 @@ void sfree(void *pv)
|
||||
memkind_free(kindFromPtr(pv), pv);
|
||||
}
|
||||
|
||||
void *srealloc(void *pv, size_t cb, enum MALLOC_CLASS class)
|
||||
void *srealloc(void *pv, size_t cb, enum MALLOC_CLASS mclass)
|
||||
{
|
||||
return memkind_realloc(kindFromClass(class), pv, cb);
|
||||
return memkind_realloc(kindFromClass(mclass), pv, cb);
|
||||
}
|
||||
|
||||
int fdNew = -1;
|
||||
File renamed without changes.
@@ -44,7 +44,7 @@ void hashTypeTryConversion(robj *o, robj **argv, int start, int end) {
|
||||
|
||||
for (i = start; i <= end; i++) {
|
||||
if (sdsEncodedObject(argv[i]) &&
|
||||
sdslen(ptrFromObj(argv[i])) > server.hash_max_ziplist_value)
|
||||
sdslen(szFromObj(argv[i])) > server.hash_max_ziplist_value)
|
||||
{
|
||||
hashTypeConvert(o, OBJ_ENCODING_HT);
|
||||
break;
|
||||
@@ -64,7 +64,7 @@ int hashTypeGetFromZiplist(robj *o, sds field,
|
||||
|
||||
serverAssert(o->encoding == OBJ_ENCODING_ZIPLIST);
|
||||
|
||||
zl = ptrFromObj(o);
|
||||
zl = (unsigned char*)ptrFromObj(o);
|
||||
fptr = ziplistIndex(zl, ZIPLIST_HEAD);
|
||||
if (fptr != NULL) {
|
||||
fptr = ziplistFind(fptr, (unsigned char*)field, sdslen(field), 1);
|
||||
@@ -92,9 +92,9 @@ sds hashTypeGetFromHashTable(robj *o, sds field) {
|
||||
|
||||
serverAssert(o->encoding == OBJ_ENCODING_HT);
|
||||
|
||||
de = dictFind(ptrFromObj(o), field);
|
||||
de = dictFind((dict*)ptrFromObj(o), field);
|
||||
if (de == NULL) return NULL;
|
||||
return dictGetVal(de);
|
||||
return (sds)dictGetVal(de);
|
||||
}
|
||||
|
||||
/* Higher level function of hashTypeGet*() that returns the hash value
|
||||
@@ -205,7 +205,7 @@ int hashTypeSet(robj *o, sds field, sds value, int flags) {
|
||||
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl, *fptr, *vptr;
|
||||
|
||||
zl = ptrFromObj(o);
|
||||
zl = (unsigned char*)ptrFromObj(o);
|
||||
fptr = ziplistIndex(zl, ZIPLIST_HEAD);
|
||||
if (fptr != NULL) {
|
||||
fptr = ziplistFind(fptr, (unsigned char*)field, sdslen(field), 1);
|
||||
@@ -237,9 +237,9 @@ int hashTypeSet(robj *o, sds field, sds value, int flags) {
|
||||
if (hashTypeLength(o) > server.hash_max_ziplist_entries)
|
||||
hashTypeConvert(o, OBJ_ENCODING_HT);
|
||||
} else if (o->encoding == OBJ_ENCODING_HT) {
|
||||
dictEntry *de = dictFind(ptrFromObj(o),field);
|
||||
dictEntry *de = dictFind((dict*)ptrFromObj(o),field);
|
||||
if (de) {
|
||||
sdsfree(dictGetVal(de));
|
||||
sdsfree((sds)dictGetVal(de));
|
||||
if (flags & HASH_SET_TAKE_VALUE) {
|
||||
dictGetVal(de) = value;
|
||||
value = NULL;
|
||||
@@ -261,7 +261,7 @@ int hashTypeSet(robj *o, sds field, sds value, int flags) {
|
||||
} else {
|
||||
v = sdsdup(value);
|
||||
}
|
||||
dictAdd(ptrFromObj(o),f,v);
|
||||
dictAdd((dict*)ptrFromObj(o),f,v);
|
||||
}
|
||||
} else {
|
||||
serverPanic("Unknown hash encoding");
|
||||
@@ -282,7 +282,7 @@ int hashTypeDelete(robj *o, sds field) {
|
||||
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl, *fptr;
|
||||
|
||||
zl = ptrFromObj(o);
|
||||
zl = (unsigned char*)ptrFromObj(o);
|
||||
fptr = ziplistIndex(zl, ZIPLIST_HEAD);
|
||||
if (fptr != NULL) {
|
||||
fptr = ziplistFind(fptr, (unsigned char*)field, sdslen(field), 1);
|
||||
@@ -298,7 +298,7 @@ int hashTypeDelete(robj *o, sds field) {
|
||||
deleted = 1;
|
||||
|
||||
/* Always check if the dictionary needs a resize after a delete. */
|
||||
if (htNeedsResize(ptrFromObj(o))) dictResize(ptrFromObj(o));
|
||||
if (htNeedsResize((dict*)ptrFromObj(o))) dictResize((dict*)ptrFromObj(o));
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -312,7 +312,7 @@ unsigned long hashTypeLength(const robj *o) {
|
||||
unsigned long length = ULONG_MAX;
|
||||
|
||||
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
length = ziplistLen(ptrFromObj(o)) / 2;
|
||||
length = ziplistLen((unsigned char*)ptrFromObj(o)) / 2;
|
||||
} else if (o->encoding == OBJ_ENCODING_HT) {
|
||||
length = dictSize((const dict*)ptrFromObj(o));
|
||||
} else {
|
||||
@@ -322,7 +322,7 @@ unsigned long hashTypeLength(const robj *o) {
|
||||
}
|
||||
|
||||
hashTypeIterator *hashTypeInitIterator(robj *subject) {
|
||||
hashTypeIterator *hi = zmalloc(sizeof(hashTypeIterator), MALLOC_LOCAL);
|
||||
hashTypeIterator *hi = (hashTypeIterator*)zmalloc(sizeof(hashTypeIterator), MALLOC_LOCAL);
|
||||
hi->subject = subject;
|
||||
hi->encoding = subject->encoding;
|
||||
|
||||
@@ -330,7 +330,7 @@ hashTypeIterator *hashTypeInitIterator(robj *subject) {
|
||||
hi->fptr = NULL;
|
||||
hi->vptr = NULL;
|
||||
} else if (hi->encoding == OBJ_ENCODING_HT) {
|
||||
hi->di = dictGetIterator(subject->m_ptr);
|
||||
hi->di = dictGetIterator((dict*)subject->m_ptr);
|
||||
} else {
|
||||
serverPanic("Unknown hash encoding");
|
||||
}
|
||||
@@ -350,7 +350,7 @@ int hashTypeNext(hashTypeIterator *hi) {
|
||||
unsigned char *zl;
|
||||
unsigned char *fptr, *vptr;
|
||||
|
||||
zl = hi->subject->m_ptr;
|
||||
zl = (unsigned char*)hi->subject->m_ptr;
|
||||
fptr = hi->fptr;
|
||||
vptr = hi->vptr;
|
||||
|
||||
@@ -407,9 +407,9 @@ sds hashTypeCurrentFromHashTable(hashTypeIterator *hi, int what) {
|
||||
serverAssert(hi->encoding == OBJ_ENCODING_HT);
|
||||
|
||||
if (what & OBJ_HASH_KEY) {
|
||||
return dictGetKey(hi->de);
|
||||
return (sds)dictGetKey(hi->de);
|
||||
} else {
|
||||
return dictGetVal(hi->de);
|
||||
return (sds)dictGetVal(hi->de);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,7 +484,7 @@ void hashTypeConvertZiplist(robj *o, int enc) {
|
||||
ret = dictAdd(dict, key, value);
|
||||
if (ret != DICT_OK) {
|
||||
serverLogHexDump(LL_WARNING,"ziplist with dup elements dump",
|
||||
ptrFromObj(o),ziplistBlobLen(ptrFromObj(o)));
|
||||
ptrFromObj(o),ziplistBlobLen((unsigned char*)ptrFromObj(o)));
|
||||
serverPanic("Ziplist corruption detected");
|
||||
}
|
||||
}
|
||||
@@ -516,10 +516,10 @@ void hsetnxCommand(client *c) {
|
||||
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
||||
hashTypeTryConversion(o,c->argv,2,3);
|
||||
|
||||
if (hashTypeExists(o, ptrFromObj(c->argv[2]))) {
|
||||
if (hashTypeExists(o, szFromObj(c->argv[2]))) {
|
||||
addReply(c, shared.czero);
|
||||
} else {
|
||||
hashTypeSet(o,ptrFromObj(c->argv[2]),ptrFromObj(c->argv[3]),HASH_SET_COPY);
|
||||
hashTypeSet(o,szFromObj(c->argv[2]),szFromObj(c->argv[3]),HASH_SET_COPY);
|
||||
addReply(c, shared.cone);
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_HASH,"hset",c->argv[1],c->db->id);
|
||||
@@ -540,10 +540,10 @@ void hsetCommand(client *c) {
|
||||
hashTypeTryConversion(o,c->argv,2,c->argc-1);
|
||||
|
||||
for (i = 2; i < c->argc; i += 2)
|
||||
created += !hashTypeSet(o,ptrFromObj(c->argv[i]),ptrFromObj(c->argv[i+1]),HASH_SET_COPY);
|
||||
created += !hashTypeSet(o,szFromObj(c->argv[i]),szFromObj(c->argv[i+1]),HASH_SET_COPY);
|
||||
|
||||
/* HMSET (deprecated) and HSET return value is different. */
|
||||
char *cmdname = ptrFromObj(c->argv[0]);
|
||||
char *cmdname = szFromObj(c->argv[0]);
|
||||
if (cmdname[1] == 's' || cmdname[1] == 'S') {
|
||||
/* HSET */
|
||||
addReplyLongLong(c, created);
|
||||
@@ -559,13 +559,13 @@ void hsetCommand(client *c) {
|
||||
void hincrbyCommand(client *c) {
|
||||
long long value, incr, oldvalue;
|
||||
robj *o;
|
||||
sds new;
|
||||
sds newstr;
|
||||
unsigned char *vstr;
|
||||
unsigned int vlen;
|
||||
|
||||
if (getLongLongFromObjectOrReply(c,c->argv[3],&incr,NULL) != C_OK) return;
|
||||
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
||||
if (hashTypeGetValue(o,ptrFromObj(c->argv[2]),&vstr,&vlen,&value) == C_OK) {
|
||||
if (hashTypeGetValue(o,szFromObj(c->argv[2]),&vstr,&vlen,&value) == C_OK) {
|
||||
if (vstr) {
|
||||
if (string2ll((char*)vstr,vlen,&value) == 0) {
|
||||
addReplyError(c,"hash value is not an integer");
|
||||
@@ -583,8 +583,8 @@ void hincrbyCommand(client *c) {
|
||||
return;
|
||||
}
|
||||
value += incr;
|
||||
new = sdsfromlonglong(value);
|
||||
hashTypeSet(o,ptrFromObj(c->argv[2]),new,HASH_SET_TAKE_VALUE);
|
||||
newstr = sdsfromlonglong(value);
|
||||
hashTypeSet(o,szFromObj(c->argv[2]),newstr,HASH_SET_TAKE_VALUE);
|
||||
addReplyLongLong(c,value);
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_HASH,"hincrby",c->argv[1],c->db->id);
|
||||
@@ -595,13 +595,13 @@ void hincrbyfloatCommand(client *c) {
|
||||
long double value, incr;
|
||||
long long ll;
|
||||
robj *o;
|
||||
sds new;
|
||||
sds newstr;
|
||||
unsigned char *vstr;
|
||||
unsigned int vlen;
|
||||
|
||||
if (getLongDoubleFromObjectOrReply(c,c->argv[3],&incr,NULL) != C_OK) return;
|
||||
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
||||
if (hashTypeGetValue(o,ptrFromObj(c->argv[2]),&vstr,&vlen,&ll) == C_OK) {
|
||||
if (hashTypeGetValue(o,szFromObj(c->argv[2]),&vstr,&vlen,&ll) == C_OK) {
|
||||
if (vstr) {
|
||||
if (string2ld((char*)vstr,vlen,&value) == 0) {
|
||||
addReplyError(c,"hash value is not a float");
|
||||
@@ -622,8 +622,8 @@ void hincrbyfloatCommand(client *c) {
|
||||
|
||||
char buf[MAX_LONG_DOUBLE_CHARS];
|
||||
int len = ld2string(buf,sizeof(buf),value,1);
|
||||
new = sdsnewlen(buf,len);
|
||||
hashTypeSet(o,ptrFromObj(c->argv[2]),new,HASH_SET_TAKE_VALUE);
|
||||
newstr = sdsnewlen(buf,len);
|
||||
hashTypeSet(o,szFromObj(c->argv[2]),newstr,HASH_SET_TAKE_VALUE);
|
||||
addReplyBulkCBuffer(c,buf,len);
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_HASH,"hincrbyfloat",c->argv[1],c->db->id);
|
||||
@@ -682,7 +682,7 @@ void hgetCommand(client *c) {
|
||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL ||
|
||||
checkType(c,o,OBJ_HASH)) return;
|
||||
|
||||
addHashFieldToReply(c, o, ptrFromObj(c->argv[2]));
|
||||
addHashFieldToReply(c, o, szFromObj(c->argv[2]));
|
||||
}
|
||||
|
||||
void hmgetCommand(client *c) {
|
||||
@@ -699,7 +699,7 @@ void hmgetCommand(client *c) {
|
||||
|
||||
addReplyArrayLen(c, c->argc-2);
|
||||
for (i = 2; i < c->argc; i++) {
|
||||
addHashFieldToReply(c, o, ptrFromObj(c->argv[i]));
|
||||
addHashFieldToReply(c, o, szFromObj(c->argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,7 +711,7 @@ void hdelCommand(client *c) {
|
||||
checkType(c,o,OBJ_HASH)) return;
|
||||
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
if (hashTypeDelete(o,ptrFromObj(c->argv[j]))) {
|
||||
if (hashTypeDelete(o,szFromObj(c->argv[j]))) {
|
||||
deleted++;
|
||||
if (hashTypeLength(o) == 0) {
|
||||
dbDelete(c->db,c->argv[1]);
|
||||
@@ -745,7 +745,7 @@ void hstrlenCommand(client *c) {
|
||||
|
||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
|
||||
checkType(c,o,OBJ_HASH)) return;
|
||||
addReplyLongLong(c,hashTypeGetValueLength(o,ptrFromObj(c->argv[2])));
|
||||
addReplyLongLong(c,hashTypeGetValueLength(o,szFromObj(c->argv[2])));
|
||||
}
|
||||
|
||||
static void addHashIteratorCursorToReply(client *c, hashTypeIterator *hi, int what) {
|
||||
@@ -772,7 +772,7 @@ void genericHgetallCommand(client *c, int flags) {
|
||||
hashTypeIterator *hi;
|
||||
int length, count = 0;
|
||||
|
||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL
|
||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],(c->resp < 3) ? shared.emptyarray : shared.null[c->resp])) == NULL
|
||||
|| checkType(c,o,OBJ_HASH)) return;
|
||||
|
||||
/* We return a map if the user requested keys and values, like in the
|
||||
@@ -820,7 +820,7 @@ void hexistsCommand(client *c) {
|
||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
|
||||
checkType(c,o,OBJ_HASH)) return;
|
||||
|
||||
addReply(c, hashTypeExists(o,ptrFromObj(c->argv[2])) ? shared.cone : shared.czero);
|
||||
addReply(c, hashTypeExists(o,szFromObj(c->argv[2])) ? shared.cone : shared.czero);
|
||||
}
|
||||
|
||||
void hscanCommand(client *c) {
|
||||
@@ -42,8 +42,8 @@ void listTypePush(robj *subject, robj *value, int where) {
|
||||
if (subject->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
int pos = (where == LIST_HEAD) ? QUICKLIST_HEAD : QUICKLIST_TAIL;
|
||||
value = getDecodedObject(value);
|
||||
size_t len = sdslen(ptrFromObj(value));
|
||||
quicklistPush(ptrFromObj(subject), ptrFromObj(value), len, pos);
|
||||
size_t len = sdslen(szFromObj(value));
|
||||
quicklistPush((quicklist*)ptrFromObj(subject), ptrFromObj(value), len, pos);
|
||||
decrRefCount(value);
|
||||
} else {
|
||||
serverPanic("Unknown list encoding");
|
||||
@@ -60,7 +60,7 @@ robj *listTypePop(robj *subject, int where) {
|
||||
|
||||
int ql_where = where == LIST_HEAD ? QUICKLIST_HEAD : QUICKLIST_TAIL;
|
||||
if (subject->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
if (quicklistPopCustom(ptrFromObj(subject), ql_where, (unsigned char **)&value,
|
||||
if (quicklistPopCustom((quicklist*)ptrFromObj(subject), ql_where, (unsigned char **)&value,
|
||||
NULL, &vlong, listPopSaver)) {
|
||||
if (!value)
|
||||
value = createStringObjectFromLongLong(vlong);
|
||||
@@ -73,7 +73,7 @@ robj *listTypePop(robj *subject, int where) {
|
||||
|
||||
unsigned long listTypeLength(const robj *subject) {
|
||||
if (subject->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
return quicklistCount(ptrFromObj(subject));
|
||||
return quicklistCount((quicklist*)ptrFromObj(subject));
|
||||
} else {
|
||||
serverPanic("Unknown list encoding");
|
||||
}
|
||||
@@ -82,7 +82,7 @@ unsigned long listTypeLength(const robj *subject) {
|
||||
/* Initialize an iterator at the specified index. */
|
||||
listTypeIterator *listTypeInitIterator(robj *subject, long index,
|
||||
unsigned char direction) {
|
||||
listTypeIterator *li = zmalloc(sizeof(listTypeIterator), MALLOC_LOCAL);
|
||||
listTypeIterator *li = (listTypeIterator*)zmalloc(sizeof(listTypeIterator), MALLOC_LOCAL);
|
||||
li->subject = subject;
|
||||
li->encoding = subject->encoding;
|
||||
li->direction = direction;
|
||||
@@ -92,7 +92,7 @@ listTypeIterator *listTypeInitIterator(robj *subject, long index,
|
||||
int iter_direction =
|
||||
direction == LIST_HEAD ? AL_START_TAIL : AL_START_HEAD;
|
||||
if (li->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
li->iter = quicklistGetIteratorAtIdx(ptrFromObj(li->subject),
|
||||
li->iter = quicklistGetIteratorAtIdx((const quicklist*)ptrFromObj(li->subject),
|
||||
iter_direction, index);
|
||||
} else {
|
||||
serverPanic("Unknown list encoding");
|
||||
@@ -141,7 +141,7 @@ robj *listTypeGet(listTypeEntry *entry) {
|
||||
void listTypeInsert(listTypeEntry *entry, robj *value, int where) {
|
||||
if (entry->li->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
value = getDecodedObject(value);
|
||||
sds str = ptrFromObj(value);
|
||||
sds str = szFromObj(value);
|
||||
size_t len = sdslen(str);
|
||||
if (where == LIST_TAIL) {
|
||||
quicklistInsertAfter((quicklist *)entry->entry.qlist,
|
||||
@@ -160,7 +160,7 @@ void listTypeInsert(listTypeEntry *entry, robj *value, int where) {
|
||||
int listTypeEqual(listTypeEntry *entry, robj *o) {
|
||||
if (entry->li->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
serverAssertWithInfo(NULL,o,sdsEncodedObject(o));
|
||||
return quicklistCompare(entry->entry.zi,ptrFromObj(o),sdslen(ptrFromObj(o)));
|
||||
return quicklistCompare(entry->entry.zi,(unsigned char*)ptrFromObj(o),sdslen(szFromObj(o)));
|
||||
} else {
|
||||
serverPanic("Unknown list encoding");
|
||||
}
|
||||
@@ -183,7 +183,7 @@ void listTypeConvert(robj *subject, int enc) {
|
||||
if (enc == OBJ_ENCODING_QUICKLIST) {
|
||||
size_t zlen = server.list_max_ziplist_size;
|
||||
int depth = server.list_compress_depth;
|
||||
subject->m_ptr = quicklistCreateFromZiplist(zlen, depth, ptrFromObj(subject));
|
||||
subject->m_ptr = quicklistCreateFromZiplist(zlen, depth, (unsigned char*)ptrFromObj(subject));
|
||||
subject->encoding = OBJ_ENCODING_QUICKLIST;
|
||||
} else {
|
||||
serverPanic("Unsupported list conversion");
|
||||
@@ -206,7 +206,7 @@ void pushGenericCommand(client *c, int where) {
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
if (!lobj) {
|
||||
lobj = createQuicklistObject();
|
||||
quicklistSetOptions(ptrFromObj(lobj), server.list_max_ziplist_size,
|
||||
quicklistSetOptions((quicklist*)ptrFromObj(lobj), server.list_max_ziplist_size,
|
||||
server.list_compress_depth);
|
||||
dbAdd(c->db,c->argv[1],lobj);
|
||||
}
|
||||
@@ -215,7 +215,7 @@ void pushGenericCommand(client *c, int where) {
|
||||
}
|
||||
addReplyLongLong(c, (lobj ? listTypeLength(lobj) : 0));
|
||||
if (pushed) {
|
||||
char *event = (where == LIST_HEAD) ? "lpush" : "rpush";
|
||||
const char *event = (where == LIST_HEAD) ? "lpush" : "rpush";
|
||||
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_LIST,event,c->argv[1],c->db->id);
|
||||
@@ -246,7 +246,7 @@ void pushxGenericCommand(client *c, int where) {
|
||||
addReplyLongLong(c,listTypeLength(subject));
|
||||
|
||||
if (pushed) {
|
||||
char *event = (where == LIST_HEAD) ? "lpush" : "rpush";
|
||||
const char *event = (where == LIST_HEAD) ? "lpush" : "rpush";
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_LIST,event,c->argv[1],c->db->id);
|
||||
}
|
||||
@@ -268,9 +268,9 @@ void linsertCommand(client *c) {
|
||||
listTypeEntry entry;
|
||||
int inserted = 0;
|
||||
|
||||
if (strcasecmp(ptrFromObj(c->argv[2]),"after") == 0) {
|
||||
if (strcasecmp(szFromObj(c->argv[2]),"after") == 0) {
|
||||
where = LIST_TAIL;
|
||||
} else if (strcasecmp(ptrFromObj(c->argv[2]),"before") == 0) {
|
||||
} else if (strcasecmp(szFromObj(c->argv[2]),"before") == 0) {
|
||||
where = LIST_HEAD;
|
||||
} else {
|
||||
addReply(c,shared.syntaxerr);
|
||||
@@ -322,7 +322,7 @@ void lindexCommand(client *c) {
|
||||
|
||||
if (o->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
quicklistEntry entry;
|
||||
if (quicklistIndex(ptrFromObj(o), index, &entry)) {
|
||||
if (quicklistIndex((quicklist*)ptrFromObj(o), index, &entry)) {
|
||||
if (entry.value) {
|
||||
value = createStringObject((char*)entry.value,entry.sz);
|
||||
} else {
|
||||
@@ -348,9 +348,9 @@ void lsetCommand(client *c) {
|
||||
return;
|
||||
|
||||
if (o->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
quicklist *ql = ptrFromObj(o);
|
||||
quicklist *ql = (quicklist*)ptrFromObj(o);
|
||||
int replaced = quicklistReplaceAtIndex(ql, index,
|
||||
ptrFromObj(value), sdslen(ptrFromObj(value)));
|
||||
szFromObj(value), sdslen(szFromObj(value)));
|
||||
if (!replaced) {
|
||||
addReply(c,shared.outofrangeerr);
|
||||
} else {
|
||||
@@ -372,7 +372,7 @@ void popGenericCommand(client *c, int where) {
|
||||
if (value == NULL) {
|
||||
addReplyNull(c);
|
||||
} else {
|
||||
char *event = (where == LIST_HEAD) ? "lpop" : "rpop";
|
||||
const char *event = (where == LIST_HEAD) ? "lpop" : "rpop";
|
||||
|
||||
addReplyBulk(c,value);
|
||||
decrRefCount(value);
|
||||
@@ -402,7 +402,7 @@ void lrangeCommand(client *c) {
|
||||
if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != C_OK) ||
|
||||
(getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != C_OK)) return;
|
||||
|
||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL
|
||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],(c->resp < 3) ? shared.emptyarray : shared.null[c->resp])) == NULL
|
||||
|| checkType(c,o,OBJ_LIST)) return;
|
||||
llen = listTypeLength(o);
|
||||
|
||||
@@ -471,8 +471,8 @@ void ltrimCommand(client *c) {
|
||||
|
||||
/* Remove list elements to perform the trim */
|
||||
if (o->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
quicklistDelRange(ptrFromObj(o),0,ltrim);
|
||||
quicklistDelRange(ptrFromObj(o),-rtrim,rtrim);
|
||||
quicklistDelRange((quicklist*)ptrFromObj(o),0,ltrim);
|
||||
quicklistDelRange((quicklist*)ptrFromObj(o),-rtrim,rtrim);
|
||||
} else {
|
||||
serverPanic("Unknown list encoding");
|
||||
}
|
||||
@@ -551,7 +551,7 @@ static void rpoplpushHandlePush(client *c, robj *dstkey, robj *dstobj, robj *val
|
||||
/* Create the list if the key does not exist */
|
||||
if (!dstobj) {
|
||||
dstobj = createQuicklistObject();
|
||||
quicklistSetOptions(ptrFromObj(dstobj), server.list_max_ziplist_size,
|
||||
quicklistSetOptions((quicklist*)ptrFromObj(dstobj), server.list_max_ziplist_size,
|
||||
server.list_compress_depth);
|
||||
dbAdd(c->db,dstkey,dstobj);
|
||||
}
|
||||
@@ -645,7 +645,7 @@ int serveClientBlockedOnList(client *receiver, robj *key, robj *dstkey, redisDb
|
||||
addReplyBulkAsync(receiver,value);
|
||||
|
||||
/* Notify event. */
|
||||
char *event = (where == LIST_HEAD) ? "lpop" : "rpop";
|
||||
const char *event = (where == LIST_HEAD) ? "lpop" : "rpop";
|
||||
notifyKeyspaceEvent(NOTIFY_LIST,event,key,receiver->db->id);
|
||||
fastlock_unlock(&receiver->lock);
|
||||
} else {
|
||||
@@ -705,7 +705,7 @@ void blockingPopGenericCommand(client *c, int where) {
|
||||
} else {
|
||||
if (listTypeLength(o) != 0) {
|
||||
/* Non empty list, this is like a non normal [LR]POP. */
|
||||
char *event = (where == LIST_HEAD) ? "lpop" : "rpop";
|
||||
const char *event = (where == LIST_HEAD) ? "lpop" : "rpop";
|
||||
robj *value = listTypePop(o,where);
|
||||
serverAssert(value != NULL);
|
||||
|
||||
+34
-31
@@ -52,7 +52,7 @@ robj *setTypeCreate(sds value) {
|
||||
int setTypeAdd(robj *subject, sds value) {
|
||||
long long llval;
|
||||
if (subject->encoding == OBJ_ENCODING_HT) {
|
||||
dict *ht = subject->m_ptr;
|
||||
dict *ht = (dict*)subject->m_ptr;
|
||||
dictEntry *de = dictAddRaw(ht,value,NULL);
|
||||
if (de) {
|
||||
dictSetKey(ht,de,sdsdup(value));
|
||||
@@ -62,11 +62,11 @@ int setTypeAdd(robj *subject, sds value) {
|
||||
} else if (subject->encoding == OBJ_ENCODING_INTSET) {
|
||||
if (isSdsRepresentableAsLongLong(value,&llval) == C_OK) {
|
||||
uint8_t success = 0;
|
||||
subject->m_ptr = intsetAdd(subject->m_ptr,llval,&success);
|
||||
subject->m_ptr = intsetAdd((intset*)subject->m_ptr,llval,&success);
|
||||
if (success) {
|
||||
/* Convert to regular set when the intset contains
|
||||
* too many entries. */
|
||||
if (intsetLen(subject->m_ptr) > server.set_max_intset_entries)
|
||||
if (intsetLen((intset*)subject->m_ptr) > server.set_max_intset_entries)
|
||||
setTypeConvert(subject,OBJ_ENCODING_HT);
|
||||
return 1;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ int setTypeAdd(robj *subject, sds value) {
|
||||
|
||||
/* The set *was* an intset and this value is not integer
|
||||
* encodable, so dictAdd should always work. */
|
||||
serverAssert(dictAdd(subject->m_ptr,sdsdup(value),NULL) == DICT_OK);
|
||||
serverAssert(dictAdd((dict*)subject->m_ptr,sdsdup(value),NULL) == DICT_OK);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
@@ -88,14 +88,14 @@ int setTypeAdd(robj *subject, sds value) {
|
||||
int setTypeRemove(robj *setobj, sds value) {
|
||||
long long llval;
|
||||
if (setobj->encoding == OBJ_ENCODING_HT) {
|
||||
if (dictDelete(setobj->m_ptr,value) == DICT_OK) {
|
||||
if (htNeedsResize(setobj->m_ptr)) dictResize(setobj->m_ptr);
|
||||
if (dictDelete((dict*)setobj->m_ptr,value) == DICT_OK) {
|
||||
if (htNeedsResize((dict*)setobj->m_ptr)) dictResize((dict*)setobj->m_ptr);
|
||||
return 1;
|
||||
}
|
||||
} else if (setobj->encoding == OBJ_ENCODING_INTSET) {
|
||||
if (isSdsRepresentableAsLongLong(value,&llval) == C_OK) {
|
||||
int success;
|
||||
setobj->m_ptr = intsetRemove(setobj->m_ptr,llval,&success);
|
||||
setobj->m_ptr = intsetRemove((intset*)setobj->m_ptr,llval,&success);
|
||||
if (success) return 1;
|
||||
}
|
||||
} else {
|
||||
@@ -119,11 +119,11 @@ int setTypeIsMember(robj *subject, sds value) {
|
||||
}
|
||||
|
||||
setTypeIterator *setTypeInitIterator(robj *subject) {
|
||||
setTypeIterator *si = zmalloc(sizeof(setTypeIterator), MALLOC_LOCAL);
|
||||
setTypeIterator *si = (setTypeIterator*)zmalloc(sizeof(setTypeIterator), MALLOC_LOCAL);
|
||||
si->subject = subject;
|
||||
si->encoding = subject->encoding;
|
||||
if (si->encoding == OBJ_ENCODING_HT) {
|
||||
si->di = dictGetIterator(subject->m_ptr);
|
||||
si->di = dictGetIterator((dict*)subject->m_ptr);
|
||||
} else if (si->encoding == OBJ_ENCODING_INTSET) {
|
||||
si->ii = 0;
|
||||
} else {
|
||||
@@ -155,10 +155,10 @@ int setTypeNext(setTypeIterator *si, sds *sdsele, int64_t *llele) {
|
||||
if (si->encoding == OBJ_ENCODING_HT) {
|
||||
dictEntry *de = dictNext(si->di);
|
||||
if (de == NULL) return -1;
|
||||
*sdsele = dictGetKey(de);
|
||||
*sdsele = (sds)dictGetKey(de);
|
||||
*llele = -123456789; /* Not needed. Defensive. */
|
||||
} else if (si->encoding == OBJ_ENCODING_INTSET) {
|
||||
if (!intsetGet(si->subject->m_ptr,si->ii++,llele))
|
||||
if (!intsetGet((intset*)si->subject->m_ptr,si->ii++,llele))
|
||||
return -1;
|
||||
*sdsele = NULL; /* Not needed. Defensive. */
|
||||
} else {
|
||||
@@ -207,11 +207,11 @@ sds setTypeNextObject(setTypeIterator *si) {
|
||||
* used field with values which are easy to trap if misused. */
|
||||
int setTypeRandomElement(robj *setobj, sds *sdsele, int64_t *llele) {
|
||||
if (setobj->encoding == OBJ_ENCODING_HT) {
|
||||
dictEntry *de = dictGetFairRandomKey(setobj->m_ptr);
|
||||
*sdsele = dictGetKey(de);
|
||||
dictEntry *de = dictGetFairRandomKey((dict*)setobj->m_ptr);
|
||||
*sdsele = (sds)dictGetKey(de);
|
||||
*llele = -123456789; /* Not needed. Defensive. */
|
||||
} else if (setobj->encoding == OBJ_ENCODING_INTSET) {
|
||||
*llele = intsetRandom(setobj->m_ptr);
|
||||
*llele = intsetRandom((intset*)setobj->m_ptr);
|
||||
*sdsele = NULL; /* Not needed. Defensive. */
|
||||
} else {
|
||||
serverPanic("Unknown set encoding");
|
||||
@@ -243,7 +243,7 @@ void setTypeConvert(robj *setobj, int enc) {
|
||||
sds element;
|
||||
|
||||
/* Presize the dict to avoid rehashing */
|
||||
dictExpand(d,intsetLen(setobj->m_ptr));
|
||||
dictExpand(d,intsetLen((intset*)setobj->m_ptr));
|
||||
|
||||
/* To add the elements we extract integers and create redis objects */
|
||||
si = setTypeInitIterator(setobj);
|
||||
@@ -267,7 +267,7 @@ void saddCommand(client *c) {
|
||||
|
||||
set = lookupKeyWrite(c->db,c->argv[1]);
|
||||
if (set == NULL) {
|
||||
set = setTypeCreate(ptrFromObj(c->argv[2]));
|
||||
set = setTypeCreate(szFromObj(c->argv[2]));
|
||||
dbAdd(c->db,c->argv[1],set);
|
||||
} else {
|
||||
if (set->type != OBJ_SET) {
|
||||
@@ -277,7 +277,7 @@ void saddCommand(client *c) {
|
||||
}
|
||||
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
if (setTypeAdd(set,ptrFromObj(c->argv[j]))) added++;
|
||||
if (setTypeAdd(set,szFromObj(c->argv[j]))) added++;
|
||||
}
|
||||
if (added) {
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
@@ -295,7 +295,7 @@ void sremCommand(client *c) {
|
||||
checkType(c,set,OBJ_SET)) return;
|
||||
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
if (setTypeRemove(set,ptrFromObj(c->argv[j]))) {
|
||||
if (setTypeRemove(set,szFromObj(c->argv[j]))) {
|
||||
deleted++;
|
||||
if (setTypeSize(set) == 0) {
|
||||
dbDelete(c->db,c->argv[1]);
|
||||
@@ -334,13 +334,13 @@ void smoveCommand(client *c) {
|
||||
|
||||
/* If srcset and dstset are equal, SMOVE is a no-op */
|
||||
if (srcset == dstset) {
|
||||
addReply(c,setTypeIsMember(srcset,ptrFromObj(ele)) ?
|
||||
addReply(c,setTypeIsMember(srcset,szFromObj(ele)) ?
|
||||
shared.cone : shared.czero);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the element cannot be removed from the src set, return 0. */
|
||||
if (!setTypeRemove(srcset,ptrFromObj(ele))) {
|
||||
if (!setTypeRemove(srcset,szFromObj(ele))) {
|
||||
addReply(c,shared.czero);
|
||||
return;
|
||||
}
|
||||
@@ -354,7 +354,7 @@ void smoveCommand(client *c) {
|
||||
|
||||
/* Create the destination set when it doesn't exist */
|
||||
if (!dstset) {
|
||||
dstset = setTypeCreate(ptrFromObj(ele));
|
||||
dstset = setTypeCreate(szFromObj(ele));
|
||||
dbAdd(c->db,c->argv[2],dstset);
|
||||
}
|
||||
|
||||
@@ -363,7 +363,7 @@ void smoveCommand(client *c) {
|
||||
server.dirty++;
|
||||
|
||||
/* An extra key has changed when ele was successfully added to dstset */
|
||||
if (setTypeAdd(dstset,ptrFromObj(ele))) {
|
||||
if (setTypeAdd(dstset,szFromObj(ele))) {
|
||||
server.dirty++;
|
||||
notifyKeyspaceEvent(NOTIFY_SET,"sadd",c->argv[2],c->db->id);
|
||||
}
|
||||
@@ -376,7 +376,7 @@ void sismemberCommand(client *c) {
|
||||
if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
|
||||
checkType(c,set,OBJ_SET)) return;
|
||||
|
||||
if (setTypeIsMember(set,ptrFromObj(c->argv[2])))
|
||||
if (setTypeIsMember(set,szFromObj(c->argv[2])))
|
||||
addReply(c,shared.cone);
|
||||
else
|
||||
addReply(c,shared.czero);
|
||||
@@ -415,7 +415,7 @@ void spopWithCountCommand(client *c) {
|
||||
|
||||
/* Make sure a key with the name inputted exists, and that it's type is
|
||||
* indeed a set. Otherwise, return nil */
|
||||
if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp]))
|
||||
if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.null[c->resp]))
|
||||
== NULL || checkType(c,set,OBJ_SET)) return;
|
||||
|
||||
/* If count is zero, serve an empty multibulk ASAP to avoid special
|
||||
@@ -478,7 +478,7 @@ void spopWithCountCommand(client *c) {
|
||||
if (encoding == OBJ_ENCODING_INTSET) {
|
||||
addReplyBulkLongLong(c,llele);
|
||||
objele = createStringObjectFromLongLong(llele);
|
||||
set->m_ptr = intsetRemove(set->m_ptr,llele,NULL);
|
||||
set->m_ptr = intsetRemove((intset*)set->m_ptr,llele,NULL);
|
||||
} else {
|
||||
addReplyBulkCBuffer(c,sdsele,sdslen(sdsele));
|
||||
objele = createStringObject(sdsele,sdslen(sdsele));
|
||||
@@ -575,10 +575,10 @@ void spopCommand(client *c) {
|
||||
/* Remove the element from the set */
|
||||
if (encoding == OBJ_ENCODING_INTSET) {
|
||||
ele = createStringObjectFromLongLong(llele);
|
||||
set->m_ptr = intsetRemove(set->m_ptr,llele,NULL);
|
||||
set->m_ptr = intsetRemove((intset*)set->m_ptr,llele,NULL);
|
||||
} else {
|
||||
ele = createStringObject(sdsele,sdslen(sdsele));
|
||||
setTypeRemove(set,ptrFromObj(ele));
|
||||
setTypeRemove(set,szFromObj(ele));
|
||||
}
|
||||
|
||||
notifyKeyspaceEvent(NOTIFY_SET,"spop",c->argv[1],c->db->id);
|
||||
@@ -740,7 +740,7 @@ void srandmemberWithCountCommand(client *c) {
|
||||
addReplySetLen(c,count);
|
||||
di = dictGetIterator(d);
|
||||
while((de = dictNext(di)) != NULL)
|
||||
addReplyBulk(c,dictGetKey(de));
|
||||
addReplyBulk(c,(robj*)dictGetKey(de));
|
||||
dictReleaseIterator(di);
|
||||
dictRelease(d);
|
||||
}
|
||||
@@ -791,7 +791,7 @@ int qsortCompareSetsByRevCardinality(const void *s1, const void *s2) {
|
||||
|
||||
void sinterGenericCommand(client *c, robj **setkeys,
|
||||
unsigned long setnum, robj *dstkey) {
|
||||
robj **sets = zmalloc(sizeof(robj*)*setnum, MALLOC_SHARED);
|
||||
robj **sets = (robj**)zmalloc(sizeof(robj*)*setnum, MALLOC_SHARED);
|
||||
setTypeIterator *si;
|
||||
robj *dstset = NULL;
|
||||
sds elesds;
|
||||
@@ -813,7 +813,10 @@ void sinterGenericCommand(client *c, robj **setkeys,
|
||||
}
|
||||
addReply(c,shared.czero);
|
||||
} else {
|
||||
addReplyNull(c);
|
||||
if (c->resp >= 3)
|
||||
addReplyNull(c);
|
||||
else
|
||||
addReply(c, shared.emptyarray);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -930,7 +933,7 @@ void sinterstoreCommand(client *c) {
|
||||
|
||||
void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum,
|
||||
robj *dstkey, int op) {
|
||||
robj **sets = zmalloc(sizeof(robj*)*setnum, MALLOC_SHARED);
|
||||
robj **sets = (robj**)zmalloc(sizeof(robj*)*setnum, MALLOC_SHARED);
|
||||
setTypeIterator *si;
|
||||
robj *dstset = NULL;
|
||||
sds ele;
|
||||
@@ -50,7 +50,7 @@ size_t streamReplyWithRangeFromConsumerPEL(client *c, stream *s, streamID *start
|
||||
|
||||
/* Create a new stream data structure. */
|
||||
stream *streamNew(void) {
|
||||
stream *s = zmalloc(sizeof(*s), MALLOC_SHARED);
|
||||
stream *s = (stream*)zmalloc(sizeof(*s), MALLOC_SHARED);
|
||||
s->prax = raxNew();
|
||||
s->length = 0;
|
||||
s->last_id.ms = 0;
|
||||
@@ -187,7 +187,7 @@ int streamAppendItem(stream *s, robj **argv, int64_t numfields, streamID *added_
|
||||
|
||||
/* Get a reference to the tail node listpack. */
|
||||
if (raxNext(&ri)) {
|
||||
lp = ri.data;
|
||||
lp = (unsigned char*)ri.data;
|
||||
lp_bytes = lpBytes(lp);
|
||||
}
|
||||
raxStop(&ri);
|
||||
@@ -261,7 +261,7 @@ int streamAppendItem(stream *s, robj **argv, int64_t numfields, streamID *added_
|
||||
lp = lpAppendInteger(lp,0); /* Zero deleted so far. */
|
||||
lp = lpAppendInteger(lp,numfields);
|
||||
for (int64_t i = 0; i < numfields; i++) {
|
||||
sds field = ptrFromObj(argv[i*2]);
|
||||
sds field = szFromObj(argv[i*2]);
|
||||
lp = lpAppend(lp,(unsigned char*)field,sdslen(field));
|
||||
}
|
||||
lp = lpAppendInteger(lp,0); /* Master entry zero terminator. */
|
||||
@@ -290,7 +290,7 @@ int streamAppendItem(stream *s, robj **argv, int64_t numfields, streamID *added_
|
||||
if (numfields == master_fields_count) {
|
||||
int64_t i;
|
||||
for (i = 0; i < master_fields_count; i++) {
|
||||
sds field = ptrFromObj(argv[i*2]);
|
||||
sds field = szFromObj(argv[i*2]);
|
||||
int64_t e_len;
|
||||
unsigned char buf[LP_INTBUF_SIZE];
|
||||
unsigned char *e = lpGet(lp_ele,&e_len,buf);
|
||||
@@ -333,7 +333,7 @@ int streamAppendItem(stream *s, robj **argv, int64_t numfields, streamID *added_
|
||||
if (!(flags & STREAM_ITEM_FLAG_SAMEFIELDS))
|
||||
lp = lpAppendInteger(lp,numfields);
|
||||
for (int64_t i = 0; i < numfields; i++) {
|
||||
sds field = ptrFromObj(argv[i*2]), value = ptrFromObj(argv[i*2+1]);
|
||||
sds field = szFromObj(argv[i*2]), value = szFromObj(argv[i*2+1]);
|
||||
if (!(flags & STREAM_ITEM_FLAG_SAMEFIELDS))
|
||||
lp = lpAppend(lp,(unsigned char*)field,sdslen(field));
|
||||
lp = lpAppend(lp,(unsigned char*)value,sdslen(value));
|
||||
@@ -380,7 +380,7 @@ int64_t streamTrimByLength(stream *s, size_t maxlen, int approx) {
|
||||
|
||||
int64_t deleted = 0;
|
||||
while(s->length > maxlen && raxNext(&ri)) {
|
||||
unsigned char *lp = ri.data, *p = lpFirst(lp);
|
||||
unsigned char *lp = (unsigned char*)ri.data, *p = lpFirst(lp);
|
||||
int64_t entries = lpGetInteger(p);
|
||||
|
||||
/* Check if we can remove the whole node, and still have at
|
||||
@@ -542,7 +542,7 @@ int streamIteratorGetID(streamIterator *si, streamID *id, int64_t *numfields) {
|
||||
/* Get the master ID. */
|
||||
streamDecodeID(si->ri.key,&si->master_id);
|
||||
/* Get the master fields count. */
|
||||
si->lp = si->ri.data;
|
||||
si->lp = (unsigned char*)si->ri.data;
|
||||
si->lp_ele = lpFirst(si->lp); /* Seek items count */
|
||||
si->lp_ele = lpNext(si->lp,si->lp_ele); /* Seek deleted count. */
|
||||
si->lp_ele = lpNext(si->lp,si->lp_ele); /* Seek num fields. */
|
||||
@@ -971,7 +971,7 @@ size_t streamReplyWithRange(client *c, stream *s, streamID *start, streamID *end
|
||||
* or update it if the consumer is the same as before. */
|
||||
if (group_inserted == 0) {
|
||||
streamFreeNACK(nack);
|
||||
nack = raxFind(group->pel,buf,sizeof(buf));
|
||||
nack = (streamNACK*)raxFind(group->pel,buf,sizeof(buf));
|
||||
serverAssert(nack != raxNotFound);
|
||||
raxRemove(nack->consumer->pel,buf,sizeof(buf),NULL);
|
||||
/* Update the consumer and NACK metadata. */
|
||||
@@ -1044,7 +1044,7 @@ size_t streamReplyWithRangeFromConsumerPEL(client *c, stream *s, streamID *start
|
||||
addReplyStreamID(c,&id);
|
||||
addReplyNullArray(c);
|
||||
} else {
|
||||
streamNACK *nack = ri.data;
|
||||
streamNACK *nack = (streamNACK*)ri.data;
|
||||
nack->delivery_time = mstime();
|
||||
nack->delivery_count++;
|
||||
}
|
||||
@@ -1109,8 +1109,9 @@ int string2ull(const char *s, unsigned long long *value) {
|
||||
* If 'c' is set to NULL, no reply is sent to the client. */
|
||||
int streamGenericParseIDOrReply(client *c, robj *o, streamID *id, uint64_t missing_seq, int strict) {
|
||||
char buf[128];
|
||||
if (sdslen(ptrFromObj(o)) > sizeof(buf)-1) goto invalid;
|
||||
memcpy(buf,ptrFromObj(o),sdslen(ptrFromObj(o))+1);
|
||||
char *dot = nullptr;
|
||||
if (sdslen(szFromObj(o)) > sizeof(buf)-1) goto invalid;
|
||||
memcpy(buf,ptrFromObj(o),sdslen(szFromObj(o))+1);
|
||||
|
||||
if (strict && (buf[0] == '-' || buf[0] == '+') && buf[1] == '\0')
|
||||
goto invalid;
|
||||
@@ -1127,7 +1128,7 @@ int streamGenericParseIDOrReply(client *c, robj *o, streamID *id, uint64_t missi
|
||||
}
|
||||
|
||||
/* Parse <ms>-<seq> form. */
|
||||
char *dot = strchr(buf,'-');
|
||||
dot = strchr(buf,'-');
|
||||
if (dot) *dot = '\0';
|
||||
unsigned long long ms, seq;
|
||||
if (string2ull(buf,&ms) == 0) goto invalid;
|
||||
@@ -1183,14 +1184,14 @@ void xaddCommand(client *c) {
|
||||
find an option, or the ID. */
|
||||
for (; i < c->argc; i++) {
|
||||
int moreargs = (c->argc-1) - i; /* Number of additional arguments. */
|
||||
char *opt = ptrFromObj(c->argv[i]);
|
||||
char *opt = szFromObj(c->argv[i]);
|
||||
if (opt[0] == '*' && opt[1] == '\0') {
|
||||
/* This is just a fast path for the common case of auto-ID
|
||||
* creation. */
|
||||
break;
|
||||
} else if (!strcasecmp(opt,"maxlen") && moreargs) {
|
||||
approx_maxlen = 0;
|
||||
char *next = ptrFromObj(c->argv[i+1]);
|
||||
char *next = szFromObj(c->argv[i+1]);
|
||||
/* Check for the form MAXLEN ~ <count>. */
|
||||
if (moreargs >= 2 && next[0] == '~' && next[1] == '\0') {
|
||||
approx_maxlen = 1;
|
||||
@@ -1226,7 +1227,7 @@ void xaddCommand(client *c) {
|
||||
robj *o;
|
||||
stream *s;
|
||||
if ((o = streamTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
||||
s = ptrFromObj(o);
|
||||
s = (stream*)ptrFromObj(o);
|
||||
|
||||
/* Append using the low level function and return the ID. */
|
||||
if (streamAppendItem(s,c->argv+field_pos,(c->argc-field_pos)/2,
|
||||
@@ -1279,7 +1280,7 @@ void xrangeGenericCommand(client *c, int rev) {
|
||||
if (c->argc > 4) {
|
||||
for (int j = 4; j < c->argc; j++) {
|
||||
int additional = c->argc-j-1;
|
||||
if (strcasecmp(ptrFromObj(c->argv[j]),"COUNT") == 0 && additional >= 1) {
|
||||
if (strcasecmp(szFromObj(c->argv[j]),"COUNT") == 0 && additional >= 1) {
|
||||
if (getLongLongFromObjectOrReply(c,c->argv[j+1],&count,NULL)
|
||||
!= C_OK) return;
|
||||
if (count < 0) count = 0;
|
||||
@@ -1295,7 +1296,7 @@ void xrangeGenericCommand(client *c, int rev) {
|
||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptyarray)) == NULL ||
|
||||
checkType(c,o,OBJ_STREAM)) return;
|
||||
|
||||
s = ptrFromObj(o);
|
||||
s = (stream*)ptrFromObj(o);
|
||||
|
||||
if (count == 0) {
|
||||
addReplyNullArray(c);
|
||||
@@ -1320,7 +1321,7 @@ void xlenCommand(client *c) {
|
||||
robj *o;
|
||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL
|
||||
|| checkType(c,o,OBJ_STREAM)) return;
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
addReplyLongLong(c,s->length);
|
||||
}
|
||||
|
||||
@@ -1342,14 +1343,16 @@ void xreadCommand(client *c) {
|
||||
streamID static_ids[STREAMID_STATIC_VECTOR_LEN];
|
||||
streamID *ids = static_ids;
|
||||
streamCG **groups = NULL;
|
||||
int xreadgroup = sdslen(ptrFromObj(c->argv[0])) == 10; /* XREAD or XREADGROUP? */
|
||||
int xreadgroup = sdslen(szFromObj(c->argv[0])) == 10; /* XREAD or XREADGROUP? */
|
||||
robj *groupname = NULL;
|
||||
robj *consumername = NULL;
|
||||
size_t arraylen = 0;
|
||||
void *arraylen_ptr = NULL;
|
||||
|
||||
/* Parse arguments. */
|
||||
for (int i = 1; i < c->argc; i++) {
|
||||
int moreargs = c->argc-i-1;
|
||||
char *o = ptrFromObj(c->argv[i]);
|
||||
char *o = szFromObj(c->argv[i]);
|
||||
if (!strcasecmp(o,"BLOCK") && moreargs) {
|
||||
i++;
|
||||
if (getTimeoutFromObjectOrReply(c,c->argv[i],&timeout,
|
||||
@@ -1407,8 +1410,8 @@ void xreadCommand(client *c) {
|
||||
|
||||
/* Parse the IDs and resolve the group name. */
|
||||
if (streams_count > STREAMID_STATIC_VECTOR_LEN)
|
||||
ids = zmalloc(sizeof(streamID)*streams_count, MALLOC_SHARED);
|
||||
if (groupname) groups = zmalloc(sizeof(streamCG*)*streams_count, MALLOC_SHARED);
|
||||
ids = (streamID*)zmalloc(sizeof(streamID)*streams_count, MALLOC_SHARED);
|
||||
if (groupname) groups = (streamCG**)zmalloc(sizeof(streamCG*)*streams_count, MALLOC_SHARED);
|
||||
|
||||
for (int i = streams_arg + streams_count; i < c->argc; i++) {
|
||||
/* Specifying "$" as last-known-id means that the client wants to be
|
||||
@@ -1424,7 +1427,7 @@ void xreadCommand(client *c) {
|
||||
* key and group actually exist. */
|
||||
if (groupname) {
|
||||
if (o == NULL ||
|
||||
(group = streamLookupCG(ptrFromObj(o),ptrFromObj(groupname))) == NULL)
|
||||
(group = streamLookupCG((stream*)ptrFromObj(o),szFromObj(groupname))) == NULL)
|
||||
{
|
||||
addReplyErrorFormat(c, "-NOGROUP No such key '%s' or consumer "
|
||||
"group '%s' in XREADGROUP with GROUP "
|
||||
@@ -1435,7 +1438,7 @@ void xreadCommand(client *c) {
|
||||
groups[id_idx] = group;
|
||||
}
|
||||
|
||||
if (strcmp(ptrFromObj(c->argv[i]),"$") == 0) {
|
||||
if (strcmp(szFromObj(c->argv[i]),"$") == 0) {
|
||||
if (xreadgroup) {
|
||||
addReplyError(c,"The $ ID is meaningless in the context of "
|
||||
"XREADGROUP: you want to read the history of "
|
||||
@@ -1445,14 +1448,14 @@ void xreadCommand(client *c) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (o) {
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
ids[id_idx] = s->last_id;
|
||||
} else {
|
||||
ids[id_idx].ms = 0;
|
||||
ids[id_idx].seq = 0;
|
||||
}
|
||||
continue;
|
||||
} else if (strcmp(ptrFromObj(c->argv[i]),">") == 0) {
|
||||
} else if (strcmp(szFromObj(c->argv[i]),">") == 0) {
|
||||
if (!xreadgroup) {
|
||||
addReplyError(c,"The > ID can be specified only when calling "
|
||||
"XREADGROUP using the GROUP <group> "
|
||||
@@ -1471,12 +1474,10 @@ void xreadCommand(client *c) {
|
||||
}
|
||||
|
||||
/* Try to serve the client synchronously. */
|
||||
size_t arraylen = 0;
|
||||
void *arraylen_ptr = NULL;
|
||||
for (int i = 0; i < streams_count; i++) {
|
||||
robj *o = lookupKeyRead(c->db,c->argv[streams_arg+i]);
|
||||
if (o == NULL) continue;
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
streamID *gt = ids+i; /* ID must be greater than this. */
|
||||
int serve_synchronously = 0;
|
||||
int serve_history = 0; /* True for XREADGROUP with ID != ">". */
|
||||
@@ -1525,7 +1526,7 @@ void xreadCommand(client *c) {
|
||||
addReplyBulk(c,c->argv[streams_arg+i]);
|
||||
streamConsumer *consumer = NULL;
|
||||
if (groups) consumer = streamLookupConsumer(groups[i],
|
||||
ptrFromObj(consumername),1);
|
||||
szFromObj(consumername),1);
|
||||
streamPropInfo spi = {c->argv[i+streams_arg],groupname};
|
||||
int flags = 0;
|
||||
if (noack) flags |= STREAM_RWR_NOACK;
|
||||
@@ -1600,7 +1601,7 @@ cleanup: /* Cleanup. */
|
||||
* time to the current time. The NACK consumer will be set to the one
|
||||
* specified as argument of the function. */
|
||||
streamNACK *streamCreateNACK(streamConsumer *consumer) {
|
||||
streamNACK *nack = zmalloc(sizeof(*nack), MALLOC_SHARED);
|
||||
streamNACK *nack = (streamNACK*)zmalloc(sizeof(*nack), MALLOC_SHARED);
|
||||
nack->delivery_time = mstime();
|
||||
nack->delivery_count = 1;
|
||||
nack->consumer = consumer;
|
||||
@@ -1633,7 +1634,7 @@ streamCG *streamCreateCG(stream *s, char *name, size_t namelen, streamID *id) {
|
||||
if (raxFind(s->cgroups,(unsigned char*)name,namelen) != raxNotFound)
|
||||
return NULL;
|
||||
|
||||
streamCG *cg = zmalloc(sizeof(*cg), MALLOC_SHARED);
|
||||
streamCG *cg = (streamCG*)zmalloc(sizeof(*cg), MALLOC_SHARED);
|
||||
cg->pel = raxNew();
|
||||
cg->consumers = raxNew();
|
||||
cg->last_id = *id;
|
||||
@@ -1652,7 +1653,7 @@ void streamFreeCG(streamCG *cg) {
|
||||
* pointer, otherwise if there is no such group, NULL is returned. */
|
||||
streamCG *streamLookupCG(stream *s, sds groupname) {
|
||||
if (s->cgroups == NULL) return NULL;
|
||||
streamCG *cg = raxFind(s->cgroups,(unsigned char*)groupname,
|
||||
streamCG *cg = (streamCG*)raxFind(s->cgroups,(unsigned char*)groupname,
|
||||
sdslen(groupname));
|
||||
return (cg == raxNotFound) ? NULL : cg;
|
||||
}
|
||||
@@ -1662,11 +1663,11 @@ streamCG *streamLookupCG(stream *s, sds groupname) {
|
||||
* of calling this function, otherwise its last seen time is updated and
|
||||
* the existing consumer reference returned. */
|
||||
streamConsumer *streamLookupConsumer(streamCG *cg, sds name, int create) {
|
||||
streamConsumer *consumer = raxFind(cg->consumers,(unsigned char*)name,
|
||||
streamConsumer *consumer = (streamConsumer*)raxFind(cg->consumers,(unsigned char*)name,
|
||||
sdslen(name));
|
||||
if (consumer == raxNotFound) {
|
||||
if (!create) return NULL;
|
||||
consumer = zmalloc(sizeof(*consumer), MALLOC_SHARED);
|
||||
consumer = (streamConsumer*)zmalloc(sizeof(*consumer), MALLOC_SHARED);
|
||||
consumer->name = sdsdup(name);
|
||||
consumer->pel = raxNew();
|
||||
raxInsert(cg->consumers,(unsigned char*)name,sdslen(name),
|
||||
@@ -1691,7 +1692,7 @@ uint64_t streamDelConsumer(streamCG *cg, sds name) {
|
||||
raxStart(&ri,consumer->pel);
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
while(raxNext(&ri)) {
|
||||
streamNACK *nack = ri.data;
|
||||
streamNACK *nack = (streamNACK*)ri.data;
|
||||
raxRemove(cg->pel,ri.key,ri.key_len,NULL);
|
||||
streamFreeNACK(nack);
|
||||
}
|
||||
@@ -1724,19 +1725,19 @@ NULL
|
||||
stream *s = NULL;
|
||||
sds grpname = NULL;
|
||||
streamCG *cg = NULL;
|
||||
char *opt = ptrFromObj(c->argv[1]); /* Subcommand name. */
|
||||
char *opt = szFromObj(c->argv[1]); /* Subcommand name. */
|
||||
int mkstream = 0;
|
||||
robj *o;
|
||||
|
||||
/* CREATE has an MKSTREAM option that creates the stream if it
|
||||
* does not exist. */
|
||||
if (c->argc == 6 && !strcasecmp(opt,"CREATE")) {
|
||||
if (strcasecmp(ptrFromObj(c->argv[5]),"MKSTREAM")) {
|
||||
if (strcasecmp(szFromObj(c->argv[5]),"MKSTREAM")) {
|
||||
addReplySubcommandSyntaxError(c);
|
||||
return;
|
||||
}
|
||||
mkstream = 1;
|
||||
grpname = ptrFromObj(c->argv[3]);
|
||||
grpname = szFromObj(c->argv[3]);
|
||||
}
|
||||
|
||||
/* Everything but the "HELP" option requires a key and group name. */
|
||||
@@ -1746,7 +1747,7 @@ NULL
|
||||
if (checkType(c,o,OBJ_STREAM)) return;
|
||||
s = (stream*)ptrFromObj(o);
|
||||
}
|
||||
grpname = ptrFromObj(c->argv[3]);
|
||||
grpname = szFromObj(c->argv[3]);
|
||||
}
|
||||
|
||||
/* Check for missing key/group. */
|
||||
@@ -1775,7 +1776,7 @@ NULL
|
||||
/* Dispatch the different subcommands. */
|
||||
if (!strcasecmp(opt,"CREATE") && (c->argc == 5 || c->argc == 6)) {
|
||||
streamID id;
|
||||
if (!strcmp(ptrFromObj(c->argv[4]),"$")) {
|
||||
if (!strcmp(szFromObj(c->argv[4]),"$")) {
|
||||
if (s) {
|
||||
id = s->last_id;
|
||||
} else {
|
||||
@@ -1791,7 +1792,7 @@ NULL
|
||||
serverAssert(mkstream);
|
||||
o = createStreamObject();
|
||||
dbAdd(c->db,c->argv[2],o);
|
||||
s = ptrFromObj(o);
|
||||
s = (stream*)ptrFromObj(o);
|
||||
}
|
||||
|
||||
streamCG *cg = streamCreateCG(s,grpname,sdslen(grpname),&id);
|
||||
@@ -1806,7 +1807,7 @@ NULL
|
||||
}
|
||||
} else if (!strcasecmp(opt,"SETID") && c->argc == 5) {
|
||||
streamID id;
|
||||
if (!strcmp(ptrFromObj(c->argv[4]),"$")) {
|
||||
if (!strcmp(szFromObj(c->argv[4]),"$")) {
|
||||
id = s->last_id;
|
||||
} else if (streamParseIDOrReply(c,c->argv[4],&id,0) != C_OK) {
|
||||
return;
|
||||
@@ -1829,7 +1830,7 @@ NULL
|
||||
} else if (!strcasecmp(opt,"DELCONSUMER") && c->argc == 5) {
|
||||
/* Delete the consumer and returns the number of pending messages
|
||||
* that were yet associated with such a consumer. */
|
||||
long long pending = streamDelConsumer(cg,ptrFromObj(c->argv[4]));
|
||||
long long pending = streamDelConsumer(cg,szFromObj(c->argv[4]));
|
||||
addReplyLongLong(c,pending);
|
||||
server.dirty++;
|
||||
notifyKeyspaceEvent(NOTIFY_STREAM,"xgroup-delconsumer",
|
||||
@@ -1848,7 +1849,7 @@ void xsetidCommand(client *c) {
|
||||
robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr);
|
||||
if (o == NULL || checkType(c,o,OBJ_STREAM)) return;
|
||||
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
streamID id;
|
||||
if (streamParseStrictIDOrReply(c,c->argv[2],&id,0) != C_OK) return;
|
||||
|
||||
@@ -1889,7 +1890,7 @@ void xackCommand(client *c) {
|
||||
robj *o = lookupKeyRead(c->db,c->argv[1]);
|
||||
if (o) {
|
||||
if (checkType(c,o,OBJ_STREAM)) return; /* Type error. */
|
||||
group = streamLookupCG(ptrFromObj(o),ptrFromObj(c->argv[2]));
|
||||
group = streamLookupCG((stream*)ptrFromObj(o),szFromObj(c->argv[2]));
|
||||
}
|
||||
|
||||
/* No key or group? Nothing to ack. */
|
||||
@@ -1908,7 +1909,7 @@ void xackCommand(client *c) {
|
||||
/* Lookup the ID in the group PEL: it will have a reference to the
|
||||
* NACK structure that will have a reference to the consumer, so that
|
||||
* we are able to remove the entry from both PELs. */
|
||||
streamNACK *nack = raxFind(group->pel,buf,sizeof(buf));
|
||||
streamNACK *nack = (streamNACK*)raxFind(group->pel,buf,sizeof(buf));
|
||||
if (nack != raxNotFound) {
|
||||
raxRemove(group->pel,buf,sizeof(buf),NULL);
|
||||
raxRemove(nack->consumer->pel,buf,sizeof(buf),NULL);
|
||||
@@ -1962,7 +1963,7 @@ void xpendingCommand(client *c) {
|
||||
|
||||
if (o && checkType(c,o,OBJ_STREAM)) return;
|
||||
if (o == NULL ||
|
||||
(group = streamLookupCG(ptrFromObj(o),ptrFromObj(groupname))) == NULL)
|
||||
(group = streamLookupCG((stream*)ptrFromObj(o),szFromObj(groupname))) == NULL)
|
||||
{
|
||||
addReplyErrorFormat(c, "-NOGROUP No such key '%s' or consumer "
|
||||
"group '%s'",
|
||||
@@ -2002,7 +2003,7 @@ void xpendingCommand(client *c) {
|
||||
void *arraylen_ptr = addReplyDeferredLen(c);
|
||||
size_t arraylen = 0;
|
||||
while(raxNext(&ri)) {
|
||||
streamConsumer *consumer = ri.data;
|
||||
streamConsumer *consumer = (streamConsumer*)ri.data;
|
||||
if (raxSize(consumer->pel) == 0) continue;
|
||||
addReplyArrayLen(c,2);
|
||||
addReplyBulkCBuffer(c,ri.key,ri.key_len);
|
||||
@@ -2016,7 +2017,7 @@ void xpendingCommand(client *c) {
|
||||
/* XPENDING <key> <group> <start> <stop> <count> [<consumer>] variant. */
|
||||
else {
|
||||
streamConsumer *consumer = consumername ?
|
||||
streamLookupConsumer(group,ptrFromObj(consumername),0):
|
||||
streamLookupConsumer(group,szFromObj(consumername),0):
|
||||
NULL;
|
||||
|
||||
/* If a consumer name was mentioned but it does not exist, we can
|
||||
@@ -2040,7 +2041,7 @@ void xpendingCommand(client *c) {
|
||||
size_t arraylen = 0;
|
||||
|
||||
while(count && raxNext(&ri) && memcmp(ri.key,endkey,ri.key_len) <= 0) {
|
||||
streamNACK *nack = ri.data;
|
||||
streamNACK *nack = (streamNACK*)ri.data;
|
||||
|
||||
arraylen++;
|
||||
count--;
|
||||
@@ -2145,7 +2146,7 @@ void xclaimCommand(client *c) {
|
||||
|
||||
if (o) {
|
||||
if (checkType(c,o,OBJ_STREAM)) return; /* Type error. */
|
||||
group = streamLookupCG(ptrFromObj(o),ptrFromObj(c->argv[2]));
|
||||
group = streamLookupCG((stream*)ptrFromObj(o),szFromObj(c->argv[2]));
|
||||
}
|
||||
|
||||
/* No key or group? Send an error given that the group creation
|
||||
@@ -2180,7 +2181,7 @@ void xclaimCommand(client *c) {
|
||||
int propagate_last_id = 0;
|
||||
for (; j < c->argc; j++) {
|
||||
int moreargs = (c->argc-1) - j; /* Number of additional arguments. */
|
||||
char *opt = ptrFromObj(c->argv[j]);
|
||||
char *opt = szFromObj(c->argv[j]);
|
||||
if (!strcasecmp(opt,"FORCE")) {
|
||||
force = 1;
|
||||
} else if (!strcasecmp(opt,"JUSTID")) {
|
||||
@@ -2232,7 +2233,7 @@ void xclaimCommand(client *c) {
|
||||
}
|
||||
|
||||
/* Do the actual claiming. */
|
||||
streamConsumer *consumer = streamLookupConsumer(group,ptrFromObj(c->argv[3]),1);
|
||||
streamConsumer *consumer = streamLookupConsumer(group,szFromObj(c->argv[3]),1);
|
||||
void *arraylenptr = addReplyDeferredLen(c);
|
||||
size_t arraylen = 0;
|
||||
for (int j = 5; j <= last_id_arg; j++) {
|
||||
@@ -2243,7 +2244,7 @@ void xclaimCommand(client *c) {
|
||||
streamEncodeID(buf,&id);
|
||||
|
||||
/* Lookup the ID in the group PEL. */
|
||||
streamNACK *nack = raxFind(group->pel,buf,sizeof(buf));
|
||||
streamNACK *nack = (streamNACK*)raxFind(group->pel,buf,sizeof(buf));
|
||||
|
||||
/* If FORCE is passed, let's check if at least the entry
|
||||
* exists in the Stream. In such case, we'll crate a new
|
||||
@@ -2252,7 +2253,7 @@ void xclaimCommand(client *c) {
|
||||
* and replication of consumer groups. */
|
||||
if (force && nack == raxNotFound) {
|
||||
streamIterator myiterator;
|
||||
streamIteratorStart(&myiterator,ptrFromObj(o),&id,&id,0);
|
||||
streamIteratorStart(&myiterator,(stream*)ptrFromObj(o),&id,&id,0);
|
||||
int64_t numfields;
|
||||
int found = 0;
|
||||
streamID item_id;
|
||||
@@ -2299,7 +2300,7 @@ void xclaimCommand(client *c) {
|
||||
if (justid) {
|
||||
addReplyStreamID(c,&id);
|
||||
} else {
|
||||
size_t emitted = streamReplyWithRange(c,ptrFromObj(o),&id,&id,1,0,
|
||||
size_t emitted = streamReplyWithRange(c,(stream*)ptrFromObj(o),&id,&id,1,0,
|
||||
NULL,NULL,STREAM_RWR_RAWENTRIES,NULL);
|
||||
if (!emitted) addReplyNull(c);
|
||||
}
|
||||
@@ -2330,7 +2331,7 @@ void xdelCommand(client *c) {
|
||||
|
||||
if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL
|
||||
|| checkType(c,o,OBJ_STREAM)) return;
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
|
||||
/* We need to sanity check the IDs passed to start. Even if not
|
||||
* a big issue, it is not great that the command is only partially
|
||||
@@ -2375,7 +2376,7 @@ void xtrimCommand(client *c) {
|
||||
* number of elements removed from the stream. */
|
||||
if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL
|
||||
|| checkType(c,o,OBJ_STREAM)) return;
|
||||
stream *s = ptrFromObj(o);
|
||||
stream *s = (stream*)ptrFromObj(o);
|
||||
|
||||
/* Argument parsing. */
|
||||
int trim_strategy = TRIM_STRATEGY_NONE;
|
||||
@@ -2388,11 +2389,11 @@ void xtrimCommand(client *c) {
|
||||
int i = 2; /* Start of options. */
|
||||
for (; i < c->argc; i++) {
|
||||
int moreargs = (c->argc-1) - i; /* Number of additional arguments. */
|
||||
char *opt = ptrFromObj(c->argv[i]);
|
||||
char *opt = szFromObj(c->argv[i]);
|
||||
if (!strcasecmp(opt,"maxlen") && moreargs) {
|
||||
approx_maxlen = 0;
|
||||
trim_strategy = TRIM_STRATEGY_MAXLEN;
|
||||
char *next = ptrFromObj(c->argv[i+1]);
|
||||
char *next = szFromObj(c->argv[i+1]);
|
||||
/* Check for the form MAXLEN ~ <count>. */
|
||||
if (moreargs >= 2 && next[0] == '~' && next[1] == '\0') {
|
||||
approx_maxlen = 1;
|
||||
@@ -2451,7 +2452,7 @@ NULL
|
||||
robj *key;
|
||||
|
||||
/* HELP is special. Handle it ASAP. */
|
||||
if (!strcasecmp(ptrFromObj(c->argv[1]),"HELP")) {
|
||||
if (!strcasecmp(szFromObj(c->argv[1]),"HELP")) {
|
||||
addReplyHelp(c, help);
|
||||
return;
|
||||
} else if (c->argc < 3) {
|
||||
@@ -2461,18 +2462,18 @@ NULL
|
||||
|
||||
/* With the exception of HELP handled before any other sub commands, all
|
||||
* the ones are in the form of "<subcommand> <key>". */
|
||||
opt = ptrFromObj(c->argv[1]);
|
||||
opt = szFromObj(c->argv[1]);
|
||||
key = c->argv[2];
|
||||
|
||||
/* Lookup the key now, this is common for all the subcommands but HELP. */
|
||||
robj *o = lookupKeyWriteOrReply(c,key,shared.nokeyerr);
|
||||
if (o == NULL || checkType(c,o,OBJ_STREAM)) return;
|
||||
s = ptrFromObj(o);
|
||||
s = (stream*)ptrFromObj(o);
|
||||
|
||||
/* Dispatch the different subcommands. */
|
||||
if (!strcasecmp(opt,"CONSUMERS") && c->argc == 4) {
|
||||
/* XINFO CONSUMERS <key> <group>. */
|
||||
streamCG *cg = streamLookupCG(s,ptrFromObj(c->argv[3]));
|
||||
streamCG *cg = streamLookupCG(s,szFromObj(c->argv[3]));
|
||||
if (cg == NULL) {
|
||||
addReplyErrorFormat(c, "-NOGROUP No such consumer group '%s' "
|
||||
"for key name '%s'",
|
||||
@@ -2486,7 +2487,7 @@ NULL
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
mstime_t now = mstime();
|
||||
while(raxNext(&ri)) {
|
||||
streamConsumer *consumer = ri.data;
|
||||
streamConsumer *consumer = (streamConsumer*)ri.data;
|
||||
mstime_t idle = now - consumer->seen_time;
|
||||
if (idle < 0) idle = 0;
|
||||
|
||||
@@ -2511,7 +2512,7 @@ NULL
|
||||
raxStart(&ri,s->cgroups);
|
||||
raxSeek(&ri,"^",NULL,0);
|
||||
while(raxNext(&ri)) {
|
||||
streamCG *cg = ri.data;
|
||||
streamCG *cg = (streamCG*)ri.data;
|
||||
addReplyMapLen(c,4);
|
||||
addReplyBulkCString(c,"name");
|
||||
addReplyBulkCBuffer(c,ri.key,ri.key_len);
|
||||
@@ -100,7 +100,7 @@ void setCommand(client *c) {
|
||||
int flags = OBJ_SET_NO_FLAGS;
|
||||
|
||||
for (j = 3; j < c->argc; j++) {
|
||||
char *a = ptrFromObj(c->argv[j]);
|
||||
const char *a = (const char*)ptrFromObj(c->argv[j]);
|
||||
robj *next = (j == c->argc-1) ? NULL : c->argv[j+1];
|
||||
|
||||
if ((a[0] == 'n' || a[0] == 'N') &&
|
||||
@@ -184,7 +184,7 @@ void getsetCommand(client *c) {
|
||||
void setrangeCommand(client *c) {
|
||||
robj *o;
|
||||
long offset;
|
||||
sds value = ptrFromObj(c->argv[3]);
|
||||
sds value = (sds)ptrFromObj(c->argv[3]);
|
||||
|
||||
if (getLongFromObjectOrReply(c,c->argv[2],&offset,NULL) != C_OK)
|
||||
return;
|
||||
@@ -231,14 +231,14 @@ void setrangeCommand(client *c) {
|
||||
}
|
||||
|
||||
if (sdslen(value) > 0) {
|
||||
o->m_ptr = sdsgrowzero(ptrFromObj(o),offset+sdslen(value));
|
||||
o->m_ptr = sdsgrowzero((sds)ptrFromObj(o),offset+sdslen(value));
|
||||
memcpy((char*)ptrFromObj(o)+offset,value,sdslen(value));
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_STRING,
|
||||
"setrange",c->argv[1],c->db->id);
|
||||
server.dirty++;
|
||||
}
|
||||
addReplyLongLong(c,sdslen(ptrFromObj(o)));
|
||||
addReplyLongLong(c,sdslen((sds)ptrFromObj(o)));
|
||||
}
|
||||
|
||||
void getrangeCommand(client *c) {
|
||||
@@ -258,7 +258,7 @@ void getrangeCommand(client *c) {
|
||||
str = llbuf;
|
||||
strlen = ll2string(llbuf,sizeof(llbuf),(long)ptrFromObj(o));
|
||||
} else {
|
||||
str = ptrFromObj(o);
|
||||
str = (char*)ptrFromObj(o);
|
||||
strlen = sdslen(str);
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ void msetnxCommand(client *c) {
|
||||
|
||||
void incrDecrCommand(client *c, long long incr) {
|
||||
long long value, oldvalue;
|
||||
robj *o, *new;
|
||||
robj *o, *newObj;
|
||||
|
||||
o = lookupKeyWrite(c->db,c->argv[1]);
|
||||
if (o != NULL && checkType(c,o,OBJ_STRING)) return;
|
||||
@@ -356,21 +356,21 @@ void incrDecrCommand(client *c, long long incr) {
|
||||
(value < 0 || value >= OBJ_SHARED_INTEGERS) &&
|
||||
value >= LONG_MIN && value <= LONG_MAX)
|
||||
{
|
||||
new = o;
|
||||
newObj = o;
|
||||
o->m_ptr = (void*)((long)value);
|
||||
} else {
|
||||
new = createStringObjectFromLongLongForValue(value);
|
||||
newObj = createStringObjectFromLongLongForValue(value);
|
||||
if (o) {
|
||||
dbOverwrite(c->db,c->argv[1],new);
|
||||
dbOverwrite(c->db,c->argv[1],newObj);
|
||||
} else {
|
||||
dbAdd(c->db,c->argv[1],new);
|
||||
dbAdd(c->db,c->argv[1],newObj);
|
||||
}
|
||||
}
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_STRING,"incrby",c->argv[1],c->db->id);
|
||||
server.dirty++;
|
||||
addReply(c,shared.colon);
|
||||
addReply(c,new);
|
||||
addReply(c,newObj);
|
||||
addReply(c,shared.crlf);
|
||||
}
|
||||
|
||||
@@ -398,7 +398,7 @@ void decrbyCommand(client *c) {
|
||||
|
||||
void incrbyfloatCommand(client *c) {
|
||||
long double incr, value;
|
||||
robj *o, *new, *aux;
|
||||
robj *o, *newObj, *aux;
|
||||
|
||||
o = lookupKeyWrite(c->db,c->argv[1]);
|
||||
if (o != NULL && checkType(c,o,OBJ_STRING)) return;
|
||||
@@ -411,15 +411,15 @@ void incrbyfloatCommand(client *c) {
|
||||
addReplyError(c,"increment would produce NaN or Infinity");
|
||||
return;
|
||||
}
|
||||
new = createStringObjectFromLongDouble(value,1);
|
||||
newObj = createStringObjectFromLongDouble(value,1);
|
||||
if (o)
|
||||
dbOverwrite(c->db,c->argv[1],new);
|
||||
dbOverwrite(c->db,c->argv[1],newObj);
|
||||
else
|
||||
dbAdd(c->db,c->argv[1],new);
|
||||
dbAdd(c->db,c->argv[1],newObj);
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_STRING,"incrbyfloat",c->argv[1],c->db->id);
|
||||
server.dirty++;
|
||||
addReplyBulk(c,new);
|
||||
addReplyBulk(c,newObj);
|
||||
|
||||
/* Always replicate INCRBYFLOAT as a SET command with the final value
|
||||
* in order to make sure that differences in float precision or formatting
|
||||
@@ -427,7 +427,7 @@ void incrbyfloatCommand(client *c) {
|
||||
aux = createStringObject("SET",3);
|
||||
rewriteClientCommandArgument(c,0,aux);
|
||||
decrRefCount(aux);
|
||||
rewriteClientCommandArgument(c,2,new);
|
||||
rewriteClientCommandArgument(c,2,newObj);
|
||||
}
|
||||
|
||||
void appendCommand(client *c) {
|
||||
@@ -448,14 +448,14 @@ void appendCommand(client *c) {
|
||||
|
||||
/* "append" is an argument, so always an sds */
|
||||
append = c->argv[2];
|
||||
totlen = stringObjectLen(o)+sdslen(ptrFromObj(append));
|
||||
totlen = stringObjectLen(o)+sdslen((sds)ptrFromObj(append));
|
||||
if (checkStringLength(c,totlen) != C_OK)
|
||||
return;
|
||||
|
||||
/* Append the value */
|
||||
o = dbUnshareStringValue(c->db,c->argv[1],o);
|
||||
o->m_ptr = sdscatlen(ptrFromObj(o),ptrFromObj(append),sdslen(ptrFromObj(append)));
|
||||
totlen = sdslen(ptrFromObj(o));
|
||||
o->m_ptr = sdscatlen((sds)ptrFromObj(o),ptrFromObj(append),sdslen((sds)ptrFromObj(append)));
|
||||
totlen = sdslen((sds)ptrFromObj(o));
|
||||
}
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_STRING,"append",c->argv[1],c->db->id);
|
||||
+175
-175
@@ -69,7 +69,7 @@ int zslLexValueLteMax(sds value, zlexrangespec *spec);
|
||||
/* Create a skiplist node with the specified number of levels.
|
||||
* The SDS string 'ele' is referenced by the node after the call. */
|
||||
zskiplistNode *zslCreateNode(int level, double score, sds ele) {
|
||||
zskiplistNode *zn =
|
||||
zskiplistNode *zn = (zskiplistNode*)
|
||||
zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel), MALLOC_SHARED);
|
||||
zn->score = score;
|
||||
zn->ele = ele;
|
||||
@@ -81,13 +81,13 @@ zskiplist *zslCreate(void) {
|
||||
int j;
|
||||
zskiplist *zsl;
|
||||
|
||||
zsl = zmalloc(sizeof(*zsl), MALLOC_SHARED);
|
||||
zsl = (zskiplist*)zmalloc(sizeof(*zsl), MALLOC_SHARED);
|
||||
zsl->level = 1;
|
||||
zsl->length = 0;
|
||||
zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
|
||||
for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
|
||||
zsl->header->level[j].forward = NULL;
|
||||
zsl->header->level[j].span = 0;
|
||||
zsl->header->level(j)->forward = NULL;
|
||||
zsl->header->level(j)->span = 0;
|
||||
}
|
||||
zsl->header->backward = NULL;
|
||||
zsl->tail = NULL;
|
||||
@@ -104,11 +104,11 @@ void zslFreeNode(zskiplistNode *node) {
|
||||
|
||||
/* Free a whole skiplist. */
|
||||
void zslFree(zskiplist *zsl) {
|
||||
zskiplistNode *node = zsl->header->level[0].forward, *next;
|
||||
zskiplistNode *node = zsl->header->level(0)->forward, *next;
|
||||
|
||||
zfree(zsl->header);
|
||||
while(node) {
|
||||
next = node->level[0].forward;
|
||||
next = node->level(0)->forward;
|
||||
zslFreeNode(node);
|
||||
node = next;
|
||||
}
|
||||
@@ -139,13 +139,13 @@ zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
/* store rank that is crossed to reach the insert position */
|
||||
rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
|
||||
while (x->level[i].forward &&
|
||||
(x->level[i].forward->score < score ||
|
||||
(x->level[i].forward->score == score &&
|
||||
sdscmp(x->level[i].forward->ele,ele) < 0)))
|
||||
while (x->level(i)->forward &&
|
||||
(x->level(i)->forward->score < score ||
|
||||
(x->level(i)->forward->score == score &&
|
||||
sdscmp(x->level(i)->forward->ele,ele) < 0)))
|
||||
{
|
||||
rank[i] += x->level[i].span;
|
||||
x = x->level[i].forward;
|
||||
rank[i] += x->level(i)->span;
|
||||
x = x->level(i)->forward;
|
||||
}
|
||||
update[i] = x;
|
||||
}
|
||||
@@ -158,28 +158,28 @@ zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {
|
||||
for (i = zsl->level; i < level; i++) {
|
||||
rank[i] = 0;
|
||||
update[i] = zsl->header;
|
||||
update[i]->level[i].span = zsl->length;
|
||||
update[i]->level(i)->span = zsl->length;
|
||||
}
|
||||
zsl->level = level;
|
||||
}
|
||||
x = zslCreateNode(level,score,ele);
|
||||
for (i = 0; i < level; i++) {
|
||||
x->level[i].forward = update[i]->level[i].forward;
|
||||
update[i]->level[i].forward = x;
|
||||
x->level(i)->forward = update[i]->level(i)->forward;
|
||||
update[i]->level(i)->forward = x;
|
||||
|
||||
/* update span covered by update[i] as x is inserted here */
|
||||
x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);
|
||||
update[i]->level[i].span = (rank[0] - rank[i]) + 1;
|
||||
x->level(i)->span = update[i]->level(i)->span - (rank[0] - rank[i]);
|
||||
update[i]->level(i)->span = (rank[0] - rank[i]) + 1;
|
||||
}
|
||||
|
||||
/* increment span for untouched levels */
|
||||
for (i = level; i < zsl->level; i++) {
|
||||
update[i]->level[i].span++;
|
||||
update[i]->level(i)->span++;
|
||||
}
|
||||
|
||||
x->backward = (update[0] == zsl->header) ? NULL : update[0];
|
||||
if (x->level[0].forward)
|
||||
x->level[0].forward->backward = x;
|
||||
if (x->level(0)->forward)
|
||||
x->level(0)->forward->backward = x;
|
||||
else
|
||||
zsl->tail = x;
|
||||
zsl->length++;
|
||||
@@ -190,19 +190,19 @@ zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {
|
||||
void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {
|
||||
int i;
|
||||
for (i = 0; i < zsl->level; i++) {
|
||||
if (update[i]->level[i].forward == x) {
|
||||
update[i]->level[i].span += x->level[i].span - 1;
|
||||
update[i]->level[i].forward = x->level[i].forward;
|
||||
if (update[i]->level(i)->forward == x) {
|
||||
update[i]->level(i)->span += x->level(i)->span - 1;
|
||||
update[i]->level(i)->forward = x->level(i)->forward;
|
||||
} else {
|
||||
update[i]->level[i].span -= 1;
|
||||
update[i]->level(i)->span -= 1;
|
||||
}
|
||||
}
|
||||
if (x->level[0].forward) {
|
||||
x->level[0].forward->backward = x->backward;
|
||||
if (x->level(0)->forward) {
|
||||
x->level(0)->forward->backward = x->backward;
|
||||
} else {
|
||||
zsl->tail = x->backward;
|
||||
}
|
||||
while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL)
|
||||
while(zsl->level > 1 && zsl->header->level(zsl->level-1)->forward == NULL)
|
||||
zsl->level--;
|
||||
zsl->length--;
|
||||
}
|
||||
@@ -221,18 +221,18 @@ int zslDelete(zskiplist *zsl, double score, sds ele, zskiplistNode **node) {
|
||||
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
while (x->level[i].forward &&
|
||||
(x->level[i].forward->score < score ||
|
||||
(x->level[i].forward->score == score &&
|
||||
sdscmp(x->level[i].forward->ele,ele) < 0)))
|
||||
while (x->level(i)->forward &&
|
||||
(x->level(i)->forward->score < score ||
|
||||
(x->level(i)->forward->score == score &&
|
||||
sdscmp(x->level(i)->forward->ele,ele) < 0)))
|
||||
{
|
||||
x = x->level[i].forward;
|
||||
x = x->level(i)->forward;
|
||||
}
|
||||
update[i] = x;
|
||||
}
|
||||
/* We may have multiple elements with the same score, what we need
|
||||
* is to find the element with both the right score and object. */
|
||||
x = x->level[0].forward;
|
||||
x = x->level(0)->forward;
|
||||
if (x && score == x->score && sdscmp(x->ele,ele) == 0) {
|
||||
zslDeleteNode(zsl, x, update);
|
||||
if (!node)
|
||||
@@ -263,26 +263,26 @@ zskiplistNode *zslUpdateScore(zskiplist *zsl, double curscore, sds ele, double n
|
||||
* we'll have to update or remove it. */
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
while (x->level[i].forward &&
|
||||
(x->level[i].forward->score < curscore ||
|
||||
(x->level[i].forward->score == curscore &&
|
||||
sdscmp(x->level[i].forward->ele,ele) < 0)))
|
||||
while (x->level(i)->forward &&
|
||||
(x->level(i)->forward->score < curscore ||
|
||||
(x->level(i)->forward->score == curscore &&
|
||||
sdscmp(x->level(i)->forward->ele,ele) < 0)))
|
||||
{
|
||||
x = x->level[i].forward;
|
||||
x = x->level(i)->forward;
|
||||
}
|
||||
update[i] = x;
|
||||
}
|
||||
|
||||
/* Jump to our element: note that this function assumes that the
|
||||
* element with the matching score exists. */
|
||||
x = x->level[0].forward;
|
||||
x = x->level(0)->forward;
|
||||
serverAssert(x && curscore == x->score && sdscmp(x->ele,ele) == 0);
|
||||
|
||||
/* If the node, after the score update, would be still exactly
|
||||
* at the same position, we can just update the score without
|
||||
* actually removing and re-inserting the element in the skiplist. */
|
||||
if ((x->backward == NULL || x->backward->score < newscore) &&
|
||||
(x->level[0].forward == NULL || x->level[0].forward->score > newscore))
|
||||
(x->level(0)->forward == NULL || x->level(0)->forward->score > newscore))
|
||||
{
|
||||
x->score = newscore;
|
||||
return x;
|
||||
@@ -318,7 +318,7 @@ int zslIsInRange(zskiplist *zsl, zrangespec *range) {
|
||||
x = zsl->tail;
|
||||
if (x == NULL || !zslValueGteMin(x->score,range))
|
||||
return 0;
|
||||
x = zsl->header->level[0].forward;
|
||||
x = zsl->header->level(0)->forward;
|
||||
if (x == NULL || !zslValueLteMax(x->score,range))
|
||||
return 0;
|
||||
return 1;
|
||||
@@ -336,13 +336,13 @@ zskiplistNode *zslFirstInRange(zskiplist *zsl, zrangespec *range) {
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
/* Go forward while *OUT* of range. */
|
||||
while (x->level[i].forward &&
|
||||
!zslValueGteMin(x->level[i].forward->score,range))
|
||||
x = x->level[i].forward;
|
||||
while (x->level(i)->forward &&
|
||||
!zslValueGteMin(x->level(i)->forward->score,range))
|
||||
x = x->level(i)->forward;
|
||||
}
|
||||
|
||||
/* This is an inner range, so the next node cannot be NULL. */
|
||||
x = x->level[0].forward;
|
||||
x = x->level(0)->forward;
|
||||
serverAssert(x != NULL);
|
||||
|
||||
/* Check if score <= max. */
|
||||
@@ -362,9 +362,9 @@ zskiplistNode *zslLastInRange(zskiplist *zsl, zrangespec *range) {
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
/* Go forward while *IN* range. */
|
||||
while (x->level[i].forward &&
|
||||
zslValueLteMax(x->level[i].forward->score,range))
|
||||
x = x->level[i].forward;
|
||||
while (x->level(i)->forward &&
|
||||
zslValueLteMax(x->level(i)->forward->score,range))
|
||||
x = x->level(i)->forward;
|
||||
}
|
||||
|
||||
/* This is an inner range, so this node cannot be NULL. */
|
||||
@@ -386,21 +386,21 @@ unsigned long zslDeleteRangeByScore(zskiplist *zsl, zrangespec *range, dict *dic
|
||||
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
while (x->level[i].forward && (range->minex ?
|
||||
x->level[i].forward->score <= range->min :
|
||||
x->level[i].forward->score < range->min))
|
||||
x = x->level[i].forward;
|
||||
while (x->level(i)->forward && (range->minex ?
|
||||
x->level(i)->forward->score <= range->min :
|
||||
x->level(i)->forward->score < range->min))
|
||||
x = x->level(i)->forward;
|
||||
update[i] = x;
|
||||
}
|
||||
|
||||
/* Current node is the last with score < or <= min. */
|
||||
x = x->level[0].forward;
|
||||
x = x->level(0)->forward;
|
||||
|
||||
/* Delete nodes while in range. */
|
||||
while (x &&
|
||||
(range->maxex ? x->score < range->max : x->score <= range->max))
|
||||
{
|
||||
zskiplistNode *next = x->level[0].forward;
|
||||
zskiplistNode *next = x->level(0)->forward;
|
||||
zslDeleteNode(zsl,x,update);
|
||||
dictDelete(dict,x->ele);
|
||||
zslFreeNode(x); /* Here is where x->ele is actually released. */
|
||||
@@ -418,18 +418,18 @@ unsigned long zslDeleteRangeByLex(zskiplist *zsl, zlexrangespec *range, dict *di
|
||||
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
while (x->level[i].forward &&
|
||||
!zslLexValueGteMin(x->level[i].forward->ele,range))
|
||||
x = x->level[i].forward;
|
||||
while (x->level(i)->forward &&
|
||||
!zslLexValueGteMin(x->level(i)->forward->ele,range))
|
||||
x = x->level(i)->forward;
|
||||
update[i] = x;
|
||||
}
|
||||
|
||||
/* Current node is the last with score < or <= min. */
|
||||
x = x->level[0].forward;
|
||||
x = x->level(0)->forward;
|
||||
|
||||
/* Delete nodes while in range. */
|
||||
while (x && zslLexValueLteMax(x->ele,range)) {
|
||||
zskiplistNode *next = x->level[0].forward;
|
||||
zskiplistNode *next = x->level(0)->forward;
|
||||
zslDeleteNode(zsl,x,update);
|
||||
dictDelete(dict,x->ele);
|
||||
zslFreeNode(x); /* Here is where x->ele is actually released. */
|
||||
@@ -448,17 +448,17 @@ unsigned long zslDeleteRangeByRank(zskiplist *zsl, unsigned int start, unsigned
|
||||
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
while (x->level[i].forward && (traversed + x->level[i].span) < start) {
|
||||
traversed += x->level[i].span;
|
||||
x = x->level[i].forward;
|
||||
while (x->level(i)->forward && (traversed + x->level(i)->span) < start) {
|
||||
traversed += x->level(i)->span;
|
||||
x = x->level(i)->forward;
|
||||
}
|
||||
update[i] = x;
|
||||
}
|
||||
|
||||
traversed++;
|
||||
x = x->level[0].forward;
|
||||
x = x->level(0)->forward;
|
||||
while (x && traversed <= end) {
|
||||
zskiplistNode *next = x->level[0].forward;
|
||||
zskiplistNode *next = x->level(0)->forward;
|
||||
zslDeleteNode(zsl,x,update);
|
||||
dictDelete(dict,x->ele);
|
||||
zslFreeNode(x);
|
||||
@@ -480,12 +480,12 @@ unsigned long zslGetRank(zskiplist *zsl, double score, sds ele) {
|
||||
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
while (x->level[i].forward &&
|
||||
(x->level[i].forward->score < score ||
|
||||
(x->level[i].forward->score == score &&
|
||||
sdscmp(x->level[i].forward->ele,ele) <= 0))) {
|
||||
rank += x->level[i].span;
|
||||
x = x->level[i].forward;
|
||||
while (x->level(i)->forward &&
|
||||
(x->level(i)->forward->score < score ||
|
||||
(x->level(i)->forward->score == score &&
|
||||
sdscmp(x->level(i)->forward->ele,ele) <= 0))) {
|
||||
rank += x->level(i)->span;
|
||||
x = x->level(i)->forward;
|
||||
}
|
||||
|
||||
/* x might be equal to zsl->header, so test if obj is non-NULL */
|
||||
@@ -504,10 +504,10 @@ zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank) {
|
||||
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
while (x->level[i].forward && (traversed + x->level[i].span) <= rank)
|
||||
while (x->level(i)->forward && (traversed + x->level(i)->span) <= rank)
|
||||
{
|
||||
traversed += x->level[i].span;
|
||||
x = x->level[i].forward;
|
||||
traversed += x->level(i)->span;
|
||||
x = x->level(i)->forward;
|
||||
}
|
||||
if (traversed == rank) {
|
||||
return x;
|
||||
@@ -569,7 +569,7 @@ static int zslParseRange(robj *min, robj *max, zrangespec *spec) {
|
||||
* If the string is not a valid range C_ERR is returned, and the value
|
||||
* of *dest and *ex is undefined. */
|
||||
int zslParseLexRangeItem(robj *item, sds *dest, int *ex) {
|
||||
char *c = ptrFromObj(item);
|
||||
char *c = szFromObj(item);
|
||||
|
||||
switch(c[0]) {
|
||||
case '+':
|
||||
@@ -658,7 +658,7 @@ int zslIsInLexRange(zskiplist *zsl, zlexrangespec *range) {
|
||||
x = zsl->tail;
|
||||
if (x == NULL || !zslLexValueGteMin(x->ele,range))
|
||||
return 0;
|
||||
x = zsl->header->level[0].forward;
|
||||
x = zsl->header->level(0)->forward;
|
||||
if (x == NULL || !zslLexValueLteMax(x->ele,range))
|
||||
return 0;
|
||||
return 1;
|
||||
@@ -676,13 +676,13 @@ zskiplistNode *zslFirstInLexRange(zskiplist *zsl, zlexrangespec *range) {
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
/* Go forward while *OUT* of range. */
|
||||
while (x->level[i].forward &&
|
||||
!zslLexValueGteMin(x->level[i].forward->ele,range))
|
||||
x = x->level[i].forward;
|
||||
while (x->level(i)->forward &&
|
||||
!zslLexValueGteMin(x->level(i)->forward->ele,range))
|
||||
x = x->level(i)->forward;
|
||||
}
|
||||
|
||||
/* This is an inner range, so the next node cannot be NULL. */
|
||||
x = x->level[0].forward;
|
||||
x = x->level(0)->forward;
|
||||
serverAssert(x != NULL);
|
||||
|
||||
/* Check if score <= max. */
|
||||
@@ -702,9 +702,9 @@ zskiplistNode *zslLastInLexRange(zskiplist *zsl, zlexrangespec *range) {
|
||||
x = zsl->header;
|
||||
for (i = zsl->level-1; i >= 0; i--) {
|
||||
/* Go forward while *IN* range. */
|
||||
while (x->level[i].forward &&
|
||||
zslLexValueLteMax(x->level[i].forward->ele,range))
|
||||
x = x->level[i].forward;
|
||||
while (x->level(i)->forward &&
|
||||
zslLexValueLteMax(x->level(i)->forward->ele,range))
|
||||
x = x->level(i)->forward;
|
||||
}
|
||||
|
||||
/* This is an inner range, so this node cannot be NULL. */
|
||||
@@ -1156,7 +1156,7 @@ unsigned char *zzlDeleteRangeByRank(unsigned char *zl, unsigned int start, unsig
|
||||
unsigned long zsetLength(const robj *zobj) {
|
||||
unsigned long length = 0;
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
length = zzlLength(zobj->m_ptr);
|
||||
length = zzlLength((unsigned char*)zobj->m_ptr);
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
length = ((const zset*)zobj->m_ptr)->zsl->length;
|
||||
} else {
|
||||
@@ -1173,7 +1173,7 @@ void zsetConvert(robj *zobj, int encoding) {
|
||||
|
||||
if (zobj->encoding == encoding) return;
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = zobj->m_ptr;
|
||||
unsigned char *zl = (unsigned char*)zobj->m_ptr;
|
||||
unsigned char *eptr, *sptr;
|
||||
unsigned char *vstr;
|
||||
unsigned int vlen;
|
||||
@@ -1182,7 +1182,7 @@ void zsetConvert(robj *zobj, int encoding) {
|
||||
if (encoding != OBJ_ENCODING_SKIPLIST)
|
||||
serverPanic("Unknown target encoding");
|
||||
|
||||
zs = zmalloc(sizeof(*zs), MALLOC_SHARED);
|
||||
zs = (zset*)zmalloc(sizeof(*zs), MALLOC_SHARED);
|
||||
zs->pdict = dictCreate(&zsetDictType,NULL);
|
||||
zs->zsl = zslCreate();
|
||||
|
||||
@@ -1215,15 +1215,15 @@ void zsetConvert(robj *zobj, int encoding) {
|
||||
|
||||
/* Approach similar to zslFree(), since we want to free the skiplist at
|
||||
* the same time as creating the ziplist. */
|
||||
zs = zobj->m_ptr;
|
||||
zs = (zset*)zobj->m_ptr;
|
||||
dictRelease(zs->pdict);
|
||||
node = zs->zsl->header->level[0].forward;
|
||||
node = zs->zsl->header->level(0)->forward;
|
||||
zfree(zs->zsl->header);
|
||||
zfree(zs->zsl);
|
||||
|
||||
while (node) {
|
||||
zl = zzlInsertAt(zl,NULL,node->ele,node->score);
|
||||
next = node->level[0].forward;
|
||||
next = node->level(0)->forward;
|
||||
zslFreeNode(node);
|
||||
node = next;
|
||||
}
|
||||
@@ -1241,9 +1241,9 @@ void zsetConvert(robj *zobj, int encoding) {
|
||||
* expected ranges. */
|
||||
void zsetConvertToZiplistIfNeeded(robj *zobj, size_t maxelelen) {
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) return;
|
||||
zset *zset = zobj->m_ptr;
|
||||
zset *set = (zset*)zobj->m_ptr;
|
||||
|
||||
if (zset->zsl->length <= server.zset_max_ziplist_entries &&
|
||||
if (set->zsl->length <= server.zset_max_ziplist_entries &&
|
||||
maxelelen <= server.zset_max_ziplist_value)
|
||||
zsetConvert(zobj,OBJ_ENCODING_ZIPLIST);
|
||||
}
|
||||
@@ -1256,9 +1256,9 @@ int zsetScore(robj *zobj, sds member, double *score) {
|
||||
if (!zobj || !member) return C_ERR;
|
||||
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
if (zzlFind(zobj->m_ptr, member, score) == NULL) return C_ERR;
|
||||
if (zzlFind((unsigned char*)zobj->m_ptr, member, score) == NULL) return C_ERR;
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
dictEntry *de = dictFind(zs->pdict, member);
|
||||
if (de == NULL) return C_ERR;
|
||||
*score = *(double*)dictGetVal(de);
|
||||
@@ -1329,7 +1329,7 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) {
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *eptr;
|
||||
|
||||
if ((eptr = zzlFind(zobj->m_ptr,ele,&curscore)) != NULL) {
|
||||
if ((eptr = zzlFind((unsigned char*)zobj->m_ptr,ele,&curscore)) != NULL) {
|
||||
/* NX? Return, same element already exists. */
|
||||
if (nx) {
|
||||
*flags |= ZADD_NOP;
|
||||
@@ -1348,16 +1348,16 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) {
|
||||
|
||||
/* Remove and re-insert when score changed. */
|
||||
if (score != curscore) {
|
||||
zobj->m_ptr = zzlDelete(zobj->m_ptr,eptr);
|
||||
zobj->m_ptr = zzlInsert(zobj->m_ptr,ele,score);
|
||||
zobj->m_ptr = zzlDelete((unsigned char*)zobj->m_ptr,eptr);
|
||||
zobj->m_ptr = zzlInsert((unsigned char*)zobj->m_ptr,ele,score);
|
||||
*flags |= ZADD_UPDATED;
|
||||
}
|
||||
return 1;
|
||||
} else if (!xx) {
|
||||
/* Optimize: check if the element is too large or the list
|
||||
* becomes too long *before* executing zzlInsert. */
|
||||
zobj->m_ptr = zzlInsert(zobj->m_ptr,ele,score);
|
||||
if (zzlLength(zobj->m_ptr) > server.zset_max_ziplist_entries)
|
||||
zobj->m_ptr = zzlInsert((unsigned char*)zobj->m_ptr,ele,score);
|
||||
if (zzlLength((unsigned char*)zobj->m_ptr) > server.zset_max_ziplist_entries)
|
||||
zsetConvert(zobj,OBJ_ENCODING_SKIPLIST);
|
||||
if (sdslen(ele) > server.zset_max_ziplist_value)
|
||||
zsetConvert(zobj,OBJ_ENCODING_SKIPLIST);
|
||||
@@ -1369,7 +1369,7 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) {
|
||||
return 1;
|
||||
}
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
zskiplistNode *znode;
|
||||
dictEntry *de;
|
||||
|
||||
@@ -1425,12 +1425,12 @@ int zsetDel(robj *zobj, sds ele) {
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *eptr;
|
||||
|
||||
if ((eptr = zzlFind(zobj->m_ptr,ele,NULL)) != NULL) {
|
||||
zobj->m_ptr = zzlDelete(zobj->m_ptr,eptr);
|
||||
if ((eptr = zzlFind((unsigned char*)zobj->m_ptr,ele,NULL)) != NULL) {
|
||||
zobj->m_ptr = zzlDelete((unsigned char*)zobj->m_ptr,eptr);
|
||||
return 1;
|
||||
}
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
dictEntry *de;
|
||||
double score;
|
||||
|
||||
@@ -1477,7 +1477,7 @@ long zsetRank(robj *zobj, sds ele, int reverse) {
|
||||
llen = zsetLength(zobj);
|
||||
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = zobj->m_ptr;
|
||||
unsigned char *zl = (unsigned char*)zobj->m_ptr;
|
||||
unsigned char *eptr, *sptr;
|
||||
|
||||
eptr = ziplistIndex(zl,0);
|
||||
@@ -1502,7 +1502,7 @@ long zsetRank(robj *zobj, sds ele, int reverse) {
|
||||
return -1;
|
||||
}
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
zskiplist *zsl = zs->zsl;
|
||||
dictEntry *de;
|
||||
double score;
|
||||
@@ -1531,7 +1531,7 @@ long zsetRank(robj *zobj, sds ele, int reverse) {
|
||||
|
||||
/* This generic command implements both ZADD and ZINCRBY. */
|
||||
void zaddGenericCommand(client *c, int flags) {
|
||||
static char *nanerr = "resulting score is not a number (NaN)";
|
||||
static const char *nanerr = "resulting score is not a number (NaN)";
|
||||
robj *key = c->argv[1];
|
||||
robj *zobj;
|
||||
sds ele;
|
||||
@@ -1550,7 +1550,7 @@ void zaddGenericCommand(client *c, int flags) {
|
||||
* of the score of the first score-element pair. */
|
||||
scoreidx = 2;
|
||||
while(scoreidx < c->argc) {
|
||||
char *opt = ptrFromObj(c->argv[scoreidx]);
|
||||
char *opt = szFromObj(c->argv[scoreidx]);
|
||||
if (!strcasecmp(opt,"nx")) flags |= ZADD_NX;
|
||||
else if (!strcasecmp(opt,"xx")) flags |= ZADD_XX;
|
||||
else if (!strcasecmp(opt,"ch")) flags |= ZADD_CH;
|
||||
@@ -1590,7 +1590,7 @@ void zaddGenericCommand(client *c, int flags) {
|
||||
/* Start parsing all the scores, we need to emit any syntax error
|
||||
* before executing additions to the sorted set, as the command should
|
||||
* either execute fully or nothing at all. */
|
||||
scores = zmalloc(sizeof(double)*elements, MALLOC_SHARED);
|
||||
scores = (double*)zmalloc(sizeof(double)*elements, MALLOC_SHARED);
|
||||
for (j = 0; j < elements; j++) {
|
||||
if (getDoubleFromObjectOrReply(c,c->argv[scoreidx+j*2],&scores[j],NULL)
|
||||
!= C_OK) goto cleanup;
|
||||
@@ -1601,7 +1601,7 @@ void zaddGenericCommand(client *c, int flags) {
|
||||
if (zobj == NULL) {
|
||||
if (xx) goto reply_to_client; /* No key + XX option: nothing to do. */
|
||||
if (server.zset_max_ziplist_entries == 0 ||
|
||||
server.zset_max_ziplist_value < sdslen(ptrFromObj(c->argv[scoreidx+1])))
|
||||
server.zset_max_ziplist_value < sdslen(szFromObj(c->argv[scoreidx+1])))
|
||||
{
|
||||
zobj = createZsetObject();
|
||||
} else {
|
||||
@@ -1620,7 +1620,7 @@ void zaddGenericCommand(client *c, int flags) {
|
||||
score = scores[j];
|
||||
int retflags = flags;
|
||||
|
||||
ele = ptrFromObj(c->argv[scoreidx+1+j*2]);
|
||||
ele = szFromObj(c->argv[scoreidx+1+j*2]);
|
||||
int retval = zsetAdd(zobj, score, ele, &retflags, &newscore);
|
||||
if (retval == 0) {
|
||||
addReplyError(c,nanerr);
|
||||
@@ -1669,7 +1669,7 @@ void zremCommand(client *c) {
|
||||
checkType(c,zobj,OBJ_ZSET)) return;
|
||||
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
if (zsetDel(zobj,ptrFromObj(c->argv[j]))) deleted++;
|
||||
if (zsetDel(zobj,szFromObj(c->argv[j]))) deleted++;
|
||||
if (zsetLength(zobj) == 0) {
|
||||
dbDelete(c->db,key);
|
||||
keyremoved = 1;
|
||||
@@ -1741,21 +1741,21 @@ void zremrangeGenericCommand(client *c, int rangetype) {
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
switch(rangetype) {
|
||||
case ZRANGE_RANK:
|
||||
zobj->m_ptr = zzlDeleteRangeByRank(zobj->m_ptr,start+1,end+1,&deleted);
|
||||
zobj->m_ptr = zzlDeleteRangeByRank((unsigned char*)zobj->m_ptr,start+1,end+1,&deleted);
|
||||
break;
|
||||
case ZRANGE_SCORE:
|
||||
zobj->m_ptr = zzlDeleteRangeByScore(zobj->m_ptr,&range,&deleted);
|
||||
zobj->m_ptr = zzlDeleteRangeByScore((unsigned char*)zobj->m_ptr,&range,&deleted);
|
||||
break;
|
||||
case ZRANGE_LEX:
|
||||
zobj->m_ptr = zzlDeleteRangeByLex(zobj->m_ptr,&lexrange,&deleted);
|
||||
zobj->m_ptr = zzlDeleteRangeByLex((unsigned char*)zobj->m_ptr,&lexrange,&deleted);
|
||||
break;
|
||||
}
|
||||
if (zzlLength(zobj->m_ptr) == 0) {
|
||||
if (zzlLength((unsigned char*)zobj->m_ptr) == 0) {
|
||||
dbDelete(c->db,key);
|
||||
keyremoved = 1;
|
||||
}
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
switch(rangetype) {
|
||||
case ZRANGE_RANK:
|
||||
deleted = zslDeleteRangeByRank(zs->zsl,start+1,end+1,zs->pdict);
|
||||
@@ -1778,7 +1778,7 @@ void zremrangeGenericCommand(client *c, int rangetype) {
|
||||
|
||||
/* Step 4: Notifications and reply. */
|
||||
if (deleted) {
|
||||
char *event[3] = {"zremrangebyrank","zremrangebyscore","zremrangebylex"};
|
||||
const char *event[3] = {"zremrangebyrank","zremrangebyscore","zremrangebylex"};
|
||||
signalModifiedKey(c->db,key);
|
||||
notifyKeyspaceEvent(NOTIFY_ZSET,event[rangetype],key,c->db->id);
|
||||
if (keyremoved)
|
||||
@@ -1803,13 +1803,13 @@ void zremrangebylexCommand(client *c) {
|
||||
zremrangeGenericCommand(c,ZRANGE_LEX);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct zsetopsrc {
|
||||
robj *subject;
|
||||
int type; /* Set, sorted set */
|
||||
int encoding;
|
||||
double weight;
|
||||
|
||||
union {
|
||||
union _uT {
|
||||
/* Set iterators. */
|
||||
union _iterset {
|
||||
struct {
|
||||
@@ -1817,7 +1817,7 @@ typedef struct {
|
||||
int ii;
|
||||
} is;
|
||||
struct {
|
||||
dict *dict;
|
||||
dict *pdict;
|
||||
dictIterator *di;
|
||||
dictEntry *de;
|
||||
} ht;
|
||||
@@ -1835,7 +1835,7 @@ typedef struct {
|
||||
} sl;
|
||||
} zset;
|
||||
} iter;
|
||||
} zsetopsrc;
|
||||
};
|
||||
|
||||
|
||||
/* Use dirty flags for pointers that need to be cleaned up in the next
|
||||
@@ -1859,37 +1859,37 @@ typedef struct {
|
||||
double score;
|
||||
} zsetopval;
|
||||
|
||||
typedef union _iterset iterset;
|
||||
typedef union _iterzset iterzset;
|
||||
typedef union zsetopsrc::_uT::_iterset iterset;
|
||||
typedef union zsetopsrc::_uT::_iterzset iterzset;
|
||||
|
||||
void zuiInitIterator(zsetopsrc *op) {
|
||||
if (op->subject == NULL)
|
||||
return;
|
||||
|
||||
if (op->type == OBJ_SET) {
|
||||
iterset *it = &op->iter.set;
|
||||
iterset *it = (iterset*)&op->iter.set;
|
||||
if (op->encoding == OBJ_ENCODING_INTSET) {
|
||||
it->is.is = op->subject->m_ptr;
|
||||
it->is.is = (intset*)op->subject->m_ptr;
|
||||
it->is.ii = 0;
|
||||
} else if (op->encoding == OBJ_ENCODING_HT) {
|
||||
it->ht.dict = op->subject->m_ptr;
|
||||
it->ht.di = dictGetIterator(op->subject->m_ptr);
|
||||
it->ht.pdict = (dict*)op->subject->m_ptr;
|
||||
it->ht.di = dictGetIterator((dict*)op->subject->m_ptr);
|
||||
it->ht.de = dictNext(it->ht.di);
|
||||
} else {
|
||||
serverPanic("Unknown set encoding");
|
||||
}
|
||||
} else if (op->type == OBJ_ZSET) {
|
||||
iterzset *it = &op->iter.zset;
|
||||
iterzset *it = (iterzset*)&op->iter.zset;
|
||||
if (op->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
it->zl.zl = op->subject->m_ptr;
|
||||
it->zl.zl = (unsigned char*)op->subject->m_ptr;
|
||||
it->zl.eptr = ziplistIndex(it->zl.zl,0);
|
||||
if (it->zl.eptr != NULL) {
|
||||
it->zl.sptr = ziplistNext(it->zl.zl,it->zl.eptr);
|
||||
serverAssert(it->zl.sptr != NULL);
|
||||
}
|
||||
} else if (op->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
it->sl.zs = op->subject->m_ptr;
|
||||
it->sl.node = it->sl.zs->zsl->header->level[0].forward;
|
||||
it->sl.zs = (zset*)op->subject->m_ptr;
|
||||
it->sl.node = it->sl.zs->zsl->header->level(0)->forward;
|
||||
} else {
|
||||
serverPanic("Unknown sorted set encoding");
|
||||
}
|
||||
@@ -1931,18 +1931,18 @@ unsigned long zuiLength(zsetopsrc *op) {
|
||||
|
||||
if (op->type == OBJ_SET) {
|
||||
if (op->encoding == OBJ_ENCODING_INTSET) {
|
||||
return intsetLen(op->subject->m_ptr);
|
||||
return intsetLen((const intset*)op->subject->m_ptr);
|
||||
} else if (op->encoding == OBJ_ENCODING_HT) {
|
||||
dict *ht = op->subject->m_ptr;
|
||||
dict *ht = (dict*)op->subject->m_ptr;
|
||||
return dictSize(ht);
|
||||
} else {
|
||||
serverPanic("Unknown set encoding");
|
||||
}
|
||||
} else if (op->type == OBJ_ZSET) {
|
||||
if (op->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
return zzlLength(op->subject->m_ptr);
|
||||
return zzlLength((unsigned char*)op->subject->m_ptr);
|
||||
} else if (op->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = op->subject->m_ptr;
|
||||
zset *zs = (zset*)op->subject->m_ptr;
|
||||
return zs->zsl->length;
|
||||
} else {
|
||||
serverPanic("Unknown sorted set encoding");
|
||||
@@ -1979,7 +1979,7 @@ int zuiNext(zsetopsrc *op, zsetopval *val) {
|
||||
} else if (op->encoding == OBJ_ENCODING_HT) {
|
||||
if (it->ht.de == NULL)
|
||||
return 0;
|
||||
val->ele = dictGetKey(it->ht.de);
|
||||
val->ele = (sds)dictGetKey(it->ht.de);
|
||||
val->score = 1.0;
|
||||
|
||||
/* Move to next element. */
|
||||
@@ -2005,7 +2005,7 @@ int zuiNext(zsetopsrc *op, zsetopval *val) {
|
||||
val->score = it->sl.node->score;
|
||||
|
||||
/* Move to next element. */
|
||||
it->sl.node = it->sl.node->level[0].forward;
|
||||
it->sl.node = it->sl.node->level(0)->forward;
|
||||
} else {
|
||||
serverPanic("Unknown sorted set encoding");
|
||||
}
|
||||
@@ -2085,7 +2085,7 @@ int zuiFind(zsetopsrc *op, zsetopval *val, double *score) {
|
||||
if (op->type == OBJ_SET) {
|
||||
if (op->encoding == OBJ_ENCODING_INTSET) {
|
||||
if (zuiLongLongFromValue(val) &&
|
||||
intsetFind(op->subject->m_ptr,val->ell))
|
||||
intsetFind((intset*)op->subject->m_ptr,val->ell))
|
||||
{
|
||||
*score = 1.0;
|
||||
return 1;
|
||||
@@ -2093,7 +2093,7 @@ int zuiFind(zsetopsrc *op, zsetopval *val, double *score) {
|
||||
return 0;
|
||||
}
|
||||
} else if (op->encoding == OBJ_ENCODING_HT) {
|
||||
dict *ht = op->subject->m_ptr;
|
||||
dict *ht = (dict*)op->subject->m_ptr;
|
||||
zuiSdsFromValue(val);
|
||||
if (dictFind(ht,val->ele) != NULL) {
|
||||
*score = 1.0;
|
||||
@@ -2108,14 +2108,14 @@ int zuiFind(zsetopsrc *op, zsetopval *val, double *score) {
|
||||
zuiSdsFromValue(val);
|
||||
|
||||
if (op->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
if (zzlFind(op->subject->m_ptr,val->ele,score) != NULL) {
|
||||
if (zzlFind((unsigned char*)op->subject->m_ptr,val->ele,score) != NULL) {
|
||||
/* Score is already set by zzlFind. */
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (op->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = op->subject->m_ptr;
|
||||
zset *zs = (zset*)op->subject->m_ptr;
|
||||
dictEntry *de;
|
||||
if ((de = dictFind(zs->pdict,val->ele)) != NULL) {
|
||||
*score = *(double*)dictGetVal(de);
|
||||
@@ -2203,7 +2203,7 @@ void zunionInterGenericCommand(client *c, robj *dstkey, int op) {
|
||||
}
|
||||
|
||||
/* read keys to be used for input */
|
||||
src = zcalloc(sizeof(zsetopsrc) * setnum, MALLOC_SHARED);
|
||||
src = (zsetopsrc*)zcalloc(sizeof(zsetopsrc) * setnum, MALLOC_SHARED);
|
||||
for (i = 0, j = 3; i < setnum; i++, j++) {
|
||||
robj *obj = lookupKeyWrite(c->db,c->argv[j]);
|
||||
if (obj != NULL) {
|
||||
@@ -2230,7 +2230,7 @@ void zunionInterGenericCommand(client *c, robj *dstkey, int op) {
|
||||
|
||||
while (remaining) {
|
||||
if (remaining >= (setnum + 1) &&
|
||||
!strcasecmp(ptrFromObj(c->argv[j]),"weights"))
|
||||
!strcasecmp(szFromObj(c->argv[j]),"weights"))
|
||||
{
|
||||
j++; remaining--;
|
||||
for (i = 0; i < setnum; i++, j++, remaining--) {
|
||||
@@ -2242,14 +2242,14 @@ void zunionInterGenericCommand(client *c, robj *dstkey, int op) {
|
||||
}
|
||||
}
|
||||
} else if (remaining >= 2 &&
|
||||
!strcasecmp(ptrFromObj(c->argv[j]),"aggregate"))
|
||||
!strcasecmp(szFromObj(c->argv[j]),"aggregate"))
|
||||
{
|
||||
j++; remaining--;
|
||||
if (!strcasecmp(ptrFromObj(c->argv[j]),"sum")) {
|
||||
if (!strcasecmp(szFromObj(c->argv[j]),"sum")) {
|
||||
aggregate = REDIS_AGGR_SUM;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"min")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"min")) {
|
||||
aggregate = REDIS_AGGR_MIN;
|
||||
} else if (!strcasecmp(ptrFromObj(c->argv[j]),"max")) {
|
||||
} else if (!strcasecmp(szFromObj(c->argv[j]),"max")) {
|
||||
aggregate = REDIS_AGGR_MAX;
|
||||
} else {
|
||||
zfree(src);
|
||||
@@ -2270,7 +2270,7 @@ void zunionInterGenericCommand(client *c, robj *dstkey, int op) {
|
||||
qsort(src,setnum,sizeof(zsetopsrc),zuiCompareByCardinality);
|
||||
|
||||
dstobj = createZsetObject();
|
||||
dstzset = ptrFromObj(dstobj);
|
||||
dstzset = (zset*)ptrFromObj(dstobj);
|
||||
memset(&zval, 0, sizeof(zval));
|
||||
|
||||
if (op == SET_OP_INTER) {
|
||||
@@ -2366,7 +2366,7 @@ void zunionInterGenericCommand(client *c, robj *dstkey, int op) {
|
||||
dictExpand(dstzset->pdict,dictSize(accumulator));
|
||||
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sds ele = dictGetKey(de);
|
||||
sds ele = (sds)dictGetKey(de);
|
||||
score = dictGetDoubleVal(de);
|
||||
znode = zslInsert(dstzset->zsl,score,ele);
|
||||
dictAdd(dstzset->pdict,ele,&znode->score);
|
||||
@@ -2420,14 +2420,14 @@ void zrangeGenericCommand(client *c, int reverse) {
|
||||
if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != C_OK) ||
|
||||
(getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != C_OK)) return;
|
||||
|
||||
if (c->argc == 5 && !strcasecmp(ptrFromObj(c->argv[4]),"withscores")) {
|
||||
if (c->argc == 5 && !strcasecmp(szFromObj(c->argv[4]),"withscores")) {
|
||||
withscores = 1;
|
||||
} else if (c->argc >= 5) {
|
||||
addReply(c,shared.syntaxerr);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((zobj = lookupKeyReadOrReply(c,key,shared.null[c->resp])) == NULL
|
||||
if ((zobj = lookupKeyReadOrReply(c,key,(c->resp < 3) ? shared.emptyarray : shared.null[c->resp])) == NULL
|
||||
|| checkType(c,zobj,OBJ_ZSET)) return;
|
||||
|
||||
/* Sanitize indexes. */
|
||||
@@ -2454,7 +2454,7 @@ void zrangeGenericCommand(client *c, int reverse) {
|
||||
addReplyArrayLen(c, rangelen);
|
||||
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = zobj->m_ptr;
|
||||
unsigned char *zl = (unsigned char*)zobj->m_ptr;
|
||||
unsigned char *eptr, *sptr;
|
||||
unsigned char *vstr;
|
||||
unsigned int vlen;
|
||||
@@ -2486,7 +2486,7 @@ void zrangeGenericCommand(client *c, int reverse) {
|
||||
}
|
||||
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
zskiplist *zsl = zs->zsl;
|
||||
zskiplistNode *ln;
|
||||
sds ele;
|
||||
@@ -2497,7 +2497,7 @@ void zrangeGenericCommand(client *c, int reverse) {
|
||||
if (start > 0)
|
||||
ln = zslGetElementByRank(zsl,llen-start);
|
||||
} else {
|
||||
ln = zsl->header->level[0].forward;
|
||||
ln = zsl->header->level(0)->forward;
|
||||
if (start > 0)
|
||||
ln = zslGetElementByRank(zsl,start+1);
|
||||
}
|
||||
@@ -2508,7 +2508,7 @@ void zrangeGenericCommand(client *c, int reverse) {
|
||||
if (withscores && c->resp > 2) addReplyArrayLen(c,2);
|
||||
addReplyBulkCBuffer(c,ele,sdslen(ele));
|
||||
if (withscores) addReplyDouble(c,ln->score);
|
||||
ln = reverse ? ln->backward : ln->level[0].forward;
|
||||
ln = reverse ? ln->backward : ln->level(0)->forward;
|
||||
}
|
||||
} else {
|
||||
serverPanic("Unknown sorted set encoding");
|
||||
@@ -2555,10 +2555,10 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
|
||||
int pos = 4;
|
||||
|
||||
while (remaining) {
|
||||
if (remaining >= 1 && !strcasecmp(ptrFromObj(c->argv[pos]),"withscores")) {
|
||||
if (remaining >= 1 && !strcasecmp(szFromObj(c->argv[pos]),"withscores")) {
|
||||
pos++; remaining--;
|
||||
withscores = 1;
|
||||
} else if (remaining >= 3 && !strcasecmp(ptrFromObj(c->argv[pos]),"limit")) {
|
||||
} else if (remaining >= 3 && !strcasecmp(szFromObj(c->argv[pos]),"limit")) {
|
||||
if ((getLongFromObjectOrReply(c, c->argv[pos+1], &offset, NULL)
|
||||
!= C_OK) ||
|
||||
(getLongFromObjectOrReply(c, c->argv[pos+2], &limit, NULL)
|
||||
@@ -2575,11 +2575,11 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
|
||||
}
|
||||
|
||||
/* Ok, lookup the key and get the range */
|
||||
if ((zobj = lookupKeyReadOrReply(c,key,shared.null[c->resp])) == NULL ||
|
||||
if ((zobj = lookupKeyReadOrReply(c,key,(c->resp < 3) ? shared.emptyarray : shared.null[c->resp])) == NULL ||
|
||||
checkType(c,zobj,OBJ_ZSET)) return;
|
||||
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = zobj->m_ptr;
|
||||
unsigned char *zl = (unsigned char*)zobj->m_ptr;
|
||||
unsigned char *eptr, *sptr;
|
||||
unsigned char *vstr;
|
||||
unsigned int vlen;
|
||||
@@ -2649,7 +2649,7 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
|
||||
}
|
||||
}
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
zskiplist *zsl = zs->zsl;
|
||||
zskiplistNode *ln;
|
||||
|
||||
@@ -2677,7 +2677,7 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
|
||||
if (reverse) {
|
||||
ln = ln->backward;
|
||||
} else {
|
||||
ln = ln->level[0].forward;
|
||||
ln = ln->level(0)->forward;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2698,7 +2698,7 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
|
||||
if (reverse) {
|
||||
ln = ln->backward;
|
||||
} else {
|
||||
ln = ln->level[0].forward;
|
||||
ln = ln->level(0)->forward;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2734,7 +2734,7 @@ void zcountCommand(client *c) {
|
||||
checkType(c, zobj, OBJ_ZSET)) return;
|
||||
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = zobj->m_ptr;
|
||||
unsigned char *zl = (unsigned char*)zobj->m_ptr;
|
||||
unsigned char *eptr, *sptr;
|
||||
double score;
|
||||
|
||||
@@ -2765,7 +2765,7 @@ void zcountCommand(client *c) {
|
||||
}
|
||||
}
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
zskiplist *zsl = zs->zsl;
|
||||
zskiplistNode *zn;
|
||||
unsigned long rank;
|
||||
@@ -2815,7 +2815,7 @@ void zlexcountCommand(client *c) {
|
||||
}
|
||||
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = zobj->m_ptr;
|
||||
unsigned char *zl = (unsigned char*)zobj->m_ptr;
|
||||
unsigned char *eptr, *sptr;
|
||||
|
||||
/* Use the first element in range as the starting point */
|
||||
@@ -2843,7 +2843,7 @@ void zlexcountCommand(client *c) {
|
||||
}
|
||||
}
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
zskiplist *zsl = zs->zsl;
|
||||
zskiplistNode *zn;
|
||||
unsigned long rank;
|
||||
@@ -2904,7 +2904,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
|
||||
int pos = 4;
|
||||
|
||||
while (remaining) {
|
||||
if (remaining >= 3 && !strcasecmp(ptrFromObj(c->argv[pos]),"limit")) {
|
||||
if (remaining >= 3 && !strcasecmp(szFromObj(c->argv[pos]),"limit")) {
|
||||
if ((getLongFromObjectOrReply(c, c->argv[pos+1], &offset, NULL) != C_OK) ||
|
||||
(getLongFromObjectOrReply(c, c->argv[pos+2], &limit, NULL) != C_OK)) {
|
||||
zslFreeLexRange(&range);
|
||||
@@ -2928,7 +2928,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
|
||||
}
|
||||
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = zobj->m_ptr;
|
||||
unsigned char *zl = (unsigned char*)zobj->m_ptr;
|
||||
unsigned char *eptr, *sptr;
|
||||
unsigned char *vstr;
|
||||
unsigned int vlen;
|
||||
@@ -2994,7 +2994,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
|
||||
}
|
||||
}
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
zskiplist *zsl = zs->zsl;
|
||||
zskiplistNode *ln;
|
||||
|
||||
@@ -3023,7 +3023,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
|
||||
if (reverse) {
|
||||
ln = ln->backward;
|
||||
} else {
|
||||
ln = ln->level[0].forward;
|
||||
ln = ln->level(0)->forward;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3042,7 +3042,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
|
||||
if (reverse) {
|
||||
ln = ln->backward;
|
||||
} else {
|
||||
ln = ln->level[0].forward;
|
||||
ln = ln->level(0)->forward;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -3079,7 +3079,7 @@ void zscoreCommand(client *c) {
|
||||
if ((zobj = lookupKeyReadOrReply(c,key,shared.null[c->resp])) == NULL ||
|
||||
checkType(c,zobj,OBJ_ZSET)) return;
|
||||
|
||||
if (zsetScore(zobj,ptrFromObj(c->argv[2]),&score) == C_ERR) {
|
||||
if (zsetScore(zobj,szFromObj(c->argv[2]),&score) == C_ERR) {
|
||||
addReplyNull(c);
|
||||
} else {
|
||||
addReplyDouble(c,score);
|
||||
@@ -3096,7 +3096,7 @@ void zrankGenericCommand(client *c, int reverse) {
|
||||
checkType(c,zobj,OBJ_ZSET)) return;
|
||||
|
||||
serverAssertWithInfo(c,ele,sdsEncodedObject(ele));
|
||||
rank = zsetRank(zobj,ptrFromObj(ele),reverse);
|
||||
rank = zsetRank(zobj,szFromObj(ele),reverse);
|
||||
if (rank >= 0) {
|
||||
addReplyLongLong(c,rank);
|
||||
} else {
|
||||
@@ -3174,7 +3174,7 @@ void genericZpopCommand(client *c, robj **keyv, int keyc, int where, int emitkey
|
||||
/* Remove the element. */
|
||||
do {
|
||||
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||
unsigned char *zl = zobj->m_ptr;
|
||||
unsigned char *zl = (unsigned char*)zobj->m_ptr;
|
||||
unsigned char *eptr, *sptr;
|
||||
unsigned char *vstr;
|
||||
unsigned int vlen;
|
||||
@@ -3194,13 +3194,13 @@ void genericZpopCommand(client *c, robj **keyv, int keyc, int where, int emitkey
|
||||
serverAssertWithInfo(c,zobj,sptr != NULL);
|
||||
score = zzlGetScore(sptr);
|
||||
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
|
||||
zset *zs = zobj->m_ptr;
|
||||
zset *zs = (zset*)zobj->m_ptr;
|
||||
zskiplist *zsl = zs->zsl;
|
||||
zskiplistNode *zln;
|
||||
|
||||
/* Get the first or last element in the sorted set. */
|
||||
zln = (where == ZSET_MAX ? zsl->tail :
|
||||
zsl->header->level[0].forward);
|
||||
zsl->header->level(0)->forward);
|
||||
|
||||
/* There must be an element in the sorted set. */
|
||||
serverAssertWithInfo(c,zobj,zln != NULL);
|
||||
@@ -3214,7 +3214,7 @@ void genericZpopCommand(client *c, robj **keyv, int keyc, int where, int emitkey
|
||||
server.dirty++;
|
||||
|
||||
if (arraylen == 0) { /* Do this only for the first iteration. */
|
||||
char *events[2] = {"zpopmin","zpopmax"};
|
||||
const char *events[2] = {"zpopmin","zpopmax"};
|
||||
notifyKeyspaceEvent(NOTIFY_ZSET,events[where],key,c->db->id);
|
||||
signalModifiedKey(c->db,key);
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#define UUID_BINARY_LEN 16
|
||||
|
||||
static inline int FUuidNil(unsigned char *uuid)
|
||||
{
|
||||
unsigned char val = 0;
|
||||
for (int i = 0; i < UUID_BINARY_LEN; ++i)
|
||||
val |= uuid[i];
|
||||
return (val == 0);
|
||||
}
|
||||
|
||||
static inline int FUuidEqual(unsigned char *uuid1, unsigned char *uuid2)
|
||||
{
|
||||
unsigned char val = 0;
|
||||
for (int i = 0; i < UUID_BINARY_LEN; ++i)
|
||||
val |= (uuid1[i] ^ uuid2[i]);
|
||||
return (val == 0);
|
||||
}
|
||||
+1
-1
@@ -1 +1 @@
|
||||
#define REDIS_VERSION "0.9.2-r2"
|
||||
#define REDIS_VERSION "0.9.4"
|
||||
@@ -34,6 +34,10 @@
|
||||
#define ZIPLIST_HEAD 0
|
||||
#define ZIPLIST_TAIL 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned char *ziplistNew(void);
|
||||
unsigned char *ziplistMerge(unsigned char **first, unsigned char **second);
|
||||
unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int slen, int where);
|
||||
@@ -54,4 +58,8 @@ void ziplistRepr(unsigned char *zl);
|
||||
int ziplistTest(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ZIPLIST_H */
|
||||
@@ -35,6 +35,10 @@
|
||||
#ifndef _ZIPMAP_H
|
||||
#define _ZIPMAP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned char *zipmapNew(void);
|
||||
unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update);
|
||||
unsigned char *zipmapDel(unsigned char *zm, unsigned char *key, unsigned int klen, int *deleted);
|
||||
@@ -50,4 +54,8 @@ void zipmapRepr(unsigned char *p);
|
||||
int zipmapTest(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+6
-2
@@ -159,6 +159,10 @@ void *zrealloc(void *ptr, size_t size, enum MALLOC_CLASS class) {
|
||||
size_t oldsize;
|
||||
void *newptr;
|
||||
|
||||
if (size == 0 && ptr != NULL) {
|
||||
zfree(ptr);
|
||||
return NULL;
|
||||
}
|
||||
if (ptr == NULL) return zmalloc(size, class);
|
||||
#ifdef HAVE_MALLOC_SIZE
|
||||
oldsize = zmalloc_size(ptr);
|
||||
@@ -354,7 +358,7 @@ int zmalloc_get_allocator_info(size_t *allocated,
|
||||
* Example: zmalloc_get_smap_bytes_by_field("Rss:",-1);
|
||||
*/
|
||||
#if defined(HAVE_PROC_SMAPS)
|
||||
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
|
||||
size_t zmalloc_get_smap_bytes_by_field(const char *field, long pid) {
|
||||
char line[1024];
|
||||
size_t bytes = 0;
|
||||
int flen = strlen(field);
|
||||
@@ -382,7 +386,7 @@ size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
|
||||
return bytes;
|
||||
}
|
||||
#else
|
||||
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
|
||||
size_t zmalloc_get_smap_bytes_by_field(const char *field, long pid) {
|
||||
((void) field);
|
||||
((void) pid);
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ void zmalloc_set_oom_handler(void (*oom_handler)(size_t));
|
||||
size_t zmalloc_get_rss(void);
|
||||
int zmalloc_get_allocator_info(size_t *allocated, size_t *active, size_t *resident);
|
||||
size_t zmalloc_get_private_dirty(long pid);
|
||||
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid);
|
||||
size_t zmalloc_get_smap_bytes_by_field(const char *field, long pid);
|
||||
size_t zmalloc_get_memory_size(void);
|
||||
void zlibc_free(void *ptr);
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ test "New Master down consecutively" {
|
||||
wait_for_condition 1000 50 {
|
||||
[master_detected $instances]
|
||||
} else {
|
||||
failover "No failover detected when master $master_id fails"
|
||||
fail "No failover detected when master $master_id fails"
|
||||
}
|
||||
|
||||
assert_cluster_state ok
|
||||
|
||||
@@ -22,7 +22,7 @@ start_server {} {
|
||||
# master and slave instances while the
|
||||
# master is loaded with writes.
|
||||
|
||||
set disconnect_period 1000 ; # Disconnect repl link every N ms.
|
||||
set disconnect_period 2000 ; # Disconnect repl link every N ms.
|
||||
|
||||
for {set j 0} {$j < 5} {incr j} {
|
||||
set R($j) [srv [expr 0-$j] client]
|
||||
@@ -71,7 +71,7 @@ start_server {} {
|
||||
test "PSYNC2: cluster is consistent after failover" {
|
||||
$R($master_id) incr x; incr counter_value
|
||||
for {set j 0} {$j < 5} {incr j} {
|
||||
wait_for_condition 50 1000 {
|
||||
wait_for_condition 50 2000 {
|
||||
[$R($j) get x] == $counter_value
|
||||
} else {
|
||||
fail "Instance #$j x variable is inconsistent"
|
||||
@@ -106,7 +106,7 @@ start_server {} {
|
||||
set x [$R($master_id) get x]
|
||||
test "PSYNC2: cluster is consistent after load (x = $x)" {
|
||||
for {set j 0} {$j < 5} {incr j} {
|
||||
wait_for_condition 50 1000 {
|
||||
wait_for_condition 50 2000 {
|
||||
[$R($j) get x] == $counter_value
|
||||
} else {
|
||||
fail "Instance #$j x variable is inconsistent"
|
||||
@@ -155,7 +155,7 @@ start_server {} {
|
||||
}
|
||||
|
||||
# Wait for slaves to sync
|
||||
wait_for_condition 50 1000 {
|
||||
wait_for_condition 50 2000 {
|
||||
[status $R($master_id) connected_slaves] == 4
|
||||
} else {
|
||||
fail "Replica not reconnecting"
|
||||
@@ -170,7 +170,7 @@ start_server {} {
|
||||
$R($slave_id) config rewrite
|
||||
$R($slave_id) debug restart
|
||||
}
|
||||
wait_for_condition 50 1000 {
|
||||
wait_for_condition 50 2000 {
|
||||
[status $R($master_id) connected_slaves] == 4
|
||||
} else {
|
||||
fail "Replica not reconnecting"
|
||||
@@ -191,7 +191,7 @@ start_server {} {
|
||||
$R($master_id) EVALSHA e6e0b547500efcec21eddb619ac3724081afee89 0
|
||||
|
||||
# Wait for the two to sync
|
||||
wait_for_condition 50 1000 {
|
||||
wait_for_condition 50 2000 {
|
||||
[$R($master_id) debug digest] == [$R($slave_id) debug digest]
|
||||
} else {
|
||||
fail "Replica not reconnecting"
|
||||
@@ -217,7 +217,7 @@ start_server {} {
|
||||
if {[catch {
|
||||
$R($slave_id) slaveof $master_host $master_port
|
||||
}]} {
|
||||
after 1000
|
||||
after 2000
|
||||
} else {
|
||||
break
|
||||
}
|
||||
@@ -225,7 +225,7 @@ start_server {} {
|
||||
}
|
||||
|
||||
# The master should be back at 4 slaves eventually
|
||||
wait_for_condition 50 1000 {
|
||||
wait_for_condition 50 2000 {
|
||||
[status $R($master_id) connected_slaves] == 4
|
||||
} else {
|
||||
fail "Replica not reconnecting"
|
||||
@@ -235,7 +235,7 @@ start_server {} {
|
||||
|
||||
# However if the slave started with the full state of the
|
||||
# scripting engine, we should now have the same digest.
|
||||
wait_for_condition 50 1000 {
|
||||
wait_for_condition 50 2000 {
|
||||
[$R($master_id) debug digest] == [$R($slave_id) debug digest]
|
||||
} else {
|
||||
fail "Debug digest mismatch between master and replica in post-restart handshake"
|
||||
@@ -243,7 +243,7 @@ start_server {} {
|
||||
}
|
||||
|
||||
if {$no_exit} {
|
||||
while 1 { puts -nonewline .; flush stdout; after 1000}
|
||||
while 1 { puts -nonewline .; flush stdout; after 2000}
|
||||
}
|
||||
|
||||
}}}}}
|
||||
@@ -0,0 +1,84 @@
|
||||
set testmodule [file normalize src/modules/hellofilter.so]
|
||||
|
||||
start_server {tags {"modules"}} {
|
||||
r module load $testmodule log-key 0
|
||||
|
||||
test {Command Filter handles redirected commands} {
|
||||
r set mykey @log
|
||||
r lrange log-key 0 -1
|
||||
} "{set mykey @log}"
|
||||
|
||||
test {Command Filter can call RedisModule_CommandFilterArgDelete} {
|
||||
r rpush mylist elem1 @delme elem2
|
||||
r lrange mylist 0 -1
|
||||
} {elem1 elem2}
|
||||
|
||||
test {Command Filter can call RedisModule_CommandFilterArgInsert} {
|
||||
r del mylist
|
||||
r rpush mylist elem1 @insertbefore elem2 @insertafter elem3
|
||||
r lrange mylist 0 -1
|
||||
} {elem1 --inserted-before-- @insertbefore elem2 @insertafter --inserted-after-- elem3}
|
||||
|
||||
test {Command Filter can call RedisModule_CommandFilterArgReplace} {
|
||||
r del mylist
|
||||
r rpush mylist elem1 @replaceme elem2
|
||||
r lrange mylist 0 -1
|
||||
} {elem1 --replaced-- elem2}
|
||||
|
||||
test {Command Filter applies on RM_Call() commands} {
|
||||
r del log-key
|
||||
r hellofilter.ping
|
||||
r lrange log-key 0 -1
|
||||
} "{ping @log}"
|
||||
|
||||
test {Command Filter applies on Lua redis.call()} {
|
||||
r del log-key
|
||||
r eval "redis.call('ping', '@log')" 0
|
||||
r lrange log-key 0 -1
|
||||
} "{ping @log}"
|
||||
|
||||
test {Command Filter applies on Lua redis.call() that calls a module} {
|
||||
r del log-key
|
||||
r eval "redis.call('hellofilter.ping')" 0
|
||||
r lrange log-key 0 -1
|
||||
} "{ping @log}"
|
||||
|
||||
test {Command Filter is unregistered implicitly on module unload} {
|
||||
r del log-key
|
||||
r module unload hellofilter
|
||||
r set mykey @log
|
||||
r lrange log-key 0 -1
|
||||
} {}
|
||||
|
||||
r module load $testmodule log-key 0
|
||||
|
||||
test {Command Filter unregister works as expected} {
|
||||
# Validate reloading succeeded
|
||||
r del log-key
|
||||
r set mykey @log
|
||||
assert_equal "{set mykey @log}" [r lrange log-key 0 -1]
|
||||
|
||||
# Unregister
|
||||
r hellofilter.unregister
|
||||
r del log-key
|
||||
|
||||
r set mykey @log
|
||||
r lrange log-key 0 -1
|
||||
} {}
|
||||
|
||||
r module unload hellofilter
|
||||
r module load $testmodule log-key 1
|
||||
|
||||
test {Command Filter REDISMODULE_CMDFILTER_NOSELF works as expected} {
|
||||
r set mykey @log
|
||||
assert_equal "{set mykey @log}" [r lrange log-key 0 -1]
|
||||
|
||||
r del log-key
|
||||
r hellofilter.ping
|
||||
assert_equal {} [r lrange log-key 0 -1]
|
||||
|
||||
r eval "redis.call('hellofilter.ping')" 0
|
||||
assert_equal {} [r lrange log-key 0 -1]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -48,7 +48,7 @@ proc warnings_from_file {filename} {
|
||||
|
||||
# Return value for INFO property
|
||||
proc status {r property} {
|
||||
if {[regexp "\r\n$property:(.*?)\r\n" [{*}$r info] _ value]} {
|
||||
if {[regexp "\r\n(\t*?)$property:(.*?)\r\n" [{*}$r info] _ __ value]} {
|
||||
set _ $value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ set ::all_tests {
|
||||
unit/lazyfree
|
||||
unit/wait
|
||||
unit/pendingquerybuf
|
||||
modules/commandfilter
|
||||
}
|
||||
# Index to the next test to run in the ::all_tests list.
|
||||
set ::next_test 0
|
||||
|
||||
Reference in new issue
Block a user