pike.git
/
lib
/
modules
/
Sql.pmod
/
pgsql_util.pmod
version
»
Context lines:
10
20
40
80
file
none
3
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);