Ticket #420 (assigned defect)
Performance issue with XMLModuleLoader
| Reported by: | cfjedimaster | Owned by: | boomfish |
|---|---|---|---|
| Priority: | normal | Milestone: | 3.2 |
| Version: | 3.1.299 | Severity: | normal |
| Keywords: | Cc: |
Description (last modified by boomfish) (diff)
I believe I sent in a message about this a few months ago, but it hit us again at work so I thought I'd check back. I believe there is a serious MG issue when your application has a mapping that points to a large set of CFCs. By that I mean - our application has one mapping, migration, that points to a folder w/ thousands of files. When I last found this issue, I noticed that CFC creation was hella slow because createObject tried to scan the folder. What I found today seems related.
So - here are the details.
XMLModuleLoader has a method, loadEventHandlers, that loads up your event handlers. Here is a loop that comprises most of the logic.
<cftry>
<cflog file="timer" text="trying to load
#ehXml.xmlAttributes.name#/#ehXml.xmlAttributes.type# xml
#isXmlTypeList#">
<!--- If the event-handler already exists, get a reference to it --->
<cfif modelglue.hasEventHandler(ehXml.xmlAttributes.name)>
<cflog file="timer" text="The EH already existed. Woot.">
<cfset ehInst = modelglue.getEventHandler(ehXml.xmlAttributes.name) />
<!--- If it's not an "extensible" event-handler, create a new eh object--->
<cfif not ehInst.extensible>
<cfset ehInst = ehFactory.create("EventHandler") />
</cfif>
<!--- Otherwise, try to instantiate the type. --->
<cfelse>
<cflog file="timer" text="Going to try to make it:
#serializejson(getmetadata(ehfactory))#">
<cfset ehInst = ehFactory.create(ehXml.xmlAttributes.type) >
</cfif>
<!--- If the type is not found, force a base EventHandler to be created --->
<cfcatch>
<cflog file="timer" text="I had to make a base EH">
<cfset ehInst = ehFactory.create("EventHandler") />
</cfcatch>
</cftry>
Obviously the logs are mine. For each EH, it will attempt to create it if it doesn't exist. It uses ehFactory. If an error occurs, the catch is thrown and a base is used.
I noticed that when my XML had 20 events, all using ONE event type called generic, that MG took 4-5 seconds for every single event. It never noticed the fact that a) generic was XML, not a CFC and that b) it tried to load it and failed anyway. It constantly tried to reload the exact same type every time. What's odd is - prior to this, there is code to see if it is an XML type:
<cfif structKeyExists(variables.eventTypes, ehXml.xmlAttributes.type)
or find(",", ehXml.xmlAttributes.type)
>
<cfset isXmlTypeList = "true" />
</cfif>
So I modified that try/catch branch like so:
<cftry>
<cflog file="timer" text="trying to load
#ehXml.xmlAttributes.name#/#ehXml.xmlAttributes.type# xml
#isXmlTypeList#">
<!--- If the event-handler already exists, get a reference to it --->
<cfif modelglue.hasEventHandler(ehXml.xmlAttributes.name)>
<cflog file="timer" text="The EH already existed. Woot.">
<cfset ehInst = modelglue.getEventHandler(ehXml.xmlAttributes.name) />
<!--- If it's not an "extensible" event-handler, create a new eh object--->
<cfif not ehInst.extensible>
<cfset ehInst = ehFactory.create("EventHandler") />
</cfif>
<!--- Otherwise, try to instantiate the type. --->
<cfelseif not isXmlTypeList>
<cflog file="timer" text="Going to try to make it:
#serializejson(getmetadata(ehfactory))#">
<cfset ehInst = ehFactory.create(ehXml.xmlAttributes.type) >
<cfelse>
<cfset ehInst = ehFactory.create("EventHandler") />
</cfif>
<!--- If the type is not found, force a base EventHandler to be created --->
<cfcatch>
<cflog file="timer" text="I had to make a base EH">
<cfset ehInst = ehFactory.create("EventHandler") />
</cfcatch>
</cftry>
Notice the new cfelseif? When I did this loading went from around 1.5 minutes to about 15 seconds.
![(please configure the [header_logo] section in trac.ini)](/ModelGlue.com/trac.cgi/chrome/site/your_project_logo.png)