Thread: BUG #3031: PHP (and others?) cannot close a connection when "in" a COPY-statement
BUG #3031: PHP (and others?) cannot close a connection when "in" a COPY-statement
From
"Arjen van der Meijden"
Date:
The following bug has been logged online: Bug reference: 3031 Logged by: Arjen van der Meijden Email address: acmmailing@tweakers.net PostgreSQL version: 8.2.1 Operating system: Debian Linux (etch, 2.6.17 kernel) Description: PHP (and others?) cannot close a connection when "in" a COPY-statement Details: We noticed that when issueing a 'die'-statement in php, compiled against both 8.1 or 8.2 will not really die when just before the die-statement a COPY-statement to postgresql was started. In stead it gets in some (busy wait?) loop, consuming 100% cpu. Here is some example code that triggers the behaviour: <? echo "Starting\n"; $conn = pg_connect(''); pg_query($conn, "CREATE TEMPORARY TABLE test (test integer);"); pg_query($conn, "COPY test FROM STDIN"); die("And now it hangs in with 100% cpu\n"); ?> Of course you'd expect a prompt to return, rather than the process consuming all cpu and never returning. I'm not sure whether this is a php-issue or a postgresql-client-api one, but when connecting gdb to that process and doing a 'bt' it displays: #0 0xa7c36d9f in free () from /lib/tls/libc.so.6 #1 0xa7c38c4f in malloc () from /lib/tls/libc.so.6 #2 0xa7f58bdb in PQmakeEmptyPGresult () from /usr/lib/libpq.so.5 #3 0xa7f59941 in PQgetResult () from /usr/lib/libpq.so.5 #4 0x08086fd0 in _close_pgsql_link (rsrc=0x81e42bc) at /usr/src/php-4.4.2/ext/pgsql/pgsql.c:276 #5 0x08139fb2 in list_entry_destructor (ptr=0x81e42bc) at /usr/src/php-4.4.2/Zend/zend_list.c:177 #6 0x08137977 in zend_hash_apply_deleter (ht=0x81a49e0, p=0x81e4284) at /usr/src/php-4.4.2/Zend/zend_hash.c:611 #7 0x08137b97 in zend_hash_graceful_reverse_destroy (ht=0x81a49e0) at /usr/src/php-4.4.2/Zend/zend_hash.c:677 #8 0x0812b9ed in shutdown_executor () at /usr/src/php-4.4.2/Zend/zend_execute_API.c:211 #9 0x08133801 in zend_deactivate () at /usr/src/php-4.4.2/Zend/zend.c:689 #10 0x08107862 in php_request_shutdown (dummy=0x0) at /usr/src/php-4.4.2/main/main.c:999 #11 0x0814ee56 in main (argc=2, argv=0xaf992f54) at /usr/src/php-4.4.2/sapi/cli/php_cli.c:881 We can reproduce this on x86-boxes with recent php4 and the latest php5(-cvs). I have not tested other sapi's than the cli-php versions but I also tested it on a (amd64) gentoo box. If it is a php-bug, perhaps it'd be usefull if one of you could comment here: http://bugs.php.net/bug.php?id=40544 Best regards, Arjen van der Meijden
Re: BUG #3031: PHP (and others?) cannot close a connection when "in" a COPY-statement
From
Tom Lane
Date:
"Arjen van der Meijden" <acmmailing@tweakers.net> writes: > I'm not sure whether this is a php-issue or a postgresql-client-api one, but > when connecting gdb to that process and doing a 'bt' it displays: > #0 0xa7c36d9f in free () from /lib/tls/libc.so.6 > #1 0xa7c38c4f in malloc () from /lib/tls/libc.so.6 > #2 0xa7f58bdb in PQmakeEmptyPGresult () from /usr/lib/libpq.so.5 > #3 0xa7f59941 in PQgetResult () from /usr/lib/libpq.so.5 > #4 0x08086fd0 in _close_pgsql_link (rsrc=0x81e42bc) at > /usr/src/php-4.4.2/ext/pgsql/pgsql.c:276 Given that stack trace, you'd better complain to the PHP folk. There is no loop in that path in libpq, so the looping must be occurring somewhere in the PHP code. regards, tom lane
Re: BUG #3031: PHP (and others?) cannot close a connection when "in" a COPY-statement
From
Arjen van der Meijden
Date:
On 20-2-2007 4:42 Tom Lane wrote: > "Arjen van der Meijden" <acmmailing@tweakers.net> writes: >> I'm not sure whether this is a php-issue or a postgresql-client-api one, but >> when connecting gdb to that process and doing a 'bt' it displays: >> #0 0xa7c36d9f in free () from /lib/tls/libc.so.6 >> #1 0xa7c38c4f in malloc () from /lib/tls/libc.so.6 >> #2 0xa7f58bdb in PQmakeEmptyPGresult () from /usr/lib/libpq.so.5 >> #3 0xa7f59941 in PQgetResult () from /usr/lib/libpq.so.5 >> #4 0x08086fd0 in _close_pgsql_link (rsrc=0x81e42bc) at >> /usr/src/php-4.4.2/ext/pgsql/pgsql.c:276 > > Given that stack trace, you'd better complain to the PHP folk. There is > no loop in that path in libpq, so the looping must be occurring > somewhere in the PHP code. I had a look at that _close_pgsql_link-function and this it the code: static void _close_pgsql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) { PGconn *link = (PGconn *)rsrc->ptr; PGresult *res; while ((res = PQgetResult(link))) { PQclear(res); } PQfinish(link); PGG(num_links)--; } So there is indeed a very clear loop. But I'm not sure whether this code is incorrect as a generic "close the connection cleanly without memory leaks"-function? If I duplicate that while-loop to my c-test code it indeed keeps getting a non-null/false result from PQgetResult and thus will loop indefinitely. Do you know a clean example that displays how to close a link cleanly, including this COPY-situation? Or can you indicate which commands should be added to do so? My knowledge of the C-api is very limited, so I don't know what's wrong here. Best regards, Arjen
Re: BUG #3031: PHP (and others?) cannot close a connection when "in" a COPY-statement
From
Tom Lane
Date:
Arjen van der Meijden <acmmailing@tweakers.net> writes: > I had a look at that _close_pgsql_link-function and this it the code: > while ((res = PQgetResult(link))) { > PQclear(res); > } > So there is indeed a very clear loop. But I'm not sure whether this code > is incorrect as a generic "close the connection cleanly without memory > leaks"-function? It's surely incorrect as a means of getting out of a COPY state. To tell the truth, if their intention is to close the connection unceremoniously, they should just do that, ie PQfinish or just quit the application. So I'd suggest removing that loop. regards, tom lane
Re: BUG #3031: PHP (and others?) cannot close a connection when "in" a COPY-statement
From
Arjen van der Meijden
Date:
On 20-2-2007 8:07 Tom Lane wrote: > It's surely incorrect as a means of getting out of a COPY state. To > tell the truth, if their intention is to close the connection > unceremoniously, they should just do that, ie PQfinish or just quit > the application. So I'd suggest removing that loop. I think its meant as a generic way of closing the connection. I.e. not only to close the connection as a last-resort "clean things up before we return to the webserver/console, but also half-way if the client asks for it (as the code behind 'pg_close'). I.e. you don't want memory-leaks to build up because someone, for some reason, needs something like this and the internal code doesn't clean up something that easily could've been cleaned up: while($something) { $c = pg_connect(".."); // Queries pg_close($c); } Although obviously, that kind of code is not so common and should only be used if there is a very good reason not to open/close the connection outside the loop. Besides that, its very common in php to just leave the garbage to the php-engine, probably even worse than in Java. I guess, that if they really wanted to keep something like this while-loop, they need to request the result-status and if its not the result of a finished query (either failed, ok, empty, etc) they should send a cancel request? Anyway, I'll add your advice to that bug-report. Best regards, Arjen