ColdFusion VARIABLES比赛条件?

时间:2016-04-29 15:18:03

标签: coldfusion race-condition

我想帮助确定为什么这个特殊代码在极少数情况下会产生竞争条件。我找到了一个解决方案,我也会概述,但我真的想了解它。

我们有一个基于CMS的系统,包含许多基于保险箱模型的模块。一切都通过一个index.cfm。

在我们的Index.cfm中,我们创建了几个Components实例,其中一些实例是在Application.cfc中创建的APPLICATION.PortalApp实例上。我不包括该代码,因为它并不完全相关:

<cfset REQUEST.ActionHandler = CreateObject("Component", "Components.ActionHandler").init(APPLICATION.PortalApp.Config) />
<cfset VARIABLES.Modules = CreateObject("Component", "Components.Modules").init(APPLICATION.PortalApp.Config, REQUEST.ActionHandler.GetModuleList(), REQUEST.ActionHandler.GetSuppressOutput(), REQUEST.ActionHandler.GetRoleList(), REQUEST.ActionHandler.GetAccessList(), REQUEST.ActionHandler.GetMasterRoleList()) />

在我们实例化这些对象之后,我们通过调用PageManager组件来获取页面上模块的内容(基于它们的&#39;上下,左,中,右)。实例化为Application.PortalApp。

的应用程序的一部分
<cfsavecontent variable="Variables.Portal_Content.Top"><cfset APPLICATION.PortalApp.PageManager.DisplayContent( SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 0  ) /></cfsavecontent>
<cfsavecontent variable="Variables.Portal_Content.Left"><cfset APPLICATION.PortalApp.PageManager.DisplayContent( SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 1  ) /></cfsavecontent>
<cfsavecontent variable="Variables.Portal_Content.Middle"><cfset APPLICATION.PortalApp.PageManager.DisplayContent( SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 2  ) /></cfsavecontent>
<cfsavecontent variable="Variables.Portal_Content.Right"><cfset APPLICATION.PortalApp.PageManager.DisplayContent( SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 3  ) /></cfsavecontent>

PageManager.DisplayContent基本上遍历模块并将它们包装在一个包装器中。但是,在某些时候,存在竞争条件和功能陨石坑并且根本不显示任何模块。它似乎是基于VARIABLES.Modules变得腐败但是在VARIABLES范围内没有共享。

要解决此问题,我们将代码更改为以下内容:

<!--- If we do not use VARIABLES scope and create a ContentManager, race condition can cause empty modules --->
<cfset VARIABLES.CurrPageMgr = CreateObject("Component", "Components.ContentManager").init() />

<cfsavecontent variable="Variables.Portal_Content.Top"><cfset VARIABLES.CurrPageMgr.DisplayContent( SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 0  ) /></cfsavecontent>
<cfsavecontent variable="Variables.Portal_Content.Left"><cfset VARIABLES.CurrPageMgr.DisplayContent( SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 1  ) /></cfsavecontent>
<cfsavecontent variable="Variables.Portal_Content.Middle"><cfset VARIABLES.CurrPageMgr.DisplayContent( SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 2  ) /></cfsavecontent>
<cfsavecontent variable="Variables.Portal_Content.Right"><cfset VARIABLES.CurrPageMgr.DisplayContent( SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 3  ) /></cfsavecontent>

ContentManager的DisplayContent是与PageManager.DisplayContent完全相同的函数文本,ContentManager上的例外仅存在于VARIABLES范围内,而PageManager作为APPLICATION的一部分存在。

在获得报告后很难再现。我基本上开始了一个jmeter会话锤击开发服务器尽可能地使用断点设置基于我知道会用VARIABLES触发的条件。模块已损坏。这是重现它的唯一方法。

我也不是100%确定这个修复工作正常,但到目前为止,jmeter还没有解决这个问题。

编辑:每个请求,DisplayContent函数:

<cffunction name="displayContent" access="public" output="true">
    <cfargument name="SessionData" required="yes" type="Struct" />
    <cfargument name="ActionHandler" required="yes" type="ActionHandler" />
    <cfargument name="Modules" required="yes" type="Modules" />
    <cfargument name="Pane" required="yes" type="numeric" />
    <cfswitch expression="#Arguments.Pane#">
        <cfcase value="1"><cfset Variables.blnPane = ARGUMENTS.Modules.getLeft()></cfcase>
        <cfcase value="2"><cfset Variables.blnPane = ARGUMENTS.Modules.getCenter()></cfcase>
        <cfcase value="3"><cfset Variables.blnPane = ARGUMENTS.Modules.getRight()></cfcase>
        <cfdefaultcase><cfset Variables.blnPane = ARGUMENTS.Modules.getTop()></cfdefaultcase>
    </cfswitch>
    <cfif VARIABLES.blnPane>
        <cfset VARIABLES.qryPaneModules = ARGUMENTS.Modules.GetModulesInPane(Arguments.Pane)>
        <cfset VARIABLES.aryModulesInPane = ArrayNew(1)>
        <cfloop query="VARIABLES.qryPaneModules">
            <cfset VARIABLES.blnResult = ArrayAppend(aryModulesInPane,VARIABLES.qryPaneModules.MOD_SYS_NR)>
        </cfloop>
        <cfset VARIABLES.Template = "../CustomTags/Portalv#ARGUMENTS.SessionData.intPortalVersion#/DisplayModuleAlternate.cfm">
        <cfif Arguments.ActionHandler.GetDocumentType() EQ 3>
            <cfset VARIABLES.Template = "../CustomTags/Portalv#ARGUMENTS.SessionData.intPortalVersion#/DisplayXMLModule.cfm">
        </cfif>
        <cfif VARIABLES.qryPaneModules.recordcount GT 0>
            <cfloop index="VARIABLES.modLoop" from="1" to="#ArrayLen(VARIABLES.aryModulesInPane)#">
                <cfparam name="VARIABLES.aryModulesInPane[VARIABLES.modLoop]" default="0">
                <cfset VARIABLES.objModuleInfo = ARGUMENTS.Modules.GetModuleInfo( VARIABLES.aryModulesInPane[VARIABLES.modLoop], ARGUMENTS.Modules.GetModules() ) />
                <cfif NOT IsNumeric(VARIABLES.objModuleInfo.intModuleID)>
                    <cfset VARIABLES.objModuleInfo.intModuleID = 0 >
                </cfif>
                <cfmodule template="#VARIABLES.Template#"
                    ModuleID="#VARIABLES.objModuleInfo.intModuleID#"
                    ModuleName="#VARIABLES.objModuleInfo.strModuleName#"
                    SecurityLevel="#VARIABLES.objModuleInfo.intRoleTypeID#"
                    ModuleDSN="#VARIABLES.objModuleInfo.strModDBDSN#"
                    ModuleUserName="#VARIABLES.objModuleInfo.strModDBUserID#"
                    ModulePassword="#VARIABLES.objModuleInfo.strModDBPassword#"
                    AlternateFunctionID="#VARIABLES.objModuleInfo.intAlternateFunctionID#"
                    AlternateFunctionName="#VARIABLES.objModuleInfo.strAlternateFunctionName#"
                    InstructionFileID="#VARIABLES.objModuleInfo.intManualID#"
                    ModuleOps="#VARIABLES.objModuleInfo.blnModuleOps#"
                    ModuleSource="#VARIABLES.objModuleInfo.strModuleSource#"
                    ItemID="#VARIABLES.objModuleInfo.intModItemID#"
                    AutoLoginID="#VARIABLES.objModuleInfo.intAutoLoginCategoryID#"
                    IPS_objPortalSessionData="#ARGUMENTS.SessionData#"
                    ModuleList="#ARGUMENTS.ActionHandler.GetModuleList_SingleRecord(VARIABLES.objModuleInfo.intModuleID)#"
                    ModulesComponent="#ARGUMENTS..Modules#"
                    ControlHeaderIR = "#VARIABLES.objModuleInfo.blnControlHeaderIR#"
                    BorderIR = "#VARIABLES.objModuleInfo.blnBorderIR#"
                    IPS_strPortalRoot = "#VARIABLES.IPS_strPortalRoot#"
                    IPS_strPortalURL = "#VARIABLES.IPS_strPortalURL#"
                    Wrapper = "#Arguments.ActionHandler.getWrapper()#"
                    Definition = "#VARIABLES.objModuleInfo.strModuleDef#"
                    Category = "#VARIABLES.objModuleInfo.strModuleCat#"
                    aryModulesInPane = "#VARIABLES.aryModulesInPane#"
                    blnLockIR = "#VARIABLES.objModuleInfo.blnLockIR#"
                    strMessageTE = "#VARIABLES.objModuleInfo.strMessageTE#" >

            </cfloop>
        </cfif>
    </cfif>
</cffunction>

1 个答案:

答案 0 :(得分:1)

在PageManager组件的DisplayContent函数中使用VARIABLES范围(它已被实例化为Application的一部分,因此共享)是问题所在。在这种情况下,VARIABLES范围将被共享,从而导致竞争条件。

除了在另一个组件中复制该函数并在index.cfm的VARIABLES范围内实例化之外,您还可以从DisplayContent函数中的VARIABLES范围切换到LOCAL范围(假设您不需要访问这些范围)函数之外的变量)。当使用jmeter进行压力测试时,两种方式都不会再次出现竞争状态。