Skip to content

Commit

Permalink
Merge pull request #195 from maxmind/greg/net-9
Browse files Browse the repository at this point in the history
Update targets
  • Loading branch information
horgh authored Nov 22, 2024
2 parents 4614e3f + 5c87de8 commit 11744d7
Show file tree
Hide file tree
Showing 15 changed files with 162 additions and 152 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.0.x
7.0.x
8.0.x
9.0.x
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.0.x
7.0.x
8.0.x
9.0.x
- name: Build
run: |
Expand Down
6 changes: 3 additions & 3 deletions MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<PropertyGroup>
<Description>Benchmark project to validate .NET reader for the MaxMind DB file format</Description>
<VersionPrefix>4.0.0</VersionPrefix>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net8.0;net7.0;net6.0;net472</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net8.0;net7.0;net6.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net9.0;net8.0;net481</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net9.0;net8.0</TargetFrameworks>
<AssemblyName>MaxMind.Db.Benchmark</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>MaxMind.Db.Benchmark</PackageId>
Expand All @@ -18,7 +18,7 @@
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<LangVersion>12.0</LangVersion>
<LangVersion>13.0</LangVersion>
<Nullable>enable</Nullable>
<AnalysisLevel>latest</AnalysisLevel>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
Expand Down
190 changes: 92 additions & 98 deletions MaxMind.Db.Test/DecoderTest.cs

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions MaxMind.Db.Test/MaxMind.Db.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<PropertyGroup>
<Description>Test project to validate .NET reader for the MaxMind DB file format</Description>
<VersionPrefix>4.0.0</VersionPrefix>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net8.0;net7.0;net6.0;net472</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net8.0;net7.0;net6.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net9.0;net8.0;net481</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net9.0;net8.0</TargetFrameworks>
<AssemblyName>MaxMind.Db.Test</AssemblyName>
<AssemblyOriginatorKeyFile>../MaxMind.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
Expand All @@ -21,7 +21,7 @@
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<LangVersion>12.0</LangVersion>
<LangVersion>13.0</LangVersion>
<Nullable>enable</Nullable>
<AnalysisLevel>latest</AnalysisLevel>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
Expand All @@ -34,7 +34,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="FluentAssertions" Version="6.12.2" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
Expand Down
6 changes: 3 additions & 3 deletions MaxMind.Db.Test/ReaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ private static void TestIPV6(Reader reader, string file)
{
TestAddresses(reader,
file,
new[] { "::1:ffff:ffff", "::2:0:0", "::2:0:40", "::2:0:50", "::2:0:58" },
["::1:ffff:ffff", "::2:0:0", "::2:0:40", "::2:0:50", "::2:0:58"],
new Dictionary<string, string>
{
{"::2:0:1", "::2:0:0"},
Expand All @@ -492,7 +492,7 @@ private static void TestIPV6(Reader reader, string file)
{"::2:0:57", "::2:0:50"},
{"::2:0:59", "::2:0:58"}
},
new[] { "1.1.1.33", "255.254.253.123", "89fa::" },
["1.1.1.33", "255.254.253.123", "89fa::"],
new Dictionary<string, int>
{
{"::2:0:1", 122}
Expand All @@ -514,7 +514,7 @@ private static void TestIPV4(Reader reader, string file)
{"1.1.1.17", "1.1.1.16"},
{"1.1.1.31", "1.1.1.16"}
},
new[] { "1.1.1.33", "255.254.253.123" },
["1.1.1.33", "255.254.253.123"],
new Dictionary<string, int>
{
{"1.1.1.3", 31},
Expand Down
21 changes: 4 additions & 17 deletions MaxMind.Db/CachedDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,6 @@ limitations under the License.

namespace MaxMind.Db
{
/// <summary>
/// Delegate that can be used to be notified when an item is removed from a CachedDictionary because the size was too big
/// </summary>
/// <typeparam name="TKey">Type of key</typeparam>
/// <typeparam name="TValue">Type of value</typeparam>
/// <param name="dictionary">Dictionary</param>
/// <param name="key">Key</param>
/// <param name="value">Value</param>
internal delegate void CachedItemRemovedDelegate<TKey, TValue>(CachedDictionary<TKey, TValue> dictionary, TKey key, TValue value);

/// <summary>
/// A dictionary that caches up to N values in memory. Once the dictionary reaches N count, the last item in the internal list is removed.
/// New items are always added to the start of the internal list.
Expand Down Expand Up @@ -95,10 +85,10 @@ protected virtual bool OnGetExternalKeyValue(ref TKey key, out TValue value)
/// Sets a new comparer. Clears the cache.
/// </summary>
/// <param name="comparer">New comparer</param>
protected void SetComparer(IEqualityComparer<TKey> comparer)
private void SetComparer(IEqualityComparer<TKey> comparer)
{
dictionary = new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(comparer);
priorityList = new LinkedList<KeyValuePair<TKey, TValue>>();
priorityList = [];
}

/// <summary>
Expand Down Expand Up @@ -126,10 +116,7 @@ public CachedDictionary(int maxCount, IEqualityComparer<TKey> comparer)
{
throw new ArgumentOutOfRangeException("Maxcount is " + maxCount + ", it must be greater than 0");
}
if (comparer == null)
{
comparer = EqualityComparer<TKey>.Default;
}
comparer ??= EqualityComparer<TKey>.Default;
this.maxCount = maxCount;
SetComparer(comparer);
}
Expand Down Expand Up @@ -210,7 +197,7 @@ public bool TryGetValue(TKey key, out TValue value)
/// <param name="key">Key to find (receives the found key)</param>
/// <param name="value">Found value (default of TValue if not found)</param>
/// <returns>True if found, false if not</returns>
public bool TryGetValueRef(ref TKey key, out TValue value)
private bool TryGetValueRef(ref TKey key, out TValue value)
{
if (dictionary.TryGetValue(key, out var node))
{
Expand Down
2 changes: 1 addition & 1 deletion MaxMind.Db/Decoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ private object DecodeArray(Type expectedType, int size, long offset, out long ou
for (var i = 0; i < size; i++)
{
var r = Decode(argType, offset, out offset, injectables, network);
addMethod.Invoke(array, new[] { r });
addMethod.Invoke(array, [r]);
}

outOffset = offset;
Expand Down
2 changes: 1 addition & 1 deletion MaxMind.Db/DictionaryActivatorCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private static ObjectActivator DictionaryActivator(Type expectedType)
{
var dictType = typeof(Dictionary<,>).MakeGenericType(genericArgs);
ReflectionUtil.CheckType(expectedType, dictType);
constructor = dictType.GetConstructor(new[] { typeof(int) });
constructor = dictType.GetConstructor([typeof(int)]);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion MaxMind.Db/ListActivatorCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private static ObjectActivator ListActivator(Type expectedType)
var listType = typeof(List<>).MakeGenericType(argType);
if (expectedType.IsAssignableFrom(listType))
{
constructor = listType.GetConstructor(new[] { typeof(int) });
constructor = listType.GetConstructor([typeof(int)]);
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions MaxMind.Db/MaxMind.Db.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<Description>.NET reader for the MaxMind DB file format</Description>
<VersionPrefix>4.1.0</VersionPrefix>
<TargetFrameworks>net8.0;net7.0;net6.0;netstandard2.1;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net9.0;net8.0;netstandard2.1;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>MaxMind.Db</AssemblyName>
<AssemblyOriginatorKeyFile>../MaxMind.snk</AssemblyOriginatorKeyFile>
Expand All @@ -26,7 +26,7 @@
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<LangVersion>12.0</LangVersion>
<LangVersion>13.0</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<AnalysisLevel>latest</AnalysisLevel>
Expand Down
34 changes: 29 additions & 5 deletions MaxMind.Db/MemoryMapBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Security.Cryptography;
using System.Text;
using System.Threading;

#endregion

namespace MaxMind.Db
{
internal sealed class MemoryMapBuffer : Buffer
{
private static readonly object FileLocker = new();
private readonly MemoryMappedFile _memoryMappedFile;
private readonly MemoryMappedViewAccessor _view;
private bool _disposed;
Expand All @@ -29,14 +30,30 @@ private MemoryMapBuffer(string file, bool useGlobalNamespace, FileInfo fileInfo)
// easily available from C#.
var objectNamespace = useGlobalNamespace ? "Global" : "Local";

string? mapName = $"{objectNamespace}\\{fileInfo.FullName.Replace("\\", "-")}-{Length}";
lock (FileLocker)
// We create a sha256 here as there are limitations on mutex names.
using var sha256 = SHA256.Create();
var suffixTxt = $"{fileInfo.FullName.Replace("\\", "-")}-{Length}";
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(suffixTxt));
var suffix = BitConverter.ToString(hashBytes).Replace("-", "");

var mapName = $"{objectNamespace}\\{suffix}";
var mutexName = $"{mapName}-Mutex";

using (var mutex = new Mutex(false, mutexName))
{
var hasHandle = false;

try
{
hasHandle = mutex.WaitOne(TimeSpan.FromSeconds(10), false);
if (!hasHandle)
{
throw new TimeoutException("Timeout waiting for mutex.");
}

_memoryMappedFile = MemoryMappedFile.OpenExisting(mapName, MemoryMappedFileRights.Read);
}
catch (Exception ex) when (ex is IOException || ex is NotImplementedException || ex is PlatformNotSupportedException)
catch (Exception ex) when (ex is IOException or NotImplementedException or PlatformNotSupportedException)
{
// In .NET Core, named maps are not supported for Unices yet: https://github.com/dotnet/corefx/issues/1329
// When executed on unsupported platform, we get the PNSE. In which case, we consruct the memory map by
Expand All @@ -47,6 +64,13 @@ private MemoryMapBuffer(string file, bool useGlobalNamespace, FileInfo fileInfo)
_memoryMappedFile = MemoryMappedFile.CreateFromFile(stream, mapName, Length,
MemoryMappedFileAccess.Read, HandleInheritability.None, false);
}
finally
{
if (hasHandle)
{
mutex.ReleaseMutex();
}
}
}

_view = _memoryMappedFile.CreateViewAccessor(0, Length, MemoryMappedFileAccess.Read);
Expand Down Expand Up @@ -77,7 +101,7 @@ public override string ReadString(long offset, int count)
}
unsafe
{
byte* ptr = (byte*)0;
var ptr = (byte*)0;
try
{
_view.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);
Expand Down
12 changes: 5 additions & 7 deletions MaxMind.Db/Reader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,17 @@ private struct NetNode
private readonly long _nodeByteSize;
private readonly long _nodeCount;
private readonly int _recordSize;
private readonly long _searchTreeSize;

// The property getter was a hotspot during profiling.

private readonly byte[] _metadataStartMarker =
{
[
0xAB, 0xCD, 0xEF, 77, 97, 120, 77, 105, 110, 100, 46, 99, 111,
109
};
];

private bool _disposed;
private int _ipV4Start;
private readonly int _ipV4Start;

/// <summary>
/// Initializes a new instance of the <see cref="Reader" /> class.
Expand Down Expand Up @@ -144,10 +143,9 @@ private Reader(Buffer buffer, string? file)
_nodeByteSize = Metadata.NodeByteSize;
_nodeCount = Metadata.NodeCount;
_recordSize = Metadata.RecordSize;
_searchTreeSize = Metadata.SearchTreeSize;
Decoder = new Decoder(_database, Metadata.SearchTreeSize + DataSectionSeparatorSize);

if (_dbIPVersion ==6)
if (_dbIPVersion == 6)
{
var node = 0;
for (var i = 0; i < 96 && node < _nodeCount; i++)
Expand Down Expand Up @@ -379,7 +377,7 @@ private long FindMetadataStart()

for (var i = dbLength - markerLength; i > 0; i--)
{
int j = 0;
var j = 0;
for (; j < markerLength; j++)
{
if (_metadataStartMarker[j] != _database.ReadOne(i + j))
Expand Down
10 changes: 4 additions & 6 deletions MaxMind.Db/TypeAcivatorCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@

namespace MaxMind.Db
{
internal struct TypeActivator
internal readonly struct TypeActivator
{
internal readonly ObjectActivator Activator;
internal readonly List<ParameterInfo> AlwaysCreatedParameters;
internal readonly object?[] _defaultParameters;
private readonly object?[] _defaultParameters;
internal readonly Dictionary<Key, ParameterInfo> DeserializationParameters;
internal readonly Dictionary<string, ParameterInfo> InjectableParameters;
internal readonly List<ParameterInfo> NetworkParameters;
internal readonly Type[] ParameterTypes;

internal TypeActivator(
ObjectActivator activator,
Expand All @@ -35,9 +34,8 @@ List<ParameterInfo> alwaysCreatedParameters
InjectableParameters = injectables;

NetworkParameters = networkParameters;
ParameterTypes =
deserializationParameters.Values.OrderBy(x => x.Position).Select(x => x.ParameterType).ToArray();
_defaultParameters = ParameterTypes.Select(DefaultValue).ToArray();
Type[] parameterTypes = deserializationParameters.Values.OrderBy(x => x.Position).Select(x => x.ParameterType).ToArray();
_defaultParameters = parameterTypes.Select(DefaultValue).ToArray();
}

internal object[] DefaultParameters() => (object[])_defaultParameters.Clone();
Expand Down
11 changes: 11 additions & 0 deletions releasenotes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Release Notes #

## 4.2.0

* .NET 6.0 and .NET 7.0 have been removed as targets as they have both
reach their end of support from Microsoft. If you are using these versions,
the .NET Standard 2.1 target should continue working for you.
* .NET 9.0 has been added as a target.
* We now use a mutex rather than a lock statement when opening the
database. This is done to reduce the likelihood of a race condition
when process are opening a single database when using
`FileAccessMode.MemoryMappedGlobal`.

## 4.1.0 (2023-12-05) ##

* .NET 5.0 has been removed as a target as it has reach its end of life.
Expand Down

0 comments on commit 11744d7

Please sign in to comment.