refactor: 使用接口代替虚类

This commit is contained in:
Argo Zhang 2025-11-22 12:53:02 +08:00
parent 33f8bf766d
commit 0b3635b3c3
7 changed files with 82 additions and 86 deletions

View File

@ -1,54 +0,0 @@
// 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 <lzh.shap@gmail.com>
// @Date 2023/07/25
// Updated by Argo Zhang <argo@live.ca> at 2025/11/21
using System.Buffers;
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;
public int IoCount { get; private set; }
protected FileStream XdbFileStream = new(xdbPath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, FileOptions.RandomAccess);
public void ResetIoCount()
{
IoCount = 0;
}
public virtual ReadOnlyMemory<byte> GetVectorIndex(int offset) => GetData(HeaderInfoLength + offset, VectorIndexSize);
public virtual ReadOnlyMemory<byte> GetData(long offset, int length)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(length);
int totalBytesRead = 0;
try
{
XdbFileStream.Seek(offset, SeekOrigin.Begin);
int bytesRead;
while (totalBytesRead < length)
{
bytesRead = XdbFileStream.Read(buffer, totalBytesRead, length);
totalBytesRead += bytesRead;
IoCount++;
}
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
return new ReadOnlyMemory<byte>(buffer, 0, totalBytesRead);
}
}

View File

