php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #39029 Persistent connections remain even after timeout has elapsed
Submitted: 2006-10-03 19:30 UTC Modified: 2006-10-11 20:13 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: kiranm at hp dot com Assigned:
Status: Not a bug Package: OCI8 related
PHP Version: 5.1.6 OS: HP-UX
Private report: No CVE-ID: None
 [2006-10-03 19:30 UTC] kiranm at hp dot com
Description:
------------
I have a small script :
<html>
<body>
<?php

$db = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)
                      (HOST = <oracleserver>)(PORT=1521))
                      (CONNECT_DATA=(SERVER=DEDICATED)
                      (SERVICE_NAME=TEST)))";

$connection = oci_pconnect("scott","tiger",$db);
$stmt = OCIParse($connection, "select * from ALL_USERS");
 OCIExecute($stmt);
 while(OCIFetch($stmt))
        echo OCIResult($stmt,"USERNAME")."<BR>\n";
 echo "\n";
?>
</body>
</html>

I use the Apache worker model. The php.ini file has the following parameters set :
[Oci8]
oci8.max_persistent=1
oci8.persistent_timeout=10
oci8.ping_interval=0

When I use the Apache bench (ab) tool to run the above script 1000 times, I get about 50 connections opened with Oracle. I tested this by executing :
netstat -an | grep 1521

After the timeout of 10 secs, when I run netstat again, I find all the connections still open. When I reissued the ab request, I found that no new connections are established and that the old connections were used. I used tusc/truss tool to check this out.


Reproduce code:
---------------
I went through the code and did not find any active housekeeping that is done to terminate connections that have passed the timeout. The decision to use an existing connection or a new connection seems to be something that is made when there is a new request.

In the php_oci_persistent_helper() function, I found that connection->idle_expiry is compared with the timestamp only when the connection is not used. So that part of the code does not get executed when there is already an open connection even when the timeout has expired.

I think this check should be made always otherwise persistent connections will continue to get used. I changed it on my machine and it works as expected.

Expected result:
----------------
Persistent connections should expire after timeout or at the least when there is a new request after the timeout period has elapsed.

Actual result:
--------------
Persistent connections continue to exist and be used even after the specified timeout.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-10-03 19:43 UTC] tony2001@php.net
>After the timeout of 10 secs, when I run netstat again, 
>I find all the connections still open.
Sure, they won't just disappear magically.
Connections are closed at extension shutdown, if extension is not used they will be still there.

>So that part of the code does not get executed
>when there is already an open connection even when the >timeout has expired.
Yes, that's the whole point (see http://php.net/oci8):
---
oci8.persistent_timeout int

The maximum length of time (in seconds) that a given process is allowed to maintain an idle persistent connection. Setting this option to -1 means that idle persistent connections will be maintained forever.
---

>I changed it on my machine and it works as expected.
No, persistent connections are NOT expected to be closed if they are still being used.

No bug here, this is the expected behaviour.

 [2006-10-03 19:53 UTC] kiranm at hp dot com
From the documentation, I understand that the timeout directive is to be used to provide the length of idle time after which the connection will be terminated (if there are no active connections).

So when I use 10 secs as the timeout and issue a request after say 60 seconds, shouldnt the existing connection be terminated and a new one opened ? That is not happening. The old one continues to be used no matter what.
 [2006-10-03 19:56 UTC] tony2001@php.net
>From the documentation, I understand that the timeout 
>directive is to be used to provide the length of idle time 
>after which the connection will be terminated (if there
>are no active connections).

That's correct.

>So when I use 10 secs as the timeout and issue a request
>after say 60 seconds, shouldnt the existing connection be
>terminated and a new one opened ? That is not happening. 

No, it shouldn't.

>The old one continues to be used no matter what.

Because only _idle_ connections are supposed to be closed and this connection is not idle anymore.
 [2006-10-03 20:26 UTC] kiranm at hp dot com
