From c8fd2335704460cd67767fa198025924f49b44b1 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 08:11:10 -0800 Subject: [PATCH 01/14] Update build targets --- .github/workflows/codeql-analysis.yml | 3 +-- .github/workflows/test.yml | 3 +-- MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj | 4 ++-- MaxMind.Db.Test/MaxMind.Db.Test.csproj | 4 ++-- MaxMind.Db/MaxMind.Db.csproj | 2 +- releasenotes.md | 7 +++++++ 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 65cf445..6544c31 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -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 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a66141a..cba0324 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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: | diff --git a/MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj b/MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj index f66845b..afe3567 100644 --- a/MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj +++ b/MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj @@ -3,8 +3,8 @@ Benchmark project to validate .NET reader for the MaxMind DB file format 4.0.0 - net8.0;net7.0;net6.0;net472 - net8.0;net7.0;net6.0 + net9.0;net8.0;net481 + net9.0;net8.0 MaxMind.Db.Benchmark Exe MaxMind.Db.Benchmark diff --git a/MaxMind.Db.Test/MaxMind.Db.Test.csproj b/MaxMind.Db.Test/MaxMind.Db.Test.csproj index 26b5905..05cd532 100644 --- a/MaxMind.Db.Test/MaxMind.Db.Test.csproj +++ b/MaxMind.Db.Test/MaxMind.Db.Test.csproj @@ -3,8 +3,8 @@ Test project to validate .NET reader for the MaxMind DB file format 4.0.0 - net8.0;net7.0;net6.0;net472 - net8.0;net7.0;net6.0 + net9.0;net8.0;net481 + net9.0;net8.0 MaxMind.Db.Test ../MaxMind.snk true diff --git a/MaxMind.Db/MaxMind.Db.csproj b/MaxMind.Db/MaxMind.Db.csproj index 1209827..0389032 100644 --- a/MaxMind.Db/MaxMind.Db.csproj +++ b/MaxMind.Db/MaxMind.Db.csproj @@ -3,7 +3,7 @@ .NET reader for the MaxMind DB file format 4.1.0 - net8.0;net7.0;net6.0;netstandard2.1;netstandard2.0 + net9.0;net8.0;netstandard2.1;netstandard2.0 true MaxMind.Db ../MaxMind.snk diff --git a/releasenotes.md b/releasenotes.md index 1423663..62f1120 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,5 +1,12 @@ # 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. + ## 4.1.0 (2023-12-05) ## * .NET 5.0 has been removed as a target as it has reach its end of life. From 593e367d45195b7d1f6e799e9acc8930814f0ef0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 06:46:18 +0000 Subject: [PATCH 02/14] Bump Microsoft.NET.Test.Sdk from 17.11.1 to 17.12.0 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.11.1 to 17.12.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md) - [Commits](https://github.com/microsoft/vstest/compare/v17.11.1...v17.12.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- MaxMind.Db.Test/MaxMind.Db.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MaxMind.Db.Test/MaxMind.Db.Test.csproj b/MaxMind.Db.Test/MaxMind.Db.Test.csproj index 05cd532..2613fd5 100644 --- a/MaxMind.Db.Test/MaxMind.Db.Test.csproj +++ b/MaxMind.Db.Test/MaxMind.Db.Test.csproj @@ -34,7 +34,7 @@ - + From 4325d10c8af204598923c5be4d98d093f487143e Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 10:35:38 -0800 Subject: [PATCH 03/14] Use a mutex rather than a lock --- MaxMind.Db/MemoryMapBuffer.cs | 30 +++++++++++++++++++++++++++--- releasenotes.md | 4 ++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/MaxMind.Db/MemoryMapBuffer.cs b/MaxMind.Db/MemoryMapBuffer.cs index c4479f8..18274d0 100644 --- a/MaxMind.Db/MemoryMapBuffer.cs +++ b/MaxMind.Db/MemoryMapBuffer.cs @@ -3,7 +3,9 @@ using System; using System.IO; using System.IO.MemoryMappedFiles; +using System.Security.Cryptography; using System.Text; +using System.Threading; #endregion @@ -11,7 +13,6 @@ 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; @@ -29,11 +30,27 @@ 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) @@ -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); diff --git a/releasenotes.md b/releasenotes.md index 62f1120..9bcb570 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -6,6 +6,10 @@ 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) ## From 041c21d34df4b5adb53a6163519779d578029236 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 11:20:36 -0800 Subject: [PATCH 04/14] Use C# 13 --- MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj | 2 +- MaxMind.Db.Test/MaxMind.Db.Test.csproj | 2 +- MaxMind.Db/MaxMind.Db.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj b/MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj index afe3567..2eefe1e 100644 --- a/MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj +++ b/MaxMind.Db.Benchmark/MaxMind.Db.Benchmark.csproj @@ -18,7 +18,7 @@ false false false - 12.0 + 13.0 enable latest true diff --git a/MaxMind.Db.Test/MaxMind.Db.Test.csproj b/MaxMind.Db.Test/MaxMind.Db.Test.csproj index 2613fd5..36dbef7 100644 --- a/MaxMind.Db.Test/MaxMind.Db.Test.csproj +++ b/MaxMind.Db.Test/MaxMind.Db.Test.csproj @@ -21,7 +21,7 @@ false false false - 12.0 + 13.0 enable latest true diff --git a/MaxMind.Db/MaxMind.Db.csproj b/MaxMind.Db/MaxMind.Db.csproj index 0389032..f26ff89 100644 --- a/MaxMind.Db/MaxMind.Db.csproj +++ b/MaxMind.Db/MaxMind.Db.csproj @@ -26,7 +26,7 @@ false false false - 12.0 + 13.0 true enable latest From f85c9fcf1f1e90eb6c96dcbf23db4812f99f7e7f Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 14:39:35 -0800 Subject: [PATCH 05/14] Add missing space --- MaxMind.Db/Reader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MaxMind.Db/Reader.cs b/MaxMind.Db/Reader.cs index b01ff09..458c20e 100644 --- a/MaxMind.Db/Reader.cs +++ b/MaxMind.Db/Reader.cs @@ -147,7 +147,7 @@ private Reader(Buffer buffer, string? file) _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++) From 7d146b4ad9ffd045b6f902709f3293cecdca2f99 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 15:26:54 -0800 Subject: [PATCH 06/14] Clean up catch slightly --- MaxMind.Db/MemoryMapBuffer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MaxMind.Db/MemoryMapBuffer.cs b/MaxMind.Db/MemoryMapBuffer.cs index 18274d0..1bc3cf2 100644 --- a/MaxMind.Db/MemoryMapBuffer.cs +++ b/MaxMind.Db/MemoryMapBuffer.cs @@ -53,7 +53,7 @@ private MemoryMapBuffer(string file, bool useGlobalNamespace, FileInfo fileInfo) _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 From 33dcdc9d2d28f093dab83facdf630831a58afabf Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 15:56:11 -0800 Subject: [PATCH 07/14] Make a few things readonly and private that can be --- MaxMind.Db/CachedDictionary.cs | 4 ++-- MaxMind.Db/Reader.cs | 2 +- MaxMind.Db/TypeAcivatorCreator.cs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MaxMind.Db/CachedDictionary.cs b/MaxMind.Db/CachedDictionary.cs index 945a700..869709a 100644 --- a/MaxMind.Db/CachedDictionary.cs +++ b/MaxMind.Db/CachedDictionary.cs @@ -95,7 +95,7 @@ protected virtual bool OnGetExternalKeyValue(ref TKey key, out TValue value) /// Sets a new comparer. Clears the cache. /// /// New comparer - protected void SetComparer(IEqualityComparer comparer) + private void SetComparer(IEqualityComparer comparer) { dictionary = new Dictionary>>(comparer); priorityList = new LinkedList>(); @@ -210,7 +210,7 @@ public bool TryGetValue(TKey key, out TValue value) /// Key to find (receives the found key) /// Found value (default of TValue if not found) /// True if found, false if not - 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)) { diff --git a/MaxMind.Db/Reader.cs b/MaxMind.Db/Reader.cs index 458c20e..56b422e 100644 --- a/MaxMind.Db/Reader.cs +++ b/MaxMind.Db/Reader.cs @@ -100,7 +100,7 @@ private struct NetNode }; private bool _disposed; - private int _ipV4Start; + private readonly int _ipV4Start; /// /// Initializes a new instance of the class. diff --git a/MaxMind.Db/TypeAcivatorCreator.cs b/MaxMind.Db/TypeAcivatorCreator.cs index f4c6c72..59670b8 100644 --- a/MaxMind.Db/TypeAcivatorCreator.cs +++ b/MaxMind.Db/TypeAcivatorCreator.cs @@ -11,15 +11,15 @@ namespace MaxMind.Db { - internal struct TypeActivator + internal readonly struct TypeActivator { internal readonly ObjectActivator Activator; internal readonly List AlwaysCreatedParameters; - internal readonly object?[] _defaultParameters; + private readonly object?[] _defaultParameters; internal readonly Dictionary DeserializationParameters; internal readonly Dictionary InjectableParameters; internal readonly List NetworkParameters; - internal readonly Type[] ParameterTypes; + private readonly Type[] ParameterTypes; internal TypeActivator( ObjectActivator activator, From e9b0489ecffd4957a3ed33d35b0bb7daa1be80d9 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 16:04:40 -0800 Subject: [PATCH 08/14] Use collection expressions --- MaxMind.Db.Test/DecoderTest.cs | 190 +++++++++++------------ MaxMind.Db.Test/ReaderTest.cs | 6 +- MaxMind.Db/CachedDictionary.cs | 2 +- MaxMind.Db/Decoder.cs | 2 +- MaxMind.Db/DictionaryActivatorCreator.cs | 2 +- MaxMind.Db/ListActivatorCreator.cs | 2 +- MaxMind.Db/Reader.cs | 4 +- 7 files changed, 101 insertions(+), 107 deletions(-) diff --git a/MaxMind.Db.Test/DecoderTest.cs b/MaxMind.Db.Test/DecoderTest.cs index eb81b25..0581a4b 100644 --- a/MaxMind.Db.Test/DecoderTest.cs +++ b/MaxMind.Db.Test/DecoderTest.cs @@ -52,60 +52,60 @@ public static IEnumerable TestUInt16() { var uint16s = new Dictionary { - {0, new byte[] {0xa0}}, - {(1 << 8) - 1, new[] {(byte) 0xa1, (byte) 0xff}}, - {500, new byte[] {0xa2, 0x1, 0xf4}}, - {10872, new byte[] {0xa2, 0x2a, 0x78}}, - {ushort.MaxValue, new[] {(byte) 0xa2, (byte) 0xff, (byte) 0xff}} + {0, [0xa0] }, + {(1 << 8) - 1, [(byte) 0xa1, (byte) 0xff] }, + {500, [0xa2, 0x1, 0xf4] }, + {10872, [0xa2, 0x2a, 0x78] }, + {ushort.MaxValue, [(byte) 0xa2, (byte) 0xff, (byte) 0xff] } }; - yield return new object[] { uint16s }; + yield return [uint16s]; } public static IEnumerable TestUInt32() { var uint32s = new Dictionary { - {0, new[] {(byte) 0xc0}}, - {(1 << 8) - 1, new[] {(byte) 0xc1, (byte) 0xff}}, - {500, new byte[] {0xc2, 0x1, 0xf4}}, - {10872, new byte[] {0xc2, 0x2a, 0x78}}, - {(1 << 16) - 1, new[] {(byte) 0xc2, (byte) 0xff, (byte) 0xff}}, - {(1 << 24) - 1, new[] {(byte) 0xc3, (byte) 0xff, (byte) 0xff, (byte) 0xff}}, - {uint.MaxValue, new[] {(byte) 0xc4, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}} + {0, [(byte) 0xc0] }, + {(1 << 8) - 1, [(byte) 0xc1, (byte) 0xff] }, + {500, [0xc2, 0x1, 0xf4] }, + {10872, [0xc2, 0x2a, 0x78] }, + {(1 << 16) - 1, [(byte) 0xc2, (byte) 0xff, (byte) 0xff] }, + {(1 << 24) - 1, [(byte) 0xc3, (byte) 0xff, (byte) 0xff, (byte) 0xff] }, + {uint.MaxValue, [(byte) 0xc4, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff] } }; - yield return new object[] { uint32s }; + yield return [uint32s]; } public static IEnumerable TestInt32s() { var int32s = new Dictionary { - {0, new byte[] {0x0, 0x1}}, - {-1, new byte[] {0x4, 0x1, 0xff, 0xff, 0xff, 0xff}}, - {(2 << 7) - 1, new byte[] {0x1, 0x1, 0xff}}, - {1 - (2 << 7), new byte[] {0x4, 0x1, 0xff, 0xff, 0xff, 0x1}}, - {500, new byte[] {0x2, 0x1, 0x1, 0xf4}}, - {-500, new byte[] {0x4, 0x1, 0xff, 0xff, 0xfe, 0xc}}, - {(2 << 15) - 1, new byte[] {0x2, 0x1, 0xff, 0xff}}, - {1 - (2 << 15), new byte[] {0x4, 0x1, 0xff, 0xff, 0x0, 0x1}}, - {(2 << 23) - 1, new byte[] {0x3, 0x1, 0xff, 0xff, 0xff}}, - {1 - (2 << 23), new byte[] {0x4, 0x1, 0xff, 0x0, 0x0, 0x1}}, - {int.MaxValue, new byte[] {0x4, 0x1, 0x7f, 0xff, 0xff, 0xff}}, - {-int.MaxValue, new byte[] {0x4, 0x1, 0x80, 0x0, 0x0, 0x1}} + {0, [0x0, 0x1] }, + {-1, [0x4, 0x1, 0xff, 0xff, 0xff, 0xff] }, + {(2 << 7) - 1, [0x1, 0x1, 0xff] }, + {1 - (2 << 7), [0x4, 0x1, 0xff, 0xff, 0xff, 0x1] }, + {500, [0x2, 0x1, 0x1, 0xf4] }, + {-500, [0x4, 0x1, 0xff, 0xff, 0xfe, 0xc] }, + {(2 << 15) - 1, [0x2, 0x1, 0xff, 0xff] }, + {1 - (2 << 15), [0x4, 0x1, 0xff, 0xff, 0x0, 0x1] }, + {(2 << 23) - 1, [0x3, 0x1, 0xff, 0xff, 0xff] }, + {1 - (2 << 23), [0x4, 0x1, 0xff, 0x0, 0x0, 0x1] }, + {int.MaxValue, [0x4, 0x1, 0x7f, 0xff, 0xff, 0xff] }, + {-int.MaxValue, [0x4, 0x1, 0x80, 0x0, 0x0, 0x1] } }; - yield return new object[] { int32s }; + yield return [int32s]; } public static IEnumerable TestInt64s() { var int64s = new Dictionary { - {0L, new byte[] {0x0, 0x2}}, - {500L, new byte[] {0x2, 0x2, 0x1, 0xf4}}, - {10872, new byte[] {0x2, 0x2, 0x2a, 0x78}} + {0L, [0x0, 0x2] }, + {500L, [0x2, 0x2, 0x1, 0xf4] }, + {10872, [0x2, 0x2, 0x2a, 0x78] } }; for (var power = 1; power < 8; power++) @@ -123,7 +123,7 @@ public static IEnumerable TestInt64s() int64s.Add(key, value); } - yield return new object[] { int64s }; + yield return [int64s]; } public static long Int64Pow(long x, int pow) @@ -143,9 +143,9 @@ public static IEnumerable TestBigIntegers() { var bigInts = new Dictionary { - {new BigInteger(0), new byte[] {0x0, 0x3}}, - {new BigInteger(500), new byte[] {0x2, 0x3, 0x1, 0xf4}}, - {new BigInteger(10872), new byte[] {0x2, 0x3, 0x2a, 0x78}} + {new BigInteger(0), [0x0, 0x3] }, + {new BigInteger(500), [0x2, 0x3, 0x1, 0xf4] }, + {new BigInteger(10872), [0x2, 0x3, 0x2a, 0x78] } }; for (var power = 1; power <= 16; power++) @@ -163,66 +163,66 @@ public static IEnumerable TestBigIntegers() bigInts.Add(key, value); } - yield return new object[] { bigInts, /*useShouldBe*/ true }; + yield return [bigInts, /*useShouldBe*/ true]; } public static IEnumerable TestDoubles() { var doubles = new Dictionary { - {0.0, new byte[] {0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, - {0.5, new byte[] {0x68, 0x3F, 0xE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, - {3.14159265359, new byte[] {0x68, 0x40, 0x9, 0x21, 0xFB, 0x54, 0x44, 0x2E, 0xEA}}, - {123.0, new byte[] {0x68, 0x40, 0x5E, 0xC0, 0x0, 0x0, 0x0, 0x0, 0x0}}, - {1073741824.12457, new byte[] {0x68, 0x41, 0xD0, 0x0, 0x0, 0x0, 0x7, 0xF8, 0xF4}}, - {-0.5, new byte[] {0x68, 0xBF, 0xE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, - {-3.14159265359, new byte[] {0x68, 0xC0, 0x9, 0x21, 0xFB, 0x54, 0x44, 0x2E, 0xEA}}, - {-1073741824.12457, new byte[] {0x68, 0xC1, 0xD0, 0x0, 0x0, 0x0, 0x7, 0xF8, 0xF4}} + {0.0, [0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] }, + {0.5, [0x68, 0x3F, 0xE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] }, + {3.14159265359, [0x68, 0x40, 0x9, 0x21, 0xFB, 0x54, 0x44, 0x2E, 0xEA] }, + {123.0, [0x68, 0x40, 0x5E, 0xC0, 0x0, 0x0, 0x0, 0x0, 0x0] }, + {1073741824.12457, [0x68, 0x41, 0xD0, 0x0, 0x0, 0x0, 0x7, 0xF8, 0xF4] }, + {-0.5, [0x68, 0xBF, 0xE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] }, + {-3.14159265359, [0x68, 0xC0, 0x9, 0x21, 0xFB, 0x54, 0x44, 0x2E, 0xEA] }, + {-1073741824.12457, [0x68, 0xC1, 0xD0, 0x0, 0x0, 0x0, 0x7, 0xF8, 0xF4] } }; - yield return new object[] { doubles }; + yield return [doubles]; } public static IEnumerable TestFloats() { var floats = new Dictionary { - {(float) 0.0, new byte[] {0x4, 0x8, 0x0, 0x0, 0x0, 0x0}}, - {(float) 1.0, new byte[] {0x4, 0x8, 0x3F, 0x80, 0x0, 0x0}}, - {(float) 1.1, new byte[] {0x4, 0x8, 0x3F, 0x8C, 0xCC, 0xCD}}, - {(float) 3.14, new byte[] {0x4, 0x8, 0x40, 0x48, 0xF5, 0xC3}}, - {(float) 9999.99, new byte[] {0x4, 0x8, 0x46, 0x1C, 0x3F, 0xF6}}, - {(float) -1.0, new byte[] {0x4, 0x8, 0xBF, 0x80, 0x0, 0x0}}, - {(float) -1.1, new byte[] {0x4, 0x8, 0xBF, 0x8C, 0xCC, 0xCD}}, - {(float) -3.14, new byte[] {0x4, 0x8, 0xC0, 0x48, 0xF5, 0xC3}}, - {(float) -9999.99, new byte[] {0x4, 0x8, 0xC6, 0x1C, 0x3F, 0xF6}} + {(float) 0.0, [0x4, 0x8, 0x0, 0x0, 0x0, 0x0] }, + {(float) 1.0, [0x4, 0x8, 0x3F, 0x80, 0x0, 0x0] }, + {(float) 1.1, [0x4, 0x8, 0x3F, 0x8C, 0xCC, 0xCD] }, + {(float) 3.14, [0x4, 0x8, 0x40, 0x48, 0xF5, 0xC3] }, + {(float) 9999.99, [0x4, 0x8, 0x46, 0x1C, 0x3F, 0xF6] }, + {(float) -1.0, [0x4, 0x8, 0xBF, 0x80, 0x0, 0x0] }, + {(float) -1.1, [0x4, 0x8, 0xBF, 0x8C, 0xCC, 0xCD] }, + {(float) -3.14, [0x4, 0x8, 0xC0, 0x48, 0xF5, 0xC3] }, + {(float) -9999.99, [0x4, 0x8, 0xC6, 0x1C, 0x3F, 0xF6] } }; - yield return new object[] { floats }; + yield return [floats]; } public static IEnumerable TestPointers() { var pointers = new Dictionary { - {0, new byte[] {0x20, 0x0}}, - {5, new byte[] {0x20, 0x5}}, - {10, new byte[] {0x20, 0xa}}, - {(1 << 10) - 1, new byte[] {0x23, 0xff}}, - {3017, new byte[] {0x28, 0x3, 0xc9}}, - {(1 << 19) - 5, new byte[] {0x2f, 0xf7, 0xfb}}, - {(1 << 19) + (1 << 11) - 1, new byte[] {0x2f, 0xff, 0xff}}, - {(1 << 27) - 2, new byte[] {0x37, 0xf7, 0xf7, 0xfe}}, - {((long) 1 << 27) + (1 << 19) + (1 << 11) - 1, new byte[] {0x37, 0xff, 0xff, 0xff}}, - {((long) 1 << 31) - 1, new byte[] {0x38, 0x7f, 0xff, 0xff, 0xff}} + {0, [0x20, 0x0] }, + {5, [0x20, 0x5] }, + {10, [0x20, 0xa] }, + {(1 << 10) - 1, [0x23, 0xff] }, + {3017, [0x28, 0x3, 0xc9] }, + {(1 << 19) - 5, [0x2f, 0xf7, 0xfb] }, + {(1 << 19) + (1 << 11) - 1, [0x2f, 0xff, 0xff] }, + {(1 << 27) - 2, [0x37, 0xf7, 0xf7, 0xfe] }, + {((long) 1 << 27) + (1 << 19) + (1 << 11) - 1, [0x37, 0xff, 0xff, 0xff] }, + {((long) 1 << 31) - 1, [0x38, 0x7f, 0xff, 0xff, 0xff] } }; - yield return new object[] { pointers }; + yield return [pointers]; } public static IEnumerable TestStrings() { - yield return new object[] { Strings() }; + yield return [Strings()]; } private static Dictionary Strings() @@ -235,18 +235,18 @@ private static Dictionary Strings() AddTestString(strings, 0x43, "123"); AddTestString(strings, 0x5b, "123456789012345678901234567"); AddTestString(strings, 0x5c, "1234567890123456789012345678"); - AddTestString(strings, new byte[] { 0x5d, 0x0 }, "12345678901234567890123456789"); - AddTestString(strings, new byte[] { 0x5d, 0x1 }, "123456789012345678901234567890"); + AddTestString(strings, [0x5d, 0x0], "12345678901234567890123456789"); + AddTestString(strings, [0x5d, 0x1], "123456789012345678901234567890"); - AddTestString(strings, new byte[] { 0x5e, 0x0, 0xd7 }, new string('x', 500)); - AddTestString(strings, new byte[] { 0x5e, 0x6, 0xb3 }, new string('x', 2000)); - AddTestString(strings, new byte[] { 0x5f, 0x0, 0x10, 0x53 }, new string('x', 70000)); + AddTestString(strings, [0x5e, 0x0, 0xd7], new string('x', 500)); + AddTestString(strings, [0x5e, 0x6, 0xb3], new string('x', 2000)); + AddTestString(strings, [0x5f, 0x0, 0x10, 0x53], new string('x', 70000)); return strings; } private static void AddTestString(Dictionary tests, byte ctrl, string str) { - AddTestString(tests, new[] { ctrl }, str); + AddTestString(tests, [ctrl], str); } private static void AddTestString(Dictionary tests, byte[] ctrl, string str) @@ -263,11 +263,11 @@ public static IEnumerable TestBooleans() { var booleans = new Dictionary { - {false, new byte[] {0x0, 0x7}}, - {true, new byte[] {0x1, 0x7}} + {false, [0x0, 0x7] }, + {true, [0x1, 0x7] } }; - yield return new object[] { booleans }; + yield return [booleans]; } public static IEnumerable TestBytes() @@ -284,7 +284,7 @@ public static IEnumerable TestBytes() bytes.Add(Encoding.UTF8.GetBytes(s), ba); } - yield return new object[] { bytes }; + yield return [bytes]; } public static IEnumerable TestMaps() @@ -292,18 +292,16 @@ public static IEnumerable TestMaps() var maps = new Dictionary, byte[]>(); var empty = new Dictionary(); - maps.Add(new Dictionary(empty), new[] { (byte)0xe0 }); + maps.Add(new Dictionary(empty), [(byte)0xe0]); var one = new Dictionary { { "en", "Foo" } }; - maps.Add(new Dictionary(one), new byte[] - { + maps.Add(new Dictionary(one), [ 0xe1, /* en */0x42, 0x65, 0x6e, /* Foo */0x43, 0x46, 0x6f, 0x6f - }); + ]); var two = new Dictionary { { "en", "Foo" }, { "zh", "人" } }; - maps.Add(new Dictionary(two), new byte[] - { + maps.Add(new Dictionary(two), [ 0xe2, /* en */ 0x42, 0x65, 0x6e, @@ -313,12 +311,11 @@ public static IEnumerable TestMaps() 0x42, 0x7a, 0x68, /* 人 */ 0x43, 0xe4, 0xba, 0xba - }); + ]); var nested = new Dictionary { { "name", two } }; - maps.Add(new Dictionary(nested), new byte[] - { + maps.Add(new Dictionary(nested), [ 0xe1, /* name */ 0x44, 0x6e, 0x61, 0x6d, 0x65, 0xe2, /* en */ 0x42, 0x65, 0x6e, @@ -328,13 +325,12 @@ public static IEnumerable TestMaps() 0x42, 0x7a, 0x68, /* 人 */ 0x43, 0xe4, 0xba, 0xba - }); + ]); var guess = new Dictionary(); var languages = new List { "en", "zh" }; guess.Add("languages", languages.AsReadOnly()); - maps.Add(new Dictionary(guess), new byte[] - { + maps.Add(new Dictionary(guess), [ 0xe1, /* languages */ 0x49, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x73, /* array */ @@ -343,9 +339,9 @@ public static IEnumerable TestMaps() 0x42, 0x65, 0x6e, /* zh */ 0x42, 0x7a, 0x68 - }); + ]); - yield return new object[] { maps }; + yield return [maps]; } public static IEnumerable TestArrays() @@ -353,27 +349,25 @@ public static IEnumerable TestArrays() var arrays = new Dictionary, byte[]>(); var f1 = new List { "Foo" }; - arrays.Add(f1, new byte[] - { + arrays.Add(f1, [ 0x1, 0x4, /* Foo */ 0x43, 0x46, 0x6f, 0x6f - }); + ]); var f2 = new List { "Foo", "人" }; - arrays.Add(f2, new byte[] - { + arrays.Add(f2, [ 0x2, 0x4, /* Foo */ 0x43, 0x46, 0x6f, 0x6f, /* 人 */ 0x43, 0xe4, 0xba, 0xba - }); + ]); var empty = new List(); - arrays.Add(empty, new byte[] { 0x0, 0x4 }); + arrays.Add(empty, [0x0, 0x4]); - yield return new object[] { arrays }; + yield return [arrays]; } } } diff --git a/MaxMind.Db.Test/ReaderTest.cs b/MaxMind.Db.Test/ReaderTest.cs index 7168e2a..9ed087a 100644 --- a/MaxMind.Db.Test/ReaderTest.cs +++ b/MaxMind.Db.Test/ReaderTest.cs @@ -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 { {"::2:0:1", "::2:0:0"}, @@ -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 { {"::2:0:1", 122} @@ -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 { {"1.1.1.3", 31}, diff --git a/MaxMind.Db/CachedDictionary.cs b/MaxMind.Db/CachedDictionary.cs index 869709a..8bb33fa 100644 --- a/MaxMind.Db/CachedDictionary.cs +++ b/MaxMind.Db/CachedDictionary.cs @@ -98,7 +98,7 @@ protected virtual bool OnGetExternalKeyValue(ref TKey key, out TValue value) private void SetComparer(IEqualityComparer comparer) { dictionary = new Dictionary>>(comparer); - priorityList = new LinkedList>(); + priorityList = []; } /// diff --git a/MaxMind.Db/Decoder.cs b/MaxMind.Db/Decoder.cs index e17c45e..87d520e 100644 --- a/MaxMind.Db/Decoder.cs +++ b/MaxMind.Db/Decoder.cs @@ -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; diff --git a/MaxMind.Db/DictionaryActivatorCreator.cs b/MaxMind.Db/DictionaryActivatorCreator.cs index 91b1dd6..d2becfd 100644 --- a/MaxMind.Db/DictionaryActivatorCreator.cs +++ b/MaxMind.Db/DictionaryActivatorCreator.cs @@ -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 { diff --git a/MaxMind.Db/ListActivatorCreator.cs b/MaxMind.Db/ListActivatorCreator.cs index 685a075..578cdc1 100644 --- a/MaxMind.Db/ListActivatorCreator.cs +++ b/MaxMind.Db/ListActivatorCreator.cs @@ -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 { diff --git a/MaxMind.Db/Reader.cs b/MaxMind.Db/Reader.cs index 56b422e..b8d172f 100644 --- a/MaxMind.Db/Reader.cs +++ b/MaxMind.Db/Reader.cs @@ -94,10 +94,10 @@ private struct NetNode // 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 readonly int _ipV4Start; From 81d155f74b1f7b22017dfc64df9b850143aeaff6 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 16:05:25 -0800 Subject: [PATCH 09/14] Remove unused member --- MaxMind.Db/Reader.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/MaxMind.Db/Reader.cs b/MaxMind.Db/Reader.cs index b8d172f..c47935d 100644 --- a/MaxMind.Db/Reader.cs +++ b/MaxMind.Db/Reader.cs @@ -89,7 +89,6 @@ 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. @@ -144,7 +143,6 @@ 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) From 7240b16bb8a002808b848432cea3d90d1b0b2797 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 16:16:55 -0800 Subject: [PATCH 10/14] Remove unnecesary casts --- MaxMind.Db.Test/DecoderTest.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/MaxMind.Db.Test/DecoderTest.cs b/MaxMind.Db.Test/DecoderTest.cs index 0581a4b..83d2509 100644 --- a/MaxMind.Db.Test/DecoderTest.cs +++ b/MaxMind.Db.Test/DecoderTest.cs @@ -53,10 +53,10 @@ public static IEnumerable TestUInt16() var uint16s = new Dictionary { {0, [0xa0] }, - {(1 << 8) - 1, [(byte) 0xa1, (byte) 0xff] }, + {(1 << 8) - 1, [0xa1, 0xff] }, {500, [0xa2, 0x1, 0xf4] }, {10872, [0xa2, 0x2a, 0x78] }, - {ushort.MaxValue, [(byte) 0xa2, (byte) 0xff, (byte) 0xff] } + {ushort.MaxValue, [0xa2, 0xff, 0xff] } }; yield return [uint16s]; @@ -66,13 +66,13 @@ public static IEnumerable TestUInt32() { var uint32s = new Dictionary { - {0, [(byte) 0xc0] }, - {(1 << 8) - 1, [(byte) 0xc1, (byte) 0xff] }, + {0, [0xc0] }, + {(1 << 8) - 1, [0xc1, 0xff] }, {500, [0xc2, 0x1, 0xf4] }, {10872, [0xc2, 0x2a, 0x78] }, - {(1 << 16) - 1, [(byte) 0xc2, (byte) 0xff, (byte) 0xff] }, - {(1 << 24) - 1, [(byte) 0xc3, (byte) 0xff, (byte) 0xff, (byte) 0xff] }, - {uint.MaxValue, [(byte) 0xc4, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff] } + {(1 << 16) - 1, [0xc2, 0xff, 0xff] }, + {(1 << 24) - 1, [0xc3, 0xff, 0xff, 0xff] }, + {uint.MaxValue, [0xc4, 0xff, 0xff, 0xff, 0xff] } }; yield return [uint32s]; @@ -292,7 +292,7 @@ public static IEnumerable TestMaps() var maps = new Dictionary, byte[]>(); var empty = new Dictionary(); - maps.Add(new Dictionary(empty), [(byte)0xe0]); + maps.Add(new Dictionary(empty), [0xe0]); var one = new Dictionary { { "en", "Foo" } }; maps.Add(new Dictionary(one), [ From 9010125b4e605a1b82f4fc2aec1843cfb58f03b4 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 16:17:38 -0800 Subject: [PATCH 11/14] Use var --- MaxMind.Db/MemoryMapBuffer.cs | 2 +- MaxMind.Db/Reader.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MaxMind.Db/MemoryMapBuffer.cs b/MaxMind.Db/MemoryMapBuffer.cs index 1bc3cf2..0132a60 100644 --- a/MaxMind.Db/MemoryMapBuffer.cs +++ b/MaxMind.Db/MemoryMapBuffer.cs @@ -101,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); diff --git a/MaxMind.Db/Reader.cs b/MaxMind.Db/Reader.cs index c47935d..9010a0f 100644 --- a/MaxMind.Db/Reader.cs +++ b/MaxMind.Db/Reader.cs @@ -377,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)) From 63f65077d01c070f730a171afc0134aab3a1e3fe Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 16:18:18 -0800 Subject: [PATCH 12/14] Use coalescing assignment --- MaxMind.Db/CachedDictionary.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MaxMind.Db/CachedDictionary.cs b/MaxMind.Db/CachedDictionary.cs index 8bb33fa..c63b934 100644 --- a/MaxMind.Db/CachedDictionary.cs +++ b/MaxMind.Db/CachedDictionary.cs @@ -126,10 +126,7 @@ public CachedDictionary(int maxCount, IEqualityComparer comparer) { throw new ArgumentOutOfRangeException("Maxcount is " + maxCount + ", it must be greater than 0"); } - if (comparer == null) - { - comparer = EqualityComparer.Default; - } + comparer ??= EqualityComparer.Default; this.maxCount = maxCount; SetComparer(comparer); } From 7f77697b249e98cf917faee27c7e203dbeb7f021 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 16:33:14 -0800 Subject: [PATCH 13/14] Remove unused delegate --- MaxMind.Db/CachedDictionary.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/MaxMind.Db/CachedDictionary.cs b/MaxMind.Db/CachedDictionary.cs index c63b934..a9b15fa 100644 --- a/MaxMind.Db/CachedDictionary.cs +++ b/MaxMind.Db/CachedDictionary.cs @@ -21,16 +21,6 @@ limitations under the License. namespace MaxMind.Db { - /// - /// Delegate that can be used to be notified when an item is removed from a CachedDictionary because the size was too big - /// - /// Type of key - /// Type of value - /// Dictionary - /// Key - /// Value - internal delegate void CachedItemRemovedDelegate(CachedDictionary dictionary, TKey key, TValue value); - /// /// 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. From 5c87de8bead603ad2f5bfef73a5a88af4f484679 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 20 Nov 2024 16:33:43 -0800 Subject: [PATCH 14/14] Maybe ParameterTypes a local variable --- MaxMind.Db/TypeAcivatorCreator.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/MaxMind.Db/TypeAcivatorCreator.cs b/MaxMind.Db/TypeAcivatorCreator.cs index 59670b8..333daee 100644 --- a/MaxMind.Db/TypeAcivatorCreator.cs +++ b/MaxMind.Db/TypeAcivatorCreator.cs @@ -19,7 +19,6 @@ internal readonly struct TypeActivator internal readonly Dictionary DeserializationParameters; internal readonly Dictionary InjectableParameters; internal readonly List NetworkParameters; - private readonly Type[] ParameterTypes; internal TypeActivator( ObjectActivator activator, @@ -35,9 +34,8 @@ List 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();