Operation
The namespace Avalanche.FileSystem.Operation contains file operation classes.
IOperation is ran inside a context of IOperationSession.
IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 1024]);
using (var s = new OperationSession())
{
new CopyFile(s, ms, "file", ms, "file.copy")
.Estimate()
.AssertCanRollback()
.Run()
.AssertSuccessful();
}
"" ├── "file" [1048576] └── "file.copy" [1048576]
IOperation.Estimate() makes checks to test if the operation can be completed. It throws exception if there is a visible reason why the operation would not complete.
var s = new OperationSession();
var op = new CopyFile(s, ms, "file", ms, "file.copy");
op.Estimate();
After .Estimate() is called, the property .CanRollback is set. It determines if the operation can be reverted.
Console.WriteLine(op.CanRollback);
.Estimate().AssertCanRollback() asserts rollback is possible.
op.Estimate().AssertCanRollback();
.Run() executes the operation. It throws an exception on unexpected error.
op.Run();
The caller should test the .CurrentState property after .Run() to see what the state is.
if (op.CurrentState == OperationState.Completed)
Console.WriteLine("ok");
... or use .Run().AssertSuccessful() to assert it.
op.Run().AssertSuccessful();
Caller can try rollback upon failure (or anyway).
try
{
op.Run();
}
catch (Exception)
{
// Rollback
op.CreateRollback()?.Run();
}
Executing .Run(rollbackOnError) rollbacks automatically on failure if rollback is possible.
op.Run(rollbackOnError: true);
CopyTree copies a directory tree from one place to another.
IFileSystem ms = new MemoryFileSystem();
ms.CreateDirectory("dir/dir/dir/");
ms.CreateFile("dir/dir/dir/file", new byte[1024 * 1024]);
using (var s = new OperationSession())
{
var op = new CopyTree(s, ms, "dir", ms, "dir.copy");
op.Estimate().AssertCanRollback().Run().AssertSuccessful();
}
"" ├── "dir" │ └── "dir" │ └── "dir" │ └── "file" └── "dir.copy" └── "dir" └── "dir" └── "file"
Batch is a list of operations to run as one operation.
IFileSystem ms = new MemoryFileSystem();
using (var s = new OperationSession(policy: OperationPolicy.EstimateOnRun/*important*/))
{
Batch batch = new Batch(s, OperationPolicy.Unset);
batch.Ops.Add(new CreateDirectory(s, ms, "dir/dir/dir"));
batch.Ops.Add(new CopyTree(s, ms, "dir", ms, "dir.copy"));
batch.Ops.Add(new Delete(s, ms, "dir/dir", true, policy: OperationPolicy.EstimateOnRun));
batch.Estimate().Run().AssertSuccessful();
}
TransferTree moves files from one location to another by copy-and-delete.
IFileSystem ms_src = new MemoryFileSystem();
ms_src.CreateDirectory("dir/dir/dir/");
ms_src.CreateFile("dir/dir/dir/file", new byte[1024 * 1024]);
IFileSystem ms_dst = new MemoryFileSystem();
using (var s = new OperationSession())
{
var op = new TransferTree(s, ms_src, "dir", ms_dst, "dir.elsewhere");
op.Estimate().AssertCanRollback().Run().AssertSuccessful();
}
Session gathers events automatically. Gathered evants can be read from the session object.
IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 1024]);
using (var s = new OperationSession())
{
new CopyFile(s, ms, "file", ms, "file.copy")
.Estimate()
.AssertCanRollback()
.Run()
.AssertSuccessful();
foreach (var @event in s.Events)
Console.WriteLine(@event);
}
ms.PrintTreeTo(Console.Out);
CopyFile(Src=file, Dst=file.copy, State=Completed) = Estimating
CopyFile(Src=file, Dst=file.copy, State=Completed) = Estimated
CopyFile(Src=file, Dst=file.copy, State=Completed) = Running
CopyFile(Src=file, Dst=file.copy, State=Completed) = Completed
Events can subscribed. Copy operation can be configured to send regular progress events. .SetProgressInterval(long) sets the interval on how often Operation.Event.Progress is sent in terms of bytes.
IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 20]);
using (var s = new OperationSession().SetProgressInterval(1024))
{
s.Subscribe(new OpEventPrinter());
new CopyFile(s, ms, "file", ms, "file.copy")
.Estimate()
.AssertCanRollback()
.Run()
.AssertSuccessful();
}
ms.PrintTreeTo(Console.Out);
using System;
using System.Threading;
using Avalanche.FileSystem;
using Avalanche.FileSystem.Operation;
public class operation
{
public static void Run(string[] args)
{
{
// <01>
IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 1024]);
using (var s = new OperationSession())
{
new CopyFile(s, ms, "file", ms, "file.copy")
.Estimate()
.AssertCanRollback()
.Run()
.AssertSuccessful();
}
// </01>
ms.PrintTreeTo(Console.Out, format: FileSystemPrintTreeExtensions.Format.Default | FileSystemPrintTreeExtensions.Format.Length);
}
{
IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 1024]);
// <1b>
var s = new OperationSession();
var op = new CopyFile(s, ms, "file", ms, "file.copy");
op.Estimate();
// </1b>
// <1b1>
Console.WriteLine(op.CanRollback);
// </1b1>
// <1b2>
op.Estimate().AssertCanRollback();
// </1b2>
// <1c>
op.Run();
// </1c>
// <1c1>
if (op.CurrentState == OperationState.Completed)
Console.WriteLine("ok");
// </1c1>
ms.Delete("file.copy");
op = (CopyFile)new CopyFile(s, ms, "file", ms, "file.copy").Estimate();
// <1c2>
op.Run().AssertSuccessful();
// </1c2>
ms.Delete("file.copy");
op = (CopyFile)new CopyFile(s, ms, "file", ms, "file.copy").Estimate();
// <1c3>
try
{
op.Run();
}
catch (Exception)
{
// Rollback
op.CreateRollback()?.Run();
}
// </1c3>
// <1c4>
op.Run(rollbackOnError: true);
// </1c4>
}
{
// <02>
IFileSystem ms = new MemoryFileSystem();
ms.CreateDirectory("dir/dir/dir/");
ms.CreateFile("dir/dir/dir/file", new byte[1024 * 1024]);
using (var s = new OperationSession())
{
var op = new CopyTree(s, ms, "dir", ms, "dir.copy");
op.Estimate().AssertCanRollback().Run().AssertSuccessful();
}
// </02>
ms.PrintTreeTo(Console.Out);
}
{
// <03>
IFileSystem ms = new MemoryFileSystem();
using (var s = new OperationSession(policy: OperationPolicy.EstimateOnRun/*important*/))
{
Batch batch = new Batch(s, OperationPolicy.Unset);
batch.Ops.Add(new CreateDirectory(s, ms, "dir/dir/dir"));
batch.Ops.Add(new CopyTree(s, ms, "dir", ms, "dir.copy"));
batch.Ops.Add(new Delete(s, ms, "dir/dir", true, policy: OperationPolicy.EstimateOnRun));
batch.Estimate().Run().AssertSuccessful();
}
// </03>
ms.PrintTreeTo(Console.Out);
}
{
// <04>
IFileSystem ms_src = new MemoryFileSystem();
ms_src.CreateDirectory("dir/dir/dir/");
ms_src.CreateFile("dir/dir/dir/file", new byte[1024 * 1024]);
IFileSystem ms_dst = new MemoryFileSystem();
using (var s = new OperationSession())
{
var op = new TransferTree(s, ms_src, "dir", ms_dst, "dir.elsewhere");
op.Estimate().AssertCanRollback().Run().AssertSuccessful();
}
// </04>
ms_dst.PrintTreeTo(Console.Out);
}
{
// <05>
IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 1024]);
using (var s = new OperationSession())
{
new CopyFile(s, ms, "file", ms, "file.copy")
.Estimate()
.AssertCanRollback()
.Run()
.AssertSuccessful();
foreach (var @event in s.Events)
Console.WriteLine(@event);
}
ms.PrintTreeTo(Console.Out);
// </05>
}
{
// <06>
IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 20]);
using (var s = new OperationSession().SetProgressInterval(1024))
{
s.Subscribe(new OpEventPrinter());
new CopyFile(s, ms, "file", ms, "file.copy")
.Estimate()
.AssertCanRollback()
.Run()
.AssertSuccessful();
}
ms.PrintTreeTo(Console.Out);
// </06>
}
{
try
{
// <07>
IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 10]);
CancellationTokenSource cancelSrc = new CancellationTokenSource();
using (var s = new OperationSession(cancelSrc: cancelSrc))
{
cancelSrc.Cancel();
new Move(s, ms, "file", ms, "file.moved")
.Estimate()
.AssertCanRollback()
.Run()
.AssertSuccessful();
}
// </07>
}
catch (Exception)
{
}
}
{
// <08>
// </08>
}
{
// <09>
// </09>
}
{
// <10>
// </10>
}
{
// <11>
// </11>
}
{
// <12>
// </12>
}
{
// <13>
// </13>
}
{
// <14>
// </14>
}
{
// <15>
// </15>
}
{
// <16>
// </16>
}
}
}
// <OpEventPrinter>
class OpEventPrinter : IObserver<IOperationEvent>
{
public void OnCompleted() => Console.WriteLine("OnCompleted");
public void OnError(Exception error) => Console.WriteLine(error);
public void OnNext(IOperationEvent @event) => Console.WriteLine(@event);
}
// </OpEventPrinter>
CopyFile(Src=file, Dst=file.copy, State=Estimating) = Estimating
CopyFile(Src=file, Dst=file.copy, State=Estimated) = Estimated
CopyFile(Src=file, Dst=file.copy, State=Running) = Running
Progress(CopyFile(Src=file, Dst=file.copy, State=Running), 20%)
Progress(CopyFile(Src=file, Dst=file.copy, State=Running), 40%)
Progress(CopyFile(Src=file, Dst=file.copy, State=Running), 60%)
Progress(CopyFile(Src=file, Dst=file.copy, State=Running), 80%)
Progress(CopyFile(Src=file, Dst=file.copy, State=Running), 100%)
CopyFile(Src=file, Dst=file.copy, State=Completed) = Completed
OnCompleted
"" ├── "file" └── "file.copy"
If cancellation token is canceled, the operation does not proceed.
IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 10]);
CancellationTokenSource cancelSrc = new CancellationTokenSource();
using (var s = new OperationSession(cancelSrc: cancelSrc))
{
cancelSrc.Cancel();
new Move(s, ms, "file", ms, "file.moved")
.Estimate()
.AssertCanRollback()
.Run()
.AssertSuccessful();
}