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

version» Context lines:

pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:15:      #pike __REAL_VERSION__   #require constant(Thread.Thread)      #include "pgsql.h"      //! The instance of the pgsql dedicated backend.   final Pike.Backend local_backend = Pike.SmallBackend();      private Thread.Mutex backendmux = Thread.Mutex(); - private int clientsregistered; + private Thread.ResourceCount clientsregistered = Thread.ResourceCount();      constant emptyarray = ({});   constant describenodata    = (["datarowdesc":emptyarray, "datarowtypes":emptyarray,    "datatypeoid":emptyarray]);   final multiset censoroptions=(<"use_ssl","force_ssl",    "cache_autoprepared_statements","reconnect","text_query","is_superuser",    "server_encoding","server_version","integer_datetimes",    "session_authorization">);   constant stdiobuftype = typeof(Stdio.Buffer());
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:120:    }   }      private void run_local_backend() {    Thread.MutexKey lock;    int looponce;    do {    looponce=0;    if(lock=backendmux->trylock()) {    PD("Starting local backend\n"); -  while (clientsregistered // Autoterminate when not needed +  while (!clientsregistered->drained() // Autoterminate when not needed    || sizeof(local_backend->call_out_info())) {    mixed err;    if (err = catch(local_backend(4096.0)))    werror(describe_backtrace(err));    }    PD("Terminating local backend\n");    lock=0; -  looponce=clientsregistered; +  looponce = !clientsregistered->drained();    }    } while(looponce);   }      //! Registers yourself as a user of this backend. If the backend   //! has not been started yet, it will be spawned automatically. - final void register_backend() { -  if(!clientsregistered++) + final Thread.ResourceCountKey register_backend() { +  int startbackend = clientsregistered->drained(); +  Thread.ResourceCountKey key = clientsregistered->acquire(); +  if (startbackend)    Thread.Thread(run_local_backend); -  +  return key;   }    - //! Unregisters yourself as a user of this backend. If there are - //! no longer any registered users, the backend will be terminated. - final void unregister_backend() { -  --clientsregistered; - } -  +    final void throwdelayederror(object parent) {    if(mixed err=parent._delayederror) {    parent._delayederror=UNDEFINED;    if(stringp(err))    err=({err,backtrace()[..<2]});    throw(err);    }   }      final int oidformat(int oid) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:185:      private inline mixed callout(function(mixed ...:void) f,    float|int delay,mixed ... args) {    return local_backend->call_out(f,delay,@args);   }      // Some pgsql utility functions      class bufcon {    inherit Stdio.Buffer; -  private int dirty; +  private Thread.ResourceCountKey dirty;      #ifdef PG_DEBUGRACE    final bufcon `chain() {    return this;    }   #endif       private conxion realbuffer;    -  protected void create(conxion _realbuffer) { +  private void create(conxion _realbuffer) {    realbuffer=_realbuffer;    }    -  final int `stashcount() { +  final Thread.ResourceCount `stashcount() {    return realbuffer->stashcount;    }       final bufcon start(void|int waitforreal) { -  dirty = 1; -  realbuffer->stashcount++; -  dirty = 2; +  dirty = realbuffer->stashcount->acquire();   #ifdef PG_DEBUG    if(waitforreal)    error("pgsql.bufcon not allowed here\n");   #endif    return this;    }       final void sendcmd(int mode,void|sql_result portal) {    Thread.MutexKey lock=realbuffer->shortmux->lock();    if (portal)
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:228:    if (mode == SYNCSEND) {    add(PGSYNC);    realbuffer->stashqueue->write(1);    mode = SENDOUT; // Demote it to prevent an extra SYNC upon stashflush    }    realbuffer->stash->add(this);    PD("%d>Stashed mode %d > %d\n",    realbuffer->socket->query_fd(), mode, realbuffer->stashflushmode);    if (mode > realbuffer->stashflushmode)    realbuffer->stashflushmode = mode; -  dirty = 1; -  if(!--realbuffer->stashcount) -  dirty = 0, realbuffer->stashavail.signal(); -  else +     dirty = 0; -  lock=0; +     this->clear();    if(lock=realbuffer->nostash->trylock(1)) {   #ifdef PG_DEBUGRACE    conxsess sess = conxsess(realbuffer);    realbuffer->started = lock;    lock = 0;    sess->sendcmd(SENDOUT);   #else    realbuffer->started = lock;    lock = 0;    realbuffer->sendcmd(SENDOUT);   #endif    }    } -  -  protected void _destruct() { -  switch (dirty) { -  case 1: -  werror("FIXME: Race condition detected %s\n", -  describe_backtrace(({"", backtrace()[..<1]}))); -  if (!realbuffer->stashcount) -  break; -  case 2: -  Thread.MutexKey lock = realbuffer->shortmux->lock(2); -  if (!--realbuffer->stashcount) -  realbuffer->stashavail.signal(); -  lock = 0; -  } -  } +    };      class conxiin {    inherit Stdio.Buffer:i;       final Thread.Condition fillread;    final Thread.Mutex fillreadmux;    final int procmsg;    private int didreadcb;    -  protected bool range_error(int howmuch) { +  protected final bool range_error(int howmuch) {   #ifdef PG_DEBUG    if(howmuch<=0)    error("Out of range %d\n",howmuch);   #endif    if(fillread) {    Thread.MutexKey lock=fillreadmux->lock();    if(!didreadcb)    fillread.wait(lock);    didreadcb=0;    lock=0;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:304:    );    Thread.MutexKey lock=fillreadmux->lock();    if(procmsg&&id)    procmsg=0,lock=0,Thread.Thread(id);    else if(fillread)    didreadcb=1, fillread.signal();    lock=0;    return 0;    }    -  protected void create() { +  private void create() {    i::create();    fillreadmux=Thread.Mutex();    fillread=Thread.Condition();    }   };      class sfile {    inherit Stdio.File; -  int query_fd() { +  final int query_fd() {    return is_open() ? ::query_fd() : -1;    }   };      class conxion {    inherit Stdio.Buffer:o;    final conxiin i;       private Thread.Queue qportals;    final Thread.Mutex shortmux;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:336:    final sfile socket;    private int towrite;    final multiset(function(void|mixed:void)) closecallbacks=(<>);       final Thread.Mutex nostash;    final Thread.MutexKey started;    final Thread.Queue stashqueue;    final Thread.Condition stashavail;    final Stdio.Buffer stash;    final int stashflushmode; -  final int stashcount; +  final Thread.ResourceCount stashcount;    final int synctransact;   #ifdef PG_DEBUGRACE    final mixed nostrack;   #endif   #ifdef PG_DEBUG    final int queueoutidx;    final int queueinidx=-1;   #endif       private inline void queueup(sql_result portal) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:361:       final bufcon|conxsess start(void|int waitforreal) {    Thread.MutexKey lock;    if(lock=(waitforreal?nostash->lock:nostash->trylock)(1)) {    int mode;   #ifdef PG_DEBUGRACE    conxsess sess = conxsess(this);   #endif    started = lock;    lock=shortmux->lock(); -  if(stashcount) -  PT(stashavail.wait(lock)); +  stashcount->wait_till_drained(lock);    mode = getstash(KEEP);    lock=0;    if (mode > KEEP)    sendcmd(mode); // Force out stash to the server   #ifdef PG_DEBUGRACE    return sess;   #else    return this;   #endif    }
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:469:    i->fillread=0;    }    lock=0;    PD("%d>Delayed close, flush write\n",socket->query_fd());    i->read_cb(socket->query_id(),0);    return 0;    } else    return -1;    }    -  protected void destroy() { +  private void destroy() {    PD("%d>Close conxion %d\n", socket ? socket->query_fd() : -1, !!nostash);    int|.pgsql_util.sql_result portal;    if (qportals) // CancelRequest does not use qportals    while (portal = qportals->try_read())    if (objectp(portal))    portal->_purgeportal();    if(nostash) {    catch {    while(sizeof(closecallbacks))    foreach(closecallbacks;function(void|mixed:void) closecb;)
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:548:       private string _sprintf(int type, void|mapping flags) {    string res=UNDEFINED;    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 stashcount: %d\n", +  "started: %d\n",    fd,sizeof(i),i->_size_object(),    qportals && qportals->size(), sizeof(this), _size_object(), -  !!started, stashcount); +  !!started);    break;    }    return res;    }    -  protected void create(object pgsqlsess,Thread.Queue _qportals,int nossl) { +  private void create(object pgsqlsess,Thread.Queue _qportals,int nossl) {    o::create();    qportals = _qportals;    synctransact = 1;    socket=sfile();    i=conxiin();    shortmux=Thread.Mutex();    nostash=Thread.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;    -  void create(conxion parent) { +  private 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|sql_result portal) {    chain->sendcmd(mode, portal);    chain = 0;    }    -  void destroy() { +  private void destroy() {    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.sql_result].   //!
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:625:    private int syncparse;    private int transtype;       final string _portalname;       private int rowsreceived;    private int inflight;    private int portalbuffersize;    private Thread.Mutex closemux;    private Thread.Queue datarows; +  private Thread.ResourceCountKey stmtifkey, portalsifkey;    private array(mapping(string:mixed)) datarowdesc;    private array(int) datarowtypes; // types from datarowdesc    private string statuscmdcomplete;    private int bytesreceived;    final int _synctransact;    final Thread.Condition _ddescribe;    final Thread.Mutex _ddescribemux;    final Thread.MutexKey _unnamedportalkey,_unnamedstatementkey;    final array _params;    final string _query;    final string _preparedname;    final mapping(string:mixed) _tprepared;    private function(:void) gottimeout;    private int timeout;    -  private string _sprintf(int type, void|mapping flags) { +  protected string _sprintf(int type) {    string res=UNDEFINED;    switch(type) {    case 'O':    int fd=-1;    if(c&&c->socket)    catch(fd=c->socket->query_fd());    res=sprintf("sql_result state: %d numrows: %d eof: %d inflight: %d\n"    "query: %O\n"    "fd: %O portalname: %O datarows: %d"    " synctransact: %d laststatus: %s\n",
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1030:    m_delete(pgsqlsess->_prepareds,_query),_tprepared=0;    waitfordescribe();    }    if(_state>=CLOSING)    lock=_unnamedstatementkey=0;    else {    plugbuffer->add_int16(sizeof(datarowtypes));    if(sizeof(datarowtypes))    plugbuffer->add_ints(map(datarowtypes,oidformat),2);    else if (syncparse < 0 && !pgsqlsess->_wasparallelisable -  && pgsqlsess->_statementsinflight > 1) { -  lock=pgsqlsess->_shortmux->lock(); -  // Decrement temporarily to account for ourselves -  if(--pgsqlsess->_statementsinflight) { -  pgsqlsess->_waittocommit++; +  && !pgsqlsess->_statementsinflight->drained(1)) { +  lock = pgsqlsess->_shortmux->lock();    PD("Commit waiting for statements to finish\n"); -  catch(PT(pgsqlsess->_readyforcommit->wait(lock))); -  pgsqlsess->_waittocommit--; +  catch(PT(pgsqlsess->_statementsinflight->wait_till_drained(lock, 1)));    } -  // Increment again to account for ourselves -  pgsqlsess->_statementsinflight++; -  } +     lock=0;    PD("Bind portal %O statement %O\n",_portalname,_preparedname);    _fetchlimit=pgsqlsess->_fetchlimit;    _bindportal();    conxsess bindbuffer = c->start();    _unnamedstatementkey=0;    CHAIN(bindbuffer)->add_int8('B')->add_hstring(plugbuffer, 4, 4);    if(!_tprepared && sizeof(_preparedname))    closestatement(CHAIN(bindbuffer), _preparedname);    _sendexecute(_fetchlimit
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1075:    _tprepared.datarowdesc=datarowdesc;    _tprepared.datarowtypes=datarowtypes;    }    }       final void _parseportal() {    Thread.MutexKey lock = closemux->lock();    _state=PARSING;    Thread.MutexKey lockc = pgsqlsess->_shortmux->lock();    if (syncparse || syncparse < 0 && pgsqlsess->_wasparallelisable) { -  if(pgsqlsess->_statementsinflight) { -  pgsqlsess->_waittocommit++; +     PD("Commit waiting for statements to finish\n"); -  // Do NOT put this in a function, it would require passing a lock -  // variable on the argumentstack to the function, which will cause -  // unpredictable lock release issues due to the extra copy on the stack -  catch(PT(pgsqlsess->_readyforcommit->wait(lockc))); -  pgsqlsess->_waittocommit--; +  catch(PT(pgsqlsess->_statementsinflight->wait_till_drained(lockc)));    } -  } -  pgsqlsess->_statementsinflight++; +  stmtifkey = pgsqlsess->_statementsinflight->acquire();    lockc = 0;    lock=0;    statuscmdcomplete=UNDEFINED;    pgsqlsess->_wasparallelisable = paralleliseprefix->match(_query);    }       final void _releasestatement(void|int nolock) {    Thread.MutexKey lock;    if (!nolock)    lock = closemux->lock();    if (_state <= BOUND) {    _state = COMMITTED; -  lock = pgsqlsess->_shortmux->lock(); -  if (!--pgsqlsess->_statementsinflight && pgsqlsess->_waittocommit) { -  PD("Signal no statements in flight\n"); -  catch(pgsqlsess->_readyforcommit->signal()); +  stmtifkey = 0;    } -  } +     lock = 0;    }       final void _bindportal() {    Thread.MutexKey lock = closemux->lock();    _state=BOUND; -  Thread.MutexKey lockc = pgsqlsess->_shortmux->lock(); -  pgsqlsess->_portalsinflight++; -  lockc = 0; +  portalsifkey = pgsqlsess->_portalsinflight->acquire();    lock=0;    }       final void _purgeportal() {    PD("Purge portal\n");    datarows->write(1); // Signal EOF    Thread.MutexKey lock=closemux->lock();    _fetchlimit=0; // disables further Executes    switch(_state) {    case COPYINPROGRESS:    case COMMITTED:    case BOUND: -  --pgsqlsess->_portalsinflight; +  portalsifkey = 0;    }    switch(_state) {    case BOUND:    case PARSING: -  --pgsqlsess->_statementsinflight; +  stmtifkey = 0;    }    _state = PURGED;    lock=0;    releaseconditions();    }       final int _closeportal(conxsess cs) {    object plugbuffer = CHAIN(cs);    int retval=KEEP;    PD("%O Try Closeportal %d\n",_portalname,_state);
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1167:    case COMMITTED:    case BOUND:    _state=CLOSING;    lock=0;    PD("Close portal %O\n",_portalname);    if (_portalname && sizeof(_portalname)) {    plugbuffer->add_int8('C')->add_hstring(({'P',_portalname,0}),4,4);    retval=FLUSHSEND;    } else    _unnamedportalkey=0; -  Thread.MutexKey lockc=pgsqlsess->_shortmux->lock(); -  if(!--pgsqlsess->_portalsinflight) { -  if(!pgsqlsess->_waittocommit && !plugbuffer->stashcount -  && transtype != TRANSBEGIN) +  portalsifkey = 0; +  if (pgsqlsess->_portalsinflight->drained()) { +  if (plugbuffer->stashcount->drained() && transtype != TRANSBEGIN)    /*    * stashcount will be non-zero if a parse request has been queued    * before the close was initiated.    * It's a bit of a tricky race, but this check should be sufficient.    */    pgsqlsess->_readyforquerycount++, retval=SYNCSEND;    pgsqlsess->_pportalcount=0;    } -  lockc=0; +     }    lock=0;    return retval;    }       final void _processdataready(array datarow,void|int msglen) {    bytesreceived+=msglen;    inflight--;    if(_state<CLOSED)    datarows->write(datarow);