Skip to content

Commit 9b3bd8e

Browse files
committed
Repair retired ZoneTree handles and checkpoint all current work
1 parent 40f87fc commit 9b3bd8e

28 files changed

Lines changed: 2618 additions & 44 deletions

‎.github/workflows/ci.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ jobs:
211211
run: |
212212
dotnet test --project tests/KeyLoad.ComparisonTests --no-build --no-restore --configuration Release --treenode-filter '/*/*/TimeSeriesWorkloadTests/*' --results-directory TestResults/comparison-images/timeseries-workload
213213
dotnet test --project tests/KeyLoad.ComparisonTests --no-build --no-restore --configuration Release --treenode-filter '/*/*/TimeSeriesPackageVersionTests/*' --results-directory TestResults/comparison-images/timeseries-package
214+
- name: Qualify isolated TimeSeries resource models
215+
run: |
216+
dotnet test --project tests/KeyLoad.ComparisonTests --no-build --no-restore --configuration Release --treenode-filter '/*/*/IsolatedTimeSeriesKeyLoadResourceTests/*' --results-directory TestResults/comparison-images/timeseries-keyload-model
217+
dotnet test --project tests/KeyLoad.ComparisonTests --no-build --no-restore --configuration Release --treenode-filter '/*/*/IsolatedTimeSeriesTimescaleResourceTests/*' --results-directory TestResults/comparison-images/timeseries-timescale-model
218+
dotnet test --project tests/KeyLoad.ComparisonTests --no-build --no-restore --configuration Release --treenode-filter '/*/*/IsolatedTimeSeriesBenchmarkResourceTests/*' --results-directory TestResults/comparison-images/timeseries-family-model
214219
- name: Retain common image bundle
215220
id: bundle
216221
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a

