/// <summary> /// Get the value of a ref most recently set in this transaction (or prior to entering). /// </summary> /// <param name="r"></param> /// <param name="tvals"></param> /// <returns>The value.</returns> internal object DoGet(Ref r) { if (!_info.IsRunning) { throw _retryex; } if (_vals.ContainsKey(r)) { return(_vals[r]); } try { r.EnterReadLock(); if (r.TVals == null) { throw new InvalidOperationException(r.ToString() + " is not bound."); } Ref.TVal ver = r.TVals; do { if (ver.Point <= _readPoint) { return(ver.Val); } } while ((ver = ver.Prior) != r.TVals); } finally { r.ExitReadLock(); } // no version of val precedes the read point r.AddFault(); throw _retryex; }
/// <summary> /// Post a commute on a ref in this transaction. /// </summary> /// <param name="r">The ref.</param> /// <param name="fn">The commuting function.</param> /// <param name="args">Additional arguments to the function.</param> /// <returns>The computed value.</returns> internal object DoCommute(Ref r, IFn fn, ISeq args) { if (!_info.IsRunning) { throw _retryex; } if (!_vals.ContainsKey(r)) { object val = null; try { r.EnterReadLock(); val = r.TryGetVal(); } finally { r.ExitReadLock(); } _vals[r] = val; } List <CFn> fns; if (!_commutes.TryGetValue(r, out fns)) { _commutes[r] = fns = new List <CFn>(); } fns.Add(new CFn(fn, args)); object ret = fn.applyTo(RT.cons(_vals[r], args)); _vals[r] = ret; return(ret); }
/// <summary> /// Touch a ref. (Lock it.) /// </summary> /// <param name="r">The ref to touch.</param> internal void DoEnsure(Ref r) { if (!_info.IsRunning) { throw _retryex; } if (_ensures.Contains(r)) { return; } r.EnterReadLock(); // someone completed a write after our shapshot if (r.CurrentValPoint() > _readPoint) { r.ExitReadLock(); throw _retryex; } Info refinfo = r.TInfo; // writer exists if (refinfo != null && refinfo.IsRunning) { r.ExitReadLock(); if (refinfo != _info) // not us, ensure is doomed { BlockAndBail(refinfo); } } else { _ensures.Add(r); } }