refactor: 使用接口代替虚类
This commit is contained in:
parent
33f8bf766d
commit
0b3635b3c3
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue