ID: 47712
Updated by: [email protected]
Reported By: ninzya at inbox dot lv
Status: Feedback
Bug Type: MySQL related
Operating System: Windows XP
PHP Version: 5.3.0RC2
Assigned To: mysql
New Comment:
Hi, I switched on the zval cache and tried to reproduce the problem,
with no success.
I tested with Apache2 MPM. `ab` concurrency level starting from 20 up
to 100. Time from 30 to 45 seconds. I got, with your code, only 3 types
of errors. I added mysql_connect() myself
- mysql_connect() fails because cannot have more connections on the
unix socket. Using TCP/IP exhausts the resources earlier for connecting
to MySQL
- mysql_query() tries to connect, although the connection has failed,
typical for mysql_query()! It fails :
-- password problem
-- no resources
I did not see any corruption whatsoever. Difference from you is that I
tested on Linux, as server. ab was running on a Mac connected over a
FastEthernet switch.
Here follows the code I used:
<?php
$conn = mysql_connect("localhost", "root", "root");
mysql_select_db("test");
$result = mysql_query("SELECT a,b FROM stress_test");
if (!$result) {
echo 'Could not run query: ' . mysql_error();
exit;
}
/* Use the result, assuming we're done with it afterwards */
$row = mysql_fetch_assoc($result);
/* Now we free up the result and continue on with our script */
mysql_free_result($result);
var_dump($row);
?>
Previous Comments:
------------------------------------------------------------------------
[2009-06-08 10:36:49] [email protected]
Is is possible to provide a package which we can run, even it is not
20-30lines of code, so we can try to reproduce the problem?
In the meanwhile I have committed a change to mysqlnd which I suppose
should lead to the problem disappearing - switching the zval cache off.
Could you try downloading and testing a binary from
http://windows.php.net/snapshots/
New snapshot should be ready in a few hours. I suppose you will need
the VC6 build.
Thank you!
Andrey
------------------------------------------------------------------------
[2009-05-12 09:42:13] ninzya at inbox dot lv
This bug is still present in PHP 5.3.0RC2 and is critical to me.
------------------------------------------------------------------------
[2009-04-19 12:04:11] ninzya at inbox dot lv
Changed bug summary.
My configuration:
Apache 2.2,
PHP 5.3.0RC1 as module,
Windows XP SP3,
MySQL community server 5.1.33
Bug being hit during high concurrency running apache benchmark: "ab -c
30 -n 10000". See previous posts for details.
------------------------------------------------------------------------
[2009-04-12 15:08:30] ninzya at inbox dot lv
Please excuse me for the delay. I have been figuring out what's the
cause of this bug and finally i have something to come up with.
The problem is in mysql_free_result function. Not in itself, but it's
behavior has changed. Consider the following example from the PHP manual
on mysql_free_result:
Example #1 A mysql_free_result() example
<?php
$result = mysql_query("SELECT id,email FROM people WHERE id = '42'");
if (!$result) {
echo 'Could not run query: ' . mysql_error();
exit;
}
/* Use the result, assuming we're done with it afterwards */
$row = mysql_fetch_assoc($result);
/* Now we free up the result and continue on with our script */
mysql_free_result($result);
echo $row['id'];
echo $row['email'];
?>
This code with PHP 5.3.0 with mysqlnd will now fail under high
concurrency, because mysql_free_result will affect $row variable and
allow another threads to use it's zval to store data. I suspect that
mysql_free_result marks the referenced by $row data as 'free' and
another threads pick that zval up and work with it. As soon as you
release result, another thread may corrupt $row variable. Test this
example under high concurrency and you will get different values for
$row['id'] and $row['email']. Run 10000 req. test and some of them will
fail to produce correct output.
In my framework i use mysql_free_result before referencing last fetched
row of result set very often, that's why i hit this bug 'randomly'.
I have another example i just tested, this is part of my framework. The
idea is the same - mysql_free_result is being called before actually
using fetched data array.
$con =mysql_pconnect( 'localhost', 'root', '');
mysql_select_db( 'ewe10');
$q =mysql_query( $sql ='SELECT id, title, keywords, descr,
template_id, `title`, `keywords`, `descr`, `template_id`
FROM pages
WHERE node_id =11
AND alt_name =\'welcome\'
LIMIT 0, 1;', $con);
$row =mysql_fetch_assoc( $q);
mysql_free_result( $q);
if( $row['id'] ===null || $row['template_id'] !=8567 || $row['title']
!='My test page' || $row['keywords'] !='asdasd' || $row['descr']
!='asdasd') {
trigger_error( 'FAIL!', E_USER_WARNING);
trigger_error( 'SQL: ' .$sql, E_USER_WARNING);
ob_start();
var_dump( $row);
trigger_error( ob_get_clean(), E_USER_WARNING);
die('NOT OK');
}
die('OK');
SQL for the table:
CREATE TABLE `ewe10`.`pages` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'unique page
id',
`node_id` int(10) unsigned NOT NULL COMMENT 'node id in which this
page is',
`title` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
COMMENT 'page title',
`keywords` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
COMMENT 'page keywords',
`descr` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT
'page description',
`template_id` int(10) unsigned DEFAULT NULL COMMENT 'template this
page is using (if NULL, template was deleted from database and this page
is stored as a backup)',
`type` enum('MAIN','PAGE') CHARACTER SET latin1 NOT NULL DEFAULT
'PAGE' COMMENT 'page type',
`alt_name` varchar(45) CHARACTER SET latin1 NOT NULL COMMENT 'page
alternative name',
`date_add` datetime NOT NULL COMMENT 'when page was added',
PRIMARY KEY (`id`),
UNIQUE KEY `NODE_ID_ALT_NAME` (`node_id`,`alt_name`) USING BTREE,
KEY `FK_pages_templates` (`template_id`),
KEY `TYPE` (`type`),
KEY `FK_pages_map` (`node_id`),
KEY `DATE_ADD` (`date_add`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED;
the only row in this table is shown on the screenshot i referenced in
previous report.
To address the issue more quickly, i would like to give you a hint -
after calling mysql_free_result there is no possibility to fetch any
more rows, so there's nothing to worry about mysql_fetch_*(), but there
is possibility that the last fetched row may be referenced. This means -
even if mysql_free_result was called, last fetched row must remain
locked in mysqlnd internal zval cache until the variable is
implicitly/explicitly unset.
------------------------------------------------------------------------
[2009-04-07 13:21:59] [email protected]
Can you give me some more details about your system and the
configuration, please.
I spent some time with load testing different configurations now using
mysqlnd, pconnects, and PHP's thread-safe mode and wasn't able to
reproduce this issue.
Maybe even try to come up with the shortest script possible showing the
issue ...
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
http://bugs.php.net/47712
--
Edit this bug report at http://bugs.php.net/?id=47712&edit=1