In the past, I had talked about how to add persistence to Seaside applications using GLASS, but up until recently, I hadn’t supplied any concrete examples. A month or so ago, the stars aligned, and I took the opportunity to start writing some Seaside examples for GLASS. I figured I would start with a simple example that ignored concurrency issues and then over a series of examples, I’d illustrate the techniques for navigating the treacherous waters of transaction conflicts. I even monkeyed around with jcrawler, so that I’d have a tool that could be used to expose concurrency flaws in the examples.
For the simple persistence example, I decide to copy WACounter, remove the count instance variable and replace it with a class variable reference (Tally) – the simplest example of persistence possible (see WATally in GemStone Examples).
No object lock, no reduced conflict class so look out boys, transaction conflicts are on the menu tonight.
Did I mention that the stars had aligned?
As I was working out the details of an object locking example based on a problem posed by Ken Tries, I realized that when an object lock is denied, the simplest answer is to just retry the HTTP request.
The standard pattern for dealing with a denied object lock in GemStone/S is to wait a bit, abort and attempt to acquire the lock again. If you recall in GLASS, when an HTTP request comes in to a server, we do a beginTransaction (equivalent to an abort), process the request and then do a commit. So, when an object lock is denied while processing a request, we throw an exception, abort the transaction, delay for a bit and retry the request. Each request is handled in its own thread, so while the request is delayed, other requests can be processed by the server. A nice, clean solution that fits very well within the GemStone/Seaside framework.
As I was coding up the solution for object locks (see WASerialNumber and SerialNumber in GemStone Examples) I realized that the same technique (wait a bit and retry the HTTP request) would be the perfect answer for handling transaction conflicts.
So to bring a long story to an end, what started out as a poor example for doing persistence in GLASS has turned into a perfectly good example for doing persistence in GLASS.
All of the rigamarole about needing to avoid transaction conflicts goes right out the window! For high traffic sites or for potentially overlapping requests (i.e., relatively long request processing times), it is still worth using Reduced Conflict classes or object locks to minimize the chance for transaction conflicts. In most cases, though, a simple class variable or global reference will do the trick.