‎README.md‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,15 @@ The [first preserving repair](docs/Features/ClusterReplication/ReplicaTermMetada
323323
now avoids repeated full-entry decoding during term checks at an identical
324324
verified store cut, retaining both public authorized quorum barriers. Its
325325
[source receipt](docs/implementation/database-term-metadata-source-r119.json)
326-
records independent review,18 authored real-store cases and full development
327-
build/formatter passes. Earlier Node-helper, SiteTests and term-test compilation
328-
failures are repaired in current source. Delivered-SHA native tests, server
329-
profiles and measured benefit remain required; this source change establishes
330-
no throughput increase or competitor ranking.
326+
records independent review,18 authored real-store cases and development
327+
build/formatter passes. The [40f native receipt](docs/implementation/database-term-metadata-native-40f-r122.json)
328+
finds all18 term cases:17 pass; one exposes repeated disposal after a failed
329+
snapshot install. RF363/63 and analyzer118/118 pass; units1737/1739 and
330+
recovery181/182 leave full qualification failed, with scalar/comparisons skipped.
331+
Current source repairs retired-handle ownership and exact real-clock waits;
332+
19 authored term cases now cover both install fault stages. New-source full
333+
native tests, server profiles and measured benefit remain required; no throughput
334+
increase or competitor ranking is established.
331335

332336

333337
The delivered `2f374fc34` [Linux run37093197474](https://github.com/managedcode/KeyLoad/actions/runs/37093197474) now passes the complete source gates,118 analyzer cases,1483 normal and1483 scalar unit cases,164 process-recovery cases and63 Docker RF3 cases without skips. The [original-source receipt](docs/implementation/isolated-source-qualification-37093197474.json) retains exact report/artifact hashes. Comparative image and diagnostic gates pass;27 native preflights finish16 job successes and11 failures, including two explicit unavailable Neo4j topologies among the successes. Complete270 performance and site publication remain unqualified. The separate TimeSeries pure30 cases pass in both modes, while its bounded runner has36 new declared TUnit cases prepared in source and native adapters/all30 cells remain pending.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System.Collections.Immutable;
2+
3+
namespace KeyLoad.ComparisonHost.Features.BenchmarkComparisons;
4+
5+
internal static class TimeSeriesIntensiveHostConstants
6+
{
7+
private const string FamilyPrefix = "Benchmarks:TimeSeries:";
8+
private const string NativePrefix = "Benchmarks:Native:";
9+
internal const string NativeSection = "Benchmarks:Native";
10+
internal const string ImageField = "Image";
11+
internal const string EndpointsField = "Endpoints";
12+
internal const string VoterIdsField = "VoterIds";
13+
internal const string IncarnationField = "Incarnation";
14+
internal const string ConnectionStringField = "ConnectionString";
15+
internal const string CellId = FamilyPrefix + "CellId";
16+
internal const string ContractSha256 = FamilyPrefix + "ContractSha256";
17+
internal const string Image = NativePrefix + ImageField;
18+
internal const string Endpoints = NativePrefix + EndpointsField;
19+
internal const string VoterIds = NativePrefix + VoterIdsField;
20+
internal const string Incarnation = NativePrefix + IncarnationField;
21+
internal const string ConnectionString = NativePrefix + ConnectionStringField;
22+
internal const string JobId = "KEYLOAD_COMPARISON_JOB_ID";
23+
internal const string InvalidCode = "TimeSeriesIntensiveHostSettingsInvalid";
24+
internal const string StorageDescription = "Fresh TimeSeries cell-owned native directories; no shared database";
25+
internal const string GuidD = "D";
26+
internal const string RootPath = "/";
27+
internal const string TcpScheme = "tcp";
28+
internal const char CarriageReturn = '\r';
29+
internal const char LineFeed = '\n';
30+
internal const char HostSeparator = ',';
31+
internal const int FirstIndex = 0;
32+
internal const int OverflowLookahead = 1;
33+
internal const int MinimumPort = 1;
34+
internal const int MaximumPort = 65_535;
35+
internal static readonly ImmutableArray<string> KeyLoadNativeFields = [ImageField, EndpointsField, VoterIdsField, IncarnationField];
36+
internal static readonly ImmutableArray<string> TimescaleNativeFields = [ImageField, EndpointsField, ConnectionStringField];
37+
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
using System.Collections.Immutable;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.Globalization;
4+
using KeyLoad.Comparisons.Features.BenchmarkComparisons.TimeSeries.Intensive;
5+
using Microsoft.Extensions.Configuration;
6+
using Npgsql;
7+
8+
namespace KeyLoad.ComparisonHost.Features.BenchmarkComparisons;
9+
10+
internal static class TimeSeriesIntensiveHostInput
11+
{
12+
internal static InvalidOperationException Invalid() => new(TimeSeriesIntensiveHostConstants.InvalidCode);
13+
14+
internal static string Required(IConfiguration configuration, string key)
15+
{
16+
var value = configuration[key];
17+
if (!IsPrivateText(value))
18+
{
19+
throw Invalid();
20+
}
21+
return value;
22+
}
23+
24+
private static bool IsPrivateText([NotNullWhen(true)] string? value) => !string.IsNullOrWhiteSpace(value)
25+
&& !value.Contains(TimeSeriesIntensiveHostConstants.CarriageReturn, StringComparison.Ordinal)
26+
&& !value.Contains(TimeSeriesIntensiveHostConstants.LineFeed, StringComparison.Ordinal);
27+
28+
internal static long ReadJob(IConfiguration configuration)
29+
{
30+
var value = Required(configuration, TimeSeriesIntensiveHostConstants.JobId);
31+
if (!long.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out var result)
32+
|| result <= TimeSeriesIntensiveHostConstants.FirstIndex || value != result.ToString(CultureInfo.InvariantCulture))
33+
{
34+
throw Invalid();
35+
}
36+
return result;
37+
}
38+
39+
internal static string ReadOutput(IConfiguration configuration)
40+
{
41+
var value = Required(configuration, ComparisonHostConstants.Output);
42+
if (!Path.IsPathFullyQualified(value))
43+
{
44+
throw Invalid();
45+
}
46+
return Path.GetFullPath(value);
47+
}
48+
49+
internal static void ValidateNativeSection(IConfiguration configuration, TimeSeriesIntensiveTargetKind target)
50+
{
51+
var allowed = target == TimeSeriesIntensiveTargetKind.KeyLoad
52+
? TimeSeriesIntensiveHostConstants.KeyLoadNativeFields : TimeSeriesIntensiveHostConstants.TimescaleNativeFields;
53+
var section = configuration.GetSection(TimeSeriesIntensiveHostConstants.NativeSection);
54+
var children = section.GetChildren().Take(allowed.Length + TimeSeriesIntensiveHostConstants.OverflowLookahead).ToArray();
55+
if (section.Value is not null || children.Length > allowed.Length)
56+
{
57+
throw Invalid();
58+
}
59+
foreach (var child in children)
60+
{
61+
if (!allowed.Contains(child.Key, StringComparer.OrdinalIgnoreCase)
62+
|| !string.Equals(child.Key, TimeSeriesIntensiveHostConstants.EndpointsField, StringComparison.OrdinalIgnoreCase)
63+
&& !string.Equals(child.Key, TimeSeriesIntensiveHostConstants.VoterIdsField, StringComparison.OrdinalIgnoreCase)
64+
&& child.GetChildren().Any())
65+
{
66+
throw Invalid();
67+
}
68+
}
69+
}
70+
71+
internal static ImmutableArray<string> ReadArray(IConfiguration configuration, string key, int count)
72+
{
73+
var section = configuration.GetSection(key);
74+
var children = section.GetChildren().Take(count + TimeSeriesIntensiveHostConstants.OverflowLookahead).ToArray();
75+
if (section.Value is not null || children.Length != count)
76+
{
77+
throw Invalid();
78+
}
79+
var values = ImmutableArray.CreateBuilder<string>(count);
80+
for (var index = TimeSeriesIntensiveHostConstants.FirstIndex; index < count; index++)
81+
{
82+
var suffix = index.ToString(CultureInfo.InvariantCulture);
83+
var child = children.SingleOrDefault(item => item.Key == suffix);
84+
if (child is null || child.GetChildren().Any())
85+
{
86+
throw Invalid();
87+
}
88+
values.Add(Required(configuration, child.Path));
89+
}
90+
return values.MoveToImmutable();
91+
}
92+
93+
internal static ImmutableArray<Uri> ReadEndpoints(IConfiguration configuration, string key, int count, bool tcp)
94+
=> ValidateAuthorities(ReadArray(configuration, key, count), tcp);
95+
96+
internal static ImmutableArray<Uri> ValidateAuthorities(ImmutableArray<string> values, bool tcp)
97+
{
98+
var endpoints = ImmutableArray.CreateBuilder<Uri>(values.Length);
99+
foreach (var value in values)
100+
{
101+
endpoints.Add(ReadAuthority(value, tcp));
102+
}
103+
var result = endpoints.MoveToImmutable();
104+
if (result.Select(item => item.GetLeftPart(UriPartial.Authority)).Distinct(StringComparer.OrdinalIgnoreCase).Count() != values.Length)
105+
{
106+
throw Invalid();
107+
}
108+
return result;
109+
}
110+
111+
private static Uri ReadAuthority(string value, bool tcp)
112+
{
113+
if (value.Any(static character => char.IsWhiteSpace(character) || char.IsControl(character))
114+
|| !Uri.TryCreate(value, UriKind.Absolute, out var endpoint) || !endpoint.IsWellFormedOriginalString()
115+
|| string.IsNullOrWhiteSpace(endpoint.Host) || endpoint.UserInfo.Length != TimeSeriesIntensiveHostConstants.FirstIndex
116+
|| endpoint.Query.Length != TimeSeriesIntensiveHostConstants.FirstIndex || endpoint.Fragment.Length != TimeSeriesIntensiveHostConstants.FirstIndex
117+
|| !string.IsNullOrEmpty(endpoint.AbsolutePath) && endpoint.AbsolutePath != TimeSeriesIntensiveHostConstants.RootPath
118+
|| (tcp ? endpoint.Scheme != TimeSeriesIntensiveHostConstants.TcpScheme
119+
|| endpoint.Port is < TimeSeriesIntensiveHostConstants.MinimumPort or > TimeSeriesIntensiveHostConstants.MaximumPort
120+
: endpoint.Scheme != Uri.UriSchemeHttp && endpoint.Scheme != Uri.UriSchemeHttps))
121+
{
122+
throw Invalid();
123+
}
124+
return endpoint;
125+
}
126+
127+
internal static Guid ReadIncarnation(IConfiguration configuration)
128+
{
129+
var value = Required(configuration, TimeSeriesIntensiveHostConstants.Incarnation);
130+
if (!Guid.TryParseExact(value, TimeSeriesIntensiveHostConstants.GuidD, out var result)
131+
|| result == Guid.Empty || value != result.ToString(TimeSeriesIntensiveHostConstants.GuidD, CultureInfo.InvariantCulture))
132+
{
133+
throw Invalid();
134+
}
135+
return result;
136+
}
137+
138+
internal static void RejectPresent(IConfiguration configuration, string key)
139+
{
140+
var section = configuration.GetSection(key);
141+
if (section.Value is not null || section.GetChildren().Any())
142+
{
143+
throw Invalid();
144+
}
145+
}
146+
147+
internal static string ReadConnection(IConfiguration configuration)
148+
{
149+
var value = Required(configuration, TimeSeriesIntensiveHostConstants.ConnectionString);
150+
try
151+
{
152+
var parsed = new NpgsqlConnectionStringBuilder(value);
153+
if (!IsPrivateText(parsed.Host) || parsed.Host.Contains(TimeSeriesIntensiveHostConstants.HostSeparator, StringComparison.Ordinal)
154+
|| parsed.Port is < TimeSeriesIntensiveHostConstants.MinimumPort or > TimeSeriesIntensiveHostConstants.MaximumPort
155+
|| !IsPrivateText(parsed.Username) || !IsPrivateText(parsed.Password))
156+
{
157+
throw Invalid();
158+
}
159+
return value;
160+
}
161+
catch (ArgumentException)
162+
{
163+
throw Invalid();
164+
}
165+
catch (FormatException)
166+
{
167+
throw Invalid();
168+
}
169+
catch (OverflowException)
170+
{
171+
throw Invalid();
172+
}
173+
}
174+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System.Collections.Immutable;
2+
using KeyLoad.Comparisons.Features.BenchmarkComparisons.TimeSeries.Intensive;
3+
using Microsoft.Extensions.Configuration;
4+
5+
namespace KeyLoad.ComparisonHost.Features.BenchmarkComparisons;
6+
7+
internal sealed record TimeSeriesIntensiveHostNativeSettings(string Image, ImmutableArray<Uri> Endpoints,
8+
ImmutableArray<string> VoterIds, Guid? Incarnation, string? AdminKey, string? ConnectionString)
9+
{
10+
public override string ToString() => nameof(TimeSeriesIntensiveHostNativeSettings);
11+
12+
internal static TimeSeriesIntensiveHostNativeSettings Read(IConfiguration configuration,
13+
TimeSeriesIntensiveSelection selection, string image)
14+
{
15+
ArgumentNullException.ThrowIfNull(configuration);
16+
try
17+
{
18+
selection.Validate();
19+
TimeSeriesIntensiveHostInput.ValidateNativeSection(configuration, selection.Target);
20+
if (!ComparisonExecutionIdentityImageReference.IsValid(image)
21+
|| TimeSeriesIntensiveHostInput.Required(configuration, TimeSeriesIntensiveHostConstants.Image) != image)
22+
{
23+
throw TimeSeriesIntensiveHostInput.Invalid();
24+
}
25+
return selection.Target == TimeSeriesIntensiveTargetKind.KeyLoad
26+
? ReadKeyLoad(configuration, selection.NodeCount, image)
27+
: ReadTimescale(configuration, selection.NodeCount, image);
28+
}
29+
catch (InvalidOperationException)
30+
{
31+
throw TimeSeriesIntensiveHostInput.Invalid();
32+
}
33+
}
34+
35+
private static TimeSeriesIntensiveHostNativeSettings ReadKeyLoad(IConfiguration configuration, int count, string image)
36+
{
37+
TimeSeriesIntensiveHostInput.RejectPresent(configuration, TimeSeriesIntensiveHostConstants.ConnectionString);
38+
var endpoints = TimeSeriesIntensiveHostInput.ReadEndpoints(configuration, TimeSeriesIntensiveHostConstants.Endpoints, count, tcp: false);
39+
var voters = TimeSeriesIntensiveHostInput.ReadArray(configuration, TimeSeriesIntensiveHostConstants.VoterIds, count);
40+
_ = TimeSeriesIntensiveHostInput.ValidateAuthorities(voters, tcp: false);
41+
var incarnation = TimeSeriesIntensiveHostInput.ReadIncarnation(configuration);
42+
var admin = TimeSeriesIntensiveHostInput.Required(configuration, ComparisonHostConstants.AdminKey);
43+
return new(image, endpoints, voters, incarnation, admin, null);
44+
}
45+
46+
private static TimeSeriesIntensiveHostNativeSettings ReadTimescale(IConfiguration configuration, int count, string image)
47+
{
48+
TimeSeriesIntensiveHostInput.RejectPresent(configuration, ComparisonHostConstants.AdminKey);
49+
TimeSeriesIntensiveHostInput.RejectPresent(configuration, TimeSeriesIntensiveHostConstants.Incarnation);
50+
TimeSeriesIntensiveHostInput.RejectPresent(configuration, TimeSeriesIntensiveHostConstants.VoterIds);
51+
var endpoints = TimeSeriesIntensiveHostInput.ReadEndpoints(configuration, TimeSeriesIntensiveHostConstants.Endpoints, count, tcp: true);
52+
var connection = TimeSeriesIntensiveHostInput.ReadConnection(configuration);
53+
return new(image, endpoints, ImmutableArray<string>.Empty, null, null, connection);
54+
}
55+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using System.Globalization;
2+
using KeyLoad.Comparisons.Features.BenchmarkComparisons.TimeSeries.Intensive;
3+
using Microsoft.Extensions.Configuration;
4+
5+
namespace KeyLoad.ComparisonHost.Features.BenchmarkComparisons;
6+
7+
internal sealed record TimeSeriesIntensiveHostSettings(TimeSeriesIntensiveSelection Selection,
8+
TimeSeriesIntensiveFamilyCell Cell, string ContractSha256, ComparisonExecutionIdentity Identity,
9+
long JobId, string Image, string OutputDirectory, string Storage, string RunId,
10+
TimeSeriesIntensiveHostNativeSettings Native)
11+
{
12+
public override string ToString() => nameof(TimeSeriesIntensiveHostSettings);
13+
14+
internal static TimeSeriesIntensiveHostSettings Read(IConfiguration configuration)
15+
{
16+
ArgumentNullException.ThrowIfNull(configuration);
17+
try
18+
{
19+
return ReadValidated(configuration);
20+
}
21+
catch (InvalidOperationException)
22+
{
23+
throw TimeSeriesIntensiveHostInput.Invalid();
24+
}
25+
catch (ArgumentException)
26+
{
27+
throw TimeSeriesIntensiveHostInput.Invalid();
28+
}
29+
catch (PathTooLongException)
30+
{
31+
throw TimeSeriesIntensiveHostInput.Invalid();
32+
}
33+
}
34+
35+
private static TimeSeriesIntensiveHostSettings ReadValidated(IConfiguration configuration)
36+
{
37+
var selection = TimeSeriesIntensiveSelection.Read(configuration);
38+
var contract = TimeSeriesIntensiveFamilyContract.Current;
39+
var plan = TimeSeriesIntensiveFamilyPlan.Create(contract);
40+
var cell = plan.Preflight.Concat(plan.Intensive).Single(item => item.Selection == selection);
41+
if (TimeSeriesIntensiveHostInput.Required(configuration, TimeSeriesIntensiveHostConstants.CellId) != cell.Id
42+
|| TimeSeriesIntensiveHostInput.Required(configuration, TimeSeriesIntensiveHostConstants.ContractSha256) != contract.ContractSha256)
43+
{
44+
throw TimeSeriesIntensiveHostInput.Invalid();
45+
}
46+
var source = TimeSeriesIntensiveHostInput.Required(configuration, ComparisonHostConstants.SourceRevision);
47+
var identity = ComparisonExecutionIdentity.ReadTimeSeriesIntensive(configuration, source);
48+
var job = TimeSeriesIntensiveHostInput.ReadJob(configuration);
49+
var image = TimeSeriesIntensiveHostInput.Required(configuration, TimeSeriesIntensiveHostConstants.Image);
50+
if (!ComparisonExecutionIdentityImageReference.IsValid(image)
51+
|| selection.Target == TimeSeriesIntensiveTargetKind.KeyLoad && image != identity.KeyLoadImage)
52+
{
53+
throw TimeSeriesIntensiveHostInput.Invalid();
54+
}
55+
var output = TimeSeriesIntensiveHostInput.ReadOutput(configuration);
56+
var storage = TimeSeriesIntensiveHostInput.Required(configuration, ComparisonHostConstants.Storage);
57+
if (storage != TimeSeriesIntensiveHostConstants.StorageDescription)
58+
{
59+
throw TimeSeriesIntensiveHostInput.Invalid();
60+
}
61+
var native = TimeSeriesIntensiveHostNativeSettings.Read(configuration, selection, image);
62+
return new(selection, cell, contract.ContractSha256, identity, job, image, output, storage,
63+
Guid.NewGuid().ToString(ComparisonHostConstants.GuidFormat, CultureInfo.InvariantCulture), native);
64+
}
65+
}

0 commit comments

Comments
 (0)