bool ConflictsWithReader(XStatus me, ICollection readers)
 {
     foreach (XStatus reader in readers)
     {
         if (reader.State == XState.ACTIVE && reader != me)
         {
             return(true);
         }
     }
     return(false);
 }
        /// <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>
        /// 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
                }
            }
        }