// Copyright 2025 The Ip2Region Authors. All rights reserved. // Use of this source code is governed by a Apache2.0-style // license that can be found in the LICENSE file. // @Author Alan // @Date 2023/07/25 // Updated by Argo Zhang at 2025/11/21 using System.Buffers; namespace IP2Region.Net.Internal; class FileCacheStrategy(string xdbPath) : ICacheStrategy { protected const int HeaderInfoLength = 256; protected const int VectorIndexSize = 8; protected const int BufferSize = 64 * 1024; protected FileStream XdbFileStream = new(xdbPath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, FileOptions.RandomAccess); public int IoCount { get; set; } public void ResetIoCount() { IoCount = 0; } public virtual ReadOnlyMemory GetVectorIndex(int offset) => GetData(HeaderInfoLength + offset, VectorIndexSize); public virtual ReadOnlyMemory GetData(long offset, int length) { var buffer = ArrayPool.Shared.Rent(length); try { int totalBytesRead = 0; XdbFileStream.Seek(offset, SeekOrigin.Begin); int bytesRead; while (totalBytesRead < length) { bytesRead = XdbFileStream.Read(buffer, totalBytesRead, length - totalBytesRead); if (bytesRead == 0) { break; } totalBytesRead += bytesRead; IoCount++; } var ret = new byte[totalBytesRead]; if (totalBytesRead > 0) { Array.Copy(buffer, 0, ret, 0, totalBytesRead); } return ret; } finally { ArrayPool.Shared.Return(buffer); } } /// /// 释放文件句柄 /// /// protected virtual void Dispose(bool disposing) { if (disposing) { XdbFileStream.Close(); XdbFileStream.Dispose(); } } /// /// /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } }