InstancePersistenceContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / System.Runtime.DurableInstancing / System / Runtime / DurableInstancing / InstancePersistenceContext.cs / 1305376 / InstancePersistenceContext.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------

namespace System.Runtime.DurableInstancing 
{
    using System.Collections.Generic; 
    using System.Runtime.Serialization; 
    using System.Security;
    using System.Threading; 
    using System.Transactions;
    using System.Xml.Linq;

    [Fx.Tag.XamlVisible(false)] 
    public sealed class InstancePersistenceContext
    { 
        readonly TimeSpan timeout; 

        Transaction transaction; 
        bool freezeTransaction;
        CommittableTransaction myTransaction;
        int cancellationHandlerCalled;
 
        internal InstancePersistenceContext(InstanceHandle handle, Transaction transaction)
            : this(handle) 
        { 
            Fx.Assert(transaction != null, "Null Transaction passed to InstancePersistenceContext.");
 
            // Let's take our own clone of the transaction. We need to do this because we might need to
            // create a TransactionScope using the transaction and in cases where we are dealing with a
            // transaction that is flowed into the workflow on a message, the DependentTransaction that the
            // dispatcher creates and sets to Transaction.Current may already be Completed by the time a 
            // Save operation is done. And since TransactionScope creates a DependentTransaction, it won't
            // be able to. 
            // We don't create another DependentClone because we are going to do a EnlistVolatile on the 
            // transaction ourselves.
            this.transaction = transaction.Clone(); 
            IsHostTransaction = true;
        }

        internal InstancePersistenceContext(InstanceHandle handle, TimeSpan timeout) 
            : this(handle)
        { 
            this.timeout = timeout; 
        }
 
        InstancePersistenceContext(InstanceHandle handle)
        {
            Fx.Assert(handle != null, "Null handle passed to InstancePersistenceContext.");
 
            InstanceHandle = handle;
 
            // Fork a copy of the current view to be the new working view. It starts with no query results. 
            InstanceView newView = handle.View.Clone();
            newView.InstanceStoreQueryResults = null; 
            InstanceView = newView;

            this.cancellationHandlerCalled = 0;
        } 

        public InstanceHandle InstanceHandle { get; private set; } 
        public InstanceView InstanceView { get; private set; } 

        public long InstanceVersion 
        {
            get
            {
                return InstanceHandle.Version; 
            }
        } 
 
        public Guid LockToken
        { 
            get
            {
                Fx.Assert(InstanceHandle.Owner == null || InstanceHandle.Owner.OwnerToken == InstanceView.InstanceOwner.OwnerToken, "Mismatched lock tokens.");
 
                // If the handle doesn't own the lock yet, return the owner LockToken, which is needed to check whether this owner already owns locks.
                return InstanceHandle.Owner == null ? Guid.Empty : InstanceHandle.Owner.OwnerToken; 
            } 
        }
 
        public object UserContext
        {
            get
            { 
                return InstanceHandle.ProviderObject;
            } 
        } 

        bool CancelRequested { get; set; } 

        ExecuteAsyncResult RootAsyncResult { get; set; }
        ExecuteAsyncResult LastAsyncResult { get; set; }
        bool IsHostTransaction { get; set; } 

        bool Active 
        { 
            get
            { 
                return RootAsyncResult != null;
            }
        }
 
        public void SetCancellationHandler(Action cancellationHandler)
        { 
            ThrowIfNotActive("SetCancellationHandler"); 
            LastAsyncResult.CancellationHandler = cancellationHandler;
            if (CancelRequested && (cancellationHandler != null)) 
            {
                try
                {
                    if (Interlocked.CompareExchange(ref this.cancellationHandlerCalled, 0, 1) == 0) 
                    {
                        cancellationHandler(this); 
                    } 
                }
                catch (Exception exception) 
                {
                    if (Fx.IsFatal(exception))
                    {
                        throw; 
                    }
                    throw Fx.Exception.AsError(new CallbackException(SRCore.OnCancelRequestedThrew, exception)); 
                } 
            }
        } 

        public void BindInstanceOwner(Guid instanceOwnerId, Guid lockToken)
        {
            if (instanceOwnerId == Guid.Empty) 
            {
                throw Fx.Exception.Argument("instanceOwnerId", SRCore.GuidCannotBeEmpty); 
            } 
            if (lockToken == Guid.Empty)
            { 
                throw Fx.Exception.Argument("lockToken", SRCore.GuidCannotBeEmpty);
            }
            ThrowIfNotActive("BindInstanceOwner");
 
            InstanceOwner owner = InstanceHandle.Store.GetOrCreateOwner(instanceOwnerId, lockToken);
 
            InstanceView.BindOwner(owner); 
            IsHandleDoomedByRollback = true;
 
            InstanceHandle.BindOwner(owner);
        }

        public void BindInstance(Guid instanceId) 
        {
            if (instanceId == Guid.Empty) 
            { 
                throw Fx.Exception.Argument("instanceId", SRCore.GuidCannotBeEmpty);
            } 
            ThrowIfNotActive("BindInstance");

            InstanceView.BindInstance(instanceId);
            IsHandleDoomedByRollback = true; 

            InstanceHandle.BindInstance(instanceId); 
        } 

        public void BindEvent(InstancePersistenceEvent persistenceEvent) 
        {
            if (persistenceEvent == null)
            {
                throw Fx.Exception.ArgumentNull("persistenceEvent"); 
            }
            ThrowIfNotActive("BindEvent"); 
 
            if (!InstanceView.IsBoundToInstanceOwner)
            { 
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.ContextMustBeBoundToOwner));
            }
            IsHandleDoomedByRollback = true;
 
            InstanceHandle.BindOwnerEvent(persistenceEvent);
        } 
 
        public void BindAcquiredLock(long instanceVersion)
        { 
            if (instanceVersion < 0)
            {
                throw Fx.Exception.ArgumentOutOfRange("instanceVersion", instanceVersion, SRCore.InvalidLockToken);
            } 
            ThrowIfNotActive("BindAcquiredLock");
 
            // This call has a synchronization, so we are guaranteed it is only successful once. 
            InstanceView.BindLock(instanceVersion);
            IsHandleDoomedByRollback = true; 

            InstanceHandle.Bind(instanceVersion);
        }
 
        public void BindReclaimedLock(long instanceVersion, TimeSpan timeout)
        { 
            AsyncWaitHandle wait = InitiateBindReclaimedLockHelper("BindReclaimedLock", instanceVersion, timeout); 
            if (!wait.Wait(timeout))
            { 
                InstanceHandle.CancelReclaim(new TimeoutException(SRCore.TimedOutWaitingForLockResolution));
            }
            ConcludeBindReclaimedLockHelper();
        } 

        public IAsyncResult BeginBindReclaimedLock(long instanceVersion, TimeSpan timeout, AsyncCallback callback, object state) 
        { 
            AsyncWaitHandle wait = InitiateBindReclaimedLockHelper("BeginBindReclaimedLock", instanceVersion, timeout);
            return new BindReclaimedLockAsyncResult(this, wait, timeout, callback, state); 
        }

        public void EndBindReclaimedLock(IAsyncResult result)
        { 
            BindReclaimedLockAsyncResult.End(result);
        } 
 
        public Exception CreateBindReclaimedLockException(long instanceVersion)
        { 
            AsyncWaitHandle wait = InitiateBindReclaimedLockHelper("CreateBindReclaimedLockException", instanceVersion, TimeSpan.MaxValue);
            return new BindReclaimedLockException(wait);
        }
 
        AsyncWaitHandle InitiateBindReclaimedLockHelper(string methodName, long instanceVersion, TimeSpan timeout)
        { 
            if (instanceVersion < 0) 
            {
                throw Fx.Exception.ArgumentOutOfRange("instanceVersion", instanceVersion, SRCore.InvalidLockToken); 
            }
            TimeoutHelper.ThrowIfNegativeArgument(timeout);
            ThrowIfNotActive(methodName);
 
            // This call has a synchronization, so we are guaranteed it is only successful once.
            InstanceView.StartBindLock(instanceVersion); 
            IsHandleDoomedByRollback = true; 

            AsyncWaitHandle wait = InstanceHandle.StartReclaim(instanceVersion); 
            if (wait == null)
            {
                InstanceHandle.Free();
                throw Fx.Exception.AsError(new InstanceHandleConflictException(LastAsyncResult.CurrentCommand.Name, InstanceView.InstanceId)); 
            }
            return wait; 
        } 

        void ConcludeBindReclaimedLockHelper() 
        {
            // If FinishReclaim doesn't throw an exception, we are done - the reclaim was successful.
            // The Try / Finally makes up for the reverse order of setting the handle, then the view.
            long instanceVersion = -1; 
            try
            { 
                if (!InstanceHandle.FinishReclaim(ref instanceVersion)) 
                {
                    InstanceHandle.Free(); 
                    throw Fx.Exception.AsError(new InstanceHandleConflictException(LastAsyncResult.CurrentCommand.Name, InstanceView.InstanceId));
                }
                Fx.Assert(instanceVersion >= 0, "Where did the instance version go?");
            } 
            finally
            { 
                if (instanceVersion >= 0) 
                {
                    InstanceView.FinishBindLock(instanceVersion); 
                }
            }
        }
 
        public void PersistedInstance(IDictionary data)
        { 
            ThrowIfNotLocked(); 
            ThrowIfCompleted();
            ThrowIfNotTransactional("PersistedInstance"); 

            InstanceView.InstanceData = data.ReadOnlyCopy(true);
            InstanceView.InstanceDataConsistency = InstanceValueConsistency.None;
            InstanceView.InstanceState = InstanceState.Initialized; 
        }
 
        public void LoadedInstance(InstanceState state, IDictionary instanceData, IDictionary instanceMetadata, IDictionary> associatedInstanceKeyMetadata, IDictionary> completedInstanceKeyMetadata) 
        {
            if (state == InstanceState.Uninitialized) 
            {
                if (instanceData != null && instanceData.Count > 0)
                {
                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.UninitializedCannotHaveData)); 
                }
            } 
            else if (state == InstanceState.Completed) 
            {
                if (associatedInstanceKeyMetadata != null && associatedInstanceKeyMetadata.Count > 0) 
                {
                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.CompletedMustNotHaveAssociatedKeys));
                }
            } 
            else if (state != InstanceState.Initialized)
            { 
                throw Fx.Exception.Argument("state", SRCore.InvalidInstanceState); 
            }
            ThrowIfNoInstance(); 
            ThrowIfNotActive("PersistedInstance");

            InstanceValueConsistency consistency = InstanceView.IsBoundToLock || state == InstanceState.Completed ? InstanceValueConsistency.None : InstanceValueConsistency.InDoubt;
 
            ReadOnlyDictionary instanceDataCopy = instanceData.ReadOnlyCopy(false);
            ReadOnlyDictionary instanceMetadataCopy = instanceMetadata.ReadOnlyCopy(false); 
 
            Dictionary keysCopy = null;
            int totalKeys = (associatedInstanceKeyMetadata != null ? associatedInstanceKeyMetadata.Count : 0) + (completedInstanceKeyMetadata != null ? completedInstanceKeyMetadata.Count : 0); 
            if (totalKeys > 0)
            {
                keysCopy = new Dictionary(totalKeys);
            } 
            if (associatedInstanceKeyMetadata != null && associatedInstanceKeyMetadata.Count > 0)
            { 
                foreach (KeyValuePair> keyMetadata in associatedInstanceKeyMetadata) 
                {
                    InstanceKeyView view = new InstanceKeyView(keyMetadata.Key); 
                    view.InstanceKeyState = InstanceKeyState.Associated;
                    view.InstanceKeyMetadata = keyMetadata.Value.ReadOnlyCopy(false);
                    view.InstanceKeyMetadataConsistency = InstanceView.IsBoundToLock ? InstanceValueConsistency.None : InstanceValueConsistency.InDoubt;
                    keysCopy.Add(view.InstanceKey, view); 
                }
            } 
 
            if (completedInstanceKeyMetadata != null && completedInstanceKeyMetadata.Count > 0)
            { 
                foreach (KeyValuePair> keyMetadata in completedInstanceKeyMetadata)
                {
                    InstanceKeyView view = new InstanceKeyView(keyMetadata.Key);
                    view.InstanceKeyState = InstanceKeyState.Completed; 
                    view.InstanceKeyMetadata = keyMetadata.Value.ReadOnlyCopy(false);
                    view.InstanceKeyMetadataConsistency = consistency; 
                    keysCopy.Add(view.InstanceKey, view); 
                }
            } 

            InstanceView.InstanceState = state;

            InstanceView.InstanceData = instanceDataCopy; 
            InstanceView.InstanceDataConsistency = consistency;
 
            InstanceView.InstanceMetadata = instanceMetadataCopy; 
            InstanceView.InstanceMetadataConsistency = consistency;
 
            InstanceView.InstanceKeys = keysCopy == null ? null : new ReadOnlyDictionary(keysCopy, false);
            InstanceView.InstanceKeysConsistency = consistency;
        }
 
        public void CompletedInstance()
        { 
            ThrowIfNotLocked(); 
            ThrowIfUninitialized();
            ThrowIfCompleted(); 
            if ((InstanceView.InstanceKeysConsistency & InstanceValueConsistency.InDoubt) == 0)
            {
                foreach (KeyValuePair key in InstanceView.InstanceKeys)
                { 
                    if (key.Value.InstanceKeyState == InstanceKeyState.Associated)
                    { 
                        throw Fx.Exception.AsError(new InvalidOperationException(SRCore.CannotCompleteWithKeys)); 
                    }
                } 
            }
            ThrowIfNotTransactional("CompletedInstance");

            InstanceView.InstanceState = InstanceState.Completed; 
        }
 
        public void ReadInstanceMetadata(IDictionary metadata, bool complete) 
        {
            ThrowIfNoInstance(); 
            ThrowIfNotActive("ReadInstanceMetadata");

            if (InstanceView.InstanceMetadataConsistency == InstanceValueConsistency.None)
            { 
                return;
            } 
 
            if (complete)
            { 
                InstanceView.InstanceMetadata = metadata.ReadOnlyCopy(false);
                InstanceView.InstanceMetadataConsistency = InstanceView.IsBoundToLock || InstanceView.InstanceState == InstanceState.Completed ? InstanceValueConsistency.None : InstanceValueConsistency.InDoubt;
            }
            else 
            {
                if ((InstanceView.IsBoundToLock || InstanceView.InstanceState == InstanceState.Completed) && (InstanceView.InstanceMetadataConsistency & InstanceValueConsistency.InDoubt) != 0) 
                { 
                    // In this case, prefer throwing out old data and keeping only authoritative data.
                    InstanceView.InstanceMetadata = metadata.ReadOnlyMergeInto(null, false); 
                    InstanceView.InstanceMetadataConsistency = InstanceValueConsistency.Partial;
                }
                else
                { 
                    InstanceView.InstanceMetadata = metadata.ReadOnlyMergeInto(InstanceView.InstanceMetadata, false);
                    InstanceView.InstanceMetadataConsistency |= InstanceValueConsistency.Partial; 
                } 
            }
        } 

        public void WroteInstanceMetadataValue(XName name, InstanceValue value)
        {
            if (name == null) 
            {
                throw Fx.Exception.ArgumentNull("name"); 
            } 
            if (value == null)
            { 
                throw Fx.Exception.ArgumentNull("value");
            }
            ThrowIfNotLocked();
            ThrowIfCompleted(); 
            ThrowIfNotTransactional("WroteInstanceMetadataValue");
 
            InstanceView.AccumulatedMetadataWrites[name] = value; 
        }
 
        public void AssociatedInstanceKey(Guid key)
        {
            if (key == Guid.Empty)
            { 
                throw Fx.Exception.Argument("key", SRCore.InvalidKeyArgument);
            } 
            ThrowIfNotLocked(); 
            ThrowIfCompleted();
            ThrowIfNotTransactional("AssociatedInstanceKey"); 

            Dictionary copy = new Dictionary(InstanceView.InstanceKeys);
            if ((InstanceView.InstanceKeysConsistency & InstanceValueConsistency.InDoubt) == 0 && copy.ContainsKey(key))
            { 
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.KeyAlreadyAssociated));
            } 
            InstanceKeyView keyView = new InstanceKeyView(key); 
            keyView.InstanceKeyState = InstanceKeyState.Associated;
            keyView.InstanceKeyMetadataConsistency = InstanceValueConsistency.None; 
            copy[keyView.InstanceKey] = keyView;
            InstanceView.InstanceKeys = new ReadOnlyDictionary(copy, false);
        }
 
        public void CompletedInstanceKey(Guid key)
        { 
            if (key == Guid.Empty) 
            {
                throw Fx.Exception.Argument("key", SRCore.InvalidKeyArgument); 
            }
            ThrowIfNotLocked();
            ThrowIfCompleted();
            ThrowIfNotTransactional("CompletedInstanceKey"); 

            InstanceKeyView existingKeyView; 
            InstanceView.InstanceKeys.TryGetValue(key, out existingKeyView); 
            if ((InstanceView.InstanceKeysConsistency & InstanceValueConsistency.InDoubt) == 0)
            { 
                if (existingKeyView != null)
                {
                    if (existingKeyView.InstanceKeyState == InstanceKeyState.Completed)
                    { 
                        throw Fx.Exception.AsError(new InvalidOperationException(SRCore.KeyAlreadyCompleted));
                    } 
                } 
                else if ((InstanceView.InstanceKeysConsistency & InstanceValueConsistency.Partial) == 0)
                { 
                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.KeyNotAssociated));
                }
            }
 
            if (existingKeyView != null)
            { 
                existingKeyView.InstanceKeyState = InstanceKeyState.Completed; 
            }
            else 
            {
                Dictionary copy = new Dictionary(InstanceView.InstanceKeys);
                InstanceKeyView keyView = new InstanceKeyView(key);
                keyView.InstanceKeyState = InstanceKeyState.Completed; 
                keyView.InstanceKeyMetadataConsistency = InstanceValueConsistency.Partial;
                copy[keyView.InstanceKey] = keyView; 
                InstanceView.InstanceKeys = new ReadOnlyDictionary(copy, false); 
            }
        } 

        public void UnassociatedInstanceKey(Guid key)
        {
            if (key == Guid.Empty) 
            {
                throw Fx.Exception.Argument("key", SRCore.InvalidKeyArgument); 
            } 
            ThrowIfNotLocked();
            ThrowIfCompleted(); 
            ThrowIfNotTransactional("UnassociatedInstanceKey");

            InstanceKeyView existingKeyView;
            InstanceView.InstanceKeys.TryGetValue(key, out existingKeyView); 
            if ((InstanceView.InstanceKeysConsistency & InstanceValueConsistency.InDoubt) == 0)
            { 
                if (existingKeyView != null) 
                {
                    if (existingKeyView.InstanceKeyState == InstanceKeyState.Associated) 
                    {
                        throw Fx.Exception.AsError(new InvalidOperationException(SRCore.KeyNotCompleted));
                    }
                } 
                else if ((InstanceView.InstanceKeysConsistency & InstanceValueConsistency.Partial) == 0)
                { 
                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.KeyAlreadyUnassociated)); 
                }
            } 

            if (existingKeyView != null)
            {
                Dictionary copy = new Dictionary(InstanceView.InstanceKeys); 
                copy.Remove(key);
                InstanceView.InstanceKeys = new ReadOnlyDictionary(copy, false); 
            } 
        }
 
        public void ReadInstanceKeyMetadata(Guid key, IDictionary metadata, bool complete)
        {
            if (key == Guid.Empty)
            { 
                throw Fx.Exception.Argument("key", SRCore.InvalidKeyArgument);
            } 
            ThrowIfNoInstance(); 
            ThrowIfNotActive("ReadInstanceKeyMetadata");
 
            InstanceKeyView keyView;
            if (!InstanceView.InstanceKeys.TryGetValue(key, out keyView))
            {
                if (InstanceView.InstanceKeysConsistency == InstanceValueConsistency.None) 
                {
                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.KeyNotAssociated)); 
                } 

                Dictionary copy = new Dictionary(InstanceView.InstanceKeys); 
                keyView = new InstanceKeyView(key);
                if (complete)
                {
                    keyView.InstanceKeyMetadata = metadata.ReadOnlyCopy(false); 
                    keyView.InstanceKeyMetadataConsistency = InstanceValueConsistency.None;
                } 
                else 
                {
                    keyView.InstanceKeyMetadata = metadata.ReadOnlyMergeInto(null, false); 
                    keyView.InstanceKeyMetadataConsistency = InstanceValueConsistency.Partial;
                }
                if (!InstanceView.IsBoundToLock && InstanceView.InstanceState != InstanceState.Completed)
                { 
                    keyView.InstanceKeyMetadataConsistency |= InstanceValueConsistency.InDoubt;
                } 
                copy[keyView.InstanceKey] = keyView; 
                InstanceView.InstanceKeys = new ReadOnlyDictionary(copy, false);
            } 
            else
            {
                if (keyView.InstanceKeyMetadataConsistency == InstanceValueConsistency.None)
                { 
                    return;
                } 
 
                if (complete)
                { 
                    keyView.InstanceKeyMetadata = metadata.ReadOnlyCopy(false);
                    keyView.InstanceKeyMetadataConsistency = InstanceView.IsBoundToLock || InstanceView.InstanceState == InstanceState.Completed ? InstanceValueConsistency.None : InstanceValueConsistency.InDoubt;
                }
                else 
                {
                    if ((InstanceView.IsBoundToLock || InstanceView.InstanceState == InstanceState.Completed) && (keyView.InstanceKeyMetadataConsistency & InstanceValueConsistency.InDoubt) != 0) 
                    { 
                        // In this case, prefer throwing out old data and keeping only authoritative data.
                        keyView.InstanceKeyMetadata = metadata.ReadOnlyMergeInto(null, false); 
                        keyView.InstanceKeyMetadataConsistency = InstanceValueConsistency.Partial;
                    }
                    else
                    { 
                        keyView.InstanceKeyMetadata = metadata.ReadOnlyMergeInto(keyView.InstanceKeyMetadata, false);
                        keyView.InstanceKeyMetadataConsistency |= InstanceValueConsistency.Partial; 
                    } 
                }
            } 
        }

        public void WroteInstanceKeyMetadataValue(Guid key, XName name, InstanceValue value)
        { 
            if (key == Guid.Empty)
            { 
                throw Fx.Exception.Argument("key", SRCore.InvalidKeyArgument); 
            }
            if (name == null) 
            {
                throw Fx.Exception.ArgumentNull("name");
            }
            if (value == null) 
            {
                throw Fx.Exception.ArgumentNull("value"); 
            } 
            ThrowIfNotLocked();
            ThrowIfCompleted(); 
            ThrowIfNotTransactional("WroteInstanceKeyMetadataValue");

            InstanceKeyView keyView;
            if (!InstanceView.InstanceKeys.TryGetValue(key, out keyView)) 
            {
                if (InstanceView.InstanceKeysConsistency == InstanceValueConsistency.None) 
                { 
                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.KeyNotAssociated));
                } 

                if (!value.IsWriteOnly() && !value.IsDeletedValue)
                {
                    Dictionary copy = new Dictionary(InstanceView.InstanceKeys); 
                    keyView = new InstanceKeyView(key);
                    keyView.AccumulatedMetadataWrites.Add(name, value); 
                    keyView.InstanceKeyMetadataConsistency = InstanceValueConsistency.Partial; 
                    copy[keyView.InstanceKey] = keyView;
                    InstanceView.InstanceKeys = new ReadOnlyDictionary(copy, false); 
                    InstanceView.InstanceKeysConsistency |= InstanceValueConsistency.Partial;
                }
            }
            else 
            {
                keyView.AccumulatedMetadataWrites.Add(name, value); 
            } 
        }
 
        public void ReadInstanceOwnerMetadata(IDictionary metadata, bool complete)
        {
            ThrowIfNoOwner();
            ThrowIfNotActive("ReadInstanceOwnerMetadata"); 

            if (InstanceView.InstanceOwnerMetadataConsistency == InstanceValueConsistency.None) 
            { 
                return;
            } 

            if (complete)
            {
                InstanceView.InstanceOwnerMetadata = metadata.ReadOnlyCopy(false); 
                InstanceView.InstanceOwnerMetadataConsistency = InstanceValueConsistency.InDoubt;
            } 
            else 
            {
                InstanceView.InstanceOwnerMetadata = metadata.ReadOnlyMergeInto(InstanceView.InstanceOwnerMetadata, false); 
                InstanceView.InstanceOwnerMetadataConsistency |= InstanceValueConsistency.Partial;
            }
        }
 
        public void WroteInstanceOwnerMetadataValue(XName name, InstanceValue value)
        { 
            if (name == null) 
            {
                throw Fx.Exception.ArgumentNull("name"); 
            }
            if (value == null)
            {
                throw Fx.Exception.ArgumentNull("value"); 
            }
            ThrowIfNoOwner(); 
            ThrowIfNotTransactional("WroteInstanceOwnerMetadataValue"); 

            InstanceView.AccumulatedOwnerMetadataWrites.Add(name, value); 
        }

        public void QueriedInstanceStore(InstanceStoreQueryResult queryResult)
        { 
            if (queryResult == null)
            { 
                throw Fx.Exception.ArgumentNull("queryResult"); 
            }
            ThrowIfNotActive("QueriedInstanceStore"); 

            InstanceView.QueryResultsBacking.Add(queryResult);
        }
 
        [Fx.Tag.Throws.Timeout("The operation timed out.")]
        [Fx.Tag.Throws(typeof(OperationCanceledException), "The operation was canceled because the InstanceHandle has been freed.")] 
        [Fx.Tag.Throws(typeof(InstancePersistenceException), "A command failed.")] 
        [Fx.Tag.Blocking(CancelMethod = "NotifyHandleFree")]
        public void Execute(InstancePersistenceCommand command, TimeSpan timeout) 
        {
            if (command == null)
            {
                throw Fx.Exception.ArgumentNull("command"); 
            }
            ThrowIfNotActive("Execute"); 
 
            try
            { 
                ReconcileTransaction();
                ExecuteAsyncResult.End(new ExecuteAsyncResult(this, command, timeout));
            }
            catch (TimeoutException) 
            {
                InstanceHandle.Free(); 
                throw; 
            }
            catch (OperationCanceledException) 
            {
                InstanceHandle.Free();
                throw;
            } 
        }
 
        // For each level of hierarchy of command execution, only one BeginExecute may be pending at a time. 
        [Fx.Tag.InheritThrows(From = "Execute")]
        public IAsyncResult BeginExecute(InstancePersistenceCommand command, TimeSpan timeout, AsyncCallback callback, object state) 
        {
            if (command == null)
            {
                throw Fx.Exception.ArgumentNull("command"); 
            }
            ThrowIfNotActive("BeginExecute"); 
 
            try
            { 
                ReconcileTransaction();
                return new ExecuteAsyncResult(this, command, timeout, callback, state);
            }
            catch (TimeoutException) 
            {
                InstanceHandle.Free(); 
                throw; 
            }
            catch (OperationCanceledException) 
            {
                InstanceHandle.Free();
                throw;
            } 
        }
 
        [Fx.Tag.InheritThrows(From = "Execute")] 
        [Fx.Tag.Blocking(CancelMethod = "NotifyHandleFree", Conditional = "!result.IsCompleted")]
        public void EndExecute(IAsyncResult result) 
        {
            ExecuteAsyncResult.End(result);
        }
 
        internal Transaction Transaction
        { 
            get 
            {
                return this.transaction; 
            }
        }

        internal bool IsHandleDoomedByRollback { get; private set; } 

        internal void RequireTransaction() 
        { 
            if (this.transaction != null)
            { 
                return;
            }
            Fx.AssertAndThrow(!this.freezeTransaction, "RequireTransaction called when transaction is frozen.");
            Fx.AssertAndThrow(Active, "RequireTransaction called when no command is active."); 

            // It's ok if some time has passed since the timeout value was acquired, it is ok to run long.  This transaction is not generally responsible 
            // for timing out the Execute operation. The exception to this rule is during Commit. 
            this.myTransaction = new CommittableTransaction(new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted, Timeout = this.timeout });
            Transaction clone = this.myTransaction.Clone(); 
            RootAsyncResult.SetInteriorTransaction(this.myTransaction, true);
            this.transaction = clone;
        }
 
        internal void PrepareForReuse()
        { 
            Fx.AssertAndThrow(!Active, "Prior use not yet complete!"); 
            Fx.AssertAndThrow(IsHostTransaction, "Can only reuse contexts with host transactions.");
        } 

        internal void NotifyHandleFree()
        {
            CancelRequested = true; 
            ExecuteAsyncResult lastAsyncResult = LastAsyncResult;
            Action onCancel = lastAsyncResult == null ? null : lastAsyncResult.CancellationHandler; 
            if (onCancel != null) 
            {
                try 
                {
                    if (Interlocked.CompareExchange(ref this.cancellationHandlerCalled, 0, 1) == 0)
                    {
                        onCancel(this); 
                    }
                } 
                catch (Exception exception) 
                {
                    if (Fx.IsFatal(exception)) 
                    {
                        throw;
                    }
                    throw Fx.Exception.AsError(new CallbackException(SRCore.OnCancelRequestedThrew, exception)); 
                }
            } 
        } 

        [Fx.Tag.Blocking(CancelMethod = "NotifyHandleFree")] 
        internal static InstanceView OuterExecute(InstanceHandle initialInstanceHandle, InstancePersistenceCommand command, Transaction transaction, TimeSpan timeout)
        {
            try
            { 
                return ExecuteAsyncResult.End(new ExecuteAsyncResult(initialInstanceHandle, command, transaction, timeout));
            } 
            catch (TimeoutException) 
            {
                initialInstanceHandle.Free(); 
                throw;
            }
            catch (OperationCanceledException)
            { 
                initialInstanceHandle.Free();
                throw; 
            } 
        }
 
        internal static IAsyncResult BeginOuterExecute(InstanceHandle initialInstanceHandle, InstancePersistenceCommand command, Transaction transaction, TimeSpan timeout, AsyncCallback callback, object state)
        {
            try
            { 
                return new ExecuteAsyncResult(initialInstanceHandle, command, transaction, timeout, callback, state);
            } 
            catch (TimeoutException) 
            {
                initialInstanceHandle.Free(); 
                throw;
            }
            catch (OperationCanceledException)
            { 
                initialInstanceHandle.Free();
                throw; 
            } 
        }
 
        [Fx.Tag.Blocking(CancelMethod = "NotifyHandleFree", Conditional = "!result.IsCompleted")]
        internal static InstanceView EndOuterExecute(IAsyncResult result)
        {
            InstanceView finalState = ExecuteAsyncResult.End(result); 
            if (finalState == null)
            { 
                throw Fx.Exception.Argument("result", SRCore.InvalidAsyncResult); 
            }
            return finalState; 
        }

        void ThrowIfNotLocked()
        { 
            if (!InstanceView.IsBoundToLock)
            { 
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InstanceOperationRequiresLock)); 
            }
        } 

        void ThrowIfNoInstance()
        {
            if (!InstanceView.IsBoundToInstance) 
            {
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InstanceOperationRequiresInstance)); 
            } 
        }
 
        void ThrowIfNoOwner()
        {
            if (!InstanceView.IsBoundToInstanceOwner)
            { 
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InstanceOperationRequiresOwner));
            } 
        } 

        void ThrowIfCompleted() 
        {
            if (InstanceView.IsBoundToLock && InstanceView.InstanceState == InstanceState.Completed)
            {
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InstanceOperationRequiresNotCompleted)); 
            }
        } 
 
        void ThrowIfUninitialized()
        { 
            if (InstanceView.IsBoundToLock && InstanceView.InstanceState == InstanceState.Uninitialized)
            {
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InstanceOperationRequiresNotUninitialized));
            } 
        }
 
        void ThrowIfNotActive(string methodName) 
        {
            if (!Active) 
            {
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.OutsideInstanceExecutionScope(methodName)));
            }
        } 

        void ThrowIfNotTransactional(string methodName) 
        { 
            ThrowIfNotActive(methodName);
            if (RootAsyncResult.CurrentCommand.IsTransactionEnlistmentOptional) 
            {
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.OutsideTransactionalCommand(methodName)));
            }
        } 

        void ReconcileTransaction() 
        { 
            // If the provider fails to flow the transaction, that's fine, we don't consider that a request
            // not to use one. 
            Transaction transaction = Transaction.Current;
            if (transaction != null)
            {
                if (this.transaction == null) 
                {
                    if (this.freezeTransaction) 
                    { 
                        throw Fx.Exception.AsError(new InvalidOperationException(SRCore.MustSetTransactionOnFirstCall));
                    } 
                    RootAsyncResult.SetInteriorTransaction(transaction, false);
                    this.transaction = transaction;
                }
                else if (!transaction.Equals(this.transaction)) 
                {
                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.CannotReplaceTransaction)); 
                } 
            }
            this.freezeTransaction = true; 
        }

        class ExecuteAsyncResult : AsyncResult, ISinglePhaseNotification
        { 
            static AsyncCompletion onAcquireContext = new AsyncCompletion(OnAcquireContext);
            static AsyncCompletion onTryCommand = new AsyncCompletion(OnTryCommand); 
            static AsyncCompletion onCommit = new AsyncCompletion(OnCommit); 
            static Action onBindReclaimed = new Action(OnBindReclaimed);
            static Action onCommitWait = new Action(OnCommitWait); 

            readonly InstanceHandle initialInstanceHandle;
            readonly Stack> executionStack;
            readonly TimeoutHelper timeoutHelper; 
            readonly ExecuteAsyncResult priorAsyncResult;
 
            InstancePersistenceContext context; 
            CommittableTransaction transactionToCommit;
            IEnumerator currentExecution; 
            AsyncWaitHandle waitForTransaction;
            Action cancellationHandler;
            bool executeCalledByCurrentCommand;
            bool rolledBack; 
            bool inDoubt;
 
            InstanceView finalState; 

            public ExecuteAsyncResult(InstanceHandle initialInstanceHandle, InstancePersistenceCommand command, Transaction transaction, TimeSpan timeout, AsyncCallback callback, object state) 
                : this(command, timeout, callback, state)
            {
                this.initialInstanceHandle = initialInstanceHandle;
 
                OnCompleting = new Action(SimpleCleanup);
 
                IAsyncResult result = this.initialInstanceHandle.BeginAcquireExecutionContext(transaction, this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(ExecuteAsyncResult.onAcquireContext), this); 
                if (result.CompletedSynchronously)
                { 
                    // After this stage, must complete explicitly in order to get Cleanup to run correctly.
                    bool completeSelf = false;
                    Exception completionException = null;
                    try 
                    {
                        completeSelf = OnAcquireContext(result); 
                    } 
                    catch (Exception exception)
                    { 
                        if (Fx.IsFatal(exception))
                        {
                            throw;
                        } 
                        completeSelf = true;
                        completionException = exception; 
                    } 
                    if (completeSelf)
                    { 
                        Complete(true, completionException);
                    }
                }
            } 

            public ExecuteAsyncResult(InstancePersistenceContext context, InstancePersistenceCommand command, TimeSpan timeout, AsyncCallback callback, object state) 
                : this(command, timeout, callback, state) 
            {
                this.context = context; 

                this.priorAsyncResult = this.context.LastAsyncResult;
                Fx.Assert(this.priorAsyncResult != null, "The LastAsyncResult should already have been checked.");
                this.priorAsyncResult.executeCalledByCurrentCommand = true; 

                OnCompleting = new Action(SimpleCleanup); 
 
                bool completeSelf = false;
                bool success = false; 
                try
                {
                    this.context.LastAsyncResult = this;
                    if (RunLoop()) 
                    {
                        completeSelf = true; 
                    } 
                    success = true;
                } 
                finally
                {
                    if (!success)
                    { 
                        this.context.LastAsyncResult = this.priorAsyncResult;
                    } 
                } 
                if (completeSelf)
                { 
                    Complete(true);
                }
            }
 
            [Fx.Tag.Blocking(CancelMethod = "NotifyHandleFree", CancelDeclaringType = typeof(InstancePersistenceContext))]
            public ExecuteAsyncResult(InstanceHandle initialInstanceHandle, InstancePersistenceCommand command, Transaction transaction, TimeSpan timeout) 
                : this(command, timeout, null, null) 
            {
                this.initialInstanceHandle = initialInstanceHandle; 
                this.context = this.initialInstanceHandle.AcquireExecutionContext(transaction, this.timeoutHelper.RemainingTime());

                Exception completionException = null;
                try 
                {
                    // After this stage, must complete explicitly in order to get Cleanup to run correctly. 
                    this.context.RootAsyncResult = this; 
                    this.context.LastAsyncResult = this;
                    OnCompleting = new Action(Cleanup); 

                    RunLoopCore(true);

                    if (this.transactionToCommit != null) 
                    {
                        try 
                        { 
                            this.transactionToCommit.Commit();
                        } 
                        catch (TransactionException)
                        {
                            // Since we are enlisted in this transaction, we can ignore exceptions from Commit.
                        } 
                        this.transactionToCommit = null;
                    } 
 
                    DoWaitForTransaction(true);
                } 
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception))
                    { 
                        throw;
                    } 
                    completionException = exception; 
                }
                Complete(true, completionException); 
            }

            [Fx.Tag.Blocking(CancelMethod = "NotifyHandleFree", CancelDeclaringType = typeof(InstancePersistenceContext))]
            public ExecuteAsyncResult(InstancePersistenceContext context, InstancePersistenceCommand command, TimeSpan timeout) 
                : this(command, timeout, null, null)
            { 
                this.context = context; 

                this.priorAsyncResult = this.context.LastAsyncResult; 
                Fx.Assert(this.priorAsyncResult != null, "The LastAsyncResult should already have been checked.");
                this.priorAsyncResult.executeCalledByCurrentCommand = true;

                bool success = false; 
                try
                { 
                    this.context.LastAsyncResult = this; 
                    RunLoopCore(true);
                    success = true; 
                }
                finally
                {
                    this.context.LastAsyncResult = this.priorAsyncResult; 
                    if (!success && this.context.IsHandleDoomedByRollback)
                    { 
                        this.context.InstanceHandle.Free(); 
                    }
                } 
                Complete(true);
            }

            ExecuteAsyncResult(InstancePersistenceCommand command, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) 
            {
                this.executionStack = new Stack>(2); 
                this.timeoutHelper = new TimeoutHelper(timeout); 

                this.currentExecution = (new List { command }).GetEnumerator(); 
            }

            internal InstancePersistenceCommand CurrentCommand { get; private set; }
 
            internal Action CancellationHandler
            { 
                get 
                {
                    Action handler = this.cancellationHandler; 
                    ExecuteAsyncResult current = this;
                    while (handler == null)
                    {
                        current = current.priorAsyncResult; 
                        if (current == null)
                        { 
                            break; 
                        }
                        handler = current.cancellationHandler; 
                    }
                    return handler;
                }
 
                set
                { 
                    this.cancellationHandler = value; 
                }
            } 

            public void SetInteriorTransaction(Transaction interiorTransaction, bool needsCommit)
            {
                Fx.Assert(!this.context.IsHostTransaction, "SetInteriorTransaction called for a host transaction."); 

                if (this.waitForTransaction != null) 
                { 
                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.ExecuteMustBeNested));
                } 

                bool success = false;
                try
                { 
                    this.waitForTransaction = new AsyncWaitHandle(EventResetMode.ManualReset);
                    interiorTransaction.EnlistVolatile(this, EnlistmentOptions.None); 
                    success = true; 
                }
                finally 
                {
                    if (!success)
                    {
                        if (this.waitForTransaction != null) 
                        {
                            this.waitForTransaction.Set(); 
                        } 
                    }
                    else if (needsCommit) 
                    {
                        this.transactionToCommit = (CommittableTransaction)interiorTransaction;
                    }
                } 
            }
 
            [Fx.Tag.Blocking(CancelMethod = "NotifyHandleFree", CancelDeclaringType = typeof(InstancePersistenceContext), Conditional = "!result.IsCOmpleted")] 
            public static InstanceView End(IAsyncResult result)
            { 
                ExecuteAsyncResult thisPtr = AsyncResult.End(result);
                Fx.Assert((thisPtr.finalState == null) == (thisPtr.initialInstanceHandle == null), "Should have thrown an exception if this is null on the outer result.");
                return thisPtr.finalState;
            } 

            static bool OnAcquireContext(IAsyncResult result) 
            { 
                ExecuteAsyncResult thisPtr = (ExecuteAsyncResult)result.AsyncState;
                thisPtr.context = thisPtr.initialInstanceHandle.EndAcquireExecutionContext(result); 
                thisPtr.context.RootAsyncResult = thisPtr;
                thisPtr.context.LastAsyncResult = thisPtr;
                thisPtr.OnCompleting = new Action(thisPtr.Cleanup);
                return thisPtr.RunLoop(); 
            }
 
            [Fx.Tag.Blocking(CancelMethod = "NotifyHandleFree", CancelDeclaringType = typeof(InstancePersistenceContext), Conditional = "synchronous")] 
            bool RunLoopCore(bool synchronous)
            { 
                while (this.currentExecution != null)
                {
                    if (this.currentExecution.MoveNext())
                    { 
                        bool isFirstCommand = CurrentCommand == null;
                        this.executeCalledByCurrentCommand = false; 
                        CurrentCommand = this.currentExecution.Current; 

                        Fx.Assert(isFirstCommand || this.executionStack.Count > 0, "The first command should always remain at the top of the stack."); 

                        if (isFirstCommand)
                        {
                            if (this.priorAsyncResult != null) 
                            {
                                if (this.priorAsyncResult.CurrentCommand.IsTransactionEnlistmentOptional && !CurrentCommand.IsTransactionEnlistmentOptional) 
                                { 
                                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.CannotInvokeTransactionalFromNonTransactional));
                                } 
                            }
                        }
                        else if (this.executionStack.Peek().Current.IsTransactionEnlistmentOptional)
                        { 
                            if (!CurrentCommand.IsTransactionEnlistmentOptional)
                            { 
                                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.CannotInvokeTransactionalFromNonTransactional)); 
                            }
                        } 
                        else if (this.priorAsyncResult == null)
                        {
                            // This is not the first command. Since the whole thing wasn't done at once by the
                            // provider, force a transaction if the first command required one. 
                            this.context.RequireTransaction();
                        } 
 
                        // Intentionally calling MayBindLockToInstanceHandle prior to Validate.  This is a publically visible order.
                        bool mayBindLockToInstanceHandle = CurrentCommand.AutomaticallyAcquiringLock; 
                        CurrentCommand.Validate(this.context.InstanceView);

                        if (mayBindLockToInstanceHandle)
                        { 
                            if (isFirstCommand)
                            { 
                                if (this.priorAsyncResult != null) 
                                {
                                    if (!this.priorAsyncResult.CurrentCommand.AutomaticallyAcquiringLock) 
                                    {
                                        throw Fx.Exception.AsError(new InvalidOperationException(SRCore.CannotInvokeBindingFromNonBinding));
                                    }
                                } 
                                else if (!this.context.InstanceView.IsBoundToInstanceOwner)
                                { 
                                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.MayBindLockCommandShouldValidateOwner)); 
                                }
                                else if (!this.context.InstanceView.IsBoundToLock) 
                                {
                                    // This is the first command in the set and it may lock, so we must start the bind.
                                    this.context.InstanceHandle.StartPotentialBind();
                                } 
                            }
                            else if (!this.executionStack.Peek().Current.AutomaticallyAcquiringLock) 
                            { 
                                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.CannotInvokeBindingFromNonBinding));
                            } 
                        }

                        if (this.context.CancelRequested)
                        { 
                            throw Fx.Exception.AsError(new OperationCanceledException(SRCore.HandleFreed));
                        } 
 
                        BindReclaimedLockException bindReclaimedLockException = null;
                        if (synchronous) 
                        {
                            bool commandProcessed;
                            TransactionScope txScope = null;
                            try 
                            {
                                txScope = Fx.CreateTransactionScope(this.context.Transaction); 
                                commandProcessed = this.context.InstanceHandle.Store.TryCommand(this.context, CurrentCommand, this.timeoutHelper.RemainingTime()); 
                            }
                            catch (BindReclaimedLockException exception) 
                            {
                                bindReclaimedLockException = exception;
                                commandProcessed = true;
                            } 
                            finally
                            { 
                                Fx.CompleteTransactionScope(ref txScope); 
                            }
                            AfterCommand(commandProcessed); 
                            if (bindReclaimedLockException != null)
                            {
                                BindReclaimed(!bindReclaimedLockException.MarkerWaitHandle.Wait(this.timeoutHelper.RemainingTime()));
                            } 
                        }
                        else 
                        { 
                            IAsyncResult result;
                            using (PrepareTransactionalCall(this.context.Transaction)) 
                            {
                                try
                                {
                                    result = this.context.InstanceHandle.Store.BeginTryCommand(this.context, CurrentCommand, this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(ExecuteAsyncResult.onTryCommand), this); 
                                }
                                catch (BindReclaimedLockException exception) 
                                { 
                                    bindReclaimedLockException = exception;
                                    result = null; 
                                }
                            }
                            if (result == null)
                            { 
                                AfterCommand(true);
                                if (!bindReclaimedLockException.MarkerWaitHandle.WaitAsync(ExecuteAsyncResult.onBindReclaimed, this, this.timeoutHelper.RemainingTime())) 
                                { 
                                    return false;
                                } 
                                BindReclaimed(false);
                            }
                            else
                            { 
                                if (!CheckSyncContinue(result) || !DoEndCommand(result))
                                { 
                                    return false; 
                                }
                            } 
                        }
                    }
                    else if (this.executionStack.Count > 0)
                    { 
                        this.currentExecution = this.executionStack.Pop();
                    } 
                    else 
                    {
                        this.currentExecution = null; 
                    }
                }

                CurrentCommand = null; 
                return true;
            } 
 
            bool RunLoop()
            { 
                if (!RunLoopCore(false))
                {
                    return false;
                } 

                // If this is an inner command, return true right away to continue this execution episode in a different async result. 
                if (this.initialInstanceHandle == null) 
                {
                    return true; 
                }

                // This is is an outer scope.  We need to commit and/or wait for commit if necessary.
                if (this.transactionToCommit != null) 
                {
                    IAsyncResult result = null; 
                    try 
                    {
                        result = this.transactionToCommit.BeginCommit(PrepareAsyncCompletion(ExecuteAsyncResult.onCommit), this); 
                    }
                    catch (TransactionException)
                    {
                        // Since we are enlisted in the transaction, we can ignore exceptions from Commit. 
                        this.transactionToCommit = null;
                    } 
                    if (result != null) 
                    {
                        return result.CompletedSynchronously ? OnCommit(result) : false; 
                    }
                }

                return DoWaitForTransaction(false); 
            }
 
            static bool OnTryCommand(IAsyncResult result) 
            {
                ExecuteAsyncResult thisPtr = (ExecuteAsyncResult)result.AsyncState; 
                return thisPtr.DoEndCommand(result) && thisPtr.RunLoop();
            }

            [Fx.Tag.GuaranteeNonBlocking] 
            bool DoEndCommand(IAsyncResult result)
            { 
                bool commandProcessed; 
                BindReclaimedLockException bindReclaimedLockException = null;
                try 
                {
                    commandProcessed = this.context.InstanceHandle.Store.EndTryCommand(result);
                }
                catch (BindReclaimedLockException exception) 
                {
                    bindReclaimedLockException = exception; 
                    commandProcessed = true; 
                }
                AfterCommand(commandProcessed); 
                if (bindReclaimedLockException != null)
                {
                    if (!bindReclaimedLockException.MarkerWaitHandle.WaitAsync(ExecuteAsyncResult.onBindReclaimed, this, this.timeoutHelper.RemainingTime()))
                    { 
                        return false;
                    } 
                    BindReclaimed(false); 
                }
                return true; 
            }

            void AfterCommand(bool commandProcessed)
            { 
                if (!object.ReferenceEquals(this.context.LastAsyncResult, this))
                { 
                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.ExecuteMustBeNested)); 
                }
                if (!commandProcessed) 
                {
                    if (this.executeCalledByCurrentCommand)
                    {
                        throw Fx.Exception.AsError(new InvalidOperationException(SRCore.TryCommandCannotExecuteSubCommandsAndReduce)); 
                    }
                    IEnumerable reduction = CurrentCommand.Reduce(this.context.InstanceView); 
                    if (reduction == null) 
                    {
                        throw Fx.Exception.AsError(new NotSupportedException(SRCore.ProviderDoesNotSupportCommand(CurrentCommand.Name))); 
                    }
                    this.executionStack.Push(this.currentExecution);
                    this.currentExecution = reduction.GetEnumerator();
                } 
            }
 
            static void OnBindReclaimed(object state, TimeoutException timeoutException) 
            {
                ExecuteAsyncResult thisPtr = (ExecuteAsyncResult)state; 

                bool completeSelf;
                Exception completionException = null;
                try 
                {
                    thisPtr.BindReclaimed(timeoutException != null); 
                    completeSelf = thisPtr.RunLoop(); 
                }
                catch (Exception exception) 
                {
                    if (Fx.IsFatal(exception))
                    {
                        throw; 
                    }
                    completionException = exception; 
                    completeSelf = true; 
                }
                if (completeSelf) 
                {
                    thisPtr.Complete(false, completionException);
                }
            } 

            void BindReclaimed(bool timedOut) 
            { 
                if (timedOut)
                { 
                    this.context.InstanceHandle.CancelReclaim(new TimeoutException(SRCore.TimedOutWaitingForLockResolution));
                }
                this.context.ConcludeBindReclaimedLockHelper();
 
                // If we get here, the reclaim attempt succeeded and we own the lock - but we are in the
                // CreateBindReclaimedLockException path, which auto-cancels on success. 
                this.context.InstanceHandle.Free(); 
                throw Fx.Exception.AsError(new OperationCanceledException(SRCore.BindReclaimSucceeded));
            } 

            [Fx.Tag.GuaranteeNonBlocking]
            static bool OnCommit(IAsyncResult result)
            { 
                ExecuteAsyncResult thisPtr = (ExecuteAsyncResult)result.AsyncState;
                try 
                { 
                    thisPtr.transactionToCommit.EndCommit(result);
                } 
                catch (TransactionException)
                {
                    // Since we are enlisted in the transaction, we can ignore exceptions from Commit.
                } 
                thisPtr.transactionToCommit = null;
                return thisPtr.DoWaitForTransaction(false); 
            } 

            [Fx.Tag.Blocking(CancelMethod = "NotifyHandleFree", CancelDeclaringType = typeof(InstancePersistenceContext), Conditional = "synchronous")] 
            bool DoWaitForTransaction(bool synchronous)
            {
                if (this.waitForTransaction != null)
                { 
                    if (synchronous)
                    { 
                        TimeSpan waitTimeout = this.timeoutHelper.RemainingTime(); 
                        if (!this.waitForTransaction.Wait(waitTimeout))
                        { 
                            throw Fx.Exception.AsError(new TimeoutException(SRCore.TimeoutOnOperation(waitTimeout)));
                        }
                    }
                    else 
                    {
                        if (!this.waitForTransaction.WaitAsync(ExecuteAsyncResult.onCommitWait, this, this.timeoutHelper.RemainingTime())) 
                        { 
                            return false;
                        } 
                    }
                    Exception exception = AfterCommitWait();
                    if (exception != null)
                    { 
                        throw Fx.Exception.AsError(exception);
                    } 
                } 
                else if (this.context.IsHostTransaction)
                { 
                    // For host transactions, we need to provide a clone of the intermediate state as the final state.
                    this.finalState = this.context.InstanceView.Clone();
                    this.finalState.MakeReadOnly();
 
                    // The intermediate state should have the query results cleared - they are per-call of Execute.
                    this.context.InstanceView.InstanceStoreQueryResults = null; 
                } 
                else
                { 
                    // If we get here, there's no transaction at all.  Need to "commit" the intermediate state.
                    CommitHelper();
                    if (this.finalState == null)
                    { 
                        this.context.InstanceHandle.Free();
                        throw Fx.Exception.AsError(new InstanceHandleConflictException(null, this.context.InstanceView.InstanceId)); 
                    } 
                }
                return true; 
            }

            static void OnCommitWait(object state, TimeoutException exception)
            { 
                ExecuteAsyncResult thisPtr = (ExecuteAsyncResult)state;
                thisPtr.Complete(false, exception ?? thisPtr.AfterCommitWait()); 
            } 

            Exception AfterCommitWait() 
            {
                if (this.inDoubt)
                {
                    this.context.InstanceHandle.Free(); 
                    return new TransactionInDoubtException(SRCore.TransactionInDoubtNonHost);
                } 
                if (this.rolledBack) 
                {
                    if (this.context.IsHandleDoomedByRollback) 
                    {
                        this.context.InstanceHandle.Free();
                    }
                    return new TransactionAbortedException(SRCore.TransactionRolledBackNonHost); 
                }
                if (this.finalState == null) 
                { 
                    this.context.InstanceHandle.Free();
                    return new InstanceHandleConflictException(null, this.context.InstanceView.InstanceId); 
                }
                return null;
            }
 
            void CommitHelper()
            { 
                this.finalState = this.context.InstanceHandle.Commit(this.context.InstanceView); 
            }
 
            void SimpleCleanup(AsyncResult result, Exception exception)
            {
                if (this.initialInstanceHandle == null)
                { 
                    Fx.Assert(this.priorAsyncResult != null, "In the non-outer case, we should always have a priorAsyncResult here, since we set it before ----igining OnComplete.");
                    this.context.LastAsyncResult = this.priorAsyncResult; 
                } 
                if (exception != null)
                { 
                    if (this.context != null && this.context.IsHandleDoomedByRollback)
                    {
                        this.context.InstanceHandle.Free();
                    } 
                    else if (exception is TimeoutException || exception is OperationCanceledException)
                    { 
                        if (this.context == null) 
                        {
                            this.initialInstanceHandle.Free(); 
                        }
                        else
                        {
                            this.context.InstanceHandle.Free(); 
                        }
                    } 
                } 
            }
 
            void Cleanup(AsyncResult result, Exception exception)
            {
                try
                { 
                    SimpleCleanup(result, exception);
                    if (this.transactionToCommit != null) 
                    { 
                        try
                        { 
                            this.transactionToCommit.Rollback(exception);
                        }
                        catch (TransactionException)
                        { 
                        }
                    } 
                } 
                finally
                { 
                    Fx.AssertAndThrowFatal(this.context.Active, "Out-of-[....] between InstanceExecutionContext and ExecutionAsyncResult.");

                    this.context.LastAsyncResult = null;
                    this.context.RootAsyncResult = null; 
                    this.context.InstanceHandle.ReleaseExecutionContext();
                } 
            } 

            void ISinglePhaseNotification.SinglePhaseCommit(SinglePhaseEnlistment singlePhaseEnlistment) 
            {
                CommitHelper();
                singlePhaseEnlistment.Committed();
                this.waitForTransaction.Set(); 
            }
 
            void IEnlistmentNotification.Commit(Enlistment enlistment) 
            {
                CommitHelper(); 
                enlistment.Done();
                this.waitForTransaction.Set();
            }
 
            void IEnlistmentNotification.InDoubt(Enlistment enlistment)
            { 
                enlistment.Done(); 
                this.inDoubt = true;
                this.waitForTransaction.Set(); 
            }

            void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
            { 
                preparingEnlistment.Prepared();
            } 
 
            void IEnlistmentNotification.Rollback(Enlistment enlistment)
            { 
                enlistment.Done();
                this.rolledBack = true;
                this.waitForTransaction.Set();
            } 
        }
 
        class BindReclaimedLockAsyncResult : AsyncResult 
        {
            static Action waitComplete = new Action(OnWaitComplete); 

            readonly InstancePersistenceContext context;

            public BindReclaimedLockAsyncResult(InstancePersistenceContext context, AsyncWaitHandle wait, TimeSpan timeout, AsyncCallback callback, object state) 
                : base(callback, state)
            { 
                this.context = context; 

                if (wait.WaitAsync(BindReclaimedLockAsyncResult.waitComplete, this, timeout)) 
                {
                    this.context.ConcludeBindReclaimedLockHelper();
                    Complete(true);
                } 
            }
 
            static void OnWaitComplete(object state, TimeoutException timeoutException) 
            {
                BindReclaimedLockAsyncResult thisPtr = (BindReclaimedLockAsyncResult)state; 

                Exception completionException = null;
                try
                { 
                    if (timeoutException != null)
                    { 
                        thisPtr.context.InstanceHandle.CancelReclaim(new TimeoutException(SRCore.TimedOutWaitingForLockResolution)); 
                    }
                    thisPtr.context.ConcludeBindReclaimedLockHelper(); 
                }
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception)) 
                    {
                        throw; 
                    } 
                    completionException = exception;
                } 
                thisPtr.Complete(false, completionException);
            }

            public static void End(IAsyncResult result) 
            {
                AsyncResult.End(result); 
            } 
        }
 
        [Serializable]
        class BindReclaimedLockException : Exception
        {
            public BindReclaimedLockException() 
            {
            } 
 
            internal BindReclaimedLockException(AsyncWaitHandle markerWaitHandle)
                : base(SRCore.BindReclaimedLockException) 
            {
                MarkerWaitHandle = markerWaitHandle;
            }
 
            internal AsyncWaitHandle MarkerWaitHandle { get; private set; }
 
            [SecurityCritical] 
            protected BindReclaimedLockException(SerializationInfo info, StreamingContext context)
                : base(info, context) 
            {
            }
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK