refactor: 重构代码

This commit is contained in:
Argo Zhang 2025-11-21 15:46:09 +08:00
parent 14d2332483
commit 426038b3fe
7 changed files with 63 additions and 69 deletions

View File

@ -14,37 +14,37 @@ public class Benchmarks
{
private static readonly string XdbPathV4 = Path.Combine(AppContext.BaseDirectory, "IP2Region", "ip2region_v4.xdb");
private static readonly string XdbPathV6 = Path.Combine(AppContext.BaseDirectory, "IP2Region", "ip2region_v6.xdb");
private static readonly Searcher _contentV4Searcher = new Searcher(CachePolicy.Content, XdbPathV4);
private static readonly Searcher _vectorV4Searcher = new Searcher(CachePolicy.VectorIndex, XdbPathV4);
private static readonly Searcher _fileV4Searcher = new Searcher(CachePolicy.File, XdbPathV4);
private static readonly Searcher _contentV6Searcher = new Searcher(CachePolicy.Content, XdbPathV6);
private static readonly Searcher _vectorV6Searcher = new Searcher(CachePolicy.VectorIndex, XdbPathV6);
private static readonly Searcher _fileV6Searcher = new Searcher(CachePolicy.File, XdbPathV6);
private static readonly Searcher _contentV4Searcher = new(CachePolicy.Content, XdbPathV4);
private static readonly Searcher _vectorV4Searcher = new(CachePolicy.VectorIndex, XdbPathV4);
private static readonly Searcher _fileV4Searcher = new(CachePolicy.File, XdbPathV4);
private static readonly Searcher _contentV6Searcher = new(CachePolicy.Content, XdbPathV6);
private static readonly Searcher _vectorV6Searcher = new(CachePolicy.VectorIndex, XdbPathV6);
private static readonly Searcher _fileV6Searcher = new(CachePolicy.File, XdbPathV6);
private readonly string _testIpV4Address = "114.114.114.114";
private readonly string _testIpV6Address = "240e:3b7:3272:d8d0:db09:c067:8d59:539e";
private readonly string _testIPv4Address = "114.114.114.114";
private readonly string _testIPv6Address = "240e:3b7:3272:d8d0:db09:c067:8d59:539e";
[Benchmark]
[BenchmarkCategory(nameof(CachePolicy.Content))]
public void ContentIpV4() => _contentV4Searcher.Search(_testIpV4Address);
//[Benchmark]
[BenchmarkCategory(nameof(CachePolicy.VectorIndex))]
public void VectorIndexIpV4() => _vectorV4Searcher.Search(_testIpV4Address);
[BenchmarkCategory("IPv4")]
public void ContentIPv4() => _contentV4Searcher.Search(_testIPv4Address);
[Benchmark]
[BenchmarkCategory(nameof(CachePolicy.File))]
public void FileIpV4() => _fileV4Searcher.Search(_testIpV4Address);
[BenchmarkCategory("IPv4")]
public void VectorIPv4() => _vectorV4Searcher.Search(_testIPv4Address);
[Benchmark]
[BenchmarkCategory(nameof(CachePolicy.Content))]
public void ContentIpV6() => _contentV6Searcher.Search(_testIpV6Address);
[BenchmarkCategory("IPv4")]
public void FileIPv4() => _fileV4Searcher.Search(_testIPv4Address);
[Benchmark]
[BenchmarkCategory(nameof(CachePolicy.VectorIndex))]
public void VectorIndexIpV6() => _vectorV6Searcher.Search(_testIpV6Address);
[BenchmarkCategory("IPv6")]
public void ContentIPv6() => _contentV6Searcher.Search(_testIPv6Address);
[Benchmark]
[BenchmarkCategory(nameof(CachePolicy.File))]
public void FileIpV6() => _fileV6Searcher.Search(_testIpV6Address);
[BenchmarkCategory("IPv6")]
public void VectorIPv6() => _vectorV6Searcher.Search(_testIPv6Address);
[Benchmark]
[BenchmarkCategory("IPv6")]
public void FileIPv6() => _fileV6Searcher.Search(_testIPv6Address);
}

View File

@ -80,17 +80,6 @@ public class SearcherTest
Assert.Equal(3, searcher.IoCount);
}
[Fact]
public void IoCount_Content_Ok()
{
var searcher = new Searcher(CachePolicy.Content, _xdbPathV4);
searcher.Search("58.251.27.201");
Assert.Equal(0, searcher.IoCount);
searcher.Search("58.251.27.201");
Assert.Equal(0, searcher.IoCount);
}
[Fact]
public void IoCount_Vector_Ok()
{
@ -102,6 +91,17 @@ public class SearcherTest
Assert.Equal(2, searcher.IoCount);
}
[Fact]
public void IoCount_Content_Ok()
{
var searcher = new Searcher(CachePolicy.Content, _xdbPathV4);
searcher.Search("58.251.27.201");
Assert.Equal(0, searcher.IoCount);
searcher.Search("58.251.27.201");
Assert.Equal(0, searcher.IoCount);
}
[Theory]
[InlineData("58.251.255.255", "中国|广东省|深圳市|联通")]
public void Search_Ip_Ok(string ipStr, string expected)

View File

