pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:132:
* 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
}
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);
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:341:
private 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();
+ 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|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:503: Inside #if PG_DEBUGHISTORY > 0
return ret;
}
#endif
private inline void queueup(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:604:
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:929:
//!
//! @seealso
//! @[Sql.Result()->status_command_complete()]
/*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:1532:
}
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:1564:
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:1632:
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:1705:
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 _destruct() {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1731:
}
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:2406:
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;