Database Reference
In-Depth Information
While we're in the transaction, those values don't appear to have changed to the code outside
it. Once the transaction is committed, then any changes we make to those locations with
ref-set
or
alter
will be visible outside that block, as shown in the following diagram:
Note the following warnings:
F
With the STM, we should use only Clojure's native, immutable data types. This sounds
restrictive, but in practice, it isn't a big deal. Clojure has a rich and lexible collection
of data types.
F
We should also limit how much we try to do in each transaction. We only want to
bundle together operations that truly must pass or fail as a collection. This keeps
transactions from being retried too much, which can hurt performance.
The STM helps us manage complexity by allowing us to divide our processing in a way
that makes the most sense to us, and then to run those processes concurrently. The STM,
together with the immutable state, keeps this system simple and easy to reason about.
In this particular recipe, the irst reference to the STM is in the deinitions of
total-hu
and
total-fams
. Each of these is a reference, initially set to zero.
The
update-totals
function contains the
dosync
that updates the references. It uses
alter
, which takes the reference and a function that updates the value. Because of the
dosync
, if either of these values is changed in another thread that is summing another
chunk of data, the call to
dosync
is repeated. That's why we calculate the items' totals
before we enter that block.
Finally, in
main
, we partition the data into chunks, then package the calls to
update-totals
for each chunk of data into a thunk, and run it in Clojure's thread pool using
future-call
,
calling
deref
on future blocks until the value is returned from the thread pool.