├── .gitignore
├── .gitmodules
├── redismodule
├── Makefile
├── ycsbe.c
└── redismodule.h
├── README.md
├── Makefile
└── scripts
├── driver.py
└── fabfile.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.pyc
3 | *.o
4 | *.so
5 | results/
6 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "r2p2"]
2 | path = r2p2
3 | url = https://github.com/epfl-dcsl/r2p2
4 | [submodule "raft"]
5 | path = raft
6 | url = https://github.com/epfl-dcsl/raft/
7 | [submodule "lancet-tool"]
8 | path = lancet-tool
9 | url = https://github.com/epfl-dcsl/lancet-tool
10 | [submodule "distbenchr"]
11 | path = distbenchr
12 | url = https://github.com/marioskogias/distbenchr/
13 | [submodule "redis"]
14 | path = redis
15 | url = https://github.com/epfl-dcsl/redis/
16 |
--------------------------------------------------------------------------------
/redismodule/Makefile:
--------------------------------------------------------------------------------
1 | SRC_C := ycsbe.c
2 | OBJ_C := $(patsubst %.c, %.o, $(SRC_C))
3 |
4 | #WERROR_FLAGS := -W -Wall -Wstrict-prototypes -Wmissing-prototypes
5 | #WERROR_FLAGS += -Wmissing-declarations -Wold-style-definition -Wpointer-arith
6 | #WERROR_FLAGS += -Wcast-align -Wnested-externs -Wcast-qual
7 | #WERROR_FLAGS += -Wformat-nonliteral -Wformat-security
8 | #WERROR_FLAGS += -Wundef -Wwrite-strings
9 |
10 | CFLAGS := $(WERROR_FLAGS) -fPIC -g -O3
11 | LDFLAGS = -shared
12 |
13 | ycsbe.so: $(OBJ_C)
14 | $(CC) -o $@ $(OBJ_C) $(LDFLAGS)
15 |
16 | clean:
17 | rm -f *.o
18 |
19 | distclean:
20 | make clean
21 | rm -f ycsbe.so
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HovercRaft
2 |
3 | This repository contains the code for the paper:
4 |
5 | > HovercRaft: Achieving Scalability and Fault-tolerance for microsecond-scale Datacenter Services
6 | > Marios Kogias, Edouard Bugnion
7 | > Eurosys 2020
8 |
9 | You can find the paper [here](https://infoscience.epfl.ch/record/276586)
10 |
11 | ## Contents
12 |
13 | The repository contains several submodules and directories.
14 |
15 |
16 | - r2p2
17 | - The codebase for the Request Response Pair Protocol for datacenter RPCs
18 |
19 | - raft
20 | - The raft codebase used with its modifications.
21 |
22 | - redis
23 | - The redis codebase with the R2P2 modifications
24 |
25 | - lancet
26 | - The lancet latency measuring tool and load generator used for the experiments
27 |
28 | - redismodule
29 | - A redis module that implements the YCSB-E workload used in HovercRaft's evaluation
30 |
31 | - distbenchr
32 | - A python package used to run distributed experiments
33 |
34 | - scripts
35 | - Basic scripts to deploy and run HovercRaft for the synthetic and Redis experiments.
36 |
37 |
38 | ## Build
39 |
40 | To get the dependencies and build an example run:
41 | ```
42 | git submodule update --init --recursive
43 | make hovercraft-stss
44 | ```
45 |
46 | Check the Makefile for more build options.
47 |
48 | ## Experiments
49 | Check the `scipts` directory for running experiments. Configure the `fabfile.py` and `driver.py` scripts accordingly.
50 |
51 | Also, configure the `r2p2.conf` for HovercRaft as described in the R2P2 [repository](https://github.com/epfl-dcsl/r2p2).
52 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # MIT License
2 | #
3 | # Copyright (c) 2019-2021 Ecole Polytechnique Federale Lausanne (EPFL)
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 |
24 | # Flags explanation
25 | # ACCELERATED=1 - split request data and metadata
26 | # LB_REPLIES=1 - load balance who replies to the client, default policy rand
27 | # SMART_LB=1 - load balance with JBSQ
28 | # SKIP_NO_SE=1 - skip no side effect operations on all nodes but the replier
29 | # SWITCH_AGG=1 - hovercraft++ (support for in-network aggregation)
30 |
31 | .PHONY: vanilla-stss hovercraft-stss hovercraftplus redismodule
32 |
33 | ROOTDIR=$(shell git rev-parse --show-toplevel)
34 | R2P2_DIR=$(ROOTDIR)/r2p2
35 |
36 | vanilla-stss:
37 | make clean-all
38 | make -C raft
39 | make -C r2p2/dpdk-apps stss
40 |
41 | hovercraft-stss:
42 | make clean-all
43 | make -C raft
44 | make -C r2p2/dpdk-apps stss ACCELERATED=1 LB_REPLIES=1 SKIP_NO_SE=1 # SMART_LB=1
45 |
46 |
47 | hovercraftplus-stss:
48 | make clean-all
49 | make -C raft SWITCH_AGG=1
50 | make -C r2p2/dpdk-apps stss SWITCH_AGG=1 ACCELERATED=1 LB_REPLIES=1 SKIP_NO_SE=1 SMART_LB=1
51 |
52 | lancet:
53 | make -C lancet-tool coordinator
54 | make -C lancet-tool agents_r2p2_nic_ts R2P2=$(R2P2_DIR)/r2p2
55 | make -C lancet-tool manager
56 | make -C lancet-tool deploy HOSTS=icnals01,icnals02,icnals03,icnals04
57 |
58 | redismodule:
59 | make -C redismodule
60 |
61 | clean-all:
62 | make -C raft clean
63 | make -C r2p2 clean
64 | make -C redismodule clean
65 |
--------------------------------------------------------------------------------
/scripts/driver.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | from fabric.tasks import execute
4 | from fabric.api import env
5 | from fabfile import *
6 | from distbenchr import *
7 | import time
8 | import signal
9 |
10 | PEERS = [
11 | ("10.90.44.216", 8000),
12 | ("10.90.44.217", 8000),
13 | ("10.90.44.220", 8000),
14 | ]
15 |
16 | PATTERNS = {
17 | 10: "step:10000:200000:5000:20000",
18 | "redis": "step:1000:180000:2000",
19 | }
20 |
21 | CFGS = {
22 | "unrep": (
23 | [0],
24 | [
25 | ("vanilla", "")
26 | ]
27 | ),
28 | "rep": (
29 | [3],
30 | [
31 | ("vanilla", "WITH_RAFT=1")
32 | ("lb_rep_skip_no_se_smart", "WITH_RAFT=1 LB_REPLIES=1 SMART_LB=1 SKIP_NO_SE=1"),
33 | ]
34 | ),
35 | "rep_accel": (
36 | [3],
37 | [
38 | ("vanilla", "WITH_RAFT=1 ACCELERATED=1")
39 | ("lb_rep_skip_no_se_smart", "WITH_RAFT=1 ACCELERATED=1 LB_REPLIES=1 SMART_LB=1 SKIP_NO_SE=1"),
40 | ]
41 | )
42 | }
43 |
44 | FOLLOWERS_FN = {
45 | 3: run_followers3,
46 | }
47 |
48 | NO_SE_RATIO = 0.75
49 |
50 | def synthetic_time():
51 | program = "stss"
52 | service_times = [10]
53 | for mode, info in CFGS.iteritems():
54 | if "rep_accel" in mode:
55 | target = "multicast"
56 | else:
57 | target = "master"
58 | for p in info[0]:
59 | for cname, cflags in info[1]:
60 | execute(build, program, flags=cflags)
61 | execute(deploy, program)
62 | for s in service_times:
63 | mnt = Monitor()
64 | if p > 0:
65 | mnt.bg_execute(run_master, program, should_wait=False)
66 | time.sleep(2)
67 | mnt.bg_execute(FOLLOWERS_FN[p], program, should_wait=False)
68 | proto = "stssr_fixed:{}_fixed:0_fixed:0_{}".format(s, NO_SE_RATIO)
69 | else:
70 | mnt.bg_execute(run_unrep, program, should_wait=False)
71 | proto = "stss_fixed:{}_fixed:0_fixed:0".format(s)
72 | time.sleep(60)
73 | fname = "st_fixed_{}_NO_SE_{}_{}_peers_{}_{}.txt".format(s, NO_SE_RATIO, mode, p, cname)
74 | mnt.bg_execute(run_lancet_sym_hw, PATTERNS[s],
75 | proto, fname, target=target, should_wait=True)
76 | mnt.monitor()
77 | mnt.killall()
78 |
79 | def redis_ycsbe():
80 | for mode, info in CFGS.iteritems():
81 | if "accel" in mode:
82 | target = "multicast"
83 | else:
84 | target = "master"
85 | for p in info[0]:
86 | for cname, cflags in info[1]:
87 | execute(build, "stss", flags=cflags)
88 | execute(build_redis, flags=cflags)
89 | execute(kill_redis)
90 | execute(deploy_redis)
91 | mnt = Monitor()
92 | if p > 0:
93 | mnt.bg_execute(run_redis_master, should_wait=False)
94 | time.sleep(2)
95 | mnt.bg_execute(run_redis_followers, should_wait=False)
96 | proto = "redis-ycsber"
97 | else:
98 | mnt.bg_execute(run_redis_single, should_wait=False)
99 | proto = "redis-ycsbe"
100 | time.sleep(60)
101 | fname = "redis_ycsbe_{}_peers_{}_{}.txt".format(mode, p, cname)
102 | mnt.bg_execute(run_lancet_sym_hw, PATTERNS["redis"],
103 | proto, fname, target=target, should_wait=True)
104 | mnt.monitor()
105 | mnt.killall()
106 |
107 | def main():
108 | execute(build_raft)
109 | execute(prepare_clients)
110 | execute(configure_peers, PEERS)
111 |
112 | print "Execute synthetic time experiment"
113 | synthetic_time()
114 |
115 | print "Run redis ycsbe experiment"
116 | redis_ycsbe()
117 |
118 | if __name__ == "__main__":
119 | os.setpgrp() # create new process group, become its leader
120 | try:
121 | main()
122 | except:
123 | import traceback
124 | traceback.print_exc()
125 | finally:
126 | os.killpg(0, signal.SIGKILL) # kill all processes in my group
127 |
--------------------------------------------------------------------------------
/redismodule/ycsbe.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "redismodule.h"
5 |
6 | #define FIELD_NO 10
7 | #define IDX_SET "indices"
8 |
9 | static RedisModuleString *indices_set;
10 | static RedisModuleString *f1;
11 | static RedisModuleString *f2;
12 | static RedisModuleString *f3;
13 | static RedisModuleString *f4;
14 | static RedisModuleString *f5;
15 | static RedisModuleString *f6;
16 | static RedisModuleString *f7;
17 | static RedisModuleString *f8;
18 | static RedisModuleString *f9;
19 | static RedisModuleString *f10;
20 |
21 | static unsigned long hash(const unsigned char *str, int len)
22 | {
23 | unsigned long hash = 5381;
24 | int c, i;
25 |
26 | for (i=0;i $i/cpufreq/scaling_governor; echo $FREQ > $i/cpufreq/scaling_setspeed; done'")
58 | run("sudo ethtool -C enp65s0 adaptive-rx off adaptive-tx off rx-usecs 0 rx-frames 0 tx-usecs 0 tx-frames 0 || true")
59 |
60 | def _prepare_huge_pages(hugepages):
61 | run('sudo sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled"')
62 | run('sudo sh -c "echo %d > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages"' % hugepages)
63 | run('sudo sh -c "echo 4096 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages"')
64 | run("sudo find /dev/hugepages -name 'rtemap_*' -delete")
65 |
66 | def _prepare_dpdk(pcie="01:00.0"):
67 | #_prepare_huge_pages(4096)
68 | run("rm -rf /tmp/{} && mkdir -p /tmp/{}".format(os.getlogin(), os.getlogin()))
69 | put("{}/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko".format(DPDK_DIR), '/tmp/{}'.format(os.getlogin()))
70 | put("{}/usertools/dpdk-devbind.py".format(DPDK_DIR), '/tmp/{}'.format(os.getlogin()))
71 | run("sudo ifdown cu0")
72 | run("sudo sudo modprobe uio")
73 | run("sudo sudo insmod /tmp/{}/igb_uio.ko || true".format(os.getlogin()))
74 | run("sudo python /tmp/{}/dpdk-devbind.py --bind=igb_uio {}".format(os.getlogin(), pcie))
75 |
76 | @roles('master-server', 'followers3')
77 | def configure_peers(peers):
78 | _prepare_dpdk()
79 | # Delete old cfg
80 | cmd1 = "sudo sed -i '/raft/,$d' /etc/r2p2.conf"
81 | run(cmd1)
82 |
83 | # if peers cfg accordingly
84 | if not peers:
85 | return
86 |
87 | def to_string(peer):
88 | return "\t{{\n\t\tip : \"{}\"\n\t\tport : {}\n\t}}".format(peer[0], peer[1])
89 | peers_str = ",\n".join([to_string(x) for x in peers])
90 | cfg = "raft=(\n{}\n)".format(peers_str)
91 | cmd2 = "echo \'{}\' | sudo tee -a /etc/r2p2.conf".format(cfg)
92 | run(cmd2)
93 |
94 | # Set freq
95 | run("sudo sh -c 'FREQ=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq` && for i in /sys/devices/system/cpu/cpu[0-9]*; do echo userspace > $i/cpufreq/scaling_governor; echo $FREQ > $i/cpufreq/scaling_setspeed; done'")
96 | run('sudo sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled"')
97 |
98 | @run_bg('master-server')
99 | def run_unrep(program_name):
100 | run("ulimit -c unlimited && sudo /tmp/{}/{} -l 2".format(os.getlogin(), program_name))
101 |
102 | @run_bg('master-server')
103 | def run_master(program_name):
104 | run("ulimit -c unlimited && sudo /tmp/{}/{} -l 2,4".format(os.getlogin(), program_name))
105 |
106 | @run_bg('followers3')
107 | def run_followers3(program_name):
108 | run("ulimit -c unlimited && sudo /tmp/{}/{} -l 2,4".format(os.getlogin(), program_name))
109 |
110 | @run_bg('master-server')
111 | def run_redis_single():
112 | run("ulimit -c unlimited && sudo /tmp/{}/redis-server -l 2 -- --save "" --protected-mode no --loadmodule /tmp/{}/ycsbe.so".format(os.getlogin(), os.getlogin()))
113 |
114 | @run_bg('master-server')
115 | def run_redis_master():
116 | run("ulimit -c unlimited && sudo /tmp/{}/redis-server -l 2,4 -- --save "" --protected-mode no --loadmodule /tmp/{}/ycsbe.so".format(os.getlogin(), os.getlogin()))
117 |
118 | @run_bg('followers3')
119 | def run_redis_followers():
120 | run("ulimit -c unlimited && sudo /tmp/{}/redis-server -l 2,4 -- --save "" --protected-mode no --loadmodule /tmp/{}/ycsbe.so".format(os.getlogin(), os.getlogin()))
121 |
122 | @run_bg('coordinator')
123 | def run_lancet_sym_hw(pattern, proto, file_dst, target="master"):
124 | run("mkdir -p {}".format(RES_DIR))
125 | if target[1:-1] == "master":
126 | dst = icnals_ip(env.roledefs['master-server'][0])
127 | elif target[1:-1] == "switch":
128 | dst = env.roledefs['switch'][0]
129 | else:
130 | dst = env.roledefs['multicast'][0]
131 |
132 | agents = ",".join(env.roledefs['lancet-agents'])
133 | cmd = "{}/coordinator/coordinator -appProto {} -comProto R2P2\
134 | -loadThreads 15 -symAgents {} -loadPattern {}\
135 | -targetHost {}:8000\
136 | -nicTS > {}/{}".format(LANCET_DIR, proto, agents, pattern,
137 | dst, RES_DIR, file_dst)
138 | run(cmd)
139 |
140 | @roles('master-server', 'followers3')
141 | def kill_redis():
142 | run("sudo kill -9 `pidof redis-server` || true")
143 |
--------------------------------------------------------------------------------
/redismodule/redismodule.h:
--------------------------------------------------------------------------------
1 | #ifndef REDISMODULE_H
2 | #define REDISMODULE_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | /* ---------------- Defines common between core and modules --------------- */
9 |
10 | /* Error status return values. */
11 | #define REDISMODULE_OK 0
12 | #define REDISMODULE_ERR 1
13 |
14 | /* API versions. */
15 | #define REDISMODULE_APIVER_1 1
16 |
17 | /* API flags and constants */
18 | #define REDISMODULE_READ (1<<0)
19 | #define REDISMODULE_WRITE (1<<1)
20 |
21 | #define REDISMODULE_LIST_HEAD 0
22 | #define REDISMODULE_LIST_TAIL 1
23 |
24 | /* Key types. */
25 | #define REDISMODULE_KEYTYPE_EMPTY 0
26 | #define REDISMODULE_KEYTYPE_STRING 1
27 | #define REDISMODULE_KEYTYPE_LIST 2
28 | #define REDISMODULE_KEYTYPE_HASH 3
29 | #define REDISMODULE_KEYTYPE_SET 4
30 | #define REDISMODULE_KEYTYPE_ZSET 5
31 | #define REDISMODULE_KEYTYPE_MODULE 6
32 |
33 | /* Reply types. */
34 | #define REDISMODULE_REPLY_UNKNOWN -1
35 | #define REDISMODULE_REPLY_STRING 0
36 | #define REDISMODULE_REPLY_ERROR 1
37 | #define REDISMODULE_REPLY_INTEGER 2
38 | #define REDISMODULE_REPLY_ARRAY 3
39 | #define REDISMODULE_REPLY_NULL 4
40 |
41 | /* Postponed array length. */
42 | #define REDISMODULE_POSTPONED_ARRAY_LEN -1
43 |
44 | /* Expire */
45 | #define REDISMODULE_NO_EXPIRE -1
46 |
47 | /* Sorted set API flags. */
48 | #define REDISMODULE_ZADD_XX (1<<0)
49 | #define REDISMODULE_ZADD_NX (1<<1)
50 | #define REDISMODULE_ZADD_ADDED (1<<2)
51 | #define REDISMODULE_ZADD_UPDATED (1<<3)
52 | #define REDISMODULE_ZADD_NOP (1<<4)
53 |
54 | /* Hash API flags. */
55 | #define REDISMODULE_HASH_NONE 0
56 | #define REDISMODULE_HASH_NX (1<<0)
57 | #define REDISMODULE_HASH_XX (1<<1)
58 | #define REDISMODULE_HASH_CFIELDS (1<<2)
59 | #define REDISMODULE_HASH_EXISTS (1<<3)
60 |
61 | /* Context Flags: Info about the current context returned by RM_GetContextFlags */
62 |
63 | /* The command is running in the context of a Lua script */
64 | #define REDISMODULE_CTX_FLAGS_LUA 0x0001
65 | /* The command is running inside a Redis transaction */
66 | #define REDISMODULE_CTX_FLAGS_MULTI 0x0002
67 | /* The instance is a master */
68 | #define REDISMODULE_CTX_FLAGS_MASTER 0x0004
69 | /* The instance is a slave */
70 | #define REDISMODULE_CTX_FLAGS_SLAVE 0x0008
71 | /* The instance is read-only (usually meaning it's a slave as well) */
72 | #define REDISMODULE_CTX_FLAGS_READONLY 0x0010
73 | /* The instance is running in cluster mode */
74 | #define REDISMODULE_CTX_FLAGS_CLUSTER 0x0020
75 | /* The instance has AOF enabled */
76 | #define REDISMODULE_CTX_FLAGS_AOF 0x0040 //
77 | /* The instance has RDB enabled */
78 | #define REDISMODULE_CTX_FLAGS_RDB 0x0080 //
79 | /* The instance has Maxmemory set */
80 | #define REDISMODULE_CTX_FLAGS_MAXMEMORY 0x0100
81 | /* Maxmemory is set and has an eviction policy that may delete keys */
82 | #define REDISMODULE_CTX_FLAGS_EVICT 0x0200
83 |
84 |
85 | #define REDISMODULE_NOTIFY_GENERIC (1<<2) /* g */
86 | #define REDISMODULE_NOTIFY_STRING (1<<3) /* $ */
87 | #define REDISMODULE_NOTIFY_LIST (1<<4) /* l */
88 | #define REDISMODULE_NOTIFY_SET (1<<5) /* s */
89 | #define REDISMODULE_NOTIFY_HASH (1<<6) /* h */
90 | #define REDISMODULE_NOTIFY_ZSET (1<<7) /* z */
91 | #define REDISMODULE_NOTIFY_EXPIRED (1<<8) /* x */
92 | #define REDISMODULE_NOTIFY_EVICTED (1<<9) /* e */
93 | #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) /* A */
94 |
95 |
96 | /* A special pointer that we can use between the core and the module to signal
97 | * field deletion, and that is impossible to be a valid pointer. */
98 | #define REDISMODULE_HASH_DELETE ((RedisModuleString*)(long)1)
99 |
100 | /* Error messages. */
101 | #define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value"
102 |
103 | #define REDISMODULE_POSITIVE_INFINITE (1.0/0.0)
104 | #define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0)
105 |
106 | #define REDISMODULE_NOT_USED(V) ((void) V)
107 |
108 | /* ------------------------- End of common defines ------------------------ */
109 |
110 | #ifndef REDISMODULE_CORE
111 |
112 | typedef long long mstime_t;
113 |
114 | /* Incomplete structures for compiler checks but opaque access. */
115 | typedef struct RedisModuleCtx RedisModuleCtx;
116 | typedef struct RedisModuleKey RedisModuleKey;
117 | typedef struct RedisModuleString RedisModuleString;
118 | typedef struct RedisModuleCallReply RedisModuleCallReply;
119 | typedef struct RedisModuleIO RedisModuleIO;
120 | typedef struct RedisModuleType RedisModuleType;
121 | typedef struct RedisModuleDigest RedisModuleDigest;
122 | typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
123 |
124 | typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
125 |
126 | typedef int (*RedisModuleNotificationFunc) (RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key);
127 | typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver);
128 | typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value);
129 | typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value);
130 | typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value);
131 | typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value);
132 | typedef void (*RedisModuleTypeFreeFunc)(void *value);
133 |
134 | #define REDISMODULE_TYPE_METHOD_VERSION 1
135 | typedef struct RedisModuleTypeMethods {
136 | uint64_t version;
137 | RedisModuleTypeLoadFunc rdb_load;
138 | RedisModuleTypeSaveFunc rdb_save;
139 | RedisModuleTypeRewriteFunc aof_rewrite;
140 | RedisModuleTypeMemUsageFunc mem_usage;
141 | RedisModuleTypeDigestFunc digest;
142 | RedisModuleTypeFreeFunc free;
143 | } RedisModuleTypeMethods;
144 |
145 | #define REDISMODULE_GET_API(name) \
146 | RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name))
147 |
148 | #define REDISMODULE_API_FUNC(x) (*x)
149 |
150 |
151 | void *REDISMODULE_API_FUNC(RedisModule_Alloc)(size_t bytes);
152 | void *REDISMODULE_API_FUNC(RedisModule_Realloc)(void *ptr, size_t bytes);
153 | void REDISMODULE_API_FUNC(RedisModule_Free)(void *ptr);
154 | void *REDISMODULE_API_FUNC(RedisModule_Calloc)(size_t nmemb, size_t size);
155 | char *REDISMODULE_API_FUNC(RedisModule_Strdup)(const char *str);
156 | int REDISMODULE_API_FUNC(RedisModule_GetApi)(const char *, void *);
157 | int REDISMODULE_API_FUNC(RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep);
158 | void REDISMODULE_API_FUNC(RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver);
159 | int REDISMODULE_API_FUNC(RedisModule_IsModuleNameBusy)(const char *name);
160 | int REDISMODULE_API_FUNC(RedisModule_WrongArity)(RedisModuleCtx *ctx);
161 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll);
162 | int REDISMODULE_API_FUNC(RedisModule_GetSelectedDb)(RedisModuleCtx *ctx);
163 | int REDISMODULE_API_FUNC(RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid);
164 | void *REDISMODULE_API_FUNC(RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode);
165 | void REDISMODULE_API_FUNC(RedisModule_CloseKey)(RedisModuleKey *kp);
166 | int REDISMODULE_API_FUNC(RedisModule_KeyType)(RedisModuleKey *kp);
167 | size_t REDISMODULE_API_FUNC(RedisModule_ValueLength)(RedisModuleKey *kp);
168 | int REDISMODULE_API_FUNC(RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele);
169 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ListPop)(RedisModuleKey *key, int where);
170 | RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
171 | const char *REDISMODULE_API_FUNC(RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len);
172 | void REDISMODULE_API_FUNC(RedisModule_FreeCallReply)(RedisModuleCallReply *reply);
173 | int REDISMODULE_API_FUNC(RedisModule_CallReplyType)(RedisModuleCallReply *reply);
174 | long long REDISMODULE_API_FUNC(RedisModule_CallReplyInteger)(RedisModuleCallReply *reply);
175 | size_t REDISMODULE_API_FUNC(RedisModule_CallReplyLength)(RedisModuleCallReply *reply);
176 | RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx);
177 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len);
178 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll);
179 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str);
180 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringPrintf)(RedisModuleCtx *ctx, const char *fmt, ...);
181 | void REDISMODULE_API_FUNC(RedisModule_FreeString)(RedisModuleCtx *ctx, RedisModuleString *str);
182 | const char *REDISMODULE_API_FUNC(RedisModule_StringPtrLen)(const RedisModuleString *str, size_t *len);
183 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err);
184 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg);
185 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len);
186 | void REDISMODULE_API_FUNC(RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len);
187 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len);
188 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str);
189 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithNull)(RedisModuleCtx *ctx);
190 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d);
191 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply);
192 | int REDISMODULE_API_FUNC(RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll);
193 | int REDISMODULE_API_FUNC(RedisModule_StringToDouble)(const RedisModuleString *str, double *d);
194 | void REDISMODULE_API_FUNC(RedisModule_AutoMemory)(RedisModuleCtx *ctx);
195 | int REDISMODULE_API_FUNC(RedisModule_Replicate)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
196 | int REDISMODULE_API_FUNC(RedisModule_ReplicateVerbatim)(RedisModuleCtx *ctx);
197 | const char *REDISMODULE_API_FUNC(RedisModule_CallReplyStringPtr)(RedisModuleCallReply *reply, size_t *len);
198 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromCallReply)(RedisModuleCallReply *reply);
199 | int REDISMODULE_API_FUNC(RedisModule_DeleteKey)(RedisModuleKey *key);
200 | int REDISMODULE_API_FUNC(RedisModule_UnlinkKey)(RedisModuleKey *key);
201 | int REDISMODULE_API_FUNC(RedisModule_StringSet)(RedisModuleKey *key, RedisModuleString *str);
202 | char *REDISMODULE_API_FUNC(RedisModule_StringDMA)(RedisModuleKey *key, size_t *len, int mode);
203 | int REDISMODULE_API_FUNC(RedisModule_StringTruncate)(RedisModuleKey *key, size_t newlen);
204 | mstime_t REDISMODULE_API_FUNC(RedisModule_GetExpire)(RedisModuleKey *key);
205 | int REDISMODULE_API_FUNC(RedisModule_SetExpire)(RedisModuleKey *key, mstime_t expire);
206 | int REDISMODULE_API_FUNC(RedisModule_ZsetAdd)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr);
207 | int REDISMODULE_API_FUNC(RedisModule_ZsetIncrby)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore);
208 | int REDISMODULE_API_FUNC(RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score);
209 | int REDISMODULE_API_FUNC(RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted);
210 | void REDISMODULE_API_FUNC(RedisModule_ZsetRangeStop)(RedisModuleKey *key);
211 | int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
212 | int REDISMODULE_API_FUNC(RedisModule_ZsetLastInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
213 | int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
214 | int REDISMODULE_API_FUNC(RedisModule_ZsetLastInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
215 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score);
216 | int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key);
217 | int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key);
218 | int REDISMODULE_API_FUNC(RedisModule_ZsetRangeEndReached)(RedisModuleKey *key);
219 | int REDISMODULE_API_FUNC(RedisModule_HashSet)(RedisModuleKey *key, int flags, ...);
220 | int REDISMODULE_API_FUNC(RedisModule_HashGet)(RedisModuleKey *key, int flags, ...);
221 | int REDISMODULE_API_FUNC(RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx);
222 | void REDISMODULE_API_FUNC(RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos);
223 | unsigned long long REDISMODULE_API_FUNC(RedisModule_GetClientId)(RedisModuleCtx *ctx);
224 | int REDISMODULE_API_FUNC(RedisModule_GetContextFlags)(RedisModuleCtx *ctx);
225 | void *REDISMODULE_API_FUNC(RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes);
226 | RedisModuleType *REDISMODULE_API_FUNC(RedisModule_CreateDataType)(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods);
227 | int REDISMODULE_API_FUNC(RedisModule_ModuleTypeSetValue)(RedisModuleKey *key, RedisModuleType *mt, void *value);
228 | RedisModuleType *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetType)(RedisModuleKey *key);
229 | void *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetValue)(RedisModuleKey *key);
230 | void REDISMODULE_API_FUNC(RedisModule_SaveUnsigned)(RedisModuleIO *io, uint64_t value);
231 | uint64_t REDISMODULE_API_FUNC(RedisModule_LoadUnsigned)(RedisModuleIO *io);
232 | void REDISMODULE_API_FUNC(RedisModule_SaveSigned)(RedisModuleIO *io, int64_t value);
233 | int64_t REDISMODULE_API_FUNC(RedisModule_LoadSigned)(RedisModuleIO *io);
234 | void REDISMODULE_API_FUNC(RedisModule_EmitAOF)(RedisModuleIO *io, const char *cmdname, const char *fmt, ...);
235 | void REDISMODULE_API_FUNC(RedisModule_SaveString)(RedisModuleIO *io, RedisModuleString *s);
236 | void REDISMODULE_API_FUNC(RedisModule_SaveStringBuffer)(RedisModuleIO *io, const char *str, size_t len);
237 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_LoadString)(RedisModuleIO *io);
238 | char *REDISMODULE_API_FUNC(RedisModule_LoadStringBuffer)(RedisModuleIO *io, size_t *lenptr);
239 | void REDISMODULE_API_FUNC(RedisModule_SaveDouble)(RedisModuleIO *io, double value);
240 | double REDISMODULE_API_FUNC(RedisModule_LoadDouble)(RedisModuleIO *io);
241 | void REDISMODULE_API_FUNC(RedisModule_SaveFloat)(RedisModuleIO *io, float value);
242 | float REDISMODULE_API_FUNC(RedisModule_LoadFloat)(RedisModuleIO *io);
243 | void REDISMODULE_API_FUNC(RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...);
244 | void REDISMODULE_API_FUNC(RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...);
245 | int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len);
246 | void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str);
247 | int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b);
248 | RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io);
249 | long long REDISMODULE_API_FUNC(RedisModule_Milliseconds)(void);
250 | void REDISMODULE_API_FUNC(RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len);
251 | void REDISMODULE_API_FUNC(RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele);
252 | void REDISMODULE_API_FUNC(RedisModule_DigestEndSequence)(RedisModuleDigest *md);
253 |
254 | /* Experimental APIs */
255 | #ifdef REDISMODULE_EXPERIMENTAL_API
256 | RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms);
257 | int REDISMODULE_API_FUNC(RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata);
258 | int REDISMODULE_API_FUNC(RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx);
259 | int REDISMODULE_API_FUNC(RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx);
260 | void *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientPrivateData)(RedisModuleCtx *ctx);
261 | int REDISMODULE_API_FUNC(RedisModule_AbortBlock)(RedisModuleBlockedClient *bc);
262 | RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetThreadSafeContext)(RedisModuleBlockedClient *bc);
263 | void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx);
264 | void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx);
265 | void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx);
266 | int REDISMODULE_API_FUNC(RedisModule_SubscribeToKeyspaceEvents)(RedisModuleCtx *ctx, int types, RedisModuleNotificationFunc cb);
267 |
268 | #endif
269 |
270 | /* This is included inline inside each Redis module. */
271 | static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused));
272 | static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) {
273 | void *getapifuncptr = ((void**)ctx)[0];
274 | RedisModule_GetApi = (int (*)(const char *, void *)) (unsigned long)getapifuncptr;
275 | REDISMODULE_GET_API(Alloc);
276 | REDISMODULE_GET_API(Calloc);
277 | REDISMODULE_GET_API(Free);
278 | REDISMODULE_GET_API(Realloc);
279 | REDISMODULE_GET_API(Strdup);
280 | REDISMODULE_GET_API(CreateCommand);
281 | REDISMODULE_GET_API(SetModuleAttribs);
282 | REDISMODULE_GET_API(IsModuleNameBusy);
283 | REDISMODULE_GET_API(WrongArity);
284 | REDISMODULE_GET_API(ReplyWithLongLong);
285 | REDISMODULE_GET_API(ReplyWithError);
286 | REDISMODULE_GET_API(ReplyWithSimpleString);
287 | REDISMODULE_GET_API(ReplyWithArray);
288 | REDISMODULE_GET_API(ReplySetArrayLength);
289 | REDISMODULE_GET_API(ReplyWithStringBuffer);
290 | REDISMODULE_GET_API(ReplyWithString);
291 | REDISMODULE_GET_API(ReplyWithNull);
292 | REDISMODULE_GET_API(ReplyWithCallReply);
293 | REDISMODULE_GET_API(ReplyWithDouble);
294 | REDISMODULE_GET_API(ReplySetArrayLength);
295 | REDISMODULE_GET_API(GetSelectedDb);
296 | REDISMODULE_GET_API(SelectDb);
297 | REDISMODULE_GET_API(OpenKey);
298 | REDISMODULE_GET_API(CloseKey);
299 | REDISMODULE_GET_API(KeyType);
300 | REDISMODULE_GET_API(ValueLength);
301 | REDISMODULE_GET_API(ListPush);
302 | REDISMODULE_GET_API(ListPop);
303 | REDISMODULE_GET_API(StringToLongLong);
304 | REDISMODULE_GET_API(StringToDouble);
305 | REDISMODULE_GET_API(Call);
306 | REDISMODULE_GET_API(CallReplyProto);
307 | REDISMODULE_GET_API(FreeCallReply);
308 | REDISMODULE_GET_API(CallReplyInteger);
309 | REDISMODULE_GET_API(CallReplyType);
310 | REDISMODULE_GET_API(CallReplyLength);
311 | REDISMODULE_GET_API(CallReplyArrayElement);
312 | REDISMODULE_GET_API(CallReplyStringPtr);
313 | REDISMODULE_GET_API(CreateStringFromCallReply);
314 | REDISMODULE_GET_API(CreateString);
315 | REDISMODULE_GET_API(CreateStringFromLongLong);
316 | REDISMODULE_GET_API(CreateStringFromString);
317 | REDISMODULE_GET_API(CreateStringPrintf);
318 | REDISMODULE_GET_API(FreeString);
319 | REDISMODULE_GET_API(StringPtrLen);
320 | REDISMODULE_GET_API(AutoMemory);
321 | REDISMODULE_GET_API(Replicate);
322 | REDISMODULE_GET_API(ReplicateVerbatim);
323 | REDISMODULE_GET_API(DeleteKey);
324 | REDISMODULE_GET_API(UnlinkKey);
325 | REDISMODULE_GET_API(StringSet);
326 | REDISMODULE_GET_API(StringDMA);
327 | REDISMODULE_GET_API(StringTruncate);
328 | REDISMODULE_GET_API(GetExpire);
329 | REDISMODULE_GET_API(SetExpire);
330 | REDISMODULE_GET_API(ZsetAdd);
331 | REDISMODULE_GET_API(ZsetIncrby);
332 | REDISMODULE_GET_API(ZsetScore);
333 | REDISMODULE_GET_API(ZsetRem);
334 | REDISMODULE_GET_API(ZsetRangeStop);
335 | REDISMODULE_GET_API(ZsetFirstInScoreRange);
336 | REDISMODULE_GET_API(ZsetLastInScoreRange);
337 | REDISMODULE_GET_API(ZsetFirstInLexRange);
338 | REDISMODULE_GET_API(ZsetLastInLexRange);
339 | REDISMODULE_GET_API(ZsetRangeCurrentElement);
340 | REDISMODULE_GET_API(ZsetRangeNext);
341 | REDISMODULE_GET_API(ZsetRangePrev);
342 | REDISMODULE_GET_API(ZsetRangeEndReached);
343 | REDISMODULE_GET_API(HashSet);
344 | REDISMODULE_GET_API(HashGet);
345 | REDISMODULE_GET_API(IsKeysPositionRequest);
346 | REDISMODULE_GET_API(KeyAtPos);
347 | REDISMODULE_GET_API(GetClientId);
348 | REDISMODULE_GET_API(GetContextFlags);
349 | REDISMODULE_GET_API(PoolAlloc);
350 | REDISMODULE_GET_API(CreateDataType);
351 | REDISMODULE_GET_API(ModuleTypeSetValue);
352 | REDISMODULE_GET_API(ModuleTypeGetType);
353 | REDISMODULE_GET_API(ModuleTypeGetValue);
354 | REDISMODULE_GET_API(SaveUnsigned);
355 | REDISMODULE_GET_API(LoadUnsigned);
356 | REDISMODULE_GET_API(SaveSigned);
357 | REDISMODULE_GET_API(LoadSigned);
358 | REDISMODULE_GET_API(SaveString);
359 | REDISMODULE_GET_API(SaveStringBuffer);
360 | REDISMODULE_GET_API(LoadString);
361 | REDISMODULE_GET_API(LoadStringBuffer);
362 | REDISMODULE_GET_API(SaveDouble);
363 | REDISMODULE_GET_API(LoadDouble);
364 | REDISMODULE_GET_API(SaveFloat);
365 | REDISMODULE_GET_API(LoadFloat);
366 | REDISMODULE_GET_API(EmitAOF);
367 | REDISMODULE_GET_API(Log);
368 | REDISMODULE_GET_API(LogIOError);
369 | REDISMODULE_GET_API(StringAppendBuffer);
370 | REDISMODULE_GET_API(RetainString);
371 | REDISMODULE_GET_API(StringCompare);
372 | REDISMODULE_GET_API(GetContextFromIO);
373 | REDISMODULE_GET_API(Milliseconds);
374 | REDISMODULE_GET_API(DigestAddStringBuffer);
375 | REDISMODULE_GET_API(DigestAddLongLong);
376 | REDISMODULE_GET_API(DigestEndSequence);
377 |
378 | #ifdef REDISMODULE_EXPERIMENTAL_API
379 | REDISMODULE_GET_API(GetThreadSafeContext);
380 | REDISMODULE_GET_API(FreeThreadSafeContext);
381 | REDISMODULE_GET_API(ThreadSafeContextLock);
382 | REDISMODULE_GET_API(ThreadSafeContextUnlock);
383 | REDISMODULE_GET_API(BlockClient);
384 | REDISMODULE_GET_API(UnblockClient);
385 | REDISMODULE_GET_API(IsBlockedReplyRequest);
386 | REDISMODULE_GET_API(IsBlockedTimeoutRequest);
387 | REDISMODULE_GET_API(GetBlockedClientPrivateData);
388 | REDISMODULE_GET_API(AbortBlock);
389 | REDISMODULE_GET_API(SubscribeToKeyspaceEvents);
390 |
391 | #endif
392 |
393 | if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR;
394 | RedisModule_SetModuleAttribs(ctx,name,ver,apiver);
395 | return REDISMODULE_OK;
396 | }
397 |
398 | #else
399 |
400 | /* Things only defined for the modules core, not exported to modules
401 | * including this file. */
402 | #define RedisModuleString robj
403 |
404 | #endif /* REDISMODULE_CORE */
405 | #endif /* REDISMOUDLE_H */
406 |
--------------------------------------------------------------------------------