Suddenly I have changed my mind ;)) It's not a problem of framework at all. It's a problem in mysqli itself. Seems like my browser cached data, so I've found that mysqli.php (from previous message) is hanging server too (!)
Anyway I think Zend_Db_Statement_Mysqli needs a simple destructor: public function __destruct() { $this->close(); } Unfortunately it will not help anyway. I'm going to bug report to PHP as it's a problem with mysqli extension. 2010/5/25 Aleksey Zapparov <i...@member.fsf.org>: > Yes. You are right! That's the problem and it's not :)) > > I have tested it with very dummy test (see attachment mysqli.php.gz) and > it works like a charm (against stormer provided before). So I have discovered > that the problem is in framework. > > The problem is that result cursor is never closed. Here's what happens in > sample application provided by me in one of previous messages. We have > following code: > > $news = new Automobili_Model_Table_News(); > $news->fetchAll($news->select()); > > In other words it can be written like this (to better understand): > > /** Zend_Db_Table_Abstract */ > $news = new Automobili_Model_Table_News(); > /** Zend_Db_Table_Select */ > $select = $news->select(); > > $news->fetchAll($select); > > The most interesting part here is fetchAll() which internally > calls protected method _fetch() which is clean enough: > > 1503 protected function _fetch(Zend_Db_Table_Select $select) > 1504 { > 1505 $stmt = $this->_db->query($select); > 1506 $data = $stmt->fetchAll(Zend_Db::FETCH_ASSOC); > 1507 return $data; > 1508 } > > Now, what we have here. This code creates a new object ($stmt) of > Zend_Db_Statement_Mysqli calls it's fetchAll() and returns it's result > (array of rows). And that's where all problems began. Statement > grabs results with standard mysqli functions, but it does not close > cursor automatically! > > After I spend another hour trying to implement some easy workarounds, > I found that there are no "easy" workaround at all. Except making some > modifications to Zend_Db_Adapter_Mysqli and Zend_Db_Adapter_Statement. > > Of course there's one easy workaround (and I'm pretty sure that some of > developers will say that it's a feature) - you can first, replace that > small code > for rows retrievement with something like this: > > $news = new Automobili_Model_Table_News(); > $select = $news->select(); > $stmt = $news->getAdapter()->query($select); > > $this->view->assign('rows', $stmt->fetchAll(Zend_Db::FETCH_OBJ)); > $stmt->closeCursor(); > $stmt->close(); > > and then add postDispatch hook with closing db handler: > > Zend_Db_Table_Abstract::getDefaultAdapter()->closeConnection(); > > > Unfortunatelly even this caused sample application (from previous post) > to hang server up after 130 requests. I'm gonna try to make some changes > to the Zend_Db_Adapter_Mysqli and Zend_Db_Statement_Mysqli today > or tomorrow and will share my investigation results :)) > > > 2010/5/25 Саша Стаменковић <umpir...@gmail.com>: >> Zend_Db_Statement in setFetchMode() calls $this->closeCursor(); only in >> default case for $mode, why not in other cases?! >> >> Regards, >> Saša Stamenković >> >> >> On Tue, May 25, 2010 at 4:37 PM, Aleksey Zapparov <i...@member.fsf.org> >> wrote: >>> >>> I'll prepare a dummy test with direct mysqli opertating - without using >>> Zend Framework at all - just to make sure that it's not a framework's >>> error. I'm pretty sure it's not but still want to have solid approvements. >>> >>> >>> 2010/5/25 Aleksey Zapparov <i...@member.fsf.org>: >>> > Forgotten trace and profiler info. >>> > >>> > 2010/5/25 Aleksey Zapparov <i...@member.fsf.org>: >>> >> Hello everybody again, >>> >> >>> >> Unfortunately I forgot to add CC to group, so we were discussing >>> >> problem >>> >> with Саша privately :)) But he mentioned that there left only two of >>> >> us, >>> >> so I'm repeating abridged summary of discussion. >>> >> >>> >> First of all, I successfully repeated error mentioned by Саша. It do >>> >> not >>> >> related with database engine (so I was able to successfully repeat it >>> >> with both MyISAM and InnoDB). >>> >> >>> >> I was keeping track of connections, while storming a server. And indeed >>> >> there were only ONE connection to the database. But after a 'storm' (in >>> >> fact 5-10 rapidly repeated requests was enough) server became down. >>> >> I'll >>> >> explain in details a little bit later. Here's dummy stormer in Ruby I >>> >> was using to reproduce an error: >>> >> >>> >> >>> >> require 'rubygems' >>> >> require 'httpclient' >>> >> >>> >> client = HTTPClient.new >>> >> uri = 'http://localhost/zfw' >>> >> status = 'ACTIVE' >>> >> >>> >> (1..128).each do >>> >> status = ('ACTIVE' == status) ? 'INACTIVE' : 'ACTIVE' >>> >> client.post(uri, { 'status' => status } >>> >> end >>> >> >>> >> >>> >> So after running this stormer, assuming 'http://localhost/zfw' is an >>> >> index action of index controller of our application which selects rows >>> >> from database (there were only 32 rows total in database on testing), >>> >> index action started throw Zend_Db_Adapter_Mysqli_Exception all the >>> >> time (until I have restarted Apache2 server). This exception had empty >>> >> message. Here's a trace: >>> >> >>> >> #0 /var/www/zfw-app/library/Zend/Db/Adapter/Abstract.php(304): >>> >> Zend_Db_Adapter_Mysqli->_connect() >>> >> #1 /var/www/zfw-app/library/Zend/Db/Adapter/Mysqli.php(194): >>> >> Zend_Db_Adapter_Abstract->getConnection() >>> >> #2 /var/www/zfw-app/library/Zend/Db/Table/Abstract.php(823): >>> >> Zend_Db_Adapter_Mysqli->describeTable('automobili_news', NULL) >>> >> #3 /var/www/zfw-app/library/Zend/Db/Table/Abstract.php(862): >>> >> Zend_Db_Table_Abstract->_setupMetadata() >>> >> #4 /var/www/zfw-app/library/Zend/Db/Table/Abstract.php(969): >>> >> Zend_Db_Table_Abstract->_setupPrimaryKey() >>> >> #5 /var/www/zfw-app/library/Zend/Db/Table/Select.php(100): >>> >> Zend_Db_Table_Abstract->info() >>> >> #6 /var/www/zfw-app/library/Zend/Db/Table/Select.php(78): >>> >> Zend_Db_Table_Select->setTable(Object(Automobili_Model_Table_News)) >>> >> #7 /var/www/zfw-app/library/Zend/Db/Table/Abstract.php(1005): >>> >> Zend_Db_Table_Select->__construct(Object(Automobili_Model_Table_News)) >>> >> #8 /var/www/zfw-app/application/controllers/IndexController.php(14): >>> >> Zend_Db_Table_Abstract->select() >>> >> #9 /var/www/zfw-app/library/Zend/Controller/Action.php(513): >>> >> IndexController->indexAction() >>> >> #10 >>> >> /var/www/zfw-app/library/Zend/Controller/Dispatcher/Standard.php(289): >>> >> Zend_Controller_Action->dispatch('indexAction') >>> >> #11 /var/www/zfw-app/library/Zend/Controller/Front.php(954): >>> >> >>> >> Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), >>> >> Object(Zend_Controller_Response_Http)) >>> >> #12 >>> >> /var/www/zfw-app/library/Zend/Application/Bootstrap/Bootstrap.php(97): >>> >> Zend_Controller_Front->dispatch() >>> >> #13 /var/www/zfw-app/library/Zend/Application.php(366): >>> >> Zend_Application_Bootstrap_Bootstrap->run() >>> >> #14 /var/www/zfw-app/public/index.php(26): Zend_Application->run() >>> >> #15 {main} >>> >> >>> >> >>> >> For those who are interested in details I have attached an xdebug >>> >> trace as an attachment (trace.xt.gz) and xdebug profiler data >>> >> (cachegrind.out.gz). >>> >> >>> >> After all I have switched config to use pdo_mysql instead of mysqli and >>> >> was able to run my (previously described) stormer without any problems >>> >> even with 1024 requests. So I guess there's something wrong with mysqli >>> >> adapter (of PHP). >>> >> >>> >> >>> >> 2010/5/25 Саша Стаменковић <umpir...@gmail.com>: >>> >>> Zend_Db_Statement ин setFetchMode() calls $this->closeCursor(); only >>> >>> in >>> >>> default case fro $mode ?! >>> >>> >>> >>> Regards, >>> >>> Saša Stamenković >>> >>> >>> >>> >>> >>> On Tue, May 25, 2010 at 11:40 AM, Саша Стаменковић >>> >>> <umpir...@gmail.com> >>> >>> wrote: >>> >>>> >>> >>>> Cache can be the temporary fix. >>> >>>> >>> >>>> Regards, >>> >>>> Saša Stamenković >>> >>>> >>> >>>> >>> >>>> On Tue, May 25, 2010 at 11:35 AM, Саша Стаменковић >>> >>>> <umpir...@gmail.com> >>> >>>> wrote: >>> >>>>> >>> >>>>> I found where the problem was! >>> >>>>> $newsTable->publishNews($ids); >>> >>>>> foreach ($newsTable->fetchNewsByIds($ids) as $news) { >>> >>>>> $news->publishOnTwitter(); >>> >>>>> } >>> >>>>> Row have this publish on twitter method, which shouldn't have >>> >>>>> nothing to >>> >>>>> do with the problem - WRONG! It has. When I post it on twitter, a >>> >>>>> great >>> >>>>> amount of traffic is generated, people are opening concrete news and >>> >>>>> break >>> >>>>> my limit of 15 connections. >>> >>>>> Looks like I need more connections, heh. >>> >>>>> Regards, >>> >>>>> Saša Stamenković >>> >>>>> >>> >>>>> >>> >>>>> On Tue, May 25, 2010 at 10:57 AM, Саша Стаменковић >>> >>>>> <umpir...@gmail.com> >>> >>>>> wrote: >>> >>>>>> >>> >>>>>> BTW, my limit is not >>> >>>>>> mysqli.max_links = 15 >>> >>>>>> its a property of mysql.user table, MAX_USER_CONNECTIONS. >>> >>>>>> http://dev.mysql.com/doc/refman/5.1/en/user-resources.html >>> >>>>>> >>> >>>>>> Regards, >>> >>>>>> Saša Stamenković >>> >>>>>> >>> >>>>>> >>> >>>>>> On Mon, May 24, 2010 at 11:44 PM, Aleksey Zapparov >>> >>>>>> <i...@member.fsf.org> >>> >>>>>> wrote: >>> >>>>>>> >>> >>>>>>> Hello, >>> >>>>>>> >>> >>>>>>> Was not able to wait until tomorow to test on FreeBSD as it was >>> >>>>>>> really >>> >>>>>>> interesting for will it work or not. And it does. Here's mysqli >>> >>>>>>> config >>> >>>>>>> of my >>> >>>>>>> php.ini on FreeBSD: >>> >>>>>>> >>> >>>>>>> mysqli.max_links = 15 >>> >>>>>>> mysqli.default_port = 3306 >>> >>>>>>> mysqli.default_socket = >>> >>>>>>> mysqli.default_host = >>> >>>>>>> mysqli.default_user = >>> >>>>>>> mysqli.default_pw = >>> >>>>>>> mysqli.reconnect = Off >>> >>>>>>> >>> >>>>>>> You can see it's working at: http://sandbox.ixti.ru/zfw/ (it will >>> >>>>>>> be >>> >>>>>>> available >>> >>>>>>> at least until 27th of May 2010). >>> >>>>>>> >>> >>>>>>> >>> >>>>>>> 2010/5/24 Aleksey Zapparov <i...@member.fsf.org>: >>> >>>>>>> > Hello, >>> >>>>>>> > >>> >>>>>>> > I guess you are doing something wrong. I have just build up a >>> >>>>>>> > little >>> >>>>>>> > app from >>> >>>>>>> > scratch with zf tool (attachment app.tar.gz) which simply >>> >>>>>>> > "batch" >>> >>>>>>> > updates >>> >>>>>>> > 32 rows with new status - very dumy logic in controller: >>> >>>>>>> > >>> >>>>>>> > $news = new Automobili_Model_Table_News(); >>> >>>>>>> > $ids = range(1,32); >>> >>>>>>> > >>> >>>>>>> > $news->update( >>> >>>>>>> > array('status' => $status), >>> >>>>>>> > $news->getAdapter()->quoteInto('id IN (?)', $ids, >>> >>>>>>> > Zend_Db::INT_TYPE) >>> >>>>>>> > ); >>> >>>>>>> > >>> >>>>>>> > And it works good for me at least on my GNU/Linux. >>> >>>>>>> > Here's my php.ini (section of MySQLi): >>> >>>>>>> > >>> >>>>>>> > mysqli.max_persistent = 15 >>> >>>>>>> > mysqli.allow_persistent = Off >>> >>>>>>> > mysqli.max_links = 15 >>> >>>>>>> > mysqli.cache_size = 2000 >>> >>>>>>> > mysqli.default_port = 3306 >>> >>>>>>> > mysqli.default_socket = >>> >>>>>>> > mysqli.default_host = >>> >>>>>>> > mysqli.default_user = >>> >>>>>>> > mysqli.default_pw = >>> >>>>>>> > mysqli.reconnect = Off >>> >>>>>>> > >>> >>>>>>> > >>> >>>>>>> > I have a FreeBSD running host so tomorow I'm gonna check this >>> >>>>>>> > app >>> >>>>>>> > against >>> >>>>>>> > it. Anyway you can try my dummy app by yourself (I've removed >>> >>>>>>> > some >>> >>>>>>> > portion >>> >>>>>>> > from your News table class (which was referring to another >>> >>>>>>> > model) to >>> >>>>>>> > be able >>> >>>>>>> > run this code). >>> >>>>>>> > >>> >>>>>>> > Attached files are: >>> >>>>>>> > app.tar.gz - Application itself >>> >>>>>>> > dump.sql.gz - MySQL dump of table (I have used to test) >>> >>>>>>> > >>> >>>>>>> > >>> >>>>>>> > 2010/5/24 Саша Стаменковић <umpir...@gmail.com>: >>> >>>>>>> >> Okay, I'm using one connection, one db, one adapter, but still, >>> >>>>>>> >> I >>> >>>>>>> >> have >>> >>>>>>> >> problems. I'm pretty sure I'm using it right, because I'm using >>> >>>>>>> >> it >>> >>>>>>> >> like it >>> >>>>>>> >> says in the doc. >>> >>>>>>> >> The problem is, I can exec up to 15 queries in the row, and >>> >>>>>>> >> this >>> >>>>>>> >> quoteInto >>> >>>>>>> >> with array param is hitting my limits. >>> >>>>>>> >> I can send you my code on private mail Thomas. >>> >>>>>>> >> >>> >>>>>>> >> Regards, >>> >>>>>>> >> Saša Stamenković >>> >>>>>>> >> >>> >>>>>>> >> >>> >>>>>>> >> On Mon, May 24, 2010 at 9:27 PM, Thomas D. >>> >>>>>>> >> <whist...@googlemail.com> >>> >>>>>>> >> wrote: >>> >>>>>>> >>> >>> >>>>>>> >>> Hi, >>> >>>>>>> >>> >>> >>>>>>> >>> Саша Стаменковић wrote: >>> >>>>>>> >>> > Sure, when you have unlimited number of db operation over >>> >>>>>>> >>> > a period of time. I'll come up with my own offline quoting. >>> >>>>>>> >>> >>> >>>>>>> >>> Seems like you are missing one fact all over the time: >>> >>>>>>> >>> That quoting would use a connection to a database server, >>> >>>>>>> >>> isn't a >>> >>>>>>> >>> problem, >>> >>>>>>> >>> because Zend_Db_* would use one connection across every >>> >>>>>>> >>> component. >>> >>>>>>> >>> Only if >>> >>>>>>> >>> you are working with multiple databases, it might be a >>> >>>>>>> >>> problem, >>> >>>>>>> >>> because you >>> >>>>>>> >>> would have one adapter per database (=nAdapter * 1 Connection >>> >>>>>>> >>> = n >>> >>>>>>> >>> connections)... >>> >>>>>>> >>> >>> >>>>>>> >>> So again: >>> >>>>>>> >>> When you are working with just *one* database, everything >>> >>>>>>> >>> should >>> >>>>>>> >>> work >>> >>>>>>> >>> fine. >>> >>>>>>> >>> If not, *you* are doing something wrong. >>> >>>>>>> >>> >>> >>>>>>> >>> Doing your own quoting is everything but not safe. You should >>> >>>>>>> >>> use >>> >>>>>>> >>> the >>> >>>>>>> >>> adapter's escape function, if your application should be safe. >>> >>>>>>> >>> >>> >>>>>>> >>> >>> >>>>>>> >>> -- >>> >>>>>>> >>> Regards, >>> >>>>>>> >>> Thomas >>> >>>>>>> >>> >>> >>>>>>> >>> >>> >>>>>>> >> >>> >>>>>>> >> >>> >>>>>>> > >>> >>>>>>> > >>> >>>>>>> > >>> >>>>>>> > -- >>> >>>>>>> > Sincerely yours, >>> >>>>>>> > Aleksey V. Zapparov A.K.A. ixti >>> >>>>>>> > FSF Member #7118 >>> >>>>>>> > Mobile Phone: +34 617 179 344 >>> >>>>>>> > Homepage: http://www.ixti.ru >>> >>>>>>> > JID: zappa...@jabber.ru >>> >>>>>>> > >>> >>>>>>> > *Origin: Happy Hacking! >>> >>>>>>> > >>> >>>>>>> >>> >>>>>>> >>> >>>>>>> >>> >>>>>>> -- >>> >>>>>>> Sincerely yours, >>> >>>>>>> Aleksey V. Zapparov A.K.A. ixti >>> >>>>>>> FSF Member #7118 >>> >>>>>>> Mobile Phone: +34 617 179 344 >>> >>>>>>> Homepage: http://www.ixti.ru >>> >>>>>>> JID: zappa...@jabber.ru >>> >>>>>>> >>> >>>>>>> *Origin: Happy Hacking! >>> >>>>>> >>> >>>>> >>> >>>> >>> >>> >>> >>> >>> >> >>> >> >>> >> >>> >> -- >>> >> Sincerely yours, >>> >> Aleksey V. Zapparov A.K.A. ixti >>> >> FSF Member #7118 >>> >> Mobile Phone: +34 617 179 344 >>> >> Homepage: http://www.ixti.ru >>> >> JID: zappa...@jabber.ru >>> >> >>> >> *Origin: Happy Hacking! >>> >> >>> > >>> > >>> > >>> > -- >>> > Sincerely yours, >>> > Aleksey V. Zapparov A.K.A. ixti >>> > FSF Member #7118 >>> > Mobile Phone: +34 617 179 344 >>> > Homepage: http://www.ixti.ru >>> > JID: zappa...@jabber.ru >>> > >>> > *Origin: Happy Hacking! >>> > >>> >>> >>> >>> -- >>> Sincerely yours, >>> Aleksey V. Zapparov A.K.A. ixti >>> FSF Member #7118 >>> Mobile Phone: +34 617 179 344 >>> Homepage: http://www.ixti.ru >>> JID: zappa...@jabber.ru >>> >>> *Origin: Happy Hacking! >> >> > > > > -- > Sincerely yours, > Aleksey V. Zapparov A.K.A. ixti > FSF Member #7118 > Mobile Phone: +34 617 179 344 > Homepage: http://www.ixti.ru > JID: zappa...@jabber.ru > > *Origin: Happy Hacking! > -- Sincerely yours, Aleksey V. Zapparov A.K.A. ixti FSF Member #7118 Mobile Phone: +34 617 179 344 Homepage: http://www.ixti.ru JID: zappa...@jabber.ru *Origin: Happy Hacking!