pike.git / lib / modules / Sql.pmod / pgsql_util.pmod

version» Context lines:

pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:78:   #else   #define MUTEX Thread.Mutex   #endif      //! The instance of the pgsql dedicated backend.   final Pike.Backend local_backend;      private Pike.Backend cb_backend;   private Result qalreadyprinted;   private Thread.Mutex backendmux = Thread.Mutex(); - private Thread.ResourceCount clientsregistered = Thread.ResourceCount(); + final multiset(proxy) clients = set_weak_flag((<>), Pike.WEAK);      constant emptyarray = ({});   constant describenodata    = (["datarowdesc":emptyarray, "datarowtypes":emptyarray,    "datatypeoid":emptyarray]);   private constant censoroptions = (<"use_ssl", "force_ssl",    "cache_autoprepared_statements", "reconnect", "text_query", "is_superuser",    "server_encoding", "server_version", "integer_datetimes",    "session_authorization">);   
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:140:    * in the majority of the real-world cases, it would be considered a good    * tradeoff.    */   private Regexp execfetchlimit    = iregexp("^\a*((UPDA|DELE)TE|INSERT)\a|\aLIMIT\a+[1-9][; \t\f\r\n]*$");      private void default_backend_runs() { // Runs as soon as the    cb_backend = Pike.DefaultBackend; // DefaultBackend has started   }    - private void create() { + protected void create() { +  atexit(_destruct);    // Run callbacks from our local_backend until DefaultBackend has started    cb_backend = local_backend = Pike.SmallBackend();    call_out(default_backend_runs, 0);   }    -  + protected void _destruct() { +  foreach (clients; proxy client; ) +  destruct(client); + } +    private Regexp iregexp(string expr) {    Stdio.Buffer ret = Stdio.Buffer();    foreach (expr; ; int c)    if (c >= 'A' && c <= 'Z')    ret->add('[', c, c + 'a' - 'A', ']');    else if (c == '\a') // Replace with generic whitespace    ret->add("[ \t\f\r\n]");    else    ret->add_int8(c);    return Regexp(ret->read());
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:172:    }   }      private void run_local_backend() {    Thread.MutexKey lock;    int looponce;    do {    looponce = 0;    if (lock = backendmux->trylock()) {    PD("Starting local backend\n"); -  while (!clientsregistered->drained() // Autoterminate when not needed +  while (sizeof(clients) // Autoterminate when not needed    || sizeof(local_backend->call_out_info())) {    mixed err;    if (err = catch(local_backend(4096.0)))    master()->handle_error(err);    }    PD("Terminating local backend\n");    lock = 0; -  looponce = !clientsregistered->drained(); +  looponce = sizeof(clients);    }    } while (looponce);   }      //! Registers yourself as a user of this backend. If the backend   //! has not been started yet, it will be spawned automatically. - final Thread.ResourceCountKey register_backend() { -  int startbackend = clientsregistered->drained(); -  Thread.ResourceCountKey key = clientsregistered->acquire(); + final void register_backend(proxy client) { +  int startbackend = !sizeof(clients); +  clients[client] = 1;    if (startbackend)    Thread.Thread(run_local_backend); -  return key; +    }      final void throwdelayederror(Result|proxy parent) {    if (mixed err = parent->delayederror) {    if (!objectp(parent->pgsqlsess))    parent->untolderror = 0;    else if (parent->pgsqlsess)    parent->pgsqlsess->untolderror = 0;    parent.delayederror = 0;    if (stringp(err))
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:330:    private Thread.ResourceCountKey dirty;      #ifdef PG_DEBUGRACE    final bufcon `chain() {    return this;    }   #endif       private conxion realbuffer;    -  private void create(conxion _realbuffer) { +  protected void create(conxion _realbuffer) {    realbuffer = _realbuffer;    }       final Thread.ResourceCount `stashcount() {    return realbuffer->stashcount;    }       final bufcon start(void|int waitforreal) {    dirty = realbuffer->stashcount->acquire();   #ifdef PG_DEBUG
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:436:   #endif    );    Thread.MutexKey lock = fillreadmux->lock();    if (procmsg && id)    procmsg = 0, lock = 0, Thread.Thread(id);    else if (fillread)    didreadcb = 1, fillread.signal();    return 0;    }    -  private void create() { +  protected void create() {    i::create();    fillreadmux = MUTEX();    fillread = Thread.Condition();    }   };      class sfile {    inherit Stdio.File;    final int query_fd() {    return is_open() ? ::query_fd() : -1;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:674:    };    destruct(nostash);    socket->set_non_blocking(); // Drop all callbacks    PD("%d>Close socket\n", socket->query_fd());    socket->close(); // This will be an asynchronous close    }    destruct(this);    }    }    -  private void _destruct() { +  protected void _destruct() {    PD("%d>Close conxion %d\n", socket ? socket->query_fd() : -1, !!nostash);    catch(purge());    }       final void connectloop(proxy pgsqlsess, int nossl) {   #ifdef PG_DEBUG    mixed err =   #endif    catch {    for (; ; clear()) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:734:    socket->set_nonblocking(i->read_cb, write_cb, close);    if (nossl != 2)    Thread.Thread(pgsqlsess->processloop, this);    return;    };    PD("Connect error %s\n", describe_backtrace(err));    catch(destruct(pgsqlsess->waitforauthready));    destruct(this);    }    -  private string _sprintf(int type) { +  protected string _sprintf(int type) {    string res;    switch (type) {    case 'O':    int fd = -1;    if (socket)    catch(fd = socket->query_fd());    res = predef::sprintf("conxion fd: %d input queue: %d/%d "    "queued portals: %d output queue: %d/%d\n"    "started: %d\n",    fd, sizeof(i), i->_size_object(),    qportals && qportals->size(), sizeof(this), _size_object(),    !!started);    break;    }    return res;    }    -  private void create(proxy pgsqlsess, Thread.Queue _qportals, int nossl) { +  protected void create(proxy pgsqlsess, Thread.Queue _qportals, int nossl) {    o::create();    qportals = _qportals;    synctransact = 1;    socket = sfile();    i = conxiin();    shortmux = MUTEX();    nostash = MUTEX();    closenext = 0;    stashavail = Thread.Condition();    stashqueue = Thread.Queue();    stash = Stdio.Buffer();    stashcount = Thread.ResourceCount();    Thread.Thread(connectloop, pgsqlsess, nossl);    }   };      #ifdef PG_DEBUGRACE   class conxsess {    final conxion chain;    -  private void create(conxion parent) { +  protected void create(conxion parent) {    if (parent->started)    werror("Overwriting conxsess %s %s\n",    describe_backtrace(({"new ", backtrace()[..<1]})),    describe_backtrace(({"old ", parent->nostrack})));    parent->nostrack = backtrace();    chain = parent;    }       final void sendcmd(int mode, void|Result portal) {    chain->sendcmd(mode, portal);    chain = 0;    }    -  private void _destruct() { +  protected void _destruct() {    if (chain)    werror("Untransmitted conxsess %s\n",    describe_backtrace(({"", backtrace()[..<1]})));    }   };   #endif      //! The result object returned by @[Sql.pgsql()->big_query()], except for   //! the noted differences it behaves the same as @[Sql.Result].   //!
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1893:    Thread.Thread(run_result_array_cb, callback, args);    }      };      class proxy {    final int _fetchlimit = FETCHLIMIT;    final MUTEX unnamedportalmux;    final MUTEX unnamedstatement;    private Thread.MutexKey termlock; -  private Thread.ResourceCountKey backendreg; +     final Thread.ResourceCount portalsinflight, statementsinflight;    final int(0..1) wasparallelisable;    final int(0..1) intransaction;       final conxion c;    private string cancelsecret;    private int backendpid;    final int(-128..127) backendstatus;    final mapping(string:mixed) options;    private array(string) lastmessage = emptyarray;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1928:    final function (:void) readyforquery_cb;       final string host;    final int(0..65535) port;    final string database, user, pass;    private Crypto.Hash.SCRAM SASLcontext;    final Thread.Condition waitforauthready;    final MUTEX shortmux;    final int readyforquerycount;    -  private string _sprintf(int type) { +  protected string _sprintf(int type) {    string res;    switch (type) {    case 'O':    res = sprintf(DRIVERNAME".proxy(%s@%s:%d/%s,%d,%d)",    user, host, port, database, c && c->socket && c->socket->query_fd(),    backendpid);    break;    }    return res;    }    -  private void create(void|string host, void|string database, +  protected void create(void|string host, void|string database,    void|string user, void|string pass,    void|mapping(string:mixed) options) {    if (this::pass = pass) {    String.secure(pass);    pass = "CENSORED";    }    this::user = user;    this::database = database;    this::options = options;       if (!host) host = PGSQL_DEFAULT_HOST;    if (has_value(host,":") && sscanf(host,"%s:%d", host, port) != 2)    error("Error in parsing the hostname argument\n");    this::host = host;       if (!port)    port = PGSQL_DEFAULT_PORT; -  backendreg = register_backend(); +  register_backend(this);    shortmux = MUTEX();    PD("Connect\n");    waitforauthready = Thread.Condition();    qportals = Thread.Queue();    readyforquerycount = 1;    qportals->write(1);    if (!(c = conxion(this, qportals, 0)))    error("Couldn't connect to database on %s:%d\n", host, port);    runtimeparameter = ([]);    unnamedportalmux = MUTEX();
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:2719:    break;    case NOERROR:    continue; // Normal production loop    }    error(a2nls(lastmessage += ({msg})));    }    }; // We only get here if there is an error    if (err == MAGICTERMINATE) { // Announce connection termination to server    catch {    void|bufcon|conxsess cs = ci->start(); -  CHAIN(cs)->add("X\0\0\0\4"); +  CHAIN(cs)->add(PGSYNC)->add("X\0\0\0\4");    cs->sendcmd(SENDOUT);    };    terminating = 1;    err = 0;    } else if (stringp(err)) {    Result or;    if (!objectp(or = portal))    or = this;    if (!or.delayederror)    or.delayederror = err;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:2784:    if (c) // Prevent trivial backtraces    c->close();    if (unnamedstatement)    lock = unnamedstatement->lock(1);    if (c)    c->purge();    }    destruct(waitforauthready);    }    -  private void _destruct() { +  protected void _destruct() {    string errstring;    mixed err = catch(close()); -  backendreg = 0; +  clients[this] = 0;    if (untolderror) {    /*    * Flush out any asynchronously reported errors to stderr; because we are    * inside a destructor, throwing an error will not work anymore.    * Warnings will be silently discarded at this point.    */    lastmessage = filter(lastmessage, lambda(string val) {    return has_prefix(val, "ERROR ") || has_prefix(val, "FATAL "); });    if (err || (err = catch(errstring = geterror(1))))    werror(describe_backtrace(err));