@ -5,14 +5,13 @@
// @Date 2023/07/25 // @Date 2023/07/25
// Updated by Argo Zhang <argo@live.ca> at 2025/11/21 // Updated by Argo Zhang <argo@live.ca> at 2025/11/21
using IP2Region.Net.Internal.Abstractions;
using IP2Region.Net.XDB; using IP2Region.Net.XDB;
namespace IP2Region.Net.Internal; namespace IP2Region.Net.Internal;
class CacheStrategyFactory(string xdbPath) static class CacheStrategyFactory
{ {
public AbstractCacheStrategy CreateCacheStrategy(CachePolicy cachePolicy) => cachePolicy switch public static ICacheStrategy CreateCacheStrategy(CachePolicy cachePolicy, string xdbPath) => cachePolicy switch
{ {
CachePolicy.Content => new ContentCacheStrategy(xdbPath), CachePolicy.Content => new ContentCacheStrategy(xdbPath),
CachePolicy.VectorIndex => new VectorIndexCacheStrategy(xdbPath), CachePolicy.VectorIndex => new VectorIndexCacheStrategy(xdbPath),

View File

@ -5,20 +5,16 @@
// @Date 2023/07/25 // @Date 2023/07/25
// Updated by Argo Zhang <argo@live.ca> at 2025/11/21 // Updated by Argo Zhang <argo@live.ca> at 2025/11/21
using IP2Region.Net.Internal.Abstractions;
namespace IP2Region.Net.Internal; namespace IP2Region.Net.Internal;
class ContentCacheStrategy : AbstractCacheStrategy class ContentCacheStrategy : FileCacheStrategy
{ {
private readonly ReadOnlyMemory<byte> _cacheData; private readonly ReadOnlyMemory<byte> _cacheData;
public ContentCacheStrategy(string xdbPath) : base(xdbPath) public ContentCacheStrategy(string xdbPath) : base(xdbPath)
{ {
_cacheData = base.GetData(0, (int)XdbFileStream.Length); _cacheData = base.GetData(0, (int)XdbFileStream.Length);
XdbFileStream.Close();
XdbFileStream.Dispose();
} }
public override ReadOnlyMemory<byte> GetData(long offset = 0, int length = 0) => _cacheData.Slice((int)offset, length); public override ReadOnlyMemory<byte> GetData(long offset, int length) => _cacheData.Slice((int)offset, length);
} }

View File

@ -5,11 +5,59 @@
// @Date 2023/07/25 // @Date 2023/07/25
// Updated by Argo Zhang <argo@live.ca> at 2025/11/21 // Updated by Argo Zhang <argo@live.ca> at 2025/11/21
using IP2Region.Net.Internal.Abstractions; using System.Buffers;
namespace IP2Region.Net.Internal; namespace IP2Region.Net.Internal;
class FileCacheStrategy(string xdbPath) : AbstractCacheStrategy(xdbPath) 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<byte> GetVectorIndex(int offset) => GetData(HeaderInfoLength + offset, VectorIndexSize);
public virtual ReadOnlyMemory<byte> GetData(long offset, int length)
{
var buffer = ArrayPool<byte>.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<byte>.Shared.Return(buffer);
}
}
} }

View File

@ -0,0 +1,19 @@
// 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 <lzh.shap@gmail.com>
// @Date 2023/07/25
// Updated by Argo Zhang <argo@live.ca> at 2025/11/21
namespace IP2Region.Net.Internal;
internal interface ICacheStrategy
{
int IoCount { get; }
void ResetIoCount();
ReadOnlyMemory<byte> GetVectorIndex(int offset);
ReadOnlyMemory<byte> GetData(long offset, int length);
}

View File

@ -5,11 +5,9 @@
// @Date 2023/07/25 // @Date 2023/07/25
// Updated by Argo Zhang <argo@live.ca> at 2025/11/21 // Updated by Argo Zhang <argo@live.ca> at 2025/11/21
using IP2Region.Net.Internal.Abstractions;
namespace IP2Region.Net.Internal; namespace IP2Region.Net.Internal;
class VectorIndexCacheStrategy : AbstractCacheStrategy class VectorIndexCacheStrategy : FileCacheStrategy
{ {
private const int VectorIndexRows = 256; private const int VectorIndexRows = 256;
private const int VectorIndexCols = 256; private const int VectorIndexCols = 256;
@ -18,10 +16,7 @@ class VectorIndexCacheStrategy : AbstractCacheStrategy
public VectorIndexCacheStrategy(string xdbPath) : base(xdbPath) public VectorIndexCacheStrategy(string xdbPath) : base(xdbPath)
{ {
XdbFileStream.Seek(HeaderInfoLength, SeekOrigin.Begin); _vectorCache = GetData(HeaderInfoLength, VectorIndexRows * VectorIndexCols * VectorIndexSize);
var buffer = new byte[VectorIndexRows * VectorIndexCols * VectorIndexSize];
var length = XdbFileStream.Read(buffer, 0, buffer.Length);
_vectorCache = new ReadOnlyMemory<byte>(buffer);
} }
public override ReadOnlyMemory<byte> GetVectorIndex(int offset) => _vectorCache.Slice(offset, VectorIndexSize); public override ReadOnlyMemory<byte> GetVectorIndex(int offset) => _vectorCache.Slice(offset, VectorIndexSize);

View File

@ -7,7 +7,6 @@
using IP2Region.Net.Abstractions; using IP2Region.Net.Abstractions;
using IP2Region.Net.Internal; using IP2Region.Net.Internal;
using IP2Region.Net.Internal.Abstractions;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Net; using System.Net;
@ -18,24 +17,18 @@ namespace IP2Region.Net.XDB;
/// <summary> /// <summary>
/// <see cref="ISearcher"/> 实现类 /// <see cref="ISearcher"/> 实现类
/// </summary> /// </summary>
public class Searcher : ISearcher /// <remarks>
/// <inheritdoc/>
/// </remarks>
public class Searcher(CachePolicy cachePolicy, string xdbPath) : ISearcher
{ {
private readonly AbstractCacheStrategy _cacheStrategy; private readonly ICacheStrategy _cacheStrategy = CacheStrategyFactory.CreateCacheStrategy(cachePolicy, xdbPath);
/// <summary> /// <summary>
/// <inheritdoc/> /// <inheritdoc/>
/// </summary> /// </summary>
public int IoCount => _cacheStrategy.IoCount; public int IoCount => _cacheStrategy.IoCount;
/// <summary>
/// <inheritdoc/>
/// </summary>
public Searcher(CachePolicy cachePolicy, string dbPath)
{
var factory = new CacheStrategyFactory(dbPath);
_cacheStrategy = factory.CreateCacheStrategy(cachePolicy);
}
/// <summary> /// <summary>
/// <inheritdoc/> /// <inheritdoc/>
/// </summary> /// </summary>
@ -93,7 +86,7 @@ public class Searcher : ISearcher
{ {
int m = (int)(l + h) >> 1; int m = (int)(l + h) >> 1;
var p = (int)sPtr + m * indexSize; var p = sPtr + m * indexSize;
var buff = _cacheStrategy.GetData(p, indexSize); var buff = _cacheStrategy.GetData(p, indexSize);
var s = buff.Span.Slice(0, length); var s = buff.Span.Slice(0, length);
@ -114,7 +107,7 @@ public class Searcher : ISearcher
} }
} }
var regionBuff = _cacheStrategy.GetData((int)dataPtr, dataLen); var regionBuff = _cacheStrategy.GetData(dataPtr, dataLen);
return Encoding.UTF8.GetString(regionBuff.Span.ToArray()); return Encoding.UTF8.GetString(regionBuff.Span.ToArray());
} }