Skip to content

Commit

Permalink
feat:support for concurrent file-based queries
Browse files Browse the repository at this point in the history
  • Loading branch information
malus2077 committed Jul 26, 2023
1 parent c8446ed commit 7f5ec33
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 143 deletions.
12 changes: 10 additions & 2 deletions binding/csharp/IP2Region.Net.BenchMark/Program.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using IP2Region.Net.Abstractions;
using IP2Region.Net.XDB;

BenchmarkRunner.Run(typeof(Program).Assembly);

public class CachePolicyCompare
{
private readonly Searcher _contentSearcher = new Searcher(CachePolicy.Content);
private readonly Searcher _vectorSearcher = new Searcher(CachePolicy.VectorIndex);
private static readonly string XdbPath = Path.Combine(AppContext.BaseDirectory, "IP2Region", "ip2region.xdb");
private readonly ISearcher _contentSearcher = new Searcher(CachePolicy.Content, XdbPath);
private readonly ISearcher _vectorSearcher = new Searcher(CachePolicy.VectorIndex,XdbPath);
private readonly ISearcher _fileSearcher = new Searcher(CachePolicy.File,XdbPath);

private readonly string _testIpAddress = "114.114.114.114";

Expand All @@ -18,4 +21,9 @@ public class CachePolicyCompare
[Benchmark]
[BenchmarkCategory(nameof(CachePolicy.VectorIndex))]
public void CachePolicy_VectorIndex() => _vectorSearcher.Search(_testIpAddress);


[Benchmark]
[BenchmarkCategory(nameof(CachePolicy.File))]
public void CachePolicy_File() => _fileSearcher.Search(_testIpAddress);
}
20 changes: 20 additions & 0 deletions binding/csharp/IP2Region.Net/Abstractions/ISearcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2023 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 <[email protected]>
// @Date 2023/07/25

using System.Net;

namespace IP2Region.Net.Abstractions;

public interface ISearcher
{
string? Search(string ipStr);

string? Search(IPAddress ipAddress);

string? Search(uint ipAddress);

int IoCount { get; }
}
16 changes: 16 additions & 0 deletions binding/csharp/IP2Region.Net/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Changelog

All notable changes to this project will be documented in this file.

## [Unreleased]

## [2.0.0] - 2023-07-26

### Removed
- Remove nuget include xdb file
- Searcher cache policy default parameters
- Searcher xdb file path default parameters

### Added
- Dependent file query policies CachePolicy.VectorIndex, CachePolicy.File support thread-safe concurrent queries
- Dramatically optimizes overall performance
19 changes: 5 additions & 14 deletions binding/csharp/IP2Region.Net/IP2Region.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,23 @@

<PropertyGroup>
<id>IP2Region.Net</id>
<version>1.0.2</version>
<version>2.0.0</version>
<title>IP2Region.Net</title>
<authors>Alan Lee</authors>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageProjectUrl>https://github.com/lionsoul2014/ip2region/tree/master/binding/csharp</PackageProjectUrl>
<RepositoryUrl>https://github.com/lionsoul2014/ip2region/tree/master/binding/csharp</RepositoryUrl>
<Description>ip2region 是一个离线IP地址定位库,极速响应,微秒级查询</Description>
<tags>IP2Region</tags>


<PackageReleaseNotes>Please refer to CHANGELOG.md for details</PackageReleaseNotes>
<Description>.NET client library for ip2region</Description>
<PackageTags>IP2Region GeoIP IPSearch</PackageTags>
<RepositoryType>git</RepositoryType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TargetFrameworks>net6.0;netstandard2.1</TargetFrameworks>
<LangVersion>10.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<Folder Include="Data" />
</ItemGroup>

<ItemGroup>
<None Update="Data\ip2region.xdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2023 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 <[email protected]>
// @Date 2023/07/25

using System.Buffers;

namespace IP2Region.Net.Internal.Abstractions;

internal abstract class AbstractCacheStrategy
{
protected const int HeaderInfoLength = 256;
protected const int VectorIndexRows = 256;
protected const int VectorIndexCols = 256;
protected const int VectorIndexSize = 8;

protected readonly FileStream XdbFileStream;
private const int BufferSize = 4096;

internal int IoCount { get; private set; }

protected AbstractCacheStrategy(string xdbPath)
{
XdbFileStream = new FileStream(xdbPath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize,
useAsync: true);
}

protected int GetVectorIndexStartPos(uint ip)
{
var il0 = ip >> 24 & 0xFF;
var il1 = ip >> 16 & 0xFF;
var idx = il0 * VectorIndexCols * VectorIndexSize + il1 * VectorIndexSize;
return (int)idx;
}

internal abstract ReadOnlyMemory<byte> GetVectorIndex(uint ip);

internal virtual ReadOnlyMemory<byte> GetData(int offset, int length)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(length);
int totalBytesRead = 0;
try
{
XdbFileStream.Seek(offset, SeekOrigin.Begin);

int bytesRead;
do
{
int bytesToRead = Math.Min(BufferSize, length - totalBytesRead);
bytesRead = XdbFileStream.Read(buffer, totalBytesRead, bytesToRead);
totalBytesRead += bytesRead;

IoCount++;
} while (bytesRead > 0 && totalBytesRead < length);
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}

return new ReadOnlyMemory<byte>(buffer, 0, totalBytesRead);
}
}
31 changes: 31 additions & 0 deletions binding/csharp/IP2Region.Net/Internal/CacheStrategyFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2023 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 <[email protected]>
// @Date 2023/07/25

