Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / System.Runtime.DurableInstancing / System / Runtime / PersistencePipeline.cs / 1305376 / PersistencePipeline.cs
//------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Runtime
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.DurableInstancing;
using System.Threading;
using System.Xml.Linq;
class PersistencePipeline
{
readonly IEnumerable modules;
Stage expectedStage;
IDictionary values;
ReadOnlyDictionary readOnlyView;
ValueDictionaryView readWriteView;
ValueDictionaryView writeOnlyView;
// Used for the save pipeline.
public PersistencePipeline(IEnumerable modules, Dictionary initialValues)
{
Fx.Assert(modules != null, "Null modules collection provided to persistence pipeline.");
this.expectedStage = Stage.Collect;
this.modules = modules;
this.values = initialValues;
this.readOnlyView = new ReadOnlyDictionary(this.values, false);
this.readWriteView = new ValueDictionaryView(this.values, false);
this.writeOnlyView = new ValueDictionaryView(this.values, true);
}
// Used for the load pipeline.
public PersistencePipeline(IEnumerable modules)
{
Fx.Assert(modules != null, "Null modules collection provided to persistence pipeline.");
this.expectedStage = Stage.Load;
this.modules = modules;
}
public ReadOnlyDictionary Values
{
get
{
return this.readOnlyView;
}
}
public bool IsSaveTransactionRequired
{
get
{
return this.modules.FirstOrDefault(value => value.IsSaveTransactionRequired) != null;
}
}
public bool IsLoadTransactionRequired
{
get
{
return this.modules.FirstOrDefault(value => value.IsLoadTransactionRequired) != null;
}
}
public void Collect()
{
Fx.AssertAndThrow(this.expectedStage == Stage.Collect, "Collect called at the wrong time.");
this.expectedStage = Stage.None;
foreach (IPersistencePipelineModule module in modules)
{
IDictionary readWriteValues;
IDictionary writeOnlyValues;
module.CollectValues(out readWriteValues, out writeOnlyValues);
if (readWriteValues != null)
{
foreach (KeyValuePair value in readWriteValues)
{
try
{
this.values.Add(value.Key, new InstanceValue(value.Value));
}
catch (ArgumentException exception)
{
throw Fx.Exception.AsError(new InvalidOperationException(SRCore.NameCollisionOnCollect(value.Key, module.GetType().Name), exception));
}
}
}
if (writeOnlyValues != null)
{
foreach (KeyValuePair value in writeOnlyValues)
{
try
{
this.values.Add(value.Key, new InstanceValue(value.Value, InstanceValueOptions.Optional | InstanceValueOptions.WriteOnly));
}
catch (ArgumentException exception)
{
throw Fx.Exception.AsError(new InvalidOperationException(SRCore.NameCollisionOnCollect(value.Key, module.GetType().Name), exception));
}
}
}
}
this.expectedStage = Stage.Map;
}
public void Map()
{
Fx.AssertAndThrow(this.expectedStage == Stage.Map, "Map called at the wrong time.");
this.expectedStage = Stage.None;
List>> pendingValues = null;
foreach (IPersistencePipelineModule module in modules)
{
IDictionary mappedValues = module.MapValues(this.readWriteView, this.writeOnlyView);
if (mappedValues != null)
{
if (pendingValues == null)
{
pendingValues = new List>>();
}
pendingValues.Add(new Tuple>(module, mappedValues));
}
}
if (pendingValues != null)
{
foreach (Tuple> writeOnlyValues in pendingValues)
{
foreach (KeyValuePair value in writeOnlyValues.Item2)
{
try
{
this.values.Add(value.Key, new InstanceValue(value.Value, InstanceValueOptions.Optional | InstanceValueOptions.WriteOnly));
}
catch (ArgumentException exception)
{
throw Fx.Exception.AsError(new InvalidOperationException(SRCore.NameCollisionOnMap(value.Key, writeOnlyValues.Item1.GetType().Name), exception));
}
}
}
this.writeOnlyView.ResetCaches();
}
this.expectedStage = Stage.Save;
}
public IAsyncResult BeginSave(TimeSpan timeout, AsyncCallback callback, object state)
{
Fx.AssertAndThrow(this.expectedStage == Stage.Save, "Save called at the wrong time.");
this.expectedStage = Stage.None;
return new IOAsyncResult(this, false, timeout, callback, state);
}
public void EndSave(IAsyncResult result)
{
IOAsyncResult.End(result);
}
public void SetLoadedValues(IDictionary values)
{
Fx.AssertAndThrow(this.expectedStage == Stage.Load, "SetLoadedValues called at the wrong time.");
Fx.Assert(values != null, "Null values collection provided to SetLoadedValues.");
this.values = values;
this.readOnlyView = values as ReadOnlyDictionary ?? new ReadOnlyDictionary(values, false);
this.readWriteView = new ValueDictionaryView(this.values, false);
}
public IAsyncResult BeginLoad(TimeSpan timeout, AsyncCallback callback, object state)
{
Fx.Assert(this.values != null, "SetLoadedValues not called.");
Fx.AssertAndThrow(this.expectedStage == Stage.Load, "Load called at the wrong time.");
this.expectedStage = Stage.None;
return new IOAsyncResult(this, true, timeout, callback, state);
}
public void EndLoad(IAsyncResult result)
{
IOAsyncResult.End(result);
this.expectedStage = Stage.Publish;
}
public void Publish()
{
Fx.AssertAndThrow(this.expectedStage == Stage.Publish || this.expectedStage == Stage.Load, "Publish called at the wrong time.");
this.expectedStage = Stage.None;
foreach (IPersistencePipelineModule module in modules)
{
module.PublishValues(this.readWriteView);
}
}
public void Abort()
{
foreach (IPersistencePipelineModule module in modules)
{
try
{
module.Abort();
}
catch (Exception exception)
{
if (Fx.IsFatal(exception))
{
throw;
}
throw Fx.Exception.AsError(new CallbackException(SRCore.PersistencePipelineAbortThrew(module.GetType().Name), exception));
}
}
}
enum Stage
{
None,
Collect,
Map,
Save,
Load,
Publish,
}
class ValueDictionaryView : IDictionary
{
IDictionary basis;
bool writeOnly;
List keys;
List