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

version» Context lines:

pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:131:    * if there is a RETURNING with a *lot* of results. In those cases    * the portal will be busy until all results have been fetched, and will    * not be able to deliver results belonging to other parallel queries    * running on the same filedescriptor.    *    * However, considering that the current heuristic increases query-speed    * 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]*$"); +  = iregexp("^\a*((UPDA|DELE)TE|INSERT" +  "|RESET|CLOSE|DISCARD)\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() {    atexit(destroy);    // Run callbacks from our local_backend until DefaultBackend has started    cb_backend = local_backend = Pike.SmallBackend();    call_out(default_backend_runs, 0);
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:293:    private conxion realbuffer;       private void create(conxion _realbuffer) {    realbuffer = _realbuffer;    }       final Thread.ResourceCount `stashcount() {    return realbuffer->stashcount;    }    -  final bufcon start(void|int waitforreal) { -  dirty = realbuffer->stashcount->acquire(); +  final MUTEX `shortmux() { +  return realbuffer->shortmux; +  } +  +  final bufcon start(void|int|array(Thread.MutexKey) waitforreal) { +  dirty = 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(); +  Thread.MutexKey lock = shortmux->lock();    if (portal)    realbuffer->stashqueue->write(portal);    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 = 0; // Countdown before releasing the lock    lock = 0; -  dirty = 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;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:455: Inside #if PG_DEBUGHISTORY > 0
   return ret;    }   #endif       private inline void queueup(sql_result portal) {    qportals->write(portal); portal->_synctransact = synctransact;    PD("%d>%O %d %d Queue portal %d bytes\n", socket->query_fd(),    portal._portalname, ++queueoutidx, synctransact, sizeof(this));    }    -  final bufcon|conxsess start(void|int waitforreal) { +  final bufcon|conxsess start(void|int|array(Thread.MutexKey) waitforreal) {    Thread.MutexKey lock;   #ifdef PG_DEBUGRACE    if (nostash->current_locking_thread())    PD("Nostash locked by %s\n",    describe_backtrace(nostash->current_locking_thread()->backtrace()));   #endif -  while (lock = (waitforreal > 0 ? nostash->lock : nostash->trylock)(1)) { +  while (lock = (intp(waitforreal) && waitforreal > 0 +  ? nostash->lock : nostash->trylock)(1)) {    int mode;    if (sizeof(stash) && (mode = getstash(KEEP)) > KEEP)    sendcmd(mode); // Force out stash to the server    if (!stashcount->drained()) {    lock = 0; // Unlock while we wait -  +  if (arrayp(waitforreal)) +  waitforreal[0] = 0;    stashcount->wait_till_drained(); -  +  if (arrayp(waitforreal)) +  return 0;    continue; // Try again    }   #ifdef PG_DEBUGRACE    conxsess sess = conxsess(this);   #endif    started = lock; // sendcmd() clears started, so delay assignment   #ifdef PG_DEBUGRACE    return sess;   #else    return this;   #endif    } -  +  if (arrayp(waitforreal)) +  waitforreal[0] = 0;    return !waitforreal && bufcon(this)->start();    }       private int write_cb() {    Thread.MutexKey lock = shortmux->lock();    if (this) { // Guard against async destructs    output_to(socket);    lock = 0;    if (!i->fillread && !sizeof(this))    close();
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:556:    PD("%d>Skip flush %d Queue %O\n",    socket->query_fd(), mode, (string)this);    break outer;    case FLUSHSEND:    PD("Flush\n");    add(PGFLUSH);    case SENDOUT:;    }    Thread.MutexKey lock = shortmux->trylock();    if (lock && sizeof(this)) { -  PD("%d>Sendcmd %O\n", -  socket->query_fd(), (string)this); +  PD("%d>Sendcmd %O\n", socket->query_fd(), (string)this);    output_to(socket);    }    } while (0);    started = 0;    if (sizeof(stash) && (started = nostash->trylock(2))) {   #ifdef PG_DEBUGRACE    conxsess sess = conxsess(this);    sess->sendcmd(SENDOUT);   #else    mode = getstash(SENDOUT);
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:883:    //!    //! @seealso    //! @[affected_rows()]    /*semi*/final string status_command_complete() {    if (!statuscmdcomplete) {    if (!datarowtypes)    waitfordescribe();    {    Thread.MutexKey lock = closemux->lock();    if (_fetchlimit) { -  array reflock = ({ _fetchlimit = 0 }); +  array(Thread.MutexKey) reflock = ({ _fetchlimit = 0 });    for (;;) {    reflock[0] = lock;    lock = 0;    if (!_sendexecute(0, reflock)) {    lock = closemux->lock();    continue;    }    } -  } else +  }    lock = 0; // Force release before acquiring next    lock = _ddescribemux->lock();    if (!statuscmdcomplete)    PT(_ddescribe->wait(lock));    }    if (this) // If object already destructed, skip the next call    trydelayederror(); // since you cannot call functions anymore    else    error(LOSTERROR);    }
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1350:    }    if (_state >= CLOSING)    lock = _unnamedstatementkey = 0;    else {    plugbuffer->add_int16(sizeof(datarowtypes));    if (sizeof(datarowtypes)) {    plugbuffer->add_ints(map(datarowtypes, readoidformat), 2);    lock = 0;    } else if (syncparse < 0 && !pgsqlsess->wasparallelisable    && !pgsqlsess->statementsinflight->drained(1)) { -  lock = 0; +  lock = 0; // Unlock while we wait    PD("Commit waiting for statements to finish\n");    catch(PT(pgsqlsess->statementsinflight->wait_till_drained(1)));    }    PD("Bind portal %O statement %O\n", _portalname, _preparedname);    _fetchlimit = pgsqlsess->_fetchlimit;    _bindportal();    conxsess bindbuffer = c->start();    stmtifkey = 0;    CHAIN(bindbuffer)->add_int8('B')->add_hstring(plugbuffer, 4, 4);    if (!_tprepared && sizeof(_preparedname))
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1382:    final void _processrowdesc(array(mapping(string:mixed)) datarowdesc,    array(int) datarowtypes) {    _setrowdesc(datarowdesc, datarowtypes);    if (_tprepared) {    _tprepared.datarowdesc = datarowdesc;    _tprepared.datarowtypes = datarowtypes;    }    }       final void _parseportal() { -  { +  for (;;) {    Thread.MutexKey lock = closemux->lock(); -  _state = PARSING; -  if (syncparse || syncparse < 0 && pgsqlsess->wasparallelisable) { +  if ((syncparse || syncparse < 0 && pgsqlsess->wasparallelisable) +  && !pgsqlsess->statementsinflight->drained()) { +  lock = 0; // Unlock while we wait    PD("Commit waiting for statements to finish\n");    catch(PT(pgsqlsess->statementsinflight->wait_till_drained())); -  +  continue;    } -  +  _state = PARSING;    stmtifkey = pgsqlsess->statementsinflight->acquire(); -  +  break;    }    statuscmdcomplete = 0;    pgsqlsess->wasparallelisable = paralleliseprefix->match(_query);    }       final void _releasestatement() {    Thread.MutexKey lock = closemux->lock();    if (_state <= BOUND) {    stmtifkey = 0;    _state = COMMITTED;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1450:    reflock[0] = 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;    portalsifkey = 0;    if (pgsqlsess->portalsinflight->drained()) { -  if (plugbuffer->stashcount->drained() && transtype != TRANSBEGIN) +  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. +     */ -  +  Thread.MutexKey lock = plugbuffer->shortmux->lock(); +  if (plugbuffer->stashcount->drained())    pgsqlsess->readyforquerycount++, retval = SYNCSEND; -  +  }    pgsqlsess->pportalcount = 0;    }    }    return retval;    }       private void replenishrows() {    if (_fetchlimit && datarows->size() <= _fetchlimit >> 1    && _state >= COMMITTED) {    Thread.MutexKey lock;    for (;;) {    lock = closemux->lock();    if (_fetchlimit) {    _fetchlimit = pgsqlsess._fetchlimit;    if (bytesreceived)    _fetchlimit = min((portalbuffersize >> 1)    * index / bytesreceived || 1, _fetchlimit);    if (_fetchlimit)    if (inflight <= (_fetchlimit - 1) >> 1) { -  array reflock = ({ lock }); +  array(Thread.MutexKey) reflock = ({ lock });    lock = 0;    if (!_sendexecute(_fetchlimit, reflock))    continue;    } else    PD("<%O _fetchlimit %d, inflight %d, skip execute\n",    _portalname, _fetchlimit, inflight);    }    break;    }    }
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1523:       final void _releasesession(void|string statusccomplete) {    c->runningportals[this] = 0;    if (statusccomplete && !statuscmdcomplete) {    Thread.MutexKey lock = _ddescribemux->lock();    statuscmdcomplete = statusccomplete;    _ddescribe->broadcast();    }    inflight = 0;    conxsess plugbuffer; -  array(Thread.MutexKey) reflock = ({closemux->lock()}); -  if (!catch(plugbuffer = c->start())) +  array(Thread.MutexKey) reflock = ({ 0 }); +  for (;;) { +  reflock[0] = closemux->lock(); +  if (!catch(plugbuffer = c->start(reflock))) { +  if (plugbuffer)    plugbuffer->sendcmd(_closeportal(plugbuffer, reflock)); -  +  else +  continue; +  } +  break; +  }    reflock[0] = 0;    if (_state < CLOSED) {    stmtifkey = 0;    _state = CLOSED;    }    datarows->write(1); // Signal EOF    releaseconditions(statusccomplete == "ABORT");    }       protected void destroy() {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1549:    }       final int _sendexecute(int fetchlimit,    void|array(Thread.MutexKey)|bufcon|conxsess plugbuffer) {    int flushmode;    array(Thread.MutexKey) reflock;    PD("Execute portal %O fetchlimit %d transtype %d\n", _portalname,    fetchlimit, transtype);    if (arrayp(plugbuffer)) {    reflock = plugbuffer; -  if (!(plugbuffer = c->start(-1))) { -  reflock[0] = 0; +  if (!(plugbuffer = c->start(reflock)))    return 0; // Found potential deadlock, release and try again    } -  } +     CHAIN(plugbuffer)->add_int8('E')->add_hstring(({_portalname, 0}), 4, 8)    ->add_int32(fetchlimit);    if (!fetchlimit) {    if (transtype != NOTRANS)    pgsqlsess.intransaction = transtype == TRANSBEGIN;    flushmode = _closeportal(plugbuffer, reflock) == SYNCSEND    || transtype == TRANSEND ? SYNCSEND : FLUSHSEND;    } else    inflight += fetchlimit, flushmode = FLUSHSEND;    plugbuffer->sendcmd(flushmode, this);
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:2224:    qp._portalname, qp._synctransact, portal);    qp->_purgeportal();    }    }    portal = 0;   #ifdef PG_DEBUGMORE    showportalstack("AFTER READYFORQUERY");   #endif    readyforquerycount--;    function (:void) cb; +  destruct(waitforauthready);    if (cb = readyforquery_cb)    readyforquery_cb = 0, cb(); -  destruct(waitforauthready); +     break;    }    case '1':   #ifdef PG_DEBUG    PD("ParseComplete portal %O\n", portal);    msglen -= 4;   #endif    break;    case 't': {    array a;