From e3b034663cae3614c3361efa57e7337f85d9f94e Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Sat, 24 Feb 2024 19:41:31 +0200 Subject: [PATCH] Using the external id generator since SQLite will do an error --- .../Controllers/CrashUploadController.cs | 25 +++++----- .../Services/HexGenerator.cs | 47 +++++++++---------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/BUTR.CrashReportServer/Controllers/CrashUploadController.cs b/src/BUTR.CrashReportServer/Controllers/CrashUploadController.cs index 6b55237..ccbfd1a 100644 --- a/src/BUTR.CrashReportServer/Controllers/CrashUploadController.cs +++ b/src/BUTR.CrashReportServer/Controllers/CrashUploadController.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using System.Diagnostics.Metrics; using System.IO.Pipelines; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; @@ -36,6 +37,7 @@ public sealed record CrashReportUploadBody(CrashReportModel CrashReport, ICollec private readonly JsonSerializerOptions _jsonSerializerOptions; private readonly AppDbContext _dbContext; private readonly GZipCompressor _gZipCompressor; + private readonly HexGenerator _hexGenerator; private readonly Counter _reportVersion; @@ -45,6 +47,7 @@ public CrashUploadController( IOptionsSnapshot jsonSerializerOptions, AppDbContext dbContext, GZipCompressor gZipCompressor, + HexGenerator hexGenerator, IMeterFactory meterFactory) { var meter = meterFactory.Create("BUTR.CrashReportServer.Controllers.CrashUploadController", "1.0.0"); @@ -56,25 +59,23 @@ public CrashUploadController( _options = options.Value ?? throw new ArgumentNullException(nameof(options)); _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); _gZipCompressor = gZipCompressor ?? throw new ArgumentNullException(nameof(gZipCompressor)); + _hexGenerator = hexGenerator ?? throw new ArgumentNullException(nameof(hexGenerator)); } - /* - private async Task GenerateFileId(CancellationToken ct) + private string GenerateFileId(CancellationToken ct) { - const int count = 100; + const int count = 300; var fileId = string.Empty; while (!ct.IsCancellationRequested) { - var fileIds = Enumerable.Range(0, count).Select(_ => _hexGenerator.GetHex()).ToHashSet(); - var existing = await _dbContext.Set().Select(x => x.FileId).Where(x => fileIds.Contains(x)).ToArrayAsync(ct); - if (existing.Length == count) continue; - fileIds.ExceptWith(existing); - fileId = fileIds.First(); + var fileIds = _hexGenerator.GetHex(count, 3); + var existing = _dbContext.Set().Select(x => x.FileId).Where(x => fileIds.Contains(x)).ToHashSet(); + if (existing.Count == count) continue; + fileId = existing.First(x => !fileIds.Contains(x)); break; } return fileId; } - */ private async Task UploadHtmlAsync(CancellationToken ct) { @@ -93,13 +94,13 @@ private async Task UploadHtmlAsync(CancellationToken ct) Converters = { new JsonStringEnumConverter() } }), ct); - idEntity = new IdEntity { FileId = default!, CrashReportId = id, Version = version, Created = DateTime.UtcNow, }; + idEntity = new IdEntity { FileId = GenerateFileId(ct), CrashReportId = id, Version = version, Created = DateTime.UtcNow, }; await _dbContext.Set().AddAsync(idEntity, ct); await _dbContext.Set().AddAsync(new FileEntity { Id = idEntity, DataCompressed = compressedHtmlStream.ToArray(), }, ct); if (version >= 13) await _dbContext.Set().AddAsync(new JsonEntity { Id = idEntity, CrashReportCompressed = compressedJsonStream.ToArray(), }, ct); await _dbContext.SaveChangesAsync(ct); - _reportVersion.Add(1, new[] {new KeyValuePair("Version", version)}); + _reportVersion.Add(1, new[] { new KeyValuePair("Version", version) }); return Ok($"{_options.BaseUri}/{idEntity.FileId}"); } @@ -121,7 +122,7 @@ private async Task UploadJsonAsync(CancellationToken ct) await using var compressedHtmlStream = await _gZipCompressor.CompressAsync(html.AsStream(), ct); await using var compressedJsonStream = await _gZipCompressor.CompressAsync(json.AsStream(), ct); - idEntity = new IdEntity { FileId = default!, CrashReportId = crashReport.Id, Version = crashReport.Version, Created = DateTime.UtcNow, }; + idEntity = new IdEntity { FileId = GenerateFileId(ct), CrashReportId = crashReport.Id, Version = crashReport.Version, Created = DateTime.UtcNow, }; await _dbContext.Set().AddAsync(idEntity, ct); await _dbContext.Set().AddAsync(new JsonEntity { Id = idEntity, CrashReportCompressed = compressedJsonStream.ToArray(), }, ct); await _dbContext.Set().AddAsync(new FileEntity { Id = idEntity, DataCompressed = compressedHtmlStream.ToArray(), }, ct); diff --git a/src/BUTR.CrashReportServer/Services/HexGenerator.cs b/src/BUTR.CrashReportServer/Services/HexGenerator.cs index 9826728..7d15706 100644 --- a/src/BUTR.CrashReportServer/Services/HexGenerator.cs +++ b/src/BUTR.CrashReportServer/Services/HexGenerator.cs @@ -1,46 +1,43 @@ -using Microsoft.Extensions.Logging; - -using System; +using System; +using System.Collections.Generic; using System.Security.Cryptography; namespace BUTR.CrashReportServer.Services; public sealed class HexGenerator { - private readonly ILogger _logger; private readonly RandomNumberGenerator _random; - public HexGenerator(ILogger logger, RandomNumberGenerator random) + public HexGenerator(RandomNumberGenerator random) { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _random = random ?? throw new ArgumentNullException(nameof(random)); } - private static int GetHexChars(in ReadOnlySpan source, Span buffer) + private static int GenerateHexChars(in ReadOnlySpan source, Span destination) { - var idx1 = 0; - var idx2 = 0; - while (idx2 < source.Length) + for (var i = 0; i < source.Length; i++) { - var num1 = (byte) ((uint) source[idx2] >> 4); - buffer[idx1] = num1 > (byte) 9 ? (char) ((int) num1 + 55 + 32) : (char) ((int) num1 + 48); - var num2 = (byte) ((uint) source[idx2] & 15U); - int num3; - buffer[num3 = idx1 + 1] = num2 > (byte) 9 ? (char) ((int) num2 + 55 + 32) : (char) ((int) num2 + 48); - ++idx2; - idx1 = num3 + 1; + var char1 = source[i] >> 4; + destination[i * 2] = char.ToUpperInvariant(char1 > 9 ? (char) (char1 + 55 + 32) : (char) (char1 + 48)); + var char2 = source[i] & 15; + destination[i * 2 + 1] = char.ToUpperInvariant(char2 > 9 ? (char) (char2 + 55 + 32) : (char) (char2 + 48)); } - return idx1; + return source.Length * 2; } - public string GetHex() + public HashSet GetHex(int maxCount, int length) { - Span input = stackalloc byte[3]; - Span output = stackalloc char[6]; + var charLength = length * 2; + var byteLength = length; + + Span output = stackalloc char[maxCount * charLength]; + Span input = stackalloc byte[maxCount * byteLength]; _random.GetBytes(input); - GetHexChars(input, output); - for (var i = 0; i < output.Length; i++) - output[i] = char.ToUpper(output[i]); - return output.ToString(); + + var unique = new HashSet(maxCount); + GenerateHexChars(input, output); + for (var i = 0; i < output.Length; i += charLength) + unique.Add(output.Slice(i, charLength).ToString()); + return unique; } } \ No newline at end of file