Skip to content

Commit 21b09a6

Browse files
gquintardcarlosabalde
authored andcommitted
introduce .easy_execute() 2: electric boogaloo (#49)
* introduce .easy_execute() * fix indentation * fix quotes in vcc * Update README.rst
1 parent 35492c3 commit 21b09a6

5 files changed

+287
-6
lines changed

README.rst

+4
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ import redis;
105105
Method VOID .retries(INT max_command_retries)
106106
Method VOID .push(STRING arg)
107107
Method VOID .execute(BOOL master=true)
108+
Method VOID .easy_execute(STRING command, [STRING command_args...], BOOL master=true, INT command_timeout, INT max_command_retries)
108109

109110
# Access to replies.
110111
Method BOOL .replied()
@@ -174,6 +175,9 @@ Single server
174175
db.push("Hello world!");
175176
db.execute();
176177

178+
# Alternatively, the same can be achieved with one single command
179+
db.easy_execute("SET", "foo", "Hello world!");
180+
177181
# LUA scripting.
178182
db.command("EVAL");
179183
db.push({"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
varnishtest "Tests easy_execution timeout"
2+
3+
server s1 {
4+
rxreq
5+
txresp
6+
} -repeat 1 -start
7+
8+
varnish v1 -arg "-p vsl_reclen=1024" -vcl+backend {
9+
import ${vmod_redis};
10+
11+
sub vcl_init {
12+
redis.subnets(
13+
masks={""});
14+
15+
redis.sentinels(
16+
locations={""},
17+
period=0,
18+
connection_timeout=500,
19+
command_timeout=0);
20+
21+
new db = redis.db(
22+
location="${redis_master1_ip}:${redis_master1_port}",
23+
type=master,
24+
connection_timeout=500,
25+
connection_ttl=0,
26+
command_timeout=0,
27+
max_command_retries=0,
28+
shared_connections=false,
29+
max_connections=1,
30+
password="",
31+
sickness_ttl=0,
32+
ignore_slaves=false,
33+
max_cluster_hops=0);
34+
}
35+
36+
sub vcl_deliver {
37+
# Fast command (no timeout).
38+
db.easy_execute("SET", "foo", "hello", master = true);
39+
set resp.http.Replied-1 = db.replied();
40+
set resp.http.Reply-1 = db.get_reply();
41+
42+
# Slow command (no timeout).
43+
db.easy_execute("DEBUG", "sleep", "3", master = true);
44+
set resp.http.Replied-2 = db.replied();
45+
set resp.http.Reply-2 = db.get_reply();
46+
47+
# Fast command (1000 ms timeout).
48+
db.easy_execute("SET", "foo", "hello", master = true, timeout = 1000);
49+
set resp.http.Replied-3 = db.replied();
50+
set resp.http.Reply-3 = db.get_reply();
51+
52+
# Slow command (1000 ms timeout).
53+
db.easy_execute("DEBUG", "sleep", "3", master = true, timeout = 1000);
54+
set resp.http.Replied-4 = db.replied();
55+
set resp.http.Reply-4 = db.get_reply();
56+
57+
# Fast command (no timeout).
58+
db.easy_execute("SET", "foo", "hello", master = true);
59+
set resp.http.Replied-5 = db.replied();
60+
set resp.http.Reply-5 = db.get_reply();
61+
62+
# Slow command (no timeout).
63+
db.easy_execute("DEBUG", "sleep", "3", master = true);
64+
set resp.http.Replied-6 = db.replied();
65+
set resp.http.Reply-6 = db.get_reply();
66+
67+
# Stats.
68+
set resp.http.db-stats = db.stats();
69+
set resp.http.db-servers-total = db.counter("servers.total");
70+
set resp.http.db-connections-total = db.counter("connections.total");
71+
set resp.http.db-connections-dropped-error = db.counter("connections.dropped.error");
72+
set resp.http.db-commands-total = db.counter("commands.total");
73+
set resp.http.db-commands-error = db.counter("commands.error");
74+
set resp.http.db-commands-failed = db.counter("commands.failed");
75+
set resp.http.db-commands-noscript = db.counter("commands.noscript");
76+
}
77+
} -start
78+
79+
client c1 {
80+
txreq
81+
rxresp
82+
83+
expect resp.http.Replied-1 == "true"
84+
expect resp.http.Reply-1 == "OK"
85+
86+
expect resp.http.Replied-2 == "true"
87+
expect resp.http.Reply-2 == "OK"
88+
89+
expect resp.http.Replied-3 == "true"
90+
expect resp.http.Reply-3 == "OK"
91+
92+
expect resp.http.Replied-4 == "false"
93+
expect resp.http.Reply-4 == ""
94+
95+
expect resp.http.Replied-5 == "true"
96+
expect resp.http.Reply-5 == "OK"
97+
98+
expect resp.http.Replied-6 == "true"
99+
expect resp.http.Reply-6 == "OK"
100+
101+
expect resp.http.db-servers-total == "1"
102+
expect resp.http.db-connections-total == "2"
103+
expect resp.http.db-connections-dropped-error == "1"
104+
expect resp.http.db-commands-total == "5"
105+
expect resp.http.db-commands-failed == "1"
106+
expect resp.http.db-commands-error == "0"
107+
expect resp.http.db-commands-noscript == "0"
108+
} -run
109+
110+
varnish v1 -expect client_req == 1

src/tests/standalone.proxied-methods.vtc

+35-6
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,29 @@ varnish v1 -arg "-p vsl_reclen=1024" -vcl+backend {
8282
redis.execute(true, db="master1");
8383
set resp.http.Reply-4 = redis.get_reply(db="master1");
8484

85+
# same, with easy_execute
86+
# SET (master1) -> GET (master1) -> GET (master2).
87+
redis.use("master1");
88+
redis.easy_execute("SET", "baz", "42");
89+
90+
redis.easy_execute("GET", "baz");
91+
set resp.http.Reply-easy-1 = redis.get_reply();
92+
93+
redis.easy_execute("GET", "baz", db="master2", master = true);
94+
set resp.http.Reply-easy-2 = redis.get_reply(db="master2");
95+
96+
# SET (master2) -> GET (master2) -> GET (master1).
97+
redis.use("master2");
98+
redis.easy_execute("SET", "qux", "42");
99+
100+
redis.command("GET");
101+
redis.easy_execute("GET", "qux");
102+
set resp.http.Reply-easy-3 = redis.get_reply();
103+
104+
redis.easy_execute("GET", "qux", db="master1");
105+
set resp.http.Reply-easy-4 = redis.get_reply(db="master1");
106+
107+
85108
# Stats.
86109
set resp.http.master1-stats = redis.stats(db="master1");
87110
set resp.http.master1-servers-total = redis.counter("servers.total", db="master1");
@@ -113,17 +136,23 @@ client c1 {
113136
expect resp.http.Reply-3 == "Hello world!"
114137
expect resp.http.Reply-4 == ""
115138

139+
expect resp.http.Reply-easy-1 == "42"
140+
expect resp.http.Reply-easy-2 == ""
141+
142+
expect resp.http.Reply-easy-3 == "42"
143+
expect resp.http.Reply-easy-4 == ""
144+
116145
expect resp.http.master1-servers-total == "1"
117-
expect resp.http.master1-connections-total == "2"
118-
expect resp.http.master1-connections-dropped-overflow == "1"
119-
expect resp.http.master1-commands-total == "3"
146+
expect resp.http.master1-connections-total == "3"
147+
expect resp.http.master1-connections-dropped-overflow == "2"
148+
expect resp.http.master1-commands-total == "6"
120149
expect resp.http.master1-commands-error == "0"
121150
expect resp.http.master1-commands-noscript == "0"
122151

123152
expect resp.http.master2-servers-total == "1"
124-
expect resp.http.master2-connections-total == "1"
125-
expect resp.http.master2-connections-dropped-overflow == "1"
126-
expect resp.http.master2-commands-total == "3"
153+
expect resp.http.master2-connections-total == "2"
154+
expect resp.http.master2-connections-dropped-overflow == "2"
155+
expect resp.http.master2-commands-total == "6"
127156
expect resp.http.master2-commands-error == "0"
128157
expect resp.http.master2-commands-noscript == "0"
129158
} -run

src/vmod_redis.c

+76
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,54 @@ vmod_db_execute(
823823
}
824824
}
825825

826+
/******************************************************************************
827+
* .easy_execute();
828+
*****************************************************************************/
829+
830+
#define HANDLE_ARG(N) \
831+
if (args->valid_cmd_arg ## N) { \
832+
vmod_db_push(ctx, db, args->task_priv, args->cmd_arg ## N); \
833+
}
834+
835+
/* we need this twice, with two different arg structures:
836+
* - one exposed directly by the vcc
837+
* - the other will be used by the proxied version
838+
* and sadly we can't use VMOD_PROXIED_METHOD because of this
839+
*/
840+
841+
#define EASY_EXEC(name, arg_type) \
842+
VCL_VOID \
843+
name( \
844+
VRT_CTX, struct vmod_redis_db *db, \
845+
struct arg_type *args) \
846+
{ \
847+
AN(ctx); \
848+
AN(db); \
849+
AN(args); \
850+
AN(args->vcl_priv); \
851+
AN(args->task_priv); \
852+
\
853+
vmod_db_command(ctx, db, args->task_priv, args->command); \
854+
HANDLE_ARG(1); HANDLE_ARG(2); HANDLE_ARG(3); HANDLE_ARG(4); \
855+
HANDLE_ARG(5); HANDLE_ARG(6); HANDLE_ARG(7); HANDLE_ARG(8); \
856+
HANDLE_ARG(9); HANDLE_ARG(10); HANDLE_ARG(11); HANDLE_ARG(12); \
857+
HANDLE_ARG(13); HANDLE_ARG(14); HANDLE_ARG(15); HANDLE_ARG(16); \
858+
\
859+
if (args->valid_timeout) { \
860+
vmod_db_timeout(ctx, db, args->task_priv, args->timeout); \
861+
} \
862+
if (args->valid_retries) { \
863+
vmod_db_retries(ctx, db, args->task_priv, args->retries); \
864+
} \
865+
\
866+
vmod_db_execute(ctx, db, args->vcl_priv, args->task_priv, args->master); \
867+
}
868+
869+
EASY_EXEC(vmod_db_easy_execute, arg_vmod_redis_db_easy_execute);
870+
EASY_EXEC(vmod_db_easy_execute_proxy, arg_vmod_redis_easy_execute);
871+
872+
#undef HANDLE_ARG
873+
826874
/******************************************************************************
827875
* .replied();
828876
*****************************************************************************/
@@ -1379,6 +1427,34 @@ vmod_use(
13791427
}
13801428
}
13811429

1430+
VCL_VOID
1431+
vmod_easy_execute(VRT_CTX, struct arg_vmod_redis_easy_execute *args)
1432+
{
1433+
struct vmod_redis_db *instance;
1434+
1435+
AN(ctx);
1436+
AN(args);
1437+
AN(args->vcl_priv);
1438+
AN(args->task_priv);
1439+
1440+
if ((args->db != NULL) && (strlen(args->db) > 0)) {
1441+
vcl_state_t *config = args->vcl_priv->priv;
1442+
instance = get_db_instance(ctx, config, args->db);
1443+
} else {
1444+
task_state_t *state = get_task_state(ctx, args->task_priv, 0);
1445+
instance = state->db;
1446+
}
1447+
1448+
if (instance != NULL) {
1449+
return vmod_db_easy_execute_proxy(ctx, instance, args);
1450+
} else {
1451+
REDIS_LOG_ERROR(ctx,
1452+
"Database instance not available%s",
1453+
"");
1454+
return;
1455+
}
1456+
}
1457+
13821458
#define _COMMA_ ,
13831459

13841460
#define VMOD_PROXIED_METHOD(type, fallback, method, margs, fargs...) \

src/vmod_redis.vcc

+62
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,33 @@ $Function VOID execute(PRIV_VCL, PRIV_TASK, BOOL master=1, STRING db="")
143143
Description
144144
Proxied version of ``.execute()``.
145145

146+
$Function VOID easy_execute(PRIV_VCL vcl_priv, PRIV_TASK task_priv,
147+
STRING command,
148+
[STRING cmd_arg1],
149+
[STRING cmd_arg2],
150+
[STRING cmd_arg3],
151+
[STRING cmd_arg4],
152+
[STRING cmd_arg5],
153+
[STRING cmd_arg6],
154+
[STRING cmd_arg7],
155+
[STRING cmd_arg8],
156+
[STRING cmd_arg9],
157+
[STRING cmd_arg10],
158+
[STRING cmd_arg11],
159+
[STRING cmd_arg12],
160+
[STRING cmd_arg13],
161+
[STRING cmd_arg14],
162+
[STRING cmd_arg15],
163+
[STRING cmd_arg16],
164+
[INT timeout],
165+
[INT retries],
166+
BOOL master = 1,
167+
STRING db=""
168+
)
169+
170+
Description
171+
Proxied version of ``.easy_execute()``.
172+
146173
$Function BOOL replied(PRIV_VCL, PRIV_TASK, STRING db="")
147174

148175
Description
@@ -527,6 +554,41 @@ Description
527554
and ``EVAL`` or ``EVALSHA`` command are submitted in order to avoid this
528555
counterintuitive scenario.
529556

557+
$Method VOID .easy_execute(PRIV_VCL vcl_priv, PRIV_TASK task_priv,
558+
STRING command,
559+
[STRING cmd_arg1],
560+
[STRING cmd_arg2],
561+
[STRING cmd_arg3],
562+
[STRING cmd_arg4],
563+
[STRING cmd_arg5],
564+
[STRING cmd_arg6],
565+
[STRING cmd_arg7],
566+
[STRING cmd_arg8],
567+
[STRING cmd_arg9],
568+
[STRING cmd_arg10],
569+
[STRING cmd_arg11],
570+
[STRING cmd_arg12],
571+
[STRING cmd_arg13],
572+
[STRING cmd_arg14],
573+
[STRING cmd_arg15],
574+
[STRING cmd_arg16],
575+
[INT timeout],
576+
[INT retries],
577+
BOOL master = 1
578+
)
579+
580+
Arguments
581+
The command argument is mandatory, followed with up to 16 arguments,
582+
optionally ending with ``timeout`` (as passed to ``.timeout()``) and/or
583+
``retries`` (as passed to ``.retries()``) and/or ``master`` (``.execute()``).
584+
For example: ``db.easy_command("set", "foo", "hello", retries=3, master=true);``
585+
Return value
586+
VOID
587+
Description
588+
Equivalent to calling, ``.command()``, ``.push()`` (possibly multiple times),
589+
``.timeout()``, ``.retries()`` then finally ``.execute()`` using a single
590+
command.
591+
530592
$Method BOOL .replied(PRIV_TASK)
531593

532594
Return value

0 commit comments

Comments
 (0)