Every week I read the ColdFusion Open-Source Update put out by Brian Rinaldi. Now, I used to pride myself on seeing Reactor mentioned frequently on that list. Unfortunately, several weeks have gone by without any real news from the Reactor camp.
This is really my fault. I honestly just haven’t felt much like blogging lately. I’ve been recovering from a stressful period in my live involving a new baby (who I am simply smitten by, by the way), selling my townhouse, moving into a new house, lots of work, too much email and a few new projects. All in all, I just caved in for a while. I’m feeling better now and I’m trying to try to blog more.
Furthermore, as much as I respect Brian, and as much as I know he tries not to be too critical or too imbalanced, I feel as if Reactor is getting bad press on his update. I understand he had some negative experiences with Reactor, though I’m not sure what they were.
Anyhow, in the attempt to try to shed some more positive light on Reactor, here’s some Reactor news I haven’t covered on my blog in the last two months:
Beth Bowen Takes the Bull By the Horns
Beth Bowden, who initially contributed Oracle support has been fixing my bugs. Since mid August she’s made nearly 40 commits to the framework. The fixes have includes a wide range of issues both large and small.
You know what? This is nothing small. I’ve done next to nothing compared to her in terms of bug fixes in that time period. She’s simply the unsung hero of Reactor and deserves wide praise and appreciation from the Reactor community in general.
Beth, take a bow!
Huge Performance Gains
As much as it pains me to say this, historically Reactor’s been a bit of a dog (in terms of speed) and a bit of a hog (in terms of memory usage).
There! I said it out loud! I feel liberated! I’ve secretly been beating myself senseless about this.
Actually, it’s not so secret. I asked for help from people in tracking down these issues months ago. The guys from Webappr stepped up the plate and determined that, yes, Reactor used a lot of ram. Furthermore, for some reason Reactor was “causing” Java to do a lot of full garbage collections (Full GCs).
These full GCs didn’t seem to be able to completely collect old memory, for some reason. As more and more memory was used the full GCs (which, by the way are a stop-the-world event) would take more and more time. Eventually servers would hang and need to be restarted.
The odd thing? It didn’t seem to happen to everyone. It although the problem occurred production mode, it was a real problem (at least for me) in development mode I personally would be guaranteed at least one manual CF restart a day. What a mess.
However, after a while Reactor’s memory usage did seem to level out. And, thankfully the Webapper guys informed me that full GCs could be disabled in JRun. That worked absolute miracles for stability. Unfortunately, Reactor continued to be slower and more memory intensive than I wanted it to be.
So, I spent quite a while thinking about the problems. There was nothing obvious that was specifically slowing down the works or eating up ram. I tried a dozens of techniques to identify where the problems were and tweaked lots code.
Ultimately I speculated that the problem lies, at least in part, with the use of so many bloody CFCs in Reactor. OO queries used to use a LOT of CFCs to do their job. So, I essentially rewrote them and removed two entire classes (choosing to store data in structs instead). This helped a bit, but not as much as I wanted.
I suspect that the deep inheritance tree on Reactor objects doesn’t help. So, I removed the base abstract object (which really served no essential function). I might in the future make the generation and use of DBMS agnostic files optional. I think that not using these might help a bit too.
The thing that made a huge difference was something I only did within the past week or so. Logically, OO queries are very dynamic when they don’t need to be. That is to say, if you create a query, join to a table, add a few where statements and sort the results, each time that code runs it’s going to have to go through all of the validation (which is expensive) and the translation of the OO query to a real SQL statement.
In development mode this process could take a quarter second. In production it was more like 60 ms (of course this is dependant on hardware, etc). This isn’t bad, but it’s not good either.
So, I decided to make a facade of OO queries which implemented the same interface as the actual OO queries. However, when you call methods the facade simply stores the commands in a structure. Then, when you run the query, the gateway, which use to be at least partially in charge of transforming the query to SQL, simply asks the facade for a file to include. The facade does a quick hash of the data you provided it and then looks for a file on disk that matches that hash. If the file is found it’s returned otherwise the facade validates the query and generates a static SQL statement (complete with cfqueryparams) to disk and returns the path to that file.
The gateway then simply includes the SQL statement into its cfquery tag. The first run of a query is on par with previous speeds. However, subsequent requests are more like 14 ms. That’s a 300% improvement in speed!
Duckies -or- Anything Goes
Speaking of speed, as is well known, a few popular frameworks have gone “typeless”. That is to say that all (or most) of the core framework’s methods have had their cffunction and cfattribute tags updated so that their returntype and type attributes are set to any, instead of specifying a specific data type. This essentially disables ColdFusion’s runtime type checking.
Because ColdFusion no longer checks the types when methods are called Reactor should theoretically get a lot faster. In practice it seems that this helped some cases but not others. Jared Rypka-Hauer praised it as being much faster while I’m not sure I saw much of a difference.
Anyhow, to make sure that the actual types were recorded for documentation I added two new made up attributes to the cffunction and cfargument tags, _returntype and _type. These hold the “real” data type and show up in the CFC’s metadata, but not in the ColdFusion-generated documentation, unfortunately.
Joe Rinehart contributed a feature whereby ColdSpring can inject itself into the ReactorFactory when it’s instantiated. Furthermore, Reactor lets you access the BeanFactory to get any ColdSpring configured bean. Simply use the _getBean() method. (Note, this won’t show up in metadata due to the fact it’s mixed in.) It’s debatable as to if this is a good thing, but it’s there!
Reactor Continues to Evolve
Simply put, there have been a ton of little things quietly changing over the past few months. Far too many to blog about.
I know the docs aren’t done yet. That’s my fault. I’ll get there soon! And before long we’ll be at a 1.0! (And no, contrary to certain reports, Reactor is still not a 1.0.)