Archive for the 'coldfusion' Category

ColdFusion Struct Literals Are Not Thread Safe (CFML Ones Are)

If you read my blog regularly or follow me on Twitter, you know how much I hate Adobe's quasi-implementation of struct (and array) literals.  I'm really hoping "third time's a charm" and CF9's implementation is sane.  The gripe is that this code:

<cfset s = {
  name = "barney",
  age = 29
} />

is executed as if it were written like this (on Adobe ColdFusion):

<cfset s = structNew() />
<cfset s.name = "barney" />
<cfset s.age = 29 />

The "correct" behaviour is to execute it as if it were written like this (which is how Railo does it):

<cfset temp = structNew() />
<cfset temp.name = "barney" />
<cfset temp.age = 29 />
<cfset s = temp />

This lets you write some really nasty code, causes some weird bugs, and today I realized (through some handy errors on our production cluster) that there are thread safety issues as well.   Consider this code (inside a getCacheForKey() method):

<cfif NOT structKeyExists(key_stats_cache, key)>
<cflock name="getCacheForKey.#key#" type="exclusive" timeout="1">
<cfif NOT structKeyExists(key_stats_cache, key)>
  <cfset key_stats_cache[key] = {
    getCount = 0,
    staleGetCount = 0,
    missCount = 0
  } />
</cfif>
</cflock>
</cfif>

If the struct literal were an expression, this code would be thread safe, because the assignment to 'key_stats_cache[key]' would be atomic.  However, because of the way ColdFusion implements it, it's not thread safe.  It's possible to have the existence checks trigger in a second request while the struct is building in the first request, and therefore some keys will not be present after the outer </cfif> tag of a second request.  Wrapping the outer <cfif> tag with a read-only CFLOCK will address the issue, of course, but if struct literals were implemented as expressions (the second behaviour above), the problem could never manifest itself.  So watch out!  Atomicity of assignment statements is not assured.

Riddle Me This, CFLOOP

Take this simple loop:

<cfloop from="1" to="10" index="i">
  #i#<br />
  <cfif i EQ 3>
    <cfset i += 3 />
  </cfif>
</cfloop>

What is the output?  My answer is the numbers 1-3 followed by 7-10.  But I was dismayed to learn this evening that it doesn't seem to be the case on my server.  There it outputs 1-10 with no breaks.  Can someone please confirm that this is NOT normal behaviour?  I'm running CF 8,0,1,195765 on x64 CentOS 5 (kernel 2.6.18-128.1.6.el5) with 64-bit Java 1.6.0_13.

Update: Clearly I'm just retarded.  It works this way on Windows, on Railo, and everyone else confirms this is known behaviour.  Somehow I've gone 10 years without running into this issue, probably because I always revert to CFSCRIPT when I do "weird" looping.

That syntax above is analogous to collection iteration (in Groovy):

(1..10).each { i ->
  println(i)
  if (i == 3) {
    i += 3
  }
}

It is NOT analogous to this for loop (also in Groovy):

for (i = 1; i <= 10; i += 1) {
  println(i)
  if (i == 3) {
    i += 3
  }
}

Weird.

Minor FB3lite Update (and a Weird CF Bug)

This evening while adding some reporting to PotD (NSFW, OMM) to help nail down some performance issues that I think are Apache's fault, I noticed a strange issue with FB3lite.  If you've used it, you know the core of the "framework" are the do() and include() UDFs.  Both contain a CFINCLUDE tag, and a weird situation arises with scoping.

CFML has implicit scope traversal, so if you have an unscoped variable, it will automatically traverse across a bunch of scopes until it finds one with the right name.  Further, you get an implicit local scope within UDFs, and you get a magic psuedo-scope within query-based CFOUTPUT and CFLOOP tags.

What I noticed was that looping over a query with a column named "template" always displayed the currently executing template, instead of the value from the query.   No worries, I thought, since prefixing it with the query name solved the issue.  "template" isn't a common query name for me, so while it surprised me I'd never noticed or heard about this magic "template" variable before, I didn't think too much of it.

Then a while later I realized it was my own fault, because of the include() UDF in FB3lite.  The argument to the UDF is named "template", and CFML places the implcit local scope at the top of the heap, including above the magic query-loop scope.  That argument was shadowing my query variable.

