Branch: Tag:

2017-06-27

2017-06-27 10:30:15 by Stephen R. van den Berg <srb@cuci.nl>

pgsql: Trim in-flight portal stack aware of transactions in progress.

30:    "cache_autoprepared_statements","reconnect","text_query","is_superuser",    "server_encoding","server_version","integer_datetimes",    "session_authorization">); - final multiset cachealways=(<"BEGIN","begin","END","end","COMMIT","commit">); +        /* Statements matching createprefix cause the prepared statement cache    * to be flushed to prevent stale references to (temporary) tables
48:   private Regexp paralleliseprefix    =iregexp("^\a*((SELEC|INSER)T|(UPDA|DELE)TE|(FETC|WIT)H)\a");    +  /* Statements matching transbeginprefix will cause the driver +  * insert a sync after the statement. +  * Failure to do so, will result in portal synchronisation errors +  * in the event of an ErrorResponse. +  */ + final Regexp transbeginprefix +  =iregexp("^\a*BEGIN[; \t\f\r\n]*$"); +  +  /* Statements matching transendprefix will cause the driver +  * insert a sync after the statement. +  * Failure to do so, will result in portal synchronisation errors +  * in the event of an ErrorResponse. +  */ + final Regexp transendprefix +  =iregexp("^\a*(COMMIT|ROLLBACK|END)[; \t\f\r\n]*$"); +     /* For statements matching execfetchlimit the resultrows will not be    * fetched in pieces    */
318:    }       final void sendcmd(void|int mode, void|sql_result portal) { -  if (portal) -  queueup(portal); +     Thread.MutexKey lock; -  +  +  int emptystash() { +  int ret = 0;    if (started) {    lock = shortmux->lock();    if (sizeof(stash)) {
328:    stash->clear();    foreach (stashqueue->try_read_array();; sql_result portal)    queueup(portal); +  ret = 1;    }    mode = mergemode(this, mode);    stashflushmode = KEEP;    } - nosync: +  return ret; +  }; +  +  emptystash();    do { -  +  if (portal) +  queueup(portal);    switch (mode) {    default: -  break nosync; +  continue;    case SYNCSEND:    PD("%d>Sync %d %d Queue\n",    socket->query_fd(), synctransact, ++queueoutidx);
349:    mode = FLUSHSEND;    }    qportals->write(synctransact++); -  } while (0); +  } while (!lock && emptystash());    catch {   outer:    do {
543:    private int alltext;    final int _forcetext;    private int syncparse; +  private int transtype;       final string _portalname;   
576:    res=sprintf("sql_result state: %d numrows: %d eof: %d inflight: %d\n"    "query: %O\n"    "fd: %O portalname: %O datarows: %d" -  " laststatus: %s\n", +  " synctransact: %d laststatus: %s\n",    _state,rowsreceived,eoffound,inflight,    _query,fd,_portalname,datarowtypes&&sizeof(datarowtypes), -  +  _synctransact,    statuscmdcomplete||(_unnamedstatementkey?"*parsing*":""));    break;    }
587:       protected void create(object _pgsqlsess,conxion _c,string query,    int _portalbuffersize,int alltyped,array params,int forcetext, -  int _timeout, int _syncparse) { +  int _timeout, int _syncparse, int _transtype) {    pgsqlsess = _pgsqlsess;    cr = (c = _c)->i;    _query = query;
604:    syncparse = _syncparse;    gottimeout = _pgsqlsess->cancelquery;    c->closecallbacks+=(<destroy>); +  transtype = _transtype;    }       //! Returns the command-complete status for this query.
953:    if(!_tprepared && sizeof(_preparedname))    closestatement(CHAIN(bindbuffer), _preparedname);    _sendexecute(_fetchlimit -  && !(cachealways[_query] +  && !(transtype != NOTRANS    || sizeof(_query)>=MINPREPARELENGTH &&    execfetchlimit->match(_query))    && _fetchlimit,bindbuffer);
1070:    _unnamedportalkey=0;    Thread.MutexKey lockc=pgsqlsess->_shortmux->lock();    if(!--pgsqlsess->_portalsinflight) { -  if(!pgsqlsess->_waittocommit && !plugbuffer->stashcount) +  if(!pgsqlsess->_waittocommit && !plugbuffer->stashcount +  && transtype != TRANSBEGIN)    /*    * stashcount will be non-zero if a parse request has been queued    * before the close was initiated.
1146:    plugbuffer=c->start(1);    CHAIN(plugbuffer)->add_int8('E')->add_hstring(({_portalname,0}), 4, 8)    ->add_int32(fetchlimit); -  if(!fetchlimit) -  flushmode=_closeportal(plugbuffer)==SYNCSEND?SYNCSEND:FLUSHSEND; -  else +  if (!fetchlimit) { +  if (transtype != NOTRANS) +  pgsqlsess._intransaction = transtype == TRANSBEGIN; +  flushmode = _closeportal(plugbuffer) == SYNCSEND +  || transtype == TRANSEND ? SYNCSEND : FLUSHSEND; +  } else    inflight+=fetchlimit, flushmode=FLUSHSEND;    plugbuffer->sendcmd(flushmode,this);    }