[thelist] CFLOCK help request

.jeff jeff at members.evolt.org
Fri Jun 7 09:31:00 CDT 2002


susan,

><><><><><><><><><><><><><><><><><><><><><><><><><><><><><
> From: Susan Wallace
>
> I inherited a CF application that was customized for one
> site, and is being moved to a new server. The
> application was written using CFLOCK in this manner:
>
> <CFLOCK name="Session.UserID" timeout="10">
><><><><><><><><><><><><><><><><><><><><><><><><><><><><><

ah, you inherited an app from a developer that cared enough to lock shared
scope variable access, but didn't understand how locking actually works and
what the proper way to do it is.

><><><><><><><><><><><><><><><><><><><><><><><><><><><><><
> The server this was moved to throws an error (I'll
> outline in a sec) and when I inquired about the server
> settings for Locking, the reply I got was "The server is
> set for full locking."....
><><><><><><><><><><><><><><><><><><><><><><><><><><><><><

oh, and you also inherited a host that hasn't a clue about how to use the
locking checkboxes in the cfadmin.  full lock checking isn't actually full
lock checking like you'd think.  it doesn't catch *every* instance of shared
scope variable access.  it only checks those that are obvious.  can you spot
the shared scope variable access in the code sample below?

<cfset myCart = ArrayNew(1)>
<cflock type="exclusive" scope="session" timeout="10">
  <cfif NOT IsStruct(myCart) AND StructKeyExists(session, "cart")>
    <cfset myCart = session.cart>
  </cfif>
</cflock>

<cfif IsArray(myCart) AND ArrayLen(myCart)>
  You have #ArrayLen(myCart)# items in your cart.
</cfif>

don't feel bad if you can't spot it right off.  the coldfusion server can't
spot it at all.

still unsure?  want a hint?

see the line where i'm copying the session.cart array to the local variable
myCart?  complex values (usually) copy by reference, not by value.  what
that means is that myCart is just a pointer to session.cart.  so, whenever i
read myCart or make a change to myCart i'm reading/writing to the shared
scope variable.  that action should be locked, but the cf server doesn't
know to check it.

so, how do you avoid it?  use the Duplicate() function.  now, no matter the
datatype, it will be copied by value creating an entirely new copy of the
data and not a pointer.  you can then, safely, read and write to the local
variable without concerns over locking.

><><><><><><><><><><><><><><><><><><><><><><><><><><><><><
> <CFIF IsDefined("Session.CalendarID")>
>   <CFIF #Session.CalendarID# NEQ #Attributes.CalendarID#>
>     <CFLOCK name="Session.CalendarID" timeout="10">
>       <CFSET Session.CalendarID = #Attributes.CalendarID#>
>     </CFLOCK>
>     <CFSET Client.OptionsSet = "no">
>     <CFINCLUDE template="/calendar/common/act_options.cfm">
>   </CFIF>
> </CFIF>
><><><><><><><><><><><><><><><><><><><><><><><><><><><><><

first, scan the code to see if the actions are all reads of shared scope
variables or if there are any writes to those shared scope variables.  if
there are only reads, a readonly lock will be enough.  however, if there's a
single write, you'll need an exclusive lock.

now, pull out the <cflock> in the code sample.

scan the code block again to determine where the first read/write is.
obviously the first line (<cfif IsDefined("session.calendarid")>) is a read.
so, place your opening lock there as an exclusive lock.  find the closing
</cfif> for this tag and place your closing </cflock> tag after it.  you've
successfully locked the shared scope variable reads/writes.

in summary, here's the corrected code sample (complete with the redundant
hashes removed -- less is best):

<cflock type="exclusive" scope="session" timeout="10" throwontimeout="no">
  <cfif IsDefined("session.CalendarID")>
    <cfif session.CalendarID NEQ attributes.CalendarID>
      <cfset session.CalendarID = attributes.CalendarID>
      <cfset client.OptionsSet = "no">
      <cfinclude template="/calendar/common/act_options.cfm">
    </cfif>
  </cfif>
</cflock>

ps, i'll bet this block of code isn't inside a custom tag is it?  if not,
i'll bet there isn't a local variable named "attributes" that's a structure
is there?  if you're not sure, you can test it like this:

<cfoutput>
#IsStruct(attributes)#
</cfoutput>

my bets are that it's not a structure and you'll actually get an error
message stating that you're trying to access a variable that doesn't exist.

this is one of my pet peeves of the fusebox mentality.  it's lazy and
lingers on in many, many cf apps on the net.

don't worry about fixing that for now.  you've got big enough problems to
tackle with this locking issue.

good luck,

.jeff

http://evolt.org/
jeff at members.evolt.org
http://members.evolt.org/jeff/





More information about the thelist mailing list