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:78:
#else #define MUTEX Thread.Mutex #endif //! The instance of the pgsql dedicated backend. final Pike.Backend local_backend; private Pike.Backend cb_backend; private Result qalreadyprinted; private Thread.Mutex backendmux = Thread.Mutex();
-
private
Thread.ResourceCount
clientsregistered
=
Thread.ResourceCount
();
+
final
multiset(proxy)
clients
=
set_weak_flag
(
(<>
)
, Pike.WEAK)
;
constant emptyarray = ({}); constant describenodata = (["datarowdesc":emptyarray, "datarowtypes":emptyarray, "datatypeoid":emptyarray]); private constant censoroptions = (<"use_ssl", "force_ssl", "cache_autoprepared_statements", "reconnect", "text_query", "is_superuser", "server_encoding", "server_version", "integer_datetimes", "session_authorization">);
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:140:
* 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]*$"); private void default_backend_runs() { // Runs as soon as the cb_backend = Pike.DefaultBackend; // DefaultBackend has started }
-
private
void create() {
+
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); }
-
+
protected void _destruct() {
+
foreach (clients; proxy client; )
+
destruct(client);
+
}
+
private Regexp iregexp(string expr) { Stdio.Buffer ret = Stdio.Buffer(); foreach (expr; ; int c) if (c >= 'A' && c <= 'Z') ret->add('[', c, c + 'a' - 'A', ']'); else if (c == '\a') // Replace with generic whitespace ret->add("[ \t\f\r\n]"); else ret->add_int8(c); return Regexp(ret->read());
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:172:
} } private void run_local_backend() { Thread.MutexKey lock; int looponce; do { looponce = 0; if (lock = backendmux->trylock()) { PD("Starting local backend\n");
-
while (
!clientsregistered->drained
() // Autoterminate when not needed
+
while (
sizeof
(
clients
)
// Autoterminate when not needed
|| sizeof(local_backend->call_out_info())) { mixed err; if (err = catch(local_backend(4096.0))) master()->handle_error(err); } PD("Terminating local backend\n"); lock = 0;
-
looponce =
!clientsregistered->drained
();
+
looponce =
sizeof
(
clients
);
} } while (looponce); } //! Registers yourself as a user of this backend. If the backend //! has not been started yet, it will be spawned automatically.
-
final
Thread.ResourceCountKey
register_backend() {
-
int startbackend =
clientsregistered->drained
();
-
Thread.ResourceCountKey
key
=
clientsregistered->acquire()
;
+
final
void
register_backend(
proxy client
) {
+
int startbackend =
!sizeof
(
clients
);
+
clients[client]
=
1
;
if (startbackend) Thread.Thread(run_local_backend);
-
return key;
+
} final void throwdelayederror(Result|proxy parent) { if (mixed err = parent->delayederror) { if (!objectp(parent->pgsqlsess)) parent->untolderror = 0; else if (parent->pgsqlsess) parent->pgsqlsess->untolderror = 0; parent.delayederror = 0; if (stringp(err))
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:330:
private Thread.ResourceCountKey dirty; #ifdef PG_DEBUGRACE final bufcon `chain() { return this; } #endif private conxion realbuffer;
-
private
void create(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(); #ifdef PG_DEBUG
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:436:
#endif ); Thread.MutexKey lock = fillreadmux->lock(); if (procmsg && id) procmsg = 0, lock = 0, Thread.Thread(id); else if (fillread) didreadcb = 1, fillread.signal(); return 0; }
-
private
void create() {
+
protected
void create() {
i::create(); fillreadmux = MUTEX(); fillread = Thread.Condition(); } }; class sfile { inherit Stdio.File; final int query_fd() { return is_open() ? ::query_fd() : -1;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:674:
}; destruct(nostash); socket->set_non_blocking(); // Drop all callbacks PD("%d>Close socket\n", socket->query_fd()); socket->close(); // This will be an asynchronous close } destruct(this); } }
-
private
void _destruct() {
+
protected
void _destruct() {
PD("%d>Close conxion %d\n", socket ? socket->query_fd() : -1, !!nostash); catch(purge()); } final void connectloop(proxy pgsqlsess, int nossl) { #ifdef PG_DEBUG mixed err = #endif catch { for (; ; clear()) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:734:
socket->set_nonblocking(i->read_cb, write_cb, close); if (nossl != 2) Thread.Thread(pgsqlsess->processloop, this); return; }; PD("Connect error %s\n", describe_backtrace(err)); catch(destruct(pgsqlsess->waitforauthready)); destruct(this); }
-
private
string _sprintf(int type) {
+
protected
string _sprintf(int type) {
string res; 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\n", fd, sizeof(i), i->_size_object(), qportals && qportals->size(), sizeof(this), _size_object(), !!started); break; } return res; }
-
private
void create(proxy pgsqlsess, Thread.Queue _qportals, int nossl) {
+
protected
void create(proxy pgsqlsess, Thread.Queue _qportals, int nossl) {
o::create(); qportals = _qportals; synctransact = 1; socket = sfile(); i = conxiin(); shortmux = MUTEX(); nostash = 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;
-
private
void create(conxion parent) {
+
protected
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|Result portal) { chain->sendcmd(mode, portal); chain = 0; }
-
private
void _destruct() {
+
protected
void _destruct() {
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.Result]. //!
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1893:
Thread.Thread(run_result_array_cb, callback, args); } }; class proxy { final int _fetchlimit = FETCHLIMIT; final MUTEX unnamedportalmux; final MUTEX unnamedstatement; private Thread.MutexKey termlock;
-
private Thread.ResourceCountKey backendreg;
+
final Thread.ResourceCount portalsinflight, statementsinflight; final int(0..1) wasparallelisable; final int(0..1) intransaction; final conxion c; private string cancelsecret; private int backendpid; final int(-128..127) backendstatus; final mapping(string:mixed) options; private array(string) lastmessage = emptyarray;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1928:
final function (:void) readyforquery_cb; final string host; final int(0..65535) port; final string database, user, pass; private Crypto.Hash.SCRAM SASLcontext; final Thread.Condition waitforauthready; final MUTEX shortmux; final int readyforquerycount;
-
private
string _sprintf(int type) {
+
protected
string _sprintf(int type) {
string res; switch (type) { case 'O': res = sprintf(DRIVERNAME".proxy(%s@%s:%d/%s,%d,%d)", user, host, port, database, c && c->socket && c->socket->query_fd(), backendpid); break; } return res; }
-
private
void create(void|string host, void|string database,
+
protected
void create(void|string host, void|string database,
void|string user, void|string pass, void|mapping(string:mixed) options) { if (this::pass = pass) { String.secure(pass); pass = "CENSORED"; } this::user = user; this::database = database; this::options = options; if (!host) host = PGSQL_DEFAULT_HOST; if (has_value(host,":") && sscanf(host,"%s:%d", host, port) != 2) error("Error in parsing the hostname argument\n"); this::host = host; if (!port) port = PGSQL_DEFAULT_PORT;
-
backendreg =
register_backend();
+
register_backend(
this
);
shortmux = MUTEX(); PD("Connect\n"); waitforauthready = Thread.Condition(); qportals = Thread.Queue(); readyforquerycount = 1; qportals->write(1); if (!(c = conxion(this, qportals, 0))) error("Couldn't connect to database on %s:%d\n", host, port); runtimeparameter = ([]); unnamedportalmux = MUTEX();
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:2719:
break; case NOERROR: continue; // Normal production loop } error(a2nls(lastmessage += ({msg}))); } }; // We only get here if there is an error if (err == MAGICTERMINATE) { // Announce connection termination to server catch { void|bufcon|conxsess cs = ci->start();
-
CHAIN(cs)->add("X\0\0\0\4");
+
CHAIN(cs)->add(
PGSYNC)->add(
"X\0\0\0\4");
cs->sendcmd(SENDOUT); }; terminating = 1; err = 0; } else if (stringp(err)) { Result or; if (!objectp(or = portal)) or = this; if (!or.delayederror) or.delayederror = err;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:2784:
if (c) // Prevent trivial backtraces c->close(); if (unnamedstatement) lock = unnamedstatement->lock(1); if (c) c->purge(); } destruct(waitforauthready); }
-
private
void _destruct() {
+
protected
void _destruct() {
string errstring; mixed err = catch(close());
-
backendreg
= 0;
+
clients[this]
= 0;
if (untolderror) { /* * Flush out any asynchronously reported errors to stderr; because we are * inside a destructor, throwing an error will not work anymore. * Warnings will be silently discarded at this point. */ lastmessage = filter(lastmessage, lambda(string val) { return has_prefix(val, "ERROR ") || has_prefix(val, "FATAL "); }); if (err || (err = catch(errstring = geterror(1)))) werror(describe_backtrace(err));