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},

Impressum / About Us