/// <summary> /// 释放资源 /// </summary> public void Dispose() { isNeedDispose = 0; if (Interlocked.CompareExchange(ref isDisposed, 1, 0) == 0) { AutoCSer.DomainUnload.Unloader.Remove(disposeHandle, DomainUnload.Type.Action, false); if (!isStartQueue) { onStart(); } if (dataFileStream != null) { dataFileStream.Dispose(); dataFileStream = null; } if (stateFileStream != null) { stateFileStream.Dispose(); stateFileStream = null; } int count = indexs.Length; if (count > 1) { PacketIndex[] indexArray = indexs.Array; while (count != 0) { long fileIndex = indexArray[--count].FileIndex; if (fileIndex == StatePacketIndex.FileIndex) { if (indexArray[count].Identity == StatePacketIndex.Identity && count != 0) { indexs.Length = count + 1; SubBuffer.PoolBufferFull buffer = default(SubBuffer.PoolBufferFull); bufferPool.Get(ref buffer); try { writeIndex(ref buffer); } finally { buffer.Free(); } } break; } if (fileIndex < StatePacketIndex.FileIndex) { break; } } } } }
/// <summary> /// 创建文件流 /// </summary> /// <param name="buffer"></param> /// <param name="version"></param> private void create(ref SubBuffer.PoolBufferFull buffer, ulong version) { if (buffer.Buffer == null) { bufferPool.Get(ref buffer); fixed(byte *bufferFixed = buffer.Buffer) { byte *bufferStart = bufferFixed + buffer.StartIndex; *(int *)bufferStart = FileHeader; *(ulong *)(bufferStart + sizeof(int) * 2) = Version; } fileStream.Write(buffer.Buffer, buffer.StartIndex, fileHeaderSize); FileLength = fileHeaderSize; IsDisposed = 0; }
private static readonly SubBuffer.Pool stringBufferPool = SubBuffer.Pool.GetPool(SubBuffer.Size.Kilobyte32);//4097 * 8 /// <summary> /// LZW压缩解码 /// </summary> /// <param name="input">输入数据</param> /// <param name="output">输出数据缓冲</param> /// <param name="size">编码长度</param> /// <returns>解码数据长度,失败返回-1</returns> private unsafe static int lzwDecode(byte[] input, byte* output, byte size) { int tableSize = (int)size + 1; short clearIndex = (short)(1 << size), nextIndex = clearIndex; SubBuffer.PoolBufferFull stringBuffer = default(SubBuffer.PoolBufferFull); stringBufferPool.Get(ref stringBuffer); try { fixed (byte* inputFixed = input, stringFixed = stringBuffer.Buffer) { byte* nextStrings = null, stringStart = stringFixed + stringBuffer.StartIndex; byte* currentInput = inputFixed, inputEnd = inputFixed + input.Length; byte* currentOutput = output, outputEnd = output + FileWriter.LzwEncodeTableBufferPool.Size; int valueBits = 0, inputSize = 0, inputOffset = (int)inputEnd & (sizeof(ulong) - 1), startSize = tableSize; ulong inputValue = 0, inputMark = ushort.MaxValue, startMark = ((ulong)1UL << startSize) - 1; short endIndex = (short)(clearIndex + 1), prefixIndex, currentIndex = 0; if (inputOffset == 0) { inputEnd -= sizeof(ulong); inputOffset = sizeof(ulong); } else inputEnd -= inputOffset; if (size == 1) ++startSize; while (currentIndex != endIndex) { if (valueBits >= startSize) { prefixIndex = (short)(inputValue & startMark); valueBits -= startSize; inputValue >>= startSize; } else { if (currentInput > inputEnd) return -1; ulong nextValue = *(ulong*)currentInput; prefixIndex = (short)((inputValue | (nextValue << valueBits)) & startMark); inputValue = nextValue >> -(valueBits -= startSize); valueBits += sizeof(ulong) << 3; if (currentInput == inputEnd && (valueBits -= (sizeof(ulong) - inputOffset) << 3) < 0) return -1; currentInput += sizeof(ulong); } if (prefixIndex == clearIndex) continue; if (prefixIndex == endIndex) break; if (currentOutput == outputEnd) return -1; AutoCSer.Memory.ClearUnsafe((ulong*)stringStart, 4097); inputSize = startSize; inputMark = startMark; nextIndex = (short)(endIndex + 1); *(short*)(nextStrings = stringStart + (nextIndex << 3)) = prefixIndex; *(short*)(nextStrings + 2) = prefixIndex; *(int*)(nextStrings + 4) = 2; *currentOutput++ = (byte)prefixIndex; do { if (valueBits >= inputSize) { currentIndex = (short)(inputValue & inputMark); valueBits -= inputSize; inputValue >>= inputSize; } else { if (currentInput > inputEnd) return -1; ulong nextValue = *(ulong*)currentInput; currentIndex = (short)((inputValue | (nextValue << valueBits)) & inputMark); inputValue = nextValue >> -(valueBits -= inputSize); valueBits += sizeof(ulong) << 3; if (currentInput == inputEnd && (valueBits -= (sizeof(ulong) - inputOffset) << 3) < 0) return -1; currentInput += sizeof(ulong); } *(short*)(nextStrings += 8) = currentIndex; if (currentIndex < clearIndex) { if (currentOutput == outputEnd) return -1; *(short*)(nextStrings + 2) = currentIndex; *(int*)(nextStrings + 4) = 2; *currentOutput++ = (byte)currentIndex; } else if (currentIndex > endIndex) { byte* currentString = stringStart + (currentIndex << 3); int outputCount = *(int*)(currentString + 4); if (outputCount == 0) return -1; *(short*)(nextStrings + 2) = *(short*)(currentString + 2); *(int*)(nextStrings + 4) = outputCount + 1; if ((currentOutput += outputCount) > outputEnd) return -1; do { *--currentOutput = *(currentString + 2 + 8); prefixIndex = *(short*)currentString; if (prefixIndex < clearIndex) break; currentString = stringStart + (prefixIndex << 3); } while (true); *--currentOutput = (byte)prefixIndex; currentOutput += outputCount; } else break; prefixIndex = currentIndex; if (nextIndex++ == (short)inputMark) { if (inputSize == 12) return -1; inputMark <<= 1; ++inputSize; ++inputMark; } } while (true); } return (int)(currentOutput - output); } } finally { stringBufferPool.Push(ref stringBuffer); } }
internal void Get(SubBuffer.Pool bufferPool) { bufferPool.Get(ref Buffer); WriteIndex = Buffer.StartIndex; IsWait = false; }
/// <summary> /// 文件流写入器 /// </summary> /// <param name="cache"></param> /// <param name="config"></param> internal FileStreamWriter(CacheManager cache, MasterServerConfig config) { this.cache = cache; Config = config; bufferPool = SubBuffer.Pool.GetPool(config.BufferSize); FileInfo file = new FileInfo(config.GetFileName); FileName = file.FullName; IsDisposed = 1; FileMode createMode = FileMode.CreateNew; FileBuffers buffer = default(FileBuffers); try { if (file.Exists) { if (file.Length == 0) { createMode = FileMode.Create; } else { fileStream = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, bufferPool.Size, FileOptions.None); bufferPool.Get(ref buffer.Buffer); if (fileStream.Read(buffer.Buffer.Buffer, buffer.Buffer.StartIndex, fileHeaderSize) == fileHeaderSize) { fixed(byte *bufferFixed = buffer.Buffer.Buffer) { byte *bufferStart = bufferFixed + buffer.Buffer.StartIndex; if (*(int *)bufferStart == FileHeader) { Version = *(ulong *)(bufferStart + sizeof(int) * 2); FileInfo switchFile = new FileInfo(config.GetSwitchFileName); if (switchFile.Exists) { FileStream switchFileStream = new FileStream(switchFile.FullName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, bufferPool.Size, FileOptions.None); if (switchFileStream.Read(buffer.Buffer.Buffer, buffer.Buffer.StartIndex, fileHeaderSize) == fileHeaderSize && *(int *)bufferStart == FileHeader && *(ulong *)(bufferStart + sizeof(int) * 2) > Version) { fileStream.Dispose(); Version = *(ulong *)(bufferStart + sizeof(int) * 2); fileStream = switchFileStream; FileName = switchFile.FullName; isSwitchFile = true; } } if (Version > 0) { LoadData loadData = new LoadData { Buffer = BufferLink.Head }; int count = fileStream.Read(buffer.Buffer.Buffer, buffer.Buffer.StartIndex, buffer.Buffer.Length), index = 0, compressionDataSize; long nextLength = (FileLength = fileStream.Length) - fileHeaderSize - count; do { while (count >= sizeof(int) * 2) { byte *read = bufferStart + index; if ((compressionDataSize = *(int *)read) < 0) { if (count >= (compressionDataSize = -compressionDataSize) + sizeof(int) * 2) { buffer.CompressionBuffer.StartIndex = *(int *)(read + sizeof(int)); AutoCSer.IO.Compression.DeflateDeCompressor.Get(buffer.Buffer.Buffer, buffer.Buffer.StartIndex + (index += sizeof(int) * 2), compressionDataSize, ref buffer.CompressionBuffer); if (buffer.CompressionBuffer.Buffer != null) { fixed(byte *dataFixed = buffer.CompressionBuffer.Buffer) { loadData.Set(buffer.CompressionBuffer.Buffer, buffer.CompressionBuffer.StartIndex, *(int *)(read + sizeof(int)), dataFixed); if (!cache.Load(ref loadData)) { throw new InvalidDataException(); } } index += compressionDataSize; count -= compressionDataSize + sizeof(int) * 2; buffer.CompressionBuffer.Free(); } else { throw new InvalidDataException(); } } else if (count + nextLength >= compressionDataSize + sizeof(int) * 2) { if (compressionDataSize + sizeof(int) * 2 <= buffer.Buffer.StartIndex) { break; } if (bigBuffer.Length < compressionDataSize) { bigBuffer = new byte[Math.Max(compressionDataSize, bigBuffer.Length << 1)]; } System.Buffer.BlockCopy(buffer.Buffer.Buffer, buffer.Buffer.StartIndex + (index + sizeof(int) * 2), bigBuffer, 0, count -= sizeof(int) * 2); do { index = fileStream.Read(bigBuffer, count, compressionDataSize - count); nextLength -= index; count += index; }while (count != compressionDataSize); buffer.CompressionBuffer.StartIndex = *(int *)(read + sizeof(int)); AutoCSer.IO.Compression.DeflateDeCompressor.Get(bigBuffer, 0, compressionDataSize, ref buffer.CompressionBuffer); if (buffer.CompressionBuffer.Buffer != null) { fixed(byte *dataFixed = buffer.CompressionBuffer.Buffer) { loadData.Set(buffer.CompressionBuffer.Buffer, buffer.CompressionBuffer.StartIndex, *(int *)(read + sizeof(int)), dataFixed); if (!cache.Load(ref loadData)) { throw new InvalidDataException(); } } index = count = 0; buffer.CompressionBuffer.Free(); } else { throw new InvalidDataException(); } } else { endError(ref buffer.Buffer, nextLength, index, count); return; } } else if (count >= compressionDataSize + sizeof(int)) { loadData.Set(buffer.Buffer.Buffer, buffer.Buffer.StartIndex + (index += sizeof(int)), compressionDataSize, bufferFixed); if (!cache.Load(ref loadData)) { throw new InvalidDataException(); } index += compressionDataSize; count -= compressionDataSize + sizeof(int); } else if (count + nextLength >= compressionDataSize + sizeof(int)) { if (compressionDataSize + sizeof(int) <= buffer.Buffer.StartIndex) { break; } if (bigBuffer.Length < compressionDataSize) { bigBuffer = new byte[Math.Max(compressionDataSize, bigBuffer.Length << 1)]; } System.Buffer.BlockCopy(buffer.Buffer.Buffer, buffer.Buffer.StartIndex + (index + sizeof(int)), bigBuffer, 0, count -= sizeof(int)); do { index = fileStream.Read(bigBuffer, count, compressionDataSize - count); nextLength -= index; count += index; }while (count != compressionDataSize); fixed(byte *dataFixed = bigBuffer) { loadData.Set(bigBuffer, 0, compressionDataSize, dataFixed); if (!cache.Load(ref loadData)) { throw new InvalidDataException(); } } index = count = 0; } else { endError(ref buffer.Buffer, nextLength, index, count); return; } } if (nextLength == 0) { if (count == 0) { fileStream.Seek(0, SeekOrigin.End); IsDisposed = 0; } else { endError(ref buffer.Buffer, nextLength, index, count); } return; } if (count != 0) { System.Buffer.BlockCopy(buffer.Buffer.Buffer, buffer.Buffer.StartIndex + index, buffer.Buffer.Buffer, buffer.Buffer.StartIndex, count); } index = fileStream.Read(buffer.Buffer.Buffer, buffer.Buffer.StartIndex + count, buffer.Buffer.Length - count); nextLength -= index; count += index; index = 0; }while (true); } } } } if (!config.IsMoveBakUnknownFile) { throw new InvalidDataException(); } fileStream.Dispose(); AutoCSer.IO.File.MoveBak(FileName); } } fileStream = new FileStream(FileName, createMode, FileAccess.Write, FileShare.Read, bufferPool.Size, FileOptions.None); create(ref buffer.Buffer, Version); } finally { buffer.Free(); BufferLink.Head.Array.SetNull(); if (IsDisposed == 0) { fileFlushSeconds = config.FileFlushSeconds; Writers.PushNotNull(this); OnTime.Set(Date.NowTime.OnTimeFlag.CacheFile); } else if (fileStream != null) { fileStream.Dispose(); } } }