>Because only _idle_ connections are supposed to be closed >and this connection is not idle anymore.

But 60 seconds of inactivity surely exceeds the 10 sec configured for timeout hence making it an idle connection. So if a connection has been idle for 60 seconds and then a new request arrives, this connection ought to be terminated and a new one established. Otherwise, the documentation needs to be updated with what constitutes 'idle time'.
 [2006-10-03 20:47 UTC] tony2001@php.net
>if a connection has been idle for 60 seconds and then a new
>request arrives, this connection ought to be terminated 
>and a new one established.

This doesn't make any sense.
The point in this ini setting is to descrease a number of idle persistent connections lingering around, it was not supposed to add more overhead dropping and re-creating connections.
And no, we're not going to change that.
No bug here.
 [2006-10-03 23:54 UTC] kiranm at hp dot com
I have not understood why this is not a bug. All the documentation I read on the topic seems to indicate that the persistent_timeout setting is the means by which a user can get rid of idle connections. An idle connection being one that is inactive for a length of time greater than the persistent_timeout interval specified.

So if I have persistent_timeout set to 10 seconds, any connection that is open and has not serviced a request for more than 10 seconds is idle and hence has to be terminated. But this does not happen.

Since this report has been repeatedly closed as bogus, I have opened a discussion in the PHP user mailing list. If you have any comment, please do reply. That will help me understand this better.
 [2006-10-11 19:50 UTC] kiranm at hp dot com
This is a follow-up and reopen of bug report #39029 Persistent connections remain even after timeout has elapsed 

This was closed as bogus, and the problem has been posted to the php-general@lists.php.net and this is a follow up to the suggestions from those discussions.  The main email involved are included.  In this bug report we have tried to remove any misunderstandings about the behavior based on the inputs received.  The problem as I see it is that the description of the oci.persistent_timeout in the php manual page, http://us2.php.net/manual/en/ref.oci8.php#ini.oci8 does not match it's behavior as documented in bug report #39029 and further documented below.

  This problem can be addressed in more than one manner.  The behavior of the how the oci8.persistent_timeout works can be changed to work as described now or closer to that description, and/or the documentation can be edited so it reflects accurately how it works and is expected to work with maybe some minor code changes, or simply say that the persistent_timeout is "useless", as has been suggested in one of the emails below, and remove it as an option.   

 Background discussion
------------------------

From Kiran Mendonce to the php-general@lists.php.net

