private static void Test(string[] args) { var sbb = new StreamBlobDatabase(false, 1024, Test_BufferManage); Random r = new Random(0); byte[] temp = new byte[1024]; int trials = 0; for (;;) { int len = r.Next(1024) + 1; if (r.Next(100) == 0) { len = 1024; } ArraySegment <byte> seg = new ArraySegment <byte>(temp, 0, len); Console.WriteLine("{0} - {1}", trials, seg.Count); if (seg.Count == 1024) { Console.Write("*************************"); } trials++; sbb.Push(seg); } }
private unsafe void CaptureStateDelta(byte[] currentState) { // Keep in mind that everything captured here is intended to be played back in // reverse. The goal is, given the current state, how to get back to the previous // state. That's why the data portion of the delta comes from the previous state, // and also why the previous state is used if we have to bail out and capture the // full state instead. if (currentState.Length != _lastState.Length) { // If the state sizes mismatch, capture a full state rather than trying to do anything clever goto CaptureFullState; } if (currentState.Length == 0) { // handle empty states as a "full" (empty) state goto CaptureFullState; } int index = 0; int stateLength = Math.Min(currentState.Length, _lastState.Length); bool inChangeSequence = false; int changeSequenceStartOffset = 0; int lastChangeSequenceStartOffset = 0; if (_deltaBuffer.Length < stateLength + 1) { _deltaBuffer = new byte[stateLength + 1]; } _deltaBuffer[index++] = 0; // Full state = false (i.e. delta) fixed(byte *pCurrentState = ¤tState[0]) fixed(byte *pLastState = &_lastState[0]) for (int i = 0; i < stateLength; i++) { bool thisByteMatches = *(pCurrentState + i) == *(pLastState + i); if (inChangeSequence == false) { if (thisByteMatches) { continue; } inChangeSequence = true; changeSequenceStartOffset = i; } if (thisByteMatches || i == stateLength - 1) { const int MaxHeaderSize = 10; int length = i - changeSequenceStartOffset + (thisByteMatches ? 0 : 1); if (index + length + MaxHeaderSize >= stateLength) { // If the delta ends up being larger than the full state, capture the full state instead goto CaptureFullState; } // Offset Delta VLInteger.WriteUnsigned((uint)(changeSequenceStartOffset - lastChangeSequenceStartOffset), _deltaBuffer, ref index); // Length VLInteger.WriteUnsigned((uint)length, _deltaBuffer, ref index); // Data Buffer.BlockCopy(_lastState, changeSequenceStartOffset, _deltaBuffer, index, length); index += length; inChangeSequence = false; lastChangeSequenceStartOffset = changeSequenceStartOffset; } } _rewindBuffer.Push(new ArraySegment <byte>(_deltaBuffer, 0, index)); UpdateLastState(currentState); return; CaptureFullState: CaptureStateNonDelta(_lastState); UpdateLastState(currentState); }
private unsafe void CaptureRewindStateDelta(byte[] currentState) { // in case the state sizes mismatch, capture a full state rather than trying to do anything clever if (currentState.Length != _lastState.Length) { CaptureRewindStateNonDelta(_lastState); UpdateLastState(currentState); return; } int index = 0; int stateLength = Math.Min(currentState.Length, _lastState.Length); bool inChangeSequence = false; int changeSequenceStartOffset = 0; int lastChangeSequenceStartOffset = 0; if (_deltaBuffer.Length < stateLength) { _deltaBuffer = new byte[stateLength]; } _deltaBuffer[index++] = 0; // Full state = false (i.e. delta) fixed(byte *pCurrentState = ¤tState[0]) fixed(byte *pLastState = &_lastState[0]) for (int i = 0; i < stateLength; i++) { bool thisByteMatches = *(pCurrentState + i) == *(pLastState + i); if (inChangeSequence == false) { if (thisByteMatches) { continue; } inChangeSequence = true; changeSequenceStartOffset = i; } if (thisByteMatches || i == stateLength - 1) { const int maxHeaderSize = 10; int length = i - changeSequenceStartOffset + (thisByteMatches ? 0 : 1); if (index + length + maxHeaderSize >= stateLength) { // If the delta ends up being larger than the full state, capture the full state instead CaptureRewindStateNonDelta(_lastState); UpdateLastState(currentState); return; } // Offset Delta VLInteger.WriteUnsigned((uint)(changeSequenceStartOffset - lastChangeSequenceStartOffset), _deltaBuffer, ref index); // Length VLInteger.WriteUnsigned((uint)length, _deltaBuffer, ref index); // Data Buffer.BlockCopy(_lastState, changeSequenceStartOffset, _deltaBuffer, index, length); index += length; inChangeSequence = false; lastChangeSequenceStartOffset = changeSequenceStartOffset; } } _rewindBuffer.Push(new ArraySegment <byte>(_deltaBuffer, 0, index)); UpdateLastState(currentState); }
private void CaptureRewindStateDelta(byte[] currentState, bool isSmall) { // in case the state sizes mismatch, capture a full state rather than trying to do anything clever if (currentState.Length != _lastState.Length) { CaptureRewindStateNonDelta(currentState); return; } var beginChangeSequence = -1; var inChangeSequence = false; // try to set up the buffer in advance so we dont ever have exceptions in here // zeromus says: this sets off red flags for me. vecna got an exception that might be related to this inflating to 2x the input size. we should add an emergency check, or analyze how much it could inflate by (perhaps 3x would be adequate in every case?) if (_tempBuf.Length < currentState.Length) { _tempBuf = new byte[currentState.Length * 2]; } var ms = new MemoryStream(_tempBuf, 0, _tempBuf.Length, true, true); RETRY: try { var writer = new BinaryWriter(ms); writer.Write(false); // delta state for (int i = 0; i < currentState.Length; i++) { if (inChangeSequence == false) { if (i >= _lastState.Length) { continue; } if (currentState[i] == _lastState[i]) { continue; } inChangeSequence = true; beginChangeSequence = i; } if (i - beginChangeSequence == 254 || i == currentState.Length - 1) { writer.Write((byte)(i - beginChangeSequence + 1)); if (isSmall) { writer.Write((ushort)beginChangeSequence); } else { writer.Write(beginChangeSequence); } writer.Write(_lastState, beginChangeSequence, i - beginChangeSequence + 1); inChangeSequence = false; continue; } if (currentState[i] == _lastState[i]) { writer.Write((byte)(i - beginChangeSequence)); if (isSmall) { writer.Write((ushort)beginChangeSequence); } else { writer.Write(beginChangeSequence); } writer.Write(_lastState, beginChangeSequence, i - beginChangeSequence); inChangeSequence = false; } } } catch (NotSupportedException) { // ok... we had an exception after all // if we did actually run out of room in the memorystream, then try it again with a bigger buffer _tempBuf = new byte[_tempBuf.Length * 2]; goto RETRY; } if (_lastState != null && _lastState.Length == currentState.Length) { Buffer.BlockCopy(currentState, 0, _lastState, 0, _lastState.Length); } else { _lastState = (byte[])currentState.Clone(); } var seg = new ArraySegment <byte>(_tempBuf, 0, (int)ms.Position); _rewindBuffer.Push(seg); }
private static void test(string[] args) { var sbb = new StreamBlobDatabase(false, 1024, test_BufferManage); Random r = new Random(0); byte[] temp = new byte[1024]; int trials = 0; for (; ; ) { int len = r.Next(1024) + 1; if (r.Next(100) == 0) len = 1024; ArraySegment<byte> seg = new ArraySegment<byte>(temp, 0, len); Console.WriteLine("{0} - {1}", trials, seg.Count); if (seg.Count == 1024) Console.Write("*************************"); trials++; sbb.Push(seg); } }