diff options
author | Rich Hickey <richhickey@gmail.com> | 2009-06-30 11:22:39 -0400 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2009-06-30 11:22:39 -0400 |
commit | 6201f5e2ddd52f1b483d75563b0380deba59777c (patch) | |
tree | bd7688bb8f124f6acadc26693a7afce1058e90e7 | |
parent | 5e34989a7098a55ca014030d7446d2dc20ebc33b (diff) |
added ref min/max history control - refs #138
-rw-r--r-- | src/clj/clojure/core.clj | 39 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LockingTransaction.java | 5 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Ref.java | 44 |
3 files changed, 85 insertions, 3 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index ba674763..38c58daf 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -1268,14 +1268,30 @@ :validator validate-fn + :min-history (default 0) + :max-history (default 10) + If metadata-map is supplied, it will be come the metadata on the ref. validate-fn must be nil or a side-effect-free fn of one argument, which will be passed the intended new state on any state change. If the new state is unacceptable, the validate-fn should return false or throw an exception. validate-fn will be called on - transaction commit, when all refs have their final values." + transaction commit, when all refs have their final values. + + Normally refs accumulate history dynamically as needed to deal with + read demands. If you know in advance you will need history you can + set :min-history to ensure it will be available when first needed (instead + of after a read fault). History is limited, and the limit can be set + with :max-history." ([x] (new clojure.lang.Ref x)) - ([x & options] (setup-reference (ref x) options))) + ([x & options] + (let [r #^clojure.lang.Ref (setup-reference (ref x) options) + opts (apply hash-map options)] + (when (:max-history opts) + (.setMaxHistory r (:max-history opts))) + (when (:min-history opts) + (.setMinHistory r (:min-history opts))) + r))) (defn deref "Also reader macro: @ref/@agent/@var/@atom/@delay/@future. Within a transaction, @@ -1383,6 +1399,25 @@ [#^clojure.lang.Ref ref val] (. ref (set val))) +(defn ref-history-count + "Returns the history count of a ref" + [#^clojure.lang.Ref ref] + (.getHistoryCount ref)) + +(defn ref-min-history + "Gets the min-history of a ref, or sets it and returns the ref" + ([#^clojure.lang.Ref ref] + (.getMinHistory ref)) + ([#^clojure.lang.Ref ref n] + (.setMinHistory ref n))) + +(defn ref-max-history + "Gets the max-history of a ref, or sets it and returns the ref" + ([#^clojure.lang.Ref ref] + (.getMaxHistory ref)) + ([#^clojure.lang.Ref ref n] + (.setMaxHistory ref n))) + (defn ensure "Must be called in a transaction. Protects the ref from modification by other transactions. Returns the in-transaction-value of diff --git a/src/jvm/clojure/lang/LockingTransaction.java b/src/jvm/clojure/lang/LockingTransaction.java index 66a262e7..4976d169 100644 --- a/src/jvm/clojure/lang/LockingTransaction.java +++ b/src/jvm/clojure/lang/LockingTransaction.java @@ -281,11 +281,14 @@ Object run(Callable fn) throws Exception{ Ref ref = e.getKey(); Object oldval = ref.tvals == null ? null : ref.tvals.val; Object newval = e.getValue(); + int hcount = ref.histCount(); + if(ref.tvals == null) { ref.tvals = new Ref.TVal(newval, commitPoint, msecs); } - else if(ref.faults.get() > 0) + else if((ref.faults.get() > 0 && hcount < ref.maxHistory) + || hcount < ref.minHistory) { ref.tvals = new Ref.TVal(newval, commitPoint, msecs, ref.tvals); ref.faults.set(0); diff --git a/src/jvm/clojure/lang/Ref.java b/src/jvm/clojure/lang/Ref.java index 90faedcc..fef7c439 100644 --- a/src/jvm/clojure/lang/Ref.java +++ b/src/jvm/clojure/lang/Ref.java @@ -26,6 +26,24 @@ public class Ref extends ARef implements IFn, Comparable<Ref>, IRef{ return 1; } +public int getMinHistory(){ + return minHistory; +} + +public Ref setMinHistory(int minHistory){ + this.minHistory = minHistory; + return this; +} + +public int getMaxHistory(){ + return maxHistory; +} + +public Ref setMaxHistory(int maxHistory){ + this.maxHistory = maxHistory; + return this; +} + public static class TVal{ Object val; long point; @@ -60,6 +78,9 @@ LockingTransaction.Info tinfo; //IFn validator; final long id; +volatile int minHistory = 0; +volatile int maxHistory = 10; + static final AtomicLong ids = new AtomicLong(); public Ref(Object initVal) throws Exception{ @@ -187,6 +208,29 @@ public void trimHistory(){ } } +public int getHistoryCount(){ + try + { + lock.writeLock().lock(); + return histCount(); + } + finally + { + lock.writeLock().unlock(); + } +} + +int histCount(){ + if(tvals == null) + return 0; + else + { + int count = 0; + for(TVal tv = tvals.next;tv != tvals;tv = tv.next) + count++; + return count; + } +} final public IFn fn(){ return (IFn) deref(); |