/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Libraries\Resiliency\UndoableMemory.sg // // Note: // using System; using System.Collections; using System.IO; using Microsoft.SingSharp; namespace Microsoft.Singularity.Resiliency { internal class UndoableMemory { private const int DefaultCapacity = 256; private byte[]! master; private byte[] shadow; private byte[] backup; private int capacity; private int length; internal UndoableMemory() : this(0) {} internal UndoableMemory(int capacity) requires (capacity >= 0); { this.master = this.shadow = new byte[capacity]; this.capacity = capacity; } internal byte[]! Restore() { byte[] buffer = new byte[length]; if (length <= 8) { int byteCount = length; while (--byteCount >= 0) { buffer[byteCount] = shadow[byteCount]; } } else { Buffer.BlockCopy(shadow, 0, buffer, 0, length); } return buffer; } internal void Store(byte[]! buffer) { int count = buffer.Length; if (master == shadow) { if (backup != null) { shadow = backup; } else { shadow = new byte[capacity]; Buffer.BlockCopy(master, 0, shadow, 0, capacity); } } if (count >= length) { int newLength = count + 1; bool mustZero = count > length; if (newLength >= capacity) { bool allocatedNewArray = EnsureCapacity(newLength); if (allocatedNewArray) { mustZero = false; } } if (mustZero) { Array.Clear(shadow, length, count - length); } length = newLength; } if (count <= 8) { int byteCount = count; while (--byteCount >= 0) { shadow[byteCount] = buffer[byteCount]; } } else { Buffer.BlockCopy(buffer, 0, shadow, 0, buffer.Length); } length = buffer.Length; } internal void DirectStore(byte[]! buffer) { shadow = (byte[])buffer; length = buffer.Length; capacity = buffer.Length; backup = null; } private bool EnsureCapacity(int value) requires (value >= 0); { if (value > capacity) { int newCapacity = value; if (newCapacity < DefaultCapacity) { newCapacity = DefaultCapacity; } if (newCapacity < capacity * 2) { newCapacity = capacity * 2; } Capacity = newCapacity; return true; } return false; } internal void Flush() { if (master != shadow) { if (shadow != null) { //DumpMaster(); //DumpShadow(); if (master.Length < length) { master = new byte[capacity]; } Buffer.BlockCopy(shadow, 0, master, 0, length); backup = shadow; } else { Array.Clear(master, 0, length); } } shadow = master; } internal void Undo() { shadow = master; backup = null; } internal int Capacity { get { return capacity; } set { if (value != capacity) { if (value < length) { throw new ArgumentOutOfRangeException( "value", "ArgumentOutOfRange_SmallCapacity"); } if (value > 0) { byte[] newBuffer = new byte[value]; if (length > 0) { Buffer.BlockCopy(shadow, 0, newBuffer, 0, length); } shadow = newBuffer; } else { shadow = null; } capacity = value; } } } internal int Length { get { return length; } } private void Dump(byte[]! buffer) { /* for (int i = 0; i < buffer.Length; i += 20) { for (int j = 0; j < 20 && i + j < buffer.Length; j++) { DebugStub.Print("{0:X2} ", __arglist(buffer[i + j])); } DebugStub.WriteLine(); } */ for (int i = 0; i < buffer.Length && i < 20; i++) { DebugStub.Print("{0:X2} ", __arglist(buffer[i])); } DebugStub.WriteLine(); } internal void DumpMaster() { DebugStub.Print("-- Dump Master\n"); Dump(master); } internal void DumpShadow() { DebugStub.Print("-- Dump Shadow\n"); Dump(shadow); } } }