Important alert: (current site time 7/16/2013 6:27:46 AM EDT)
 

article

Shared Scope Variable Locking. MUST READ IF YOU USE CF! CAN PROBABLY SOLVE MANY CONFLICTS!

Email
Submitted on: 9/7/2001 12:25:45 AM
By: Jeremy McAnally  
Level: Intermediate
User Rating: By 12 Users
Compatibility: Cold Fusion 4.5, Pre Cold Fusion 4.5
Views: 24938
(About the author)
 
     This will teach you how to lock shared scope variables. This can lead to the elimination of some problems and poosibly major conflicts in your server.

 
 
Terms of Agreement:   
By using this article, you agree to the following terms...   
  1. You may use this article in your own programs (and may compile it into a program and distribute it in compiled format for languages that allow it) freely and with no charge.
  2. You MAY NOT redistribute this article (for example to a web site) without written permission from the original author. Failure to do so is a violation of copyright laws.   
  3. You may link to this article from another website, but ONLY if it is not wrapped in a frame. 
  4. You will abide by any additional copyright restrictions which the author may have placed in the article or article's description.
				

Locking shared scope variables within ColdFusion templates is an often overlooked process that has severe consequences when best practices are not followed. This document will explain why the process of locking shared scope variables is important and the corresponding best practices.

Developers should be advised that these practices should not be considered optional under any circumstances. Most cases of ColdFusion site instability can be traced back to inproper use or complete lack of locking. A few extra lines of code and an understanding of the underlying concepts of locking can go a long way towards ensuring robust Web applications with maximum availability and performance.

What Are Shared Scope Variables?

Session scope variables, application scope variables, and server scope variables are shared scope variables. They are so named because they are stored in a part of memory that is shared by all of the threads used by ColdFusion Server to run requests. The physical pieces of memory that are used to store these variables can be accessed by any of the threads within the server. Variables are "accessed" when reading their values or writing values to them.

Why Does Shared Scope Variable Access Need to Be Locked?

Because ColdFusion Server uses multiple threads (multithreading), it is able to simultaneously work on requests from multiple users at the same time. It is also able to work on multiple requests from the same user at the same time. This can happen with a Web site that utilizes frames, when a user clicks the reload button on her browser before the initial request has completed, or when a user has multiple browser windows open.

Since these threads can access the same variables in memory at the same time, we are presented with the problem of the threads competing for the same resource. This competition normally leads to memory corruption. Corruption occurs because of the way the data is structured in memory and the changes that take place in these structures when the variables are altered. If one thread modifies the shared scope variable while another thread attempts to read the value of the variable, for example, memory corruption may result. Because the read and write are happening concurrently, the read may try to access the structure in a way that would be invalid after the write to the variable modified the data structure. Accessing memory in an invalid way, such as requesting the contents of a physical piece of memory that doesn't exist, causes memory corruption and process crashes.

In addition, if the data structures that track memory allocation become corrupted, the allocator will work incorrectly and large amounts of memory can "leak." Memory corruption also leads to crashes and/or server instability. Some of the symptoms of memory corruption follow:

  • ColdFusion PCode errors

  • cfserver process crashing/stopping/restarting

  • Unexpected shared scope variable evaluation results

  • Large growth in the amount of memory used by the cfserver process

  • Operating system instability

Locking variables prevent these problems by only allowing one thread to access the shared scope variable at a time. All of the other threads must wait in line to access the shared variables until the previous thread completes its action. In effect, access to the locked piece of code is single threaded.

How to Lock Access to Shared Scope Variables

Locking is accomplished by encapsulating CFML that accesses shared scope variables with CFLOCK. The six basic scenarios in which you use CFLOCK for variable access are: writing to server scope variables, reading from server scope variables, writing to application scope variables, reading from application scope variables, writing to session scope variables, and reading from session scope variables.

Writing to server scope variables:

Reading from server scope variables:

#server.myservervar#

Writing to application scope variables:

Reading from application scope variables:

#application.myappvar#

Writing to session scope variables:

Reading from session scope variables:

#session.mysessionvar#

How Does CFLOCK Work?

The CFLOCK tag can be implemented as exclusive or as read only. As the pervious examples showed, exclusive locking is used for writing to variables, and read-only locking is used for reading variables.

