Ticket #368: ModelGlue_ticket368_lockAndLoad.patch

File ModelGlue_ticket368_lockAndLoad.patch, 14.3 kB (added by boomfish, 16 years ago)

Patch against trunk that implements a "lock-and-load" solution to the framework initalization issue

  • ModelGlue/gesture/ModelGlue.cfm

     
    88<cfparam name="ModelGlue_LOCAL_COLDSPRING_DEFAULT_ATTRIBUTES" default="#structNew()#" /> 
    99<cfparam name="ModelGlue_LOCAL_COLDSPRING_DEFAULT_PROPERTIES" default="#structNew()#" /> 
    1010<cfparam name="ModelGlue_VERSION_INDICATOR" default="GESTURE" /> 
     11<cfparam name="ModelGlue_INITIALIZATION_LOCK_TIMEOUT" default="60" /> 
    1112<cfparam name="request._modelglue.bootstrap" default="#structNew()#" /> 
    1213<cfparam name="request._modelglue.bootstrap.blockEvent" default="0" /> 
    1314 
    1415<cfset request._modelglue.bootstrap.initializationRequest = false /> 
    1516<cfset request._modelglue.bootstrap.appKey = ModelGlue_APP_KEY /> 
     17<cfset request._modelglue.bootstrap.initializationLockPrefix = expandPath(".") & "/.modelglue" /> 
     18<cfset request._modelglue.bootstrap.initializationLockTimeout = ModelGlue_INITIALIZATION_LOCK_TIMEOUT /> 
    1619 
    1720<cfif not structKeyExists(application, ModelGlue_APP_KEY)  
    1821                        or ( 
     
    2225                        or ( 
    2326                                        application[ModelGlue_APP_KEY].configuration.reload 
    2427                        )> 
    25         <cflock name="#expandPath(".")#/.modelglue.loading" type="exclusive" timeout="60"> 
     28        <cflock name="#request._modelglue.bootstrap.initializationLockPrefix#.loading" type="exclusive" timeout="#request._modelglue.bootstrap.initializationLockTimeout#"> 
    2629                <cfif not structKeyExists(application, ModelGlue_APP_KEY) 
    2730                                        or ( 
    2831                                                        structKeyExists(url, application[ModelGlue_APP_KEY].configuration.reloadKey) 
  • ModelGlue/gesture/eventrequest/EventContext.cfc

     
    150150        <cftry> 
    151151                <cfif isArray(variables._requestPhases) and arrayLen(variables._requestPhases)> 
    152152                        <cfloop from="1" to="#arrayLen(variables._requestPhases)#" index="i"> 
    153                                 <cfset this.addTraceStatement(variables._requestPhases[i].name, "Beginning request phase.") />  
    154                                  
    155                                 <cfset variables._requestPhases[i].execute(this) /> 
    156                                  
     153                                <cfset this.addTraceStatement(variables._requestPhases[i].name, "Setting up request phase.") />  
     154                                <cfset variables._requestPhases[i].setup(this,request._modelglue.bootstrap.initializationLockPrefix,request._modelglue.bootstrap.initializationLockTimeout) /> 
     155                                <cfset this.addTraceStatement(variables._requestPhases[i].name, "Executing request phase.") />  
     156                                <cfset variables._requestPhases[i].execute(this) />                              
    157157                                <cfset this.addTraceStatement(variables._requestPhases[i].name, "Request phase complete.") />  
    158158                        </cfloop> 
    159159                <cfelse> 
  • ModelGlue/gesture/eventrequest/phase/Initialization.cfc

     
    44         
    55<cfset this.name = "Initialization" /> 
    66         
    7 <cffunction name="execute" returntype="void" output="false" hint="Executes the request phase."> 
    8         <cfargument name="eventContext" hint="I am the event context to act upon.  Duck typed for speed.  Should have no queued events when execute() is called, but this isn't checked (to save time)." /> 
     7<cffunction name="load" access="private" returntype="void" output="false" hint="I perform the loading for this phase."> 
     8        <cfargument name="eventContext" hint="I am the event context to use for loading.  Duck typed for speed.  Should have no queued events, but this isn't checked (to save time)." /> 
    99         
    1010        <cfset var modelglue = arguments.eventContext.getModelGlue() /> 
    1111        <cfset var event = "" /> 
    1212         
    13         <!--- Only do anything if this is a initialization request. ---> 
    14         <cfif request._modelglue.bootstrap.initializationRequest> 
    15                 <!---  
    16                         Before event queue runs, we need to load any configured modules. 
    17                 ---> 
    18                  
    19                 <cfset loadModules(modelglue) /> 
    20                  
    21                 <!--- Add the newly loaded event to the queue. ---> 
    22                 <cfset event =  modelglue.getEventHandler("modelglue.onApplicationInitialization") /> 
    23                 <cfset arguments.eventContext.addEventHandler(event) /> 
    24                  
    25                 <!--- Tell the context to run its queue. ---> 
    26                 <cfset arguments.eventContext.executeEventQueue() /> 
     13        <cfset super.load(arguments.eventContext) /> 
    2714         
    28                 <cfset event =  modelglue.getEventHandler("modelglue.onApplicationStoredInScope") /> 
    29                 <cfset arguments.eventContext.addEventHandler(event) /> 
    30         </cfif>  
     15        <!--- Add the newly loaded event to the queue. ---> 
     16        <cfset event =  modelglue.getEventHandler("modelglue.onApplicationInitialization") /> 
     17        <cfset arguments.eventContext.addEventHandler(event) /> 
     18         
     19        <!--- Tell the context to run its queue. ---> 
     20        <cfset arguments.eventContext.executeEventQueue() /> 
     21 
     22        <cfset event =  modelglue.getEventHandler("modelglue.onApplicationStoredInScope") /> 
     23        <cfset arguments.eventContext.addEventHandler(event) /> 
     24</cffunction> 
     25 
     26<cffunction name="execute" returntype="void" output="false" hint="Executes the request phase."> 
     27        <cfargument name="eventContext" hint="I am the event context to act upon.  Duck typed for speed.  Should have no queued events when execute() is called, but this isn't checked (to save time)." /> 
     28 
     29        <!--- This is a load-only phase: Nothing to do on execute ---> 
    3130</cffunction> 
    3231 
    3332</cfcomponent> 
     33 No newline at end of file 
  • ModelGlue/gesture/eventrequest/phase/ModuleLoadingRequestPhase.cfc

     
    1010        <cfset variables._modules = arguments.modules />         
    1111</cffunction> 
    1212 
    13 <cffunction name="loadModules" access="private" output="false" hint="Loads modules associated with this phase if we're in an initializing request."> 
     13<cffunction name="load" access="private" returntype="void" output="false" hint="I perform the loading for this phase."> 
     14        <cfargument name="eventContext" hint="I am the event context to use for loading.  Duck typed for speed.  Should have no queued events, but this isn't checked (to save time)." /> 
     15         
     16        <cfset loadModules(arguments.eventContext.getModelGlue()) /> 
     17</cffunction> 
     18 
     19<cffunction name="loadModules" access="private" output="false" hint="Loads modules associated with this phase."> 
    1420        <cfargument name="modelglue" /> 
    1521         
    1622        <cfset var i = "" /> 
    1723         
    18         <cfif request._modelglue.bootstrap.initializationRequest> 
    19                 <cfloop from="1" to="#arrayLen(variables._modules)#" index="i"> 
    20                         <cfset variables._moduleLoader.load(modelglue, variables._modules[i]) /> 
    21                 </cfloop> 
    22         </cfif> 
     24        <cfloop from="1" to="#arrayLen(variables._modules)#" index="i"> 
     25                <cfset variables._moduleLoader.load(modelglue, variables._modules[i]) /> 
     26        </cfloop> 
    2327</cffunction> 
    2428 
    2529</cfcomponent> 
     30 No newline at end of file 
  • ModelGlue/gesture/eventrequest/phase/Configuration.cfc

     
    44 
    55<cfset this.name = "Configuration" /> 
    66 
    7 <cffunction name="execute" returntype="void" output="false" hint="Executes the request phase."> 
    8         <cfargument name="eventContext" hint="I am the event context to act upon.  Duck typed for speed.  Should have no queued events when execute() is called, but this isn't checked (to save time)." /> 
     7<cffunction name="load" access="private" returntype="void" output="false" hint="I perform the loading for this phase."> 
     8        <cfargument name="eventContext" hint="I am the event context to use for loading.  Duck typed for speed.  Should have no queued events, but this isn't checked (to save time)." /> 
    99         
    1010        <cfset var modelglue = arguments.eventContext.getModelGlue() /> 
    1111        <cfset var event = "" /> 
    1212         
    13         <!--- Only do anything if this isn't an initialization request. ---> 
    14         <cfif request._modelglue.bootstrap.initializationRequest> 
    15                 <!---  
    16                         Before event queue runs, we need to load any configured modules. 
    17                 ---> 
    18                 <cfset loadModules(modelglue) /> 
    19                  
    20                 <!--- Add the newly loaded event to the queue. ---> 
    21                 <cfset event =  modelglue.getEventHandler("modelglue.readyForModuleLoading") /> 
    22                 <cfset arguments.eventContext.addEventHandler(event) /> 
    23                 <cfset event =  modelglue.getEventHandler("modelglue.modulesLoaded") /> 
    24                 <cfset arguments.eventContext.addEventHandler(event) /> 
    25                  
    26                 <!--- Tell the context to run its queue. ---> 
    27                 <cfset arguments.eventContext.executeEventQueue() /> 
    28         </cfif> 
     13        <cfset super.load(arguments.eventContext) /> 
     14         
     15        <!--- Add the newly loaded event to the queue. ---> 
     16        <cfset event =  modelglue.getEventHandler("modelglue.readyForModuleLoading") /> 
     17        <cfset arguments.eventContext.addEventHandler(event) /> 
     18        <cfset event =  modelglue.getEventHandler("modelglue.modulesLoaded") /> 
     19        <cfset arguments.eventContext.addEventHandler(event) /> 
     20         
     21        <!--- Tell the context to run its queue. ---> 
     22        <cfset arguments.eventContext.executeEventQueue() /> 
     23</cffunction> 
     24 
     25<cffunction name="execute" returntype="void" output="false" hint="Executes the request phase."> 
     26        <cfargument name="eventContext" hint="I am the event context to act upon.  Duck typed for speed.  Should have no queued events when execute() is called, but this isn't checked (to save time)." /> 
     27 
     28        <!--- This is a load-only phase: Nothing to do on execute ---> 
    2929</cffunction> 
    3030 
    3131</cfcomponent> 
     32 No newline at end of file 
  • ModelGlue/gesture/eventrequest/phase/Population.cfc

     
    1010        <cfset var modelglue = arguments.eventContext.getModelGlue() /> 
    1111        <cfset var event = "" /> 
    1212         
    13         <!---  
    14                 Before event queue runs, we need to load any configured modules. 
    15         ---> 
    16         <cfset loadModules(modelglue) /> 
    17          
    1813        <!--- Add the newly loaded event to the queue. ---> 
    1914        <cfset event =  modelglue.getEventHandler("modelglue.onEventContextCreation") /> 
    2015        <cfset arguments.eventContext.addEventHandler(event) /> 
  • ModelGlue/gesture/eventrequest/phase/Invocation.cfc

     
    44 
    55<cfset this.name = "Invocation" /> 
    66 
     7<cffunction name="load" access="private" returntype="void" output="false" hint="I perform the loading for this phase."> 
     8        <cfargument name="eventContext" hint="I am the event context to use for loading.  Duck typed for speed.  Should have no queued events, but this isn't checked (to save time)." /> 
     9         
     10        <cfset var modelglue = arguments.eventContext.getModelGlue() /> 
     11        <cfset var event = "" /> 
     12         
     13        <cfset super.load(arguments.eventContext) /> 
     14         
     15        <!--- onApplicationStart ---> 
     16        <cfset event =  modelglue.getEventHandler("modelglue.onApplicationStart") /> 
     17        <cfset arguments.eventContext.addEventHandler(event) /> 
     18</cffunction> 
     19 
    720<cffunction name="execute" returntype="void" output="false" hint="Executes the request phase."> 
    821        <cfargument name="eventContext" hint="I am the event context to act upon.  Duck typed for speed.  Should have no queued events when execute() is called, but this isn't checked (to save time)." /> 
    922 
     
    1225        <cfset var initialEventHandler = "" /> 
    1326        <cfset var event = "" /> 
    1427 
    15         <cfset loadModules(modelglue) /> 
    16          
    17         <!--- onApplicationStart ---> 
    18         <cfif request._modelglue.bootstrap.initializationRequest> 
    19                 <cfset event =  modelglue.getEventHandler("modelglue.onApplicationStart") /> 
    20                 <cfset arguments.eventContext.addEventHandler(event) /> 
    21         </cfif> 
    22  
    2328        <!--- onSessionStart ---> 
    2429        <cfif structKeyExists(request._modelglue.bootstrap, "sessionStart")> 
    2530                <cfset event =  modelglue.getEventHandler("modelglue.onSessionStart") /> 
  • ModelGlue/gesture/eventrequest/EventRequestPhase.cfc

     
    11<cfcomponent output="false" hint="I represent a phase inside of an event request.  I'm basically a Command script for how this phase should execute."> 
    22 
    33<cfset this.name = "Unknown request phase." /> 
     4<cfset this.loaded = false /> 
     5 
     6<cffunction name="setup" returntype="void" output="false" hint="I make sure the phase is loaded exactly once."> 
     7        <cfargument name="eventContext" hint="I am the event context to use for loading.  Duck typed for speed.  Should have no queued events, but this isn't checked (to save time)." /> 
     8        <cfargument name="lockPrefix" type="string" required="true" hint="Prefix for name of lock to use for setup" /> 
     9        <cfargument name="lockTimeout" type="numeric" required="true" hint="Timeout for setup lock" /> 
     10         
     11        <cfif not this.loaded> 
     12                <cflock type="exclusive" name="#arguments.lockPrefix#.phase.#this.name#.loading" timeout="#arguments.lockTimeout#"> 
     13                        <!--- Load could have been completed by a thread which held the lock before this thread, so check again ---> 
     14                        <cfif not this.loaded> 
     15                                <cfset load(arguments.eventContext) /> 
     16                                <cfset this.loaded = true /> 
     17                        </cfif> 
     18                </cflock> 
     19        </cfif> 
     20</cffunction> 
     21 
     22<cffunction name="load" access="private" returntype="void" output="false" hint="I perform the loading for this phase."> 
     23        <cfargument name="eventContext" hint="I am the event context to use for loading.  Duck typed for speed.  Should have no queued events, but this isn't checked (to save time)." /> 
     24        <!---  
     25                Custom phases:  
     26                 
     27                Put things to do _before_ the first execute. 
     28        ---> 
     29</cffunction> 
    430 
    531<cffunction name="execute" returntype="void" output="false" hint="Executes the request phase."> 
    632        <cfargument name="eventContext" hint="I am the event context to act upon.  Duck typed for speed.  Should have no queued events when execute() is called, but this isn't checked (to save time)." />