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 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 string XdbPathV6 = Path.Combine(AppContext.BaseDirectory, "IP2Region", "ip2region_v6.xdb");
private static readonly Searcher _contentV4Searcher = new Searcher(CachePolicy.Content, XdbPathV4); private static readonly Searcher _contentV4Searcher = new(CachePolicy.Content, XdbPathV4);
private static readonly Searcher _vectorV4Searcher = new Searcher(CachePolicy.VectorIndex, XdbPathV4); private static readonly Searcher _vectorV4Searcher = new(CachePolicy.VectorIndex, XdbPathV4);
private static readonly Searcher _fileV4Searcher = new Searcher(CachePolicy.File, XdbPathV4); private static readonly Searcher _fileV4Searcher = new(CachePolicy.File, XdbPathV4);
private static readonly Searcher _contentV6Searcher = new Searcher(CachePolicy.Content, XdbPathV6); private static readonly Searcher _contentV6Searcher = new(CachePolicy.Content, XdbPathV6);
private static readonly Searcher _vectorV6Searcher = new Searcher(CachePolicy.VectorIndex, XdbPathV6); private static readonly Searcher _vectorV6Searcher = new(CachePolicy.VectorIndex, XdbPathV6);
private static readonly Searcher _fileV6Searcher = new Searcher(CachePolicy.File, XdbPathV6); private static readonly Searcher _fileV6Searcher = new(CachePolicy.File, XdbPathV6);
private readonly string _testIpV4Address = "114.114.114.114"; private readonly string _testIPv4Address = "114.114.114.114";
private readonly string _testIpV6Address = "240e:3b7:3272:d8d0:db09:c067:8d59:539e"; private readonly string _testIPv6Address = "240e:3b7:3272:d8d0:db09:c067:8d59:539e";
[Benchmark] [Benchmark]
[BenchmarkCategory(nameof(CachePolicy.Content))] [BenchmarkCategory("IPv4")]
public void ContentIpV4() => _contentV4Searcher.Search(_testIpV4Address); public void ContentIPv4() => _contentV4Searcher.Search(_testIPv4Address);
//[Benchmark]
[BenchmarkCategory(nameof(CachePolicy.VectorIndex))]
public void VectorIndexIpV4() => _vectorV4Searcher.Search(_testIpV4Address);
[Benchmark] [Benchmark]
[BenchmarkCategory(nameof(CachePolicy.File))] [BenchmarkCategory("IPv4")]
public void FileIpV4() => _fileV4Searcher.Search(_testIpV4Address); public void VectorIPv4() => _vectorV4Searcher.Search(_testIPv4Address);
[Benchmark] [Benchmark]
[BenchmarkCategory(nameof(CachePolicy.Content))] [BenchmarkCategory("IPv4")]
public void ContentIpV6() => _contentV6Searcher.Search(_testIpV6Address); public void FileIPv4() => _fileV4Searcher.Search(_testIPv4Address);
[Benchmark] [Benchmark]
[BenchmarkCategory(nameof(CachePolicy.VectorIndex))] [BenchmarkCategory("IPv6")]
public void VectorIndexIpV6() => _vectorV6Searcher.Search(_testIpV6Address); public void ContentIPv6() => _contentV6Searcher.Search(_testIPv6Address);
[Benchmark] [Benchmark]
[BenchmarkCategory(nameof(CachePolicy.File))] [BenchmarkCategory("IPv6")]
public void FileIpV6() => _fileV6Searcher.Search(_testIpV6Address); 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); 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] [Fact]
public void IoCount_Vector_Ok() public void IoCount_Vector_Ok()
{ {
@ -102,6 +91,17 @@ public class SearcherTest
Assert.Equal(2, searcher.IoCount); 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] [Theory]
[InlineData("58.251.255.255", "中国|广东省|深圳市|联通")] [InlineData("58.251.255.255", "中国|广东省|深圳市|联通")]
public void Search_Ip_Ok(string ipStr, string expected) 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) internal abstract class AbstractCacheStrategy(string xdbPath)
{ {
protected const int HeaderInfoLength = 256;
protected const int VectorIndexSize = 8;
private const int BufferSize = 64 * 1024; 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; } public int IoCount { get; private set; }
@ -20,25 +24,26 @@ internal abstract class AbstractCacheStrategy(string xdbPath)
IoCount = 0; IoCount = 0;
} }
public virtual ReadOnlyMemory<byte> GetVectorIndexStartPos(int offset) public virtual ReadOnlyMemory<byte> GetVectorIndex(int offset) => GetData(HeaderInfoLength + offset, VectorIndexSize);
{
return GetData(256 + offset, 8);
}
public virtual ReadOnlyMemory<byte> GetData(int offset, int length) public virtual ReadOnlyMemory<byte> GetData(int offset = 0, int length = 0)
{ {
if (length == 0)
{
length = (int)_xdbFileStream.Length;
}
byte[] buffer = ArrayPool<byte>.Shared.Rent(length); byte[] buffer = ArrayPool<byte>.Shared.Rent(length);
int totalBytesRead = 0; int totalBytesRead = 0;
try try
{ {
var stream = GetXdbFileStream(); _xdbFileStream.Seek(offset, SeekOrigin.Begin);
stream.Seek(offset, SeekOrigin.Begin);
int bytesRead; int bytesRead;
while (totalBytesRead < length) while (totalBytesRead < length)
{ {
int bytesToRead = Math.Min(BufferSize, length - totalBytesRead); int bytesToRead = Math.Min(BufferSize, length - totalBytesRead);
bytesRead = stream.Read(buffer, totalBytesRead, bytesToRead); bytesRead = _xdbFileStream.Read(buffer, totalBytesRead, bytesToRead);
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
IoCount++; IoCount++;
@ -51,15 +56,4 @@ internal abstract class AbstractCacheStrategy(string xdbPath)
return new ReadOnlyMemory<byte>(buffer, 0, totalBytesRead); 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; namespace IP2Region.Net.Internal;
internal class CacheStrategyFactory(string xdbPath) class CacheStrategyFactory(string xdbPath)
{ {
public AbstractCacheStrategy CreateCacheStrategy(CachePolicy cachePolicy) => cachePolicy switch public AbstractCacheStrategy CreateCacheStrategy(CachePolicy cachePolicy) => cachePolicy switch
{ {

View File

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

View File

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