An exclusive lock prevents more than one request from the same application or session from entering the code enclosed within the CFLOCK code at the same time. This means that the code can only be executed one request at a time. If any other request is executing at the same time, it will stop when it reaches a CFLOCK tag and wait for the other request holding the exclusive lock to finish executing the code. Once the other request releases the lock, the queued requests will be processed on a first-come, first-served basis.

A read-only lock does not force single threading, however, it will prevent an exclusive lock from being concurrently established. This means that multiple requests can read from the same variable at the same time, but a request won't be able to write to a variable while another request is reading from it.

The scope attribute of the CFLOCK tag corresponds to the scope of the variables whose access should be locked. The server keeps track of locks defined with different scopes separately. This is advantageous because a CFLOCK defined with a session scope does not have to contend with requests for locks from other sessions outside its own. Likewise, a CFLOCK defined with an application scope does not have to contend for locks with locking requests from other applications on the same server. It is important to match the scope of the lock to the scope of the data so that the server knows the context for which you want to protect access to the data. Application variables locked with a session scoped CFLOCK would not prevent other sessions in the same application from performing unlocked reads and writes. Likewise, mixed shared scopes (i.e. application and session) should not be combined in the same CFLOCK statement.

The required timeout attribute takes a value in seconds to wait for ColdFusion to issue the requested lock. To maximize throughput, set a low value for timeout. Under normal circumstances, it should never take more than a few seconds for the tag to be able to obtain a lock. If your tag is consistently timing out, eliminate excess code from within all CFLOCK tags. Only access to variables need to be included. One common mistake is to include a CFQUERY call within the CFLOCK tag.

Bad:

SELECT FirstName, LastName

FROM Users

WHERE UserID = #request.UserID#

Good:

SELECT FirstName, LastName

FROM Users

WHERE UserID = #request.UserID#

This avoids the problem of the lock persisting for the duration of the query execution time. Now, the lock only persists for the duration of the execution of the CFSET tag. Here is another common mistake:

Bad:

SELECT FirstName, LastName

FROM Users

WHERE UserID = #form.UserID#

Good:

SELECT FirstName, LastName

FROM Users

WHERE UserID = #form.UserID#

Again, this solution again allows us to prevent the lock from persisting for the duration of the database query. Although application variables are widely used to store data source names, it probably makes more sense to avoid using an application variable in this case. This can be done by instead setting a request scope variable in the application.cfm file.

Care should be taken when using CFSET to move complex data types like structures from one scope to another. This action does not really copy the structure from one scope to the other; it creates a pointer to the original object. This means that accesses to this new structure will be accesses to a shared scope variable if the original variable was shared scope, regardless of the new scope. The Duplicate( ) function can be used to copy the structure instead of creating a pointer to it.

Using CFSET:

In this case, request.strDATA should still be treated as an application variable and locked appropriately.

Using Duplicate( ):

In this case, request.strDATA is not a pointer and can be treated like a request scope variable.

To avoid deadlocks, do not nest CFLOCK tags, especially those of mixed scope.

Single Threaded Sessions

In the ColdFusion Administrator, there is a setting on the locking page called single threaded sessions. Turning this switch on enforces individual browser sessions to use only one thread at a time. One request from the browser must completely execute before the next one can start. This would prevent a request spawned by clicking the refresh button in the browser from running until the first request from that browser finished. Enabling single threaded sessions eliminates the need to lock reads and writes to session variables because there are no longer concerns about concurrent access. This feature may cause performance degradation in frames-based sites because it will prevent both frames from being processed simultaneously.

Automatic Read Locking

For each of the shared scopes, there are options on the locking page of the ColdFusion Administrator to enable automatic read locking. This feature effectively places read-only locks around all read accesses to variables in the specific scope. Additionally, it checks all writes to these variables and ensures that locks are in the code. An error will be thrown if it discovers that a write to one of these variables was left unlocked.

There are pros and cons to using this feature. Due to the need to insert read-only locks, this feature adds an additional step to the precompilation process. Performance degradation is realized because of the overhead associated with checking all shared scope variable access for locking. On the other hand, this feature can be valuable when retrofitting a site that was mistakenly coded without locking variables. If performance is not most important, a site can be retrofitted by simply locking all writes to shared scope variables and then enabling this feature.

