7

Given that the STM holds a history of say 10 values of refs, agents etc, can those values be read ?

The reason is, I'm updating a load of agents and I need to keep a history of values. If the STM is keeping them already, I'd rather just use them. I can't find functions in the API that look like they read values from the STM history so I guess not, nor can I find any methods in the java source code, but maybe I didn't look right.

Hendekagon
  • 4,405
  • 2
  • 25
  • 42
  • Your givens are incorrect. There is no history that you can read because there is no history. When a transaction commits, the old values are no longer referenced and are eligible for garbage collection. – Gabe Jun 27 '11 at 05:02
  • Oh I see now, the history is only held during a transaction. Thanks for the answer. – Hendekagon Jun 27 '11 at 05:03

1 Answers1

9

You cannot access the stm history of values directly. But you can make use of add-watch to record the history of values:

(def a-history (ref []))
(def a (agent 0))
(add-watch a :my-history 
  (fn [key ref old new] (alter a-history conj old)))

Every time a is updated (the stm transaction commits) the old value will be conjed onto the sequence that is held in a-history.

If you want to get access to all the intermediary values, even for rolled back transactions you can send the values to an agent during the transaction:

(def r-history (agent [])
(def r (ref 0))
(dosync (alter r
          (fn [new-val] 
            (send r-history conj new-val) ;; record potential new value 
            (inc r))))                    ;; update ref as you like

After the transaction finished, all changes to the agent r-history will be executed.

ordnungswidrig
  • 3,068
  • 1
  • 15
  • 29
  • 1
    +1. It's also worth noting that in many cases (thanks to persistent data structures) keeping the past values will use significantly less space than holding entire copies. So this can actually be a very space-efficient way of storing history. – mikera Jun 27 '11 at 17:36
  • Thanks for the additional ideas. In the end I used a clojure.lang.PersistentQueue – Hendekagon Jun 29 '11 at 06:36