/// <summary> /// Open object with intention to modify. /// </summary> /// <returns>Private version of object</returns> public ICloneable OpenWrite() { XState me = XAction.XState; // my transaction Locator oldLocator = (Locator)this.start; XState writer = oldLocator.writer; if (writer == me) { return(oldLocator.newObject); } IContentionManager manager = XAction.Manager; // my manager // allocate successor Locator newLocator = new Locator(); newLocator.writer = me; ICloneable oldVersion = null; ICloneable newVersion = null; while (true) { retry: // read locator switch (writer.State) { case XStates.ACTIVE: // abort or wait? manager.ResolveConflict(me, writer); goto retry; // try again case XStates.COMMITTED: oldVersion = newLocator.oldObject = oldLocator.newObject; break; case XStates.ABORTED: oldVersion = newLocator.oldObject = oldLocator.oldObject; break; default: throw new PanicException("Unexpected transaction state: {0}", writer.State); } switch (me.State) { case XStates.ABORTED: throw new AbortedException(); case XStates.COMMITTED: return(oldVersion); case XStates.ACTIVE: // check for read conflicts bool readConflict = false; foreach (XState reader in oldLocator) { if (reader.State == XStates.ACTIVE && reader != me) { manager.ResolveConflict(me, reader); readConflict = true; } if (readConflict) { goto retry; } } // no conflict newVersion = newLocator.newObject = (ICloneable)oldVersion.Clone(); // try to install if ((Locator)(Interlocked.CompareExchange( ref start, newLocator, oldLocator)) == oldLocator) { return(newVersion); } break; default: throw new PanicException("Unknown transaction state: {0}", me.State); } oldLocator = (Locator)this.start; writer = oldLocator.writer; } }
/// <summary> /// Open object with intention to modify. /// </summary> /// <returns>Private version of object</returns> public ICloneable OpenWrite() { XStatus me = Xaction.XStatus; // my transaction IContentionManager manager = Xaction.Manager; // my manager // allocate successor Locator newLocator = new Locator(); newLocator.writer = me; ICloneable oldVersion = null; ICloneable newVersion = null; while (true) { retry: // read locator Locator oldLocator = (Locator)this.start; XStatus writer = oldLocator.writer; switch (writer.State) { case XState.ACTIVE: case XState.WAITING: // abort or wait? manager.ResolveConflict(me, writer); goto retry; // try again case XState.COMMITTED: oldVersion = newLocator.oldObject = oldLocator.newObject; break; case XState.ABORTED: oldVersion = newLocator.oldObject = oldLocator.oldObject; break; default: Panic.SystemError("Unknown transaction state: {0}", me.State); break; // not reached } switch (me.State) { case XState.ABORTED: throw new AbortedException(); case XState.COMMITTED: return(oldVersion); case XState.ACTIVE: // check for read conflicts if (ConflictsWithReader(me, oldLocator.readers)) { manager.ResolveConflict(me, oldLocator.readers); goto retry; } // no conflict newVersion = newLocator.newObject = (ICloneable)oldVersion.Clone(); // try to install if ((Locator)(Interlocked.CompareExchange( ref start, newLocator, oldLocator)) == oldLocator) { #if DEBUG Xaction.myMisses++; #endif Xaction.AddToCache(readCache, newVersion); Xaction.AddToCache(writeCache, newVersion); return(newVersion); } break; default: Panic.SystemError("Unknown transaction state: {0}", me.State); break; // not reached } } }
/// <summary> /// Open object with intention to read. /// </summary> /// <returns>Shared version of object</returns> public ICloneable OpenRead() { XState me = XAction.XState; // my transaction Locator oldLocator = (Locator)this.start; XState writer = oldLocator.writer; if (writer == me) { return(oldLocator.newObject); } foreach (XState reader in oldLocator) { if (reader == me) { return(oldLocator.newObject); } } IContentionManager manager = XAction.Manager; // my manager // allocate successor Locator newLocator = new Locator(); newLocator.writer = XState.COMMITTED; while (true) { retry: // read locator ICloneable version = null; switch (writer.State) { case XStates.ACTIVE: // abort or wait? manager.ResolveConflict(me, writer); goto retry; // try again case XStates.COMMITTED: version = oldLocator.newObject; break; case XStates.ABORTED: version = oldLocator.oldObject; break; default: throw new PanicException("Unknown transaction state: {0}", writer.State); } switch (me.State) { case XStates.ABORTED: throw new AbortedException(); case XStates.COMMITTED: return(version); case XStates.ACTIVE: newLocator.newObject = version; newLocator.reader = me; if (oldLocator.reader != null) { newLocator.prevReader = oldLocator; } else { newLocator.prevReader = null; } if (Interlocked.CompareExchange( ref start, newLocator, oldLocator) == oldLocator) { return(version); } break; default: throw new PanicException("Unknown transaction state: {0}", me.State); } oldLocator = (Locator)this.start; writer = oldLocator.writer; } }
/// <summary> /// If object hasn't changed since snapshot, upgrade to read access. /// </summary> /// <returns>Shared version of object</returns> public bool Upgrade(ICloneable snapshot) { XStatus me = Xaction.XStatus; // my transaction IContentionManager manager = Xaction.Manager; // my manager // allocate successor Locator newLocator = new Locator(); newLocator.writer = XStatus.COMMITTED; while (true) { retry: // read locator Locator oldLocator = (Locator)this.start; XStatus writer = oldLocator.writer; switch (writer.State) { case XState.ACTIVE: // abort or wait? manager.ResolveConflict(me, writer); goto retry; // try again case XState.COMMITTED: if (snapshot != oldLocator.newObject) { return(false); } break; case XState.ABORTED: if (snapshot != oldLocator.oldObject) { return(false); } break; default: Panic.SystemError("Unknown transaction state: {0}", me.State); break; // not reached } switch (me.State) { case XState.ABORTED: throw new AbortedException(); case XState.ACTIVE: newLocator.newObject = snapshot; // copy live readers into new locator newLocator.readers.Clear(); newLocator.readers.Add(me); foreach (XStatus t in oldLocator.readers) { if (t.State == XState.ACTIVE) { newLocator.readers.Add(t); } } if (Interlocked.CompareExchange( ref start, newLocator, oldLocator) == oldLocator) { #if DEBUG Xaction.myMisses++; #endif Xaction.AddToCache(readCache, snapshot); return(true); } break; default: Panic.SystemError("Unknown transaction state: {0}", me.State); break; // not reached } } }