Full Checking

For each of the shared scopes, there are options on the locking page of the ColdFusion Administrator to enable full checking. This feature will cause the server to throw an error whenever an unlocked read or write access to a shared scope variable is discovered.

It is highly desirable to enable this feature on your development server before you begin your project. Doing so will force all developers on the project to lock variables appropriately to make their code work. This feature can also be useful to quality assurance personnel while testing an application. If there is no doubt that all shared scope variables in an application have been locked prior to "going live," it is recommended that this feature not be enabled in production because performance degradation will occur due to the overhead associated with checking all accesses to shared scope variables. However, unless QA testing can confirm that all variables have been locked, use of this feature should be considered as a fail-safe to ensure protection against inadvertently unlocked variable accesses.

Why Isn't There Automatic Write Locking?

Automatic write locking or universal locking has not been included as a feature of ColdFusion Server for several reasons. Performance is one reason. Automatic write locking would place a lock around the code that writes to each variable causing a single lock to surround each individual CFSET statement. It is much more efficient to use one CFLOCK to surround multiple CFSET statements.

The granularity itself is another reason. Although the highly granular locking model would prevent corrupted memory with individual locks for each access, it would not provide any options for transactional integrity. Here is a hypothetical scenario:

An e-commerce application provides the user with a shopping cart interface. When the user adds a widget, with quantity "1," to her cart, the following two statements of code execute:

1A.

[auto exclusive lock]

[/auto lock]

1B.

[auto exclusive lock]

[/auto exclusive lock]

In our hypothetical scenario, the user decides (after clicking the add button) that she really doesn't want one widget. She really wants two sprockets. She clicks the stop button on her Web browser and addss two sprockets to her cart. A new thread executes the following two statements of code:

2A.

[auto exclusive lock]

[/auto exclusive lock]

2B.

[auto exclusive lock]

[/auto exclusive lock]

Clicking the stop button on the browser does not kill the first thread.

For this hypothetical situation, imagine that Thread 1 starts up and finishes Statement 1A. In turn, the operating system's thread management system bumps Thread 1, and Thread 2 starts. Thread 2 finishes Statements 2A and 2B before being bumped, and Thread 1 resumes to complete Statement 1B. Because of the automatic locking, nothing is happening concurrently; everything is sequential. The sequence looks like this:

Thread

Statement

1

1A

2

2A

2

2B

1

1B

Because of the arbitrary order that the threads completed the statements, we end up with the following:

session.cart.product[1] = "sprocket"

session.cart.quantity[1] = "1"

The problem here is that we set the product value of the second request and the quantity value of the first request.

This problem is avoided using CFLOCK by including both CFSET statements in a single lock. This transactional coding would not be an option with automatic write locking.


Other 2 submission(s) by this author

 


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this article (in the Intermediate category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)
 

Other User Comments
9/7/2001 1:55:38 PMJared Bruni

very well written structured tutorial, worth way more than 5 globes :)
(If this comment was disrespectful, please report it.)

 
9/23/2001 12:37:21 AMJared Bruni

:)
(If this comment was disrespectful, please report it.)

 
9/27/2001 7:05:23 PM;]

This is very well written.
(If this comment was disrespectful, please report it.)

 
7/1/2003 1:42:23 AM

I got a problem with the coldfusion
when I run the coldfusion.exe there is no problem but when I run a coldfusion file with the extension of .cfm on the server I found out that I can view the coldfusion code when I view source and all the coldfusion code does not work on the server but I try to upgrade the coldfusion to the latest version but the problem still occurs can you tell me what is the problem with the coldfusion
(If this comment was disrespectful, please report it.)

 
7/15/2003 5:28:59 AM

can't see the cf-code! (tags are not showing up...)
(If this comment was disrespectful, please report it.)

 
10/19/2005 10:13:40 AMBobby Nichols

I can not see the CF tags either. A little investigation revealed that the tags are being colored '000000', or White so they blend in,
(If this comment was disrespectful, please report it.)

 

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular article, please click here instead.)
 

To post feedback, first please login.