aka, attack of the TLAs.
This webapp’s architecture is depicted below:
- The CAL functions store persistent data using Software Transactional Memory. This is a simple Java implementation based on the description in Composable memory transactions. It is given a CAL interface similar to a subset of Haskell’s Control.Concurrent.STM.
- Each STM TVar stores its value as a key-value pair in a Berkeley DB Java Edition database.
Any data structure can be built on top of TVars — and each TVar is a mutable reference, these are not functional data structures.
In this application a simple hashmap is used. Skiplists and relaxed balance btrees are other data structures which might allow reasonable concurrency too, while also providing features like in-order traversal.
This illustrates the relationship between the CAL objects in the CAL ExecutionContext and key-value pairs in the BDB:
The root of the persistent data structure is a TVar with a ‘well-known’ id — 1 in the example, which is created by a constant applicative form function. This TVar will retrieve its value from the BDB when it is created, or if no value exists for its id, it will be initialised with a default value, which in the case of a hashmap is an array of TVars, each containing an empty list of key-value pairs. A value stored in a TVar is persisted to the BDB by serialising it using CAL’s default
output function and Xstream, which can serialize and deserialize instances which are not serializable and do not have accessible constructors.
TVars themselves have
transient values, so only the id is persisted — the value is lazily loaded when required, using the id. So even though a TVar may persist a complicated tree of CAL algebraic values, this stops at the first TVar. (The root TVar is never persisted itself — only its value is stored).
ant build script includes a target
run-tests which runs some Selenium tests. Stop the server before running that target.
Note that the source code includes various bits of half-baked rubbish, in addition to that described above!