webmcp
changeset 393:b2d2ff6e4385
Added <db_handle>:wait(...) method to wait for NOTIFYs
author | jbe |
---|---|
date | Wed Dec 09 03:40:27 2015 +0100 (2015-12-09) |
parents | c048f0af2497 |
children | 912a1b9c2551 |
files | libraries/mondelefant/mondelefant_native.autodoc.lua libraries/mondelefant/mondelefant_native.c |
line diff
1.1 --- a/libraries/mondelefant/mondelefant_native.autodoc.lua Fri Dec 04 14:04:54 2015 +0100 1.2 +++ b/libraries/mondelefant/mondelefant_native.autodoc.lua Wed Dec 09 03:40:27 2015 +0100 1.3 @@ -25,6 +25,18 @@ 1.4 1.5 1.6 --[[-- 1.7 +<db_handle>.fd -- file descriptor of underlaying database connection 1.8 + 1.9 +The file descriptor number of the underlaying database connection. This value may be used in conjunction with :wait(0) and a select/poll system call to wait for several events at once. 1.10 + 1.11 +--]]-- 1.12 +-- set/unset in mondelefant_native.c in 1.13 +-- static int mondelefant_connect(lua_State *L) and 1.14 +-- static int mondelefant_close(lua_State *L) 1.15 +--//-- 1.16 + 1.17 + 1.18 +--[[-- 1.19 <db_handle>:close() 1.20 1.21 Closes the database connection. This method may be called multiple times and is called automatically when the database handle is garbage collected. 1.22 @@ -65,6 +77,22 @@ 1.23 1.24 1.25 --[[-- 1.26 +channel, -- notification channel name 1.27 +payload, -- notification payload string 1.28 +pid = -- process ID of notifying server process 1.29 +<db_handle>:wait( 1.30 + timeout -- number of seconds to wait, 0 = do not block, nil = wait infinitely 1.31 +) 1.32 + 1.33 +Waits for any NOTIFY event that is being LISTENed for. One or more LISTEN commands must have been sent previously with <db_handle>:query("LISTEN channel_name"). 1.34 + 1.35 +--]]-- 1.36 +-- implemented in mondelefant_native.c as 1.37 +-- static int mondelefant_conn_wait(lua_State *L) 1.38 +--//-- 1.39 + 1.40 + 1.41 +--[[-- 1.42 db_list = -- database result being an empty list 1.43 <db_handle>:create_list() 1.44
2.1 --- a/libraries/mondelefant/mondelefant_native.c Fri Dec 04 14:04:54 2015 +0100 2.2 +++ b/libraries/mondelefant/mondelefant_native.c Wed Dec 09 03:40:27 2015 +0100 2.3 @@ -4,6 +4,7 @@ 2.4 #include <postgres.h> 2.5 #include <catalog/pg_type.h> 2.6 #include <stdint.h> 2.7 +#include <time.h> 2.8 2.9 // NOTE: Comments with format "// <number>" denote the Lua stack position 2.10 2.11 @@ -310,6 +311,8 @@ 2.12 lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CONN_DATA_REGKEY); // 2 2.13 lua_pushvalue(L, 1); // 3 2.14 lua_newtable(L); // 4 2.15 + lua_pushinteger(L, PQsocket(pgconn)); // determine file descriptor 2.16 + lua_setfield(L, 4, "fd"); // set "fd" attribute 2.17 lua_settable(L, 2); 2.18 lua_settop(L, 1); 2.19 // store key "engine" with value "postgresql" as connection specific data: 2.20 @@ -402,6 +405,11 @@ 2.21 conn = mondelefant_get_conn(L, 1); 2.22 PQfinish(conn->pgconn); 2.23 conn->pgconn = NULL; 2.24 + lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CONN_DATA_REGKEY); // 2 2.25 + lua_pushvalue(L, 1); // 3 2.26 + lua_gettable(L, 2); // 3 2.27 + lua_pushnil(L); // 4 2.28 + lua_setfield(L, 3, "fd"); // set "fd" attribute to nil 2.29 return 0; 2.30 } 2.31 2.32 @@ -438,6 +446,88 @@ 2.33 return 1; 2.34 } 2.35 2.36 +// method "wait" of database handles: 2.37 +static int mondelefant_conn_wait(lua_State *L) { 2.38 + mondelefant_conn_t *conn; 2.39 + int infinite, nonblock = 0; 2.40 + struct timespec wakeup; 2.41 + int fd; 2.42 + fd_set fds; 2.43 + conn = mondelefant_get_conn(L, 1); 2.44 + infinite = lua_isnoneornil(L, 2); 2.45 + if (!infinite) { 2.46 + lua_Number n; 2.47 + int isnum; 2.48 + n = lua_tonumberx(L, 2, &isnum); 2.49 + if (isnum && n>0 && n<=86400*366) { 2.50 + if (clock_gettime(CLOCK_MONOTONIC, &wakeup)) { 2.51 + return luaL_error(L, "Could not access CLOCK_MONOTONIC"); 2.52 + } 2.53 + wakeup.tv_sec += n; 2.54 + wakeup.tv_nsec += 1000000000 * (n - (time_t)n); 2.55 + if (wakeup.tv_nsec >= 1000000000) { 2.56 + wakeup.tv_sec += 1; 2.57 + wakeup.tv_nsec -= 1000000000; 2.58 + } 2.59 + } else if (isnum && n==0) { 2.60 + nonblock = 1; 2.61 + } else { 2.62 + luaL_argcheck(L, 0, 2, "not a valid timeout"); 2.63 + } 2.64 + } 2.65 + if (!nonblock) { 2.66 + fd = PQsocket(conn->pgconn); 2.67 + FD_ZERO(&fds); 2.68 + FD_SET(fd, &fds); 2.69 + } 2.70 + while (true) { 2.71 + { 2.72 + PGnotify *notify; 2.73 + if (!PQconsumeInput(conn->pgconn)) { 2.74 + lua_pushnil(L); 2.75 + mondelefant_push_first_line(L, PQerrorMessage(conn->pgconn)); 2.76 + return 2; 2.77 + } 2.78 + notify = PQnotifies(conn->pgconn); 2.79 + if (notify) { 2.80 + lua_pushstring(L, notify->relname); 2.81 + lua_pushstring(L, notify->extra); 2.82 + lua_pushinteger(L, notify->be_pid); 2.83 + PQfreemem(notify); 2.84 + return 3; 2.85 + } 2.86 + } 2.87 + if (infinite) { 2.88 + select(fd+1, &fds, NULL, NULL, NULL); 2.89 + } else if (nonblock) { 2.90 + break; 2.91 + } else { 2.92 + struct timespec tp; 2.93 + struct timeval timeout = { 0, }; 2.94 + if (clock_gettime(CLOCK_MONOTONIC, &tp)) { 2.95 + return luaL_error(L, "Could not access CLOCK_MONOTONIC"); 2.96 + } 2.97 + tp.tv_sec = wakeup.tv_sec - tp.tv_sec; 2.98 + tp.tv_nsec = wakeup.tv_nsec - tp.tv_nsec; 2.99 + if (tp.tv_nsec < 0) { 2.100 + tp.tv_sec -= 1; 2.101 + tp.tv_nsec += 1000000000; 2.102 + } 2.103 + timeout.tv_sec = tp.tv_sec; 2.104 + timeout.tv_usec = (tp.tv_nsec + 500) / 1000; 2.105 + if ( 2.106 + timeout.tv_sec < 0 || 2.107 + (timeout.tv_sec == 0 && timeout.tv_usec == 0) 2.108 + ) break; 2.109 + select(fd+1, &fds, NULL, NULL, &timeout); 2.110 + } 2.111 + } 2.112 + lua_pushboolean(L, 0); 2.113 + if (nonblock) lua_pushliteral(L, "No notification pending"); 2.114 + else lua_pushliteral(L, "Timeout while waiting for notification"); 2.115 + return 2; 2.116 +} 2.117 + 2.118 // method "create_list" of database handles: 2.119 static int mondelefant_conn_create_list(lua_State *L) { 2.120 // ensure that first argument is a database connection: 2.121 @@ -1767,6 +1857,7 @@ 2.122 {"close", mondelefant_conn_close}, 2.123 {"is_ok", mondelefant_conn_is_ok}, 2.124 {"get_transaction_status", mondelefant_conn_get_transaction_status}, 2.125 + {"wait", mondelefant_conn_wait}, 2.126 {"create_list", mondelefant_conn_create_list}, 2.127 {"create_object", mondelefant_conn_create_object}, 2.128 {"quote_string", mondelefant_conn_quote_string},