@ -11,7 +11,11 @@ namespace IP2Region.Net.Internal.Abstractions;
internal abstract class AbstractCacheStrategy(string xdbPath)
{
protected const int HeaderInfoLength = 256;
protected const int VectorIndexSize = 8;
private const int BufferSize = 64 * 1024;
private readonly FileStream _xdbFileStream = new(xdbPath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, FileOptions.RandomAccess);
public int IoCount { get; private set; }
@ -20,25 +24,26 @@ internal abstract class AbstractCacheStrategy(string xdbPath)
IoCount = 0;
}
public virtual ReadOnlyMemory<byte> GetVectorIndexStartPos(int offset)
public virtual ReadOnlyMemory<byte> GetVectorIndex(int offset) => GetData(HeaderInfoLength + offset, VectorIndexSize);
public virtual ReadOnlyMemory<byte> GetData(int offset = 0, int length = 0)
{
return GetData(256 + offset, 8);
if (length == 0)
{
length = (int)_xdbFileStream.Length;
}
public virtual ReadOnlyMemory<byte> GetData(int offset, int length)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(length);
int totalBytesRead = 0;
try
{
var stream = GetXdbFileStream();
stream.Seek(offset, SeekOrigin.Begin);
_xdbFileStream.Seek(offset, SeekOrigin.Begin);
int bytesRead;
while (totalBytesRead < length)
{
int bytesToRead = Math.Min(BufferSize, length - totalBytesRead);
bytesRead = stream.Read(buffer, totalBytesRead, bytesToRead);
bytesRead = _xdbFileStream.Read(buffer, totalBytesRead, bytesToRead);
totalBytesRead += bytesRead;
IoCount++;
@ -51,15 +56,4 @@ internal abstract class AbstractCacheStrategy(string xdbPath)
return new ReadOnlyMemory<byte>(buffer, 0, totalBytesRead);
}
FileStream? _xdbFileStream;
protected FileStream GetXdbFileStream()
{
if (_xdbFileStream == null)
{
_xdbFileStream = new FileStream(xdbPath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, FileOptions.RandomAccess);
}
return _xdbFileStream;
}
}

View File

@ -10,7 +10,7 @@ using IP2Region.Net.XDB;
namespace IP2Region.Net.Internal;
internal class CacheStrategyFactory(string xdbPath)
class CacheStrategyFactory(string xdbPath)
{
public AbstractCacheStrategy CreateCacheStrategy(CachePolicy cachePolicy) => cachePolicy switch
{

View File

@ -11,16 +11,12 @@ namespace IP2Region.Net.Internal;
class ContentCacheStrategy : AbstractCacheStrategy
{
readonly ReadOnlyMemory<byte> _cacheData = default;
private readonly ReadOnlyMemory<byte> _cacheData;
public ContentCacheStrategy(string xdbPath) : base(xdbPath)
{
using var reader = base.GetXdbFileStream();
_cacheData = base.GetData(0, (int)reader.Length);
_cacheData = base.GetData();
}
public override ReadOnlyMemory<byte> GetData(int offset, int length)
{
return _cacheData.Slice(offset, length);
}
public override ReadOnlyMemory<byte> GetData(int offset = 0, int length = 0) => _cacheData.Slice(offset, length);
}

View File

@ -9,14 +9,17 @@ using IP2Region.Net.Internal.Abstractions;
namespace IP2Region.Net.Internal;
internal class VectorIndexCacheStrategy : AbstractCacheStrategy
class VectorIndexCacheStrategy : AbstractCacheStrategy
{
readonly ReadOnlyMemory<byte> _vectorCache = default;
private const int VectorIndexRows = 256;
private const int VectorIndexCols = 256;
private readonly ReadOnlyMemory<byte> _vectorCache;
public VectorIndexCacheStrategy(string xdbPath) : base(xdbPath)
{
_vectorCache = base.GetData(256, 256 * 256 * 8);
_vectorCache = GetData(HeaderInfoLength, VectorIndexRows * VectorIndexCols * VectorIndexSize);
}
public override ReadOnlyMemory<byte> GetVectorIndexStartPos(int offset) => _vectorCache.Slice(offset, 8);
public override ReadOnlyMemory<byte> GetVectorIndex(int offset) => _vectorCache.Slice(offset, VectorIndexSize);
}

View File

@ -78,9 +78,9 @@ public class Searcher : ISearcher
var il1 = ipBytes[1];
var idx = il0 * vectorIndexCols * vectorIndexSize + il1 * vectorIndexSize;
var data = _cacheStrategy.GetVectorIndexStartPos(idx);
var sPtr = BinaryPrimitives.ReadUInt32LittleEndian(data.Span);
var ePtr = BinaryPrimitives.ReadUInt32LittleEndian(data.Span.Slice(4));
var vector = _cacheStrategy.GetVectorIndex(idx);
var sPtr = BinaryPrimitives.ReadUInt32LittleEndian(vector.Span);
var ePtr = BinaryPrimitives.ReadUInt32LittleEndian(vector.Span.Slice(4));
var length = ipBytes.Length;
var indexSize = length * 2 + 6;
@ -125,11 +125,12 @@ public class Searcher : ISearcher
var ret = 0;
for (int i = 0; i < ip1.Length; i++)
{
if (ip1[i] < ip2[ip1.Length - 1 - i])
var ip2Index = ip1.Length - 1 - i;
if (ip1[i] < ip2[ip2Index])
{
return -1;
}
else if (ip1[i] > ip2[ip1.Length - 1 - i])
else if (ip1[i] > ip2[ip2Index])
{
return 1;
}