singrdk/base/Libraries/Resiliency/UndoableMemory.sg

202 lines
5.9 KiB
Plaintext
Raw Normal View History

2008-03-05 09:52:00 -05:00
///////////////////////////////////////////////////////////////////////////////
//
// 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);
}
}
}