I've fixed FB3lite to use a prefix on all it's UDF arguments, so this problem cannot manifest itself anymore.  Well, I suppose it could, but you'd have to have a weird-ass variable name (e.g., "_fb3lite_template").  You can download the latest version, or pull it from Subversion.

The Latest ColdFusion Mindƒµ©Ҝ

It's pretty common knowledge that ColdFusion passes arrays to UDF by value, and not by reference like pretty much every other language.  It's a weird behaviour, but as long as you remember to write array-processing functions to be used like this:

<cfset myArray = modifyArray(myArray) />

instead of like this:

<cfset modifyArray(myArray) />

you'll be fine.  However, someone pointed out on the Railo mailing list that this behaviour is not constrained to UDFs.  Assignment behave the same way!  Yes, if you assign an array to another variable, you get a copy.  The only "assignment" that is exempt from this behaviour is if you use structInsert.

Consider this code:

<cfset a = [37] />
<cfset a2 = a />
<cfset s1 = {array = a} />
<cfset s2 = {} />
<cfset s3 = {} />
<cfset s4 = {} />
<cfset s2.array = a />
<cfset s3["array"] = a />
<cfset structInsert(s4, "array", a) />
<cfset arrayAppend(a, 42) />
<cfset System = createObject("java", "java.lang.System") />
<cfoutput>
<p>#System.identityHashcode(a)# - #a.toString()#               <!--- [37, 42] --->
<p>#System.identityHashcode(a2)# - #a2.toString()#             <!--- [37]     --->
<p>#System.identityHashcode(s1.array)# - #s1.array.toString()# <!--- [37]     --->
<p>#System.identityHashcode(s2.array)# - #s2.array.toString()# <!--- [37]     --->
<p>#System.identityHashcode(s3.array)# - #s3.array.toString()# <!--- [37]     --->
<p>#System.identityHashcode(s4.array)# - #s4.array.toString()# <!--- [37, 42] --->
</cfoutput>

At the end of this code, there are five distinct arrays, one containing 37 and 42, and the other four containing only 37.  The blue lines create the four copies, and the red line creates a new "pointer" to the existing array.  Then when the green line executes the original array has 42 added to it, which only affects 'a' and 's4.array', because the rest are copies.

On Railo, arrays are universally reference types, so there would only be a single array in the above example.  This is consistent with most other languages.

Ben Nadel - At It Again

Ben Nadel posted another interesting code snippet this moring.  I think Ben and I stand in agreement on the technique: NEVER EVER USE IT.  It leverages a horrible bug in ColdFusion's implementation of struct literals that I've blogged about previously.

Here's the snippet:

<cfset objConfig = {
  root = getDirectoryFromPath(getCurrentTemplatePath()),
  tags = objConfig.root & "tags/",
  com = objConfig.root & "com/"
} />

Yes, that actually works.  Let me repeat, NEVER EVER USE IT.  It is the devil incarnate, and only works because of a horrible implementation error in Adobe ColdFusion.  Note this is a ColdFusion bug, not a CFML language issue.  Railo implements struct literals correctly (as well as treating them as expressions instead of statements).  I don't know about OBD - the last time I used it there wasn't struct literal support at all, but it's been a while.

A Groovy Letdown

I'm a huge fan of Groovy, but it's major downside drove over me like a bus this evening.  What's that, you say?  Performance, of course.  Runtime "stuff" necessarily happens at runtime, and therefore affects performance.  Does this matter in most cases?  No, absolutely not.  In general it's far cheaper to buy hardware than to employ developers, so ease of development and maintenance almost always trumps raw performance.  This is why we use high level languages as opposed to writing everything in assembler.

As you probably expect, I was working on Project Euler.  Problem 39, to be specific.  The algorithm is simple, and if you pay attention, you don't even have to do the full scan to get the answer.  However, I couldn't get within the minute boundary with my algorithm.  I did a whole bunch of optimizations to ensure I was doing absolutely as little work as possible (including stopping the search at the known answer!) and still couldn't even come close to the minute deadline.

On a whim, I took my brutish, unoptimized version (because the syntax was less Groovy-ish) and dropped it into a Java class.  I had to add a pile of semicolons and variable types, insert a couple imports, and convert a GString, but the rest was untouched.  Full scan (from 1-1000) in 172 milliseconds.  Needless to say I was disappointed.