This is a follow up to the bug (#39029) that I reported earlier which has been repeatedly closed as bogus.

The oci8.persistent_timeout setting in the php.ini file is documented as :
"The maximum length of time (in seconds) that a given process is allowed to maintain an idle persistent connection. Setting this option to -1 means that idle persistent connections will be maintained forever. "

If I do not want the connection to be persist forever, then by using this setting, I should be able to ensure that a connection is not idle for longer than what I specified. However, when I set persistent_timeout to 10 seconds, I 
find that the connection is not terminated even after 10 seconds have passed.  In fact, it doesn?t terminate at all. So the question is what is the purpose of this setting ? And what does an 'idle connection' mean ? A goggle query 
for 'idle timeout' yields enough results to point that when the timeout occurs, the idle connection is terminated.

Obviously there is a bug somewhere. Either in the documentation or in the behavior. Please advise.

Reply from php-general@lists.php.net:

I think that there is no bug and that option is useless.

If you are using Apache, it will rotate the processes that serve each request. So, unless your server is mostly idle or your scripts rarely access the database, your connections will keep being reused before reaching that timeout.

If you are willing to reduce the number of persistent Oracle connections, you will most likely get better results if you move your site images to a separate Web server. Image requests do not establish Oracle connections, but they raise the need for Apache to fork more processes, which
leads to more opened persistent connections.

Here you may find more details about that strategy:

http://www.meta-language.net/metabase-faq.html#excessive-connections

Regards, Manuel Lemos

From:  Kiran Mendonce to: php-general@lists.php.net8

I understand the performance boost one can get by reusing existing connections. And I did see for myself that with the default settings, oci_pconnect() does reuse all the connections.

But what should happen if there are idle connections and the timeout is reached? That is my question. What is the purpose of the persistent_timeout setting? Does it give the user a means of specifying a timeout after which idle connections are removed?

I did some checking on the web and noticed that another user encountered a similar problem and even reported it as a bug (#36634). The documentation is misleading here with the intent of the persistent_timeout setting not clearly 
explained.

If the behavior is as designed, can someone please update the documentation so its more clearer to the end user ?

Thanks and Regards, Kiran 


Reply from php-general@lists.php.net:

Yes.

Their claim is that your tests are invalid because your have MULTIPLE Apache processing swapping the connections around, so they are NOT idle for 10 seconds.

To prove them wrong, you would need to:
Set up a dev server on a private network with Apache having ONE, and ONLY ONE, child.
Set the timeout to 10 seconds.
Surf to a test page.
Wait 10 seconds.
See if the connection goes away.

If anybody else on the planet (or off-planet, for that matter, assuming our astronauts have time to surf to your site) can surf to the site and keep the connection "alive" by having Apache re-use it, then it's going to stay alive.
Richard Lynch [ceo@l-i-e.com]

Hello Richard,

  First let me introduce myself, I'm Jay Bauer and have been supporting the Apache webserver for the last couple of years and have been doing networking support for over 15 years.  I want to thank you for explaining why the folks 
replying to our lab's enquiries don't think the tests are valid.  I can appreciate the need of doing fault isolation of a problem so that all possible extraneous causes are eliminated.   

  However, I don't think their specific concerns are valid, as these systems are on internal networks, and very few people access them at all, and only Kiran or I would be accessing the oracle database and that is for our tests.  
And yes we will get some 50 httpd servers up and running, but once we stop our testing there is little access to the system and none to these persistent connections, and they
will stay around for hours or days till one of us decides to do more testing or stop and restart the Apache server. 

  Now having said all of that, I had no problem implementing the test setup you suggested.  If that is what it takes to get everyone on the same page, I'm happy to oblige.

Test environment
-----------------

 The HP-UX Apache web server only provides the worker MPM so in order to set up Apache as requested we use the following configuration in httpd.conf:

 changed the worker.c configuration to:

<IfModule worker.c>
StartServers         1
MaxClients           1
MinSpareThreads      1
MaxSpareThreads      1
ThreadsPerChild      1
MaxRequestsPerChild  1
</IfModule>

and commented out mod_cgid:
#LoadModule cgid_module modules/mod_cgid.so 

and in php.ini:

extension=oci8.sl
oci8.max_persistent=1
oci8.persistent_timeout=10
oci8.ping_interval=0

And the php version information:
/opt/hpws/apache/php>bin/php -v
PHP 5.0.4 (cli) (built: Sep 21 2006 15:26:12)

Testing
--------

After starting Apache with the above httpd.conf worker configuration there are two process running:

ps -ef |grep apache     
     www 29362 29361  0 23:39:52 ?         0:00 
/opt/hpws/apache/bin/httpd -d /opt/hpws/apache -k start   
    root 29361     1  0 23:39:52 ?         0:00 
/opt/hpws/apache/bin/httpd -d /opt/hpws/apache -k start

Pid 29361, the master httpd server, and one worker httpd server pid 29362, which is the minimum configuration possible with the worker MPM.

 I then ran the apache bench mark for just one connection:

bin/ab -n 1 http://maggie.india.hp.com/oracle_mufasa.php
...
Document Path:          /oracle_mufasa.php
Document Length:        334 bytes

Concurrency Level:      1
Time taken for tests:   0.370606 seconds
Complete requests:      1
 
Results and preliminary Analysis
----------------------------------

And then checked on the connection
 
As quick as possible:
>netstat -an |grep 1521
tcp        0      0  15.42.227.146.59262    15.106.72.129.1521      ESTABLISHED

30 sends later:
>netstat -an |grep 1521
tcp        0      0  15.42.227.146.59262    15.106.72.129.1521      ESTABLISHED

2 minutes later:
>netstat -an |grep 1521
tcp        0      0  15.42.227.146.59262    15.106.72.129.1521      ESTABLISHED

5 minutes later:
>netstat -an |grep 1521
tcp        0      0  15.42.227.146.59262    15.106.72.129.1521      ESTABLISHED

It wasn't until about 40 minutes later that this connection did finally terminate. 

And when I checked the error_log, it was clear what terminated it:

[error] [client 15.10.45.59] Symbolic link not allowed:
 /opt/hpws/apache/htdocs/index.html
[debug] worker.c(1342): taking over scoreboard slot from 29362 (quiescing)

 Another request finally came in to this system , which caused an error, and since there was only one server allowed to run it did and that is what killed this 
persistent connection.   This is what we have also observed that other apache requests will cause persistent connections to be terminated, as they don't close on their own.   And as said earlier this system's webserver doesn't get many hits, it is a test environment, not a production system.  And as we can see it took 40 minutes for any traffic to hit this system.  

  I hope this test is adequate to clear up the concerns that the testing is invalid.   

Best regards, Jay Bauer 
WTEC Engineer, Internet Services HP-UX
Hewlett Packard Co.

From Richard:


Excellent!

Submit that to bugs.php.net, and you have very good odds that it won't get marked bogus and ignored.

You got caught in the net of trigger-happy bug-bogus-marking
before, right?

It happens, but if you check through the size/scale of the bugs db...

In this case, you've clearly shown that nothing else is keeping the connection "alive"

Though, for one other wrinkle -- make some request after your timeout that does not "re-connect" to the persistent connection.

It's possible that PHP cannot shutdown the connection after the timeout unless it's being actively run by a non-db request, if you see what I mean.

Hi Richard,

  Yes there have been some trigger-happy, bug-bogus-marking going on, but that happens.

  And yes, this stays alive without anything going on.  And we have tested your "other wrinkle" and that is how we have been able to end the persistent connections by making connections to a non-oracle-db request which will terminate
the persistent connections.  The only other way has been to restart apache.  And I can redo the test with just one server and one connection and explicitly terminate the persistent connection by making a new non-oracle-db request.

 Thanks and regards, Jay 


Further Testing
------------------

This time I first enabled the access_log on maggie, so I had that history, and used browser windows to connect to http://maggie.india.hp.com/oracle_mufasa.php to set up a persistent connection and then about 15 minutes later in another browser connect to http://maggie.india.hp.com/.  Within that time there were no other attempts to connect to the web server.  The access_log gives the times quite clearly:

/opt/hpws/apache>more logs/access_log
16.113.41.14 - - [11/Oct/2006:20:16:03 +0530] 
"GET /oracle_mufasa.php HTTP/1.1" 200 334
16.113.41.14 - - [11/Oct/2006:20:31:52 +0530] 
"GET / HTTP/1.1" 200 1456
16.113.41.14 - - [11/Oct/2006:20:31:53 +0530]
"GET /apache_pb.gif HTTP/1.1" 200 2326

And the error_log entry is the same as seen in the test yesterday when the persistent connection was terminated by a random request.  It is good to confirm that under this restricted configuration those are the errors we are getting:

/opt/hpws/apache>tail logs/error_log  
...
[Wed Oct 11 20:31:52 2006] [error] [client 16.113.41.14] Symbolic link not llowed: /opt/hpws/apache/htdocs/index.html
[Wed Oct 11 20:31:53 2006] [debug] worker.c(1342): taking over scoreboard slot from 11077 (quiescing)
[Wed Oct 11 20:31:53 2006] [debug] util_ldap.c(1697): Initialisation of global mutex /opt/hpws/apache/ in child process 11267 successful.

  And using netstat and date we see the persistent connection stay ESTABLISHED till the non-oracle-db request comes in:

/user/jwbau>netstat -an|grep 1521
tcp        0      0  15.42.227.146.62365    15.106.72.129.1521      ESTABLISHED
/user/jwbau>date
Wed Oct 11 20:17:34 IST 2006

/user/jwbau>netstat -an|grep 1521
tcp        0      0  15.42.227.146.62365    15.106.72.129.1521      ESTABLISHED
/user/jwbau>date
Wed Oct 11 20:21:26 IST 2006

/user/jwbau>netstat -an|grep 1521
tcp        0      0  15.42.227.146.62365    15.106.72.129.1521      ESTABLISHED
/user/jwbau>date
Wed Oct 11 20:21:45 IST 2006

/user/jwbau>netstat -an|grep 1521
tcp        0      0  15.42.227.146.62365    15.106.72.129.1521      ESTABLISHED
/user/jwbau>date
Wed Oct 11 20:23:20 IST 2006

/user/jwbau>netstat -an|grep 1521
tcp        0      0  15.42.227.146.62365    15.106.72.129.1521      ESTABLISHED
/user/jwbau>date
Wed Oct 11 20:25:09 IST 2006

/user/jwbau>netstat -an|grep 1521
tcp        0      0  15.42.227.146.62365    15.106.72.129.1521      ESTABLISHED
/user/jwbau>date
Wed Oct 11 20:31:21 IST 2006

/user/jwbau>netstat -an|grep 1521
tcp        0      0  15.42.227.146.62365    15.106.72.129.1521      TIME_WAIT
/user/jwbau>date
Wed Oct 11 20:32:11 IST 2006

/user/jwbau>netstat -an|grep 1521
tcp        0      0  15.42.227.146.62365    15.106.72.129.1521      TIME_WAIT
/user/jwbau>date
Wed Oct 11 20:33:35 IST 2006

/user/jwbau>netstat -an|grep 1521
/user/jwbau>date
Wed Oct 11 20:34:26 IST 2006

 
Expectations
---------------

  At this point I hope there aren't any concerns about something else clouding up the issue that with the  oci8.persistent_timeout set at 10 seconds these connections will not terminate until Apache requires them for another non-oracle-db request.  If there are other concerns, please make  that concern clear, and we'll try to address it to your satisfaction.   And again what we are looking for here is that the documentation about the oci8.persistent_timeout and it's behavior match, which they do not do at this time.

 Thanks and regards, Jay Bauer 
Internet Services, World-Wide Expert Center, HP
 [2006-10-11 20:13 UTC] tony2001@php.net
>If I do not want the connection to be persist forever,
>then by using this setting, I should be able to ensure
>that a connection is not idle for longer than what I
>specified. However, when I set persistent_timeout to 10
>seconds, I find that the connection is not terminated 
>even after 10 seconds have passed.  In fact, it doesn&#8217;t 
>terminate at all. So the question is what
>is the purpose of this setting ? 

The purpose it to reduce number of open Oracle connections by closing IDLE connections.
A connection can be still there after the time out if this particular process was not reused since then.
Here is how it works:
1) each Apache childs maintains it's own list of persistent connections.
2) helper functions that check if it's time to close the connection are called _at shutdown_ of this particular Apache child.
When you set oci8.persistent_timeout to 10 seconds, it doesn't mean that all persistent connection will be closed 
in 10 seconds, but only if they were _not reused_ (the timeout is refreshed at this moment) and shutdown functions were called.

>And what does an 'idle connection' mean? 

"Idle connection" stands for "connection not being used anymore".
Since you wait for 10 seconds and then re-use the connection again, it is not considered "idle" at shutdown.

This is how it works and this is how it should work.
If you have any further questions - feel free to contact me directly, but please keep this report marked as bogus.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Apr 27 20:01:29 2024 UTC