summaryrefslogtreecommitdiff
path: root/proxy_lua.c
diff options
context:
space:
mode:
authordormando <dormando@rydia.net>2023-01-31 17:20:30 -0800
committerdormando <dormando@rydia.net>2023-02-01 14:28:29 -0800
commit58d8f40a90ee22d78adc0ae99f4b915e65f69be6 (patch)
tree4516a274f0f4a692db97ed235f400c4123534092 /proxy_lua.c
parent0d8ebbfb823c94e5ce68550c9ae186d8af789446 (diff)
downloadmemcached-58d8f40a90ee22d78adc0ae99f4b915e65f69be6.tar.gz
proxy: add mcp.backend(t) for more overrides
ie: local b1 = mcp.backend({ label = "b1", host = "127.0.0.1", port = 11511, connecttimeout = 1, retrytimeout = 0.5, readtimeout = 0.1, failurelimit = 11 }) ... to allow for overriding connect/retry/etc tunables on a per-backend basis. If not passed in the global settings are used.
Diffstat (limited to 'proxy_lua.c')
-rw-r--r--proxy_lua.c122
1 files changed, 112 insertions, 10 deletions
diff --git a/proxy_lua.c b/proxy_lua.c
index 14f2564..f309515 100644
--- a/proxy_lua.c
+++ b/proxy_lua.c
@@ -2,6 +2,10 @@
#include "proxy.h"
+// sad, I had to look this up...
+#define NANOSECONDS(x) ((x) * 1E9 + 0.5)
+#define MICROSECONDS(x) ((x) * 1E6 + 0.5)
+
// func prototype example:
// static int fname (lua_State *L)
// normal library open:
@@ -140,13 +144,112 @@ static int mcplib_backend_gc(lua_State *L) {
// backend label object; given to pools which then find or create backend
// objects as necessary.
+// allow optionally passing a table of arguments for extended options:
+// { label = "etc", "host" = "127.0.0.1", port = "11211",
+// readtimeout = 0.5, connecttimeout = 1, retrytime = 3,
+// failurelimit = 3, tcpkeepalive = false }
static int mcplib_backend(lua_State *L) {
size_t llen = 0;
size_t nlen = 0;
size_t plen = 0;
- const char *label = luaL_checklstring(L, 1, &llen);
- const char *name = luaL_checklstring(L, 2, &nlen);
- const char *port = luaL_checklstring(L, 3, &plen);
+ proxy_ctx_t *ctx = settings.proxy_ctx;
+ mcp_backend_label_t *be = lua_newuserdatauv(L, sizeof(mcp_backend_label_t), 0);
+ memset(be, 0, sizeof(*be));
+ const char *label;
+ const char *name;
+ const char *port;
+ // copy global defaults for tunables.
+ memcpy(&be->tunables, &ctx->tunables, sizeof(be->tunables));
+
+ if (lua_istable(L, 1)) {
+
+ // We don't pop the label/host/port strings so lua won't change them
+ // until after the function call.
+ if (lua_getfield(L, 1, "label") != LUA_TNIL) {
+ label = luaL_checklstring(L, -1, &llen);
+ } else {
+ proxy_lua_error(L, "backend must have a label argument");
+ return 0;
+ }
+
+ if (lua_getfield(L, 1, "host") != LUA_TNIL) {
+ name = luaL_checklstring(L, -1, &nlen);
+ } else {
+ proxy_lua_error(L, "backend must have a host argument");
+ return 0;
+ }
+
+ // TODO: allow a default port.
+ if (lua_getfield(L, 1, "port") != LUA_TNIL) {
+ port = luaL_checklstring(L, -1, &plen);
+ } else {
+ proxy_lua_error(L, "backend must have a port argument");
+ return 0;
+ }
+
+ if (lua_getfield(L, 1, "tcpkeepalive") != LUA_TNIL) {
+ be->tunables.tcp_keepalive = lua_toboolean(L, -1);
+ }
+ lua_pop(L, 1);
+
+ if (lua_getfield(L, 1, "failurelimit") != LUA_TNIL) {
+ int limit = luaL_checkinteger(L, -1);
+ if (limit < 0) {
+ proxy_lua_error(L, "failure_limit must be >= 0");
+ return 0;
+ }
+
+ be->tunables.backend_failure_limit = limit;
+ }
+ lua_pop(L, 1);
+
+ if (lua_getfield(L, 1, "connecttimeout") != LUA_TNIL) {
+ lua_Number secondsf = luaL_checknumber(L, -1);
+ lua_Integer secondsi = (lua_Integer) secondsf;
+ lua_Number subseconds = secondsf - secondsi;
+
+ be->tunables.connect.tv_sec = secondsi;
+ be->tunables.connect.tv_usec = MICROSECONDS(subseconds);
+#ifdef HAVE_LIBURING
+ be->tunables.connect_ur.tv_sec = secondsi;
+ be->tunables.connect_ur.tv_nsec = NANOSECONDS(subseconds);
+#endif
+ }
+ lua_pop(L, 1);
+
+ if (lua_getfield(L, 1, "retrytimeout") != LUA_TNIL) {
+ lua_Number secondsf = luaL_checknumber(L, -1);
+ lua_Integer secondsi = (lua_Integer) secondsf;
+ lua_Number subseconds = secondsf - secondsi;
+
+ be->tunables.retry.tv_sec = secondsi;
+ be->tunables.retry.tv_usec = MICROSECONDS(subseconds);
+#ifdef HAVE_LIBURING
+ be->tunables.retry_ur.tv_sec = secondsi;
+ be->tunables.retry_ur.tv_nsec = NANOSECONDS(subseconds);
+#endif
+ }
+ lua_pop(L, 1);
+
+ if (lua_getfield(L, 1, "readtimeout") != LUA_TNIL) {
+ lua_Number secondsf = luaL_checknumber(L, -1);
+ lua_Integer secondsi = (lua_Integer) secondsf;
+ lua_Number subseconds = secondsf - secondsi;
+
+ be->tunables.read.tv_sec = secondsi;
+ be->tunables.read.tv_usec = MICROSECONDS(subseconds);
+#ifdef HAVE_LIBURING
+ be->tunables.read_ur.tv_sec = secondsi;
+ be->tunables.read_ur.tv_nsec = NANOSECONDS(subseconds);
+#endif
+ }
+ lua_pop(L, 1);
+
+ } else {
+ label = luaL_checklstring(L, 1, &llen);
+ name = luaL_checklstring(L, 2, &nlen);
+ port = luaL_checklstring(L, 3, &plen);
+ }
if (llen > MAX_LABELLEN-1) {
proxy_lua_error(L, "backend label too long");
@@ -163,8 +266,6 @@ static int mcplib_backend(lua_State *L) {
return 0;
}
- mcp_backend_label_t *be = lua_newuserdatauv(L, sizeof(mcp_backend_label_t), 0);
- memset(be, 0, sizeof(*be));
memcpy(be->label, label, llen);
be->label[llen] = '\0';
memcpy(be->name, name, nlen);
@@ -172,6 +273,9 @@ static int mcplib_backend(lua_State *L) {
memcpy(be->port, port, plen);
be->port[plen] = '\0';
be->llen = llen;
+ if (lua_istable(L, 1)) {
+ lua_pop(L, 3); // drop label, name, port.
+ }
luaL_getmetatable(L, "mcp.backend");
lua_setmetatable(L, -2); // set metatable to userdata.
@@ -187,7 +291,8 @@ static mcp_backend_wrap_t *_mcplib_backend_checkcache(lua_State *L, mcp_backend_
if (ret != LUA_TNIL) {
mcp_backend_wrap_t *be_orig = luaL_checkudata(L, -1, "mcp.backendwrap");
if (strncmp(be_orig->be->name, bel->name, MAX_NAMELEN) == 0
- && strncmp(be_orig->be->port, bel->port, MAX_PORTLEN) == 0) {
+ && strncmp(be_orig->be->port, bel->port, MAX_PORTLEN) == 0
+ && memcmp(&be_orig->be->tunables, &bel->tunables, sizeof(bel->tunables)) == 0) {
// backend is the same, return it.
return be_orig;
} else {
@@ -218,6 +323,7 @@ static mcp_backend_wrap_t *_mcplib_make_backendconn(lua_State *L, mcp_backend_la
strncpy(be->name, bel->name, MAX_NAMELEN+1);
strncpy(be->port, bel->port, MAX_PORTLEN+1);
+ memcpy(&be->tunables, &bel->tunables, sizeof(bel->tunables));
STAILQ_INIT(&be->io_head);
be->state = mcp_backend_read;
@@ -628,10 +734,6 @@ static int mcplib_backend_failure_limit(lua_State *L) {
return 0;
}
-// sad, I had to look this up...
-#define NANOSECONDS(x) ((x) * 1E9 + 0.5)
-#define MICROSECONDS(x) ((x) * 1E6 + 0.5)
-
static int mcplib_backend_connect_timeout(lua_State *L) {
lua_Number secondsf = luaL_checknumber(L, -1);
lua_Integer secondsi = (lua_Integer) secondsf;