Am I going to abandon Groovy for Java?  Hell no.  But definitely going to consider reimplementing some of my hard-core subroutines in Java.  Just another case of knowing your tools so you can pick the right one for the job.  And just to be clear, I have no expectation that this sort of performance difference is in any way indicative of Groovy's general performance.  In fact, I find Groovy to be ridiculously fast, in general, because I'm typically doing far higher-level operations (like using Hibernate).

One interesting point was that copy and pasting the Java version into a Groovy file and running it (with all the semicolons and explicit variable typings) didn't affect the Groovy performance much.  That surprised me.  Apparently the Groovy compiler treats 'int' as 'Integer' or something similar.  I've never looked into it very deeply, but worth mentioning I thought.

Also interesting is that CFSCRIPT on CF 8.0.1 turns in times that are slightly faster than Groovy running through CFGroovy on the same page.  I would have expected the reverse since CF uses java.lang.Double internally, but it seems the lack of unboxing/reboxing makes up for the floating point calculations.

My Found Art Finder

I was bored tonight, so I found some art.  And being the good programmer, generalized it to create a tool for others to find their own art.  Here are a couple samples (dynamically generated):

You can also grab the source from Subversion.  It's quite simple, it's not very scalable, and dear god please let CF9 make the image functions not suck.  Why can't I stream an image to the browser?  Why don't boolean imageSetXXX() functions accept booleans?  Why do I have to pass an empty string to imageNew?  CFML is null-less, don't fake it with the empty string.

ColdFusion to Railo

Just completed my first port of a major app from ColdFusion to Railo.  Time elapsed from downloading the Railo WAR to my dev box to see if the app would run to reenabling the prod instance: 1.5 hours.

Downloaded the WAR, unpacked it into my webroot, unzipped a new Tomcat, set up a Context pointer to my webroot, and fired it up.  Worked like a charm, and after adding my DSN to the config file, the app was running.

I had to make a couple minor tweaks for Railo compatibility:

  1. Railo seems to stick getContextRoot() into cgi.script_name automatically, so I had to remove the function calls in my 'self' variable's definition
  2. Railo has an issue with non-defaulted, non-required, numeric method arguments that are omitted from a call.  I added it as bug 147 in JIRA.

After that I just checked /WEB-INF/ and the tweaks into Subversion for deployment to production.  On my prod server I did basically the same process: unzip  a Tomcat, set up a Context pointer to the existing webroot, configure an init script, and fire it up.  Once Tomcat was happy (first try!), I took the Alias directive out of my Apache config, replaced it with a mod_rewrite proxy directive, redeployed the app (to get /WEB-INF/ and the tweaks), changed the DSN credentials, and bounced Apache.  Done.  Live.  No errors.  And cookie-based session tracking worked flawlessly across the engine replacement.

Needless to say this is a HUGE win for both me and Railo.  I've been writing new stuff to Railo, but hadn't ported anything substantial because I didn't want to deal with the pain.  But with how minor the pain is, it's totally overshadowed by the benefits of separate contexts (or VMs!) per app.  That was never really an option with CF because of the memory footprint (350MB for CF vs 60MB for Railo).

Java SE 1.6.0_10

Just did the 1.6.0_10 upgrade on my server.  Oh how I love Linux.  Just unarchved the new JDK, repointed a single symlink and restarted my Java servers.  There didn't seem to be a significant difference in spinup time for my ColdSpring AOP-heavy apps - perhaps a touch faster.  No problems with Magnolia either as near as I've been able to tell.  WordPress, not surprisingly, was unaffected.

"Missing Huffman code" Error Using ImageWrite()

I've been having troubles with thumbnail generation on one of my apps recently.  Just sporadically, with no obvious pattern as to why.  The error is about a missing Huffman code (used for JPEG compression).  Turns out that certain images when being written at certain sizes, throw this error when you use the built-in imageWrite().

The solution is to skip the CF solution and manually do it the Java way.  So what used to be this:

<cfset imageWrite(image, filename) />

now looks like this:

<cfset createObject("java", "javax.imageio.ImageIO").write(
   imageGetBufferedImage(image),
   "jpeg",
   createObject("java", "java.io.File").init(filename)
) />

Fortunately, Adobe had the foresight to include the wonderfully named imageGetBufferedImage() built-in so you can access the raw image data with the native Java APIs.  Note that with the Java you have to specify the encoding type explicitly, instead of letting CF figure it out based on the filename's extension.  Since I'm only dealing with JPEG images, I just hard coded it.