Rewind - if memory allocation fails, back off the size until successful.
This commit is contained in:
parent
9f6c0ca695
commit
bcb6b20ec2
|
@ -10,13 +10,14 @@ namespace BizHawk.Client.Common
|
|||
public class Rewinder
|
||||
{
|
||||
private StreamBlobDatabase _rewindBuffer;
|
||||
private byte[] _rewindBufferBacking;
|
||||
private long? _overrideMemoryLimit;
|
||||
private RewindThreader _rewindThread;
|
||||
private byte[] _lastState;
|
||||
private bool _rewindImpossible;
|
||||
private int _rewindFrequency = 1;
|
||||
private bool _rewindDeltaEnable;
|
||||
private byte[] _rewindFellationBuf;
|
||||
private byte[] _tempBuf = new byte[0];
|
||||
private byte[] _deltaBuffer = new byte[0];
|
||||
|
||||
public Rewinder()
|
||||
{
|
||||
|
@ -122,14 +123,14 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (rewind_enabled)
|
||||
{
|
||||
var cap = Global.Config.Rewind_BufferSize * (long)1024 * 1024;
|
||||
var capacity = Global.Config.Rewind_BufferSize * (long)1024 * 1024;
|
||||
|
||||
if (_rewindBuffer != null)
|
||||
{
|
||||
_rewindBuffer.Dispose();
|
||||
}
|
||||
|
||||
_rewindBuffer = new StreamBlobDatabase(Global.Config.Rewind_OnDisk, cap, BufferManage);
|
||||
_rewindBuffer = new StreamBlobDatabase(Global.Config.Rewind_OnDisk, capacity, BufferManage);
|
||||
|
||||
if (_rewindThread != null)
|
||||
{
|
||||
|
@ -216,24 +217,53 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
}
|
||||
|
||||
private byte[] BufferManage(byte[] inbuf, long size, bool allocate)
|
||||
private byte[] BufferManage(byte[] inbuf, ref long size, bool allocate)
|
||||
{
|
||||
if (allocate)
|
||||
{
|
||||
// if we have an appropriate buffer free, return it
|
||||
if (_rewindFellationBuf != null && _rewindFellationBuf.LongLength == size)
|
||||
if (size > Int32.MaxValue)
|
||||
{
|
||||
var ret = _rewindFellationBuf;
|
||||
_rewindFellationBuf = null;
|
||||
return ret;
|
||||
// I think we need .NET 4.5+ on x64 to allocate > 2GB
|
||||
size = Int32.MaxValue;
|
||||
}
|
||||
|
||||
if (_overrideMemoryLimit != null)
|
||||
{
|
||||
size = Math.Min(_overrideMemoryLimit.Value, size);
|
||||
}
|
||||
|
||||
// if we have an appropriate buffer free, return it
|
||||
if (_rewindBufferBacking != null)
|
||||
{
|
||||
var buf = _rewindBufferBacking;
|
||||
_rewindBufferBacking = null;
|
||||
if (buf.LongLength == size)
|
||||
{
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, allocate it
|
||||
return new byte[size];
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
return new byte[size];
|
||||
}
|
||||
catch (OutOfMemoryException)
|
||||
{
|
||||
size /= 2;
|
||||
_overrideMemoryLimit = size;
|
||||
}
|
||||
}
|
||||
while (size > 1);
|
||||
throw new OutOfMemoryException();
|
||||
}
|
||||
else
|
||||
{
|
||||
_rewindBufferBacking = inbuf;
|
||||
return null;
|
||||
}
|
||||
|
||||
_rewindFellationBuf = inbuf;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void CaptureRewindStateNonDelta(byte[] state)
|
||||
|
@ -277,12 +307,12 @@ namespace BizHawk.Client.Common
|
|||
int changeSequenceStartOffset = 0;
|
||||
int lastChangeSequenceStartOffset = 0;
|
||||
|
||||
if (_tempBuf.Length < stateLength)
|
||||
if (_deltaBuffer.Length < stateLength)
|
||||
{
|
||||
_tempBuf = new byte[stateLength];
|
||||
_deltaBuffer = new byte[stateLength];
|
||||
}
|
||||
|
||||
_tempBuf[index++] = 0; // Full state = false (i.e. delta)
|
||||
_deltaBuffer[index++] = 0; // Full state = false (i.e. delta)
|
||||
|
||||
fixed (byte* pCurrentState = ¤tState[0])
|
||||
fixed (byte* pLastState = &_lastState[0])
|
||||
|
@ -315,13 +345,13 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
// Offset Delta
|
||||
VLInteger.WriteUnsigned((uint)(changeSequenceStartOffset - lastChangeSequenceStartOffset), _tempBuf, ref index);
|
||||
VLInteger.WriteUnsigned((uint)(changeSequenceStartOffset - lastChangeSequenceStartOffset), _deltaBuffer, ref index);
|
||||
|
||||
// Length
|
||||
VLInteger.WriteUnsigned((uint)length, _tempBuf, ref index);
|
||||
VLInteger.WriteUnsigned((uint)length, _deltaBuffer, ref index);
|
||||
|
||||
// Data
|
||||
Buffer.BlockCopy(_lastState, changeSequenceStartOffset, _tempBuf, index, length);
|
||||
Buffer.BlockCopy(_lastState, changeSequenceStartOffset, _deltaBuffer, index, length);
|
||||
index += length;
|
||||
|
||||
inChangeSequence = false;
|
||||
|
@ -329,7 +359,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
}
|
||||
|
||||
_rewindBuffer.Push(new ArraySegment<byte>(_tempBuf, 0, index));
|
||||
_rewindBuffer.Push(new ArraySegment<byte>(_deltaBuffer, 0, index));
|
||||
|
||||
UpdateLastState(currentState);
|
||||
}
|
||||
|
|
|
@ -10,14 +10,14 @@ namespace BizHawk.Client.Common
|
|||
/// </summary>
|
||||
public class StreamBlobDatabase : IDisposable
|
||||
{
|
||||
private Func<byte[], long, bool, byte[]> _mBufferManage;
|
||||
private StreamBlobDatabaseBufferManager _mBufferManage;
|
||||
private byte[] _mAllocatedBuffer;
|
||||
private Stream _mStream;
|
||||
private LinkedList<ListItem> _mBookmarks = new LinkedList<ListItem>();
|
||||
private LinkedListNode<ListItem> _mHead, _mTail;
|
||||
private long _mCapacity, _mSize;
|
||||
|
||||
public StreamBlobDatabase(bool onDisk, long capacity, Func<byte[], long, bool, byte[]> mBufferManage)
|
||||
public StreamBlobDatabase(bool onDisk, long capacity, StreamBlobDatabaseBufferManager mBufferManage)
|
||||
{
|
||||
_mBufferManage = mBufferManage;
|
||||
_mCapacity = capacity;
|
||||
|
@ -32,7 +32,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
_mAllocatedBuffer = _mBufferManage(null, capacity, true);
|
||||
_mAllocatedBuffer = _mBufferManage(null, ref capacity, true);
|
||||
_mStream = new MemoryStream(_mAllocatedBuffer);
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,8 @@ namespace BizHawk.Client.Common
|
|||
_mStream = null;
|
||||
if (_mAllocatedBuffer != null)
|
||||
{
|
||||
_mBufferManage(_mAllocatedBuffer, 0, false);
|
||||
long capacity = 0;
|
||||
_mBufferManage(_mAllocatedBuffer, ref capacity, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,7 +265,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
}
|
||||
|
||||
private static byte[] test_BufferManage(byte[] inbuf, long size, bool allocate)
|
||||
private static byte[] test_BufferManage(byte[] inbuf, ref long size, bool allocate)
|
||||
{
|
||||
if (allocate)
|
||||
{
|
||||
|
@ -305,4 +306,6 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public delegate byte[] StreamBlobDatabaseBufferManager(byte[] existingBuffer, ref long capacity, bool allocate);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue