Ticket #842 (defect)

Opened 3 months ago

InvalidOperationException with APC due to late/early binding issues

Status: new

Reported by: mikl Assigned to: xue
Priority: normal Milestone: 3.1.3
Component: Prado Framework v3 Version: 3.1
Severity: crash Keywords:
Cc:

Problem description

When using APC there sometimes occur exceptions like these:

TInvalidOperationException
Description

Unknown component type 'TMysqlCommandBuilder'. This may be caused 
by the following parsing error in the TMysqlCommandBuilder class 
file: [Warning] PradoBase::include_once(TDbCommandBuilder.php) 
[<a href='function.PradoBase-include-once'>function.PradoBase-include-once</a>]: 
failed to open stream: No such file or directory (@line 96 in file 
C:\EclipseWorkspace\Prado-svn\framework\PradoBase.php).

The error can also occur with other classes. I've also seen it with ActiveRecordRelations?.

Steps to reproduce

Due to the complex nature of the problem it looks at first like the problem only appears sporadically. But it can be reproduced with a setup like this (APC 3.0.18):

  • In application.xml add both: an ActiveRecord? and a SqlMap? configuration
  • Create a page A that OnLoad? does a dummy request using SqlMap?
  • Create a page B that OnLoad? does a dummy request using ActiveRecord?
  • Restart apache or clear APC opcode cache
  • First load A then B -> Error occurs

If you do the same and first load B then A the error does not occur.

Workaround

This is not a fix but a workaround. Put the path where the missing class resides into a using statement in application.xml:

<using namespace="System.Data.Common.*"/>

or

<using namespace="System.Data.ActiveRecord.Relations.*"/>

Analysis

The error seems to be related to a known APC problem with early/late binding. More information on this can be found here: http://pecl.php.net/bugs/bug.php?id=6503. Main reason is dynamic/conditional inclusion of classes with complex inheritance structure.

To get more evidence for this i enabled apc.report_autofilter on my site, which logs any classes that where filtered by APC due to this issue. That gave me these messages in my logfile:

[Sun Apr 27 13:17:38 2008] [apc-warning] Dynamic inheritance detected for class tmysqlcommandbuilder
[Sun Apr 27 13:17:38 2008] [apc-warning] Autofiltering C:\EclipseWorkspace\Prado-svn\framework\Data\Common\Mysql\TMysqlCommandBuilder.php
[Sun Apr 27 13:17:38 2008] [apc-warning] Recompiling ¨×¨×X=

As Rasmus Lerdorf explains in the link above, for APC "the first request after a server restart sets the tone for the remaining requests until you either restart or change one of the files in question".

He continues: The reason being that if the first request which triggers the cache insert of a particular file is a conditional include which pushes the class definition into the executor, then the cached opcodes will include the FETCH_CLASS call and you will always be doing late binding. This is slow, but will always work. If, on the other hand, the first request is a non-conditional top-level include then the early binding optimization kicks in and the cached opcode array won't include the FETCH_CLASS which means that a later conditional include on that same file will then exhibit the problem.

I'm not sure if and how we can fix this problem on Prado's side. But we shouldn't expect to get this fixed soon in APC.