using IP2Region.Net.Internal.Abstractions;
using IP2Region.Net.XDB;

namespace IP2Region.Net.Internal;

internal class CacheStrategyFactory
{
private readonly string _xdbPath;

public CacheStrategyFactory(string xdbPath)
{
_xdbPath = xdbPath;
}

public AbstractCacheStrategy CreateCacheStrategy(CachePolicy cachePolicy)
{
return cachePolicy switch
{
CachePolicy.Content => new ContentCacheStrategy(_xdbPath),
CachePolicy.VectorIndex => new VectorIndexCacheStrategy(_xdbPath),
CachePolicy.File => new FileCacheStrategy(_xdbPath),
_ => throw new ArgumentException(nameof(cachePolicy))
};
}
}
32 changes: 32 additions & 0 deletions binding/csharp/IP2Region.Net/Internal/ContentCacheStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2023 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 <[email protected]>
// @Date 2023/07/25

using IP2Region.Net.Internal.Abstractions;

namespace IP2Region.Net.Internal;

internal class ContentCacheStrategy : AbstractCacheStrategy
{
private readonly ReadOnlyMemory<byte> _cacheData;

public ContentCacheStrategy(string xdbPath) : base(xdbPath)
{
_cacheData = base.GetData(0, (int)XdbFileStream.Length);
XdbFileStream.Close();
XdbFileStream.Dispose();
}

internal override ReadOnlyMemory<byte> GetVectorIndex(uint ip)
{
int idx = GetVectorIndexStartPos(ip);
return _cacheData.Slice(HeaderInfoLength + idx, VectorIndexSize);
}

internal override ReadOnlyMemory<byte> GetData(int offset, int length)
{
return _cacheData.Slice(offset, length);
}
}
22 changes: 22 additions & 0 deletions binding/csharp/IP2Region.Net/Internal/FileCacheStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2023 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 <[email protected]>
// @Date 2023/07/25

using IP2Region.Net.Internal.Abstractions;

namespace IP2Region.Net.Internal;

internal class FileCacheStrategy : AbstractCacheStrategy
{
public FileCacheStrategy(string xdbPath) : base(xdbPath)
{
}

internal override ReadOnlyMemory<byte> GetVectorIndex(uint ip)
{
var idx = GetVectorIndexStartPos(ip);
return GetData(HeaderInfoLength + idx, VectorIndexSize);
}
}
26 changes: 26 additions & 0 deletions binding/csharp/IP2Region.Net/Internal/VectorIndexCacheStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2023 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 <[email protected]>
// @Date 2023/07/25

using IP2Region.Net.Internal.Abstractions;

namespace IP2Region.Net.Internal;

internal class VectorIndexCacheStrategy : AbstractCacheStrategy
{
private readonly ReadOnlyMemory<byte> _vectorIndex;

public VectorIndexCacheStrategy(string xdbPath) : base(xdbPath)
{
var vectorLength = VectorIndexRows * VectorIndexCols * VectorIndexSize;
_vectorIndex = base.GetData(HeaderInfoLength, vectorLength);
}

internal override ReadOnlyMemory<byte> GetVectorIndex(uint ip)
{
var idx = GetVectorIndexStartPos(ip);
return _vectorIndex.Slice(idx, VectorIndexSize);
}
}
6 changes: 3 additions & 3 deletions binding/csharp/IP2Region.Net/XDB/CachePolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ namespace IP2Region.Net.XDB;
public enum CachePolicy
{
/// <summary>
/// no cache , not thread safe!
/// no cache
/// </summary>
File,
/// <summary>
/// cache vector index , reduce the number of IO operations , not thread safe!
/// cache vector index , reduce the number of IO operations
/// </summary>
VectorIndex,
/// <summary>
/// default cache policy , cache whole xdb file , thread safe
/// default cache policy , cache whole xdb file
/// </summary>
Content
}
14 changes: 0 additions & 14 deletions binding/csharp/IP2Region.Net/XDB/ISearcher.cs

This file was deleted.

Loading

0 comments on commit 7f5ec33

Please sign in to comment.