-module(lightspeed@ops@contention_harness).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lightspeed/ops/contention_harness.gleam").
-export([budget_failures/1, default_budget/0, evaluate_budget/2, run_scenario/1, run_matrix/0, budget_version_label/0, scenario_label/1, pass_fail_label/1, signature/1, deterministic/1, invariants_met/1, scenario/1, profile_metrics/1, outcomes/1, budget_results/1, failed_scenarios/1, nondeterministic_failures/1, invariant_failures/1, failed_budgets/1, metrics_signature/1, report_signature/1, snapshot_signature/0, snapshot_report_markdown/0]).
-export_type([scenario/0, metrics/0, scenario_outcome/0, budget/0, budget_result/0, report/0, claim/0, claim_accumulator/0, renewal_sample/0, renewal_accumulator/0, continuity_entry/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(" Deterministic durable-store contention profiling harness for M37.\n").
-type scenario() :: ownership_fencing_contention |
lease_renewal_contention |
takeover_queue_retry_pressure |
checkpoint_replay_windows.
-type metrics() :: {metrics,
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer()}.
-type scenario_outcome() :: {scenario_outcome,
scenario(),
boolean(),
boolean(),
boolean(),
binary(),
metrics()}.
-type budget() :: {budget,
scenario(),
integer(),
integer(),
integer(),
integer(),
integer()}.
-type budget_result() :: {budget_result, scenario(), boolean(), binary()}.
-type report() :: {report,
list(scenario_outcome()),
list(budget_result()),
integer(),
integer(),
integer(),
integer()}.
-type claim() :: {claim, binary(), integer(), binary(), integer(), integer()}.
-type claim_accumulator() :: {claim_accumulator,
lightspeed@cluster@durable_session:durable_session(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer()}.
-type renewal_sample() :: {renewal_sample, integer(), integer()}.
-type renewal_accumulator() :: {renewal_accumulator,
lightspeed@cluster@durable_session:durable_session(),
integer(),
integer(),
integer(),
integer(),
integer(),
list(integer())}.
-type continuity_entry() :: {continuity_entry,
boolean(),
binary(),
lightspeed@cluster@durable_session:continuity_report(),
boolean()}.
-file("src/lightspeed/ops/contention_harness.gleam", 176).
?DOC(" Count failing budget checks.\n").
-spec budget_failures(list(budget_result())) -> integer().
budget_failures(Results) ->
case Results of
[] ->
0;
[Result | Rest] ->
case erlang:element(3, Result) of
true ->
budget_failures(Rest);
false ->
1 + budget_failures(Rest)
end
end.
-file("src/lightspeed/ops/contention_harness.gleam", 1116).
-spec count_invariant_failures(list(scenario_outcome())) -> integer().
count_invariant_failures(Outcomes) ->
case Outcomes of
[] ->
0;
[Outcome | Rest] ->
case erlang:element(5, Outcome) of
true ->
count_invariant_failures(Rest);
false ->
1 + count_invariant_failures(Rest)
end
end.
-file("src/lightspeed/ops/contention_harness.gleam", 1105).
-spec count_nondeterministic(list(scenario_outcome())) -> integer().
count_nondeterministic(Outcomes) ->
case Outcomes of
[] ->
0;
[Outcome | Rest] ->
case erlang:element(4, Outcome) of
true ->
count_nondeterministic(Rest);
false ->
1 + count_nondeterministic(Rest)
end
end.
-file("src/lightspeed/ops/contention_harness.gleam", 1094).
-spec count_failed(list(scenario_outcome())) -> integer().
count_failed(Outcomes) ->
case Outcomes of
[] ->
0;
[Outcome | Rest] ->
case erlang:element(3, Outcome) of
true ->
count_failed(Rest);
false ->
1 + count_failed(Rest)
end
end.
-file("src/lightspeed/ops/contention_harness.gleam", 130).
?DOC(" Default deterministic M37 contention budgets.\n").
-spec default_budget() -> list(budget()).
default_budget() ->
[{budget, ownership_fencing_contention, 50, 1, 50, 8, 8},
{budget, lease_renewal_contention, 10, 1, 50, 4, 16},
{budget, takeover_queue_retry_pressure, 50, 1, 40, 6, 6},
{budget, checkpoint_replay_windows, 50, 1, 30, 4, 4}].
-file("src/lightspeed/ops/contention_harness.gleam", 1159).
-spec bool_label(boolean()) -> binary().
bool_label(Value) ->
case Value of
true ->
<<"true"/utf8>>;
false ->
<<"false"/utf8>>
end.
-file("src/lightspeed/ops/contention_harness.gleam", 1152).
-spec max_int(integer(), integer()) -> integer().
max_int(Left, Right) ->
case Left >= Right of
true ->
Left;
false ->
Right
end.
-file("src/lightspeed/ops/contention_harness.gleam", 1025).
-spec evaluate_budget_outcome(scenario_outcome(), budget()) -> budget_result().
evaluate_budget_outcome(Outcome, Budget) ->
Lease_within = erlang:element(7, erlang:element(7, Outcome)) =< erlang:element(
3,
Budget
),
Checkpoint_within = erlang:element(11, erlang:element(7, Outcome)) =< erlang:element(
4,
Budget
),
Replay_within = erlang:element(12, erlang:element(7, Outcome)) =< erlang:element(
5,
Budget
),
Queue_peak = max_int(
erlang:element(8, erlang:element(7, Outcome)),
erlang:element(9, erlang:element(7, Outcome))
),
Queue_within = Queue_peak =< erlang:element(6, Budget),
Retry_within = erlang:element(10, erlang:element(7, Outcome)) =< erlang:element(
7,
Budget
),
Passed = (((((erlang:element(3, Outcome) andalso erlang:element(5, Outcome))
andalso Lease_within)
andalso Checkpoint_within)
andalso Replay_within)
andalso Queue_within)
andalso Retry_within,
Reason = case Passed of
true ->
<<"within_budget"/utf8>>;
false ->
<<<<<<<<<<<<<<<<<<<<<<<<<<"lease="/utf8,
(bool_label(
Lease_within
))/binary>>/binary,
":checkpoint="/utf8>>/binary,
(bool_label(
Checkpoint_within
))/binary>>/binary,
":replay="/utf8>>/binary,
(bool_label(Replay_within))/binary>>/binary,
":queue="/utf8>>/binary,
(bool_label(Queue_within))/binary>>/binary,
":retry="/utf8>>/binary,
(bool_label(Retry_within))/binary>>/binary,
":scenario_passed="/utf8>>/binary,
(bool_label(erlang:element(3, Outcome)))/binary>>/binary,
":invariants="/utf8>>/binary,
(bool_label(erlang:element(5, Outcome)))/binary>>
end,
{budget_result, erlang:element(2, Budget), Passed, Reason}.
-file("src/lightspeed/ops/contention_harness.gleam", 1073).
-spec find_outcome(list(scenario_outcome()), scenario()) -> gleam@option:option(scenario_outcome()).
find_outcome(Outcomes, Scenario) ->
case Outcomes of
[] ->
none;
[Outcome | Rest] ->
case erlang:element(2, Outcome) =:= Scenario of
true ->
{some, Outcome};
false ->
find_outcome(Rest, Scenario)
end
end.
-file("src/lightspeed/ops/contention_harness.gleam", 1002).
-spec evaluate_budget_loop(
list(scenario_outcome()),
list(budget()),
list(budget_result())
) -> list(budget_result()).
evaluate_budget_loop(Outcomes, Budgets, Acc_rev) ->
case Budgets of
[] ->
lists:reverse(Acc_rev);
[Budget | Rest] ->
Result = case find_outcome(Outcomes, erlang:element(2, Budget)) of
none ->
{budget_result,
erlang:element(2, Budget),
false,
<<"missing_scenario"/utf8>>};
{some, Outcome} ->
evaluate_budget_outcome(Outcome, Budget)
end,
evaluate_budget_loop(Outcomes, Rest, [Result | Acc_rev])
end.
-file("src/lightspeed/ops/contention_harness.gleam", 168).
?DOC(" Evaluate one outcome list against one budget profile.\n").
-spec evaluate_budget(list(scenario_outcome()), list(budget())) -> list(budget_result()).
evaluate_budget(Outcomes, Budgets) ->
evaluate_budget_loop(Outcomes, Budgets, []).
-file("src/lightspeed/ops/contention_harness.gleam", 1166).
-spec join_with(binary(), list(binary())) -> binary().
join_with(Separator, Values) ->
case Values of
[] ->
<<""/utf8>>;
[Value] ->
Value;
[Value@1 | Rest] ->
<<<<Value@1/binary, Separator/binary>>/binary,
(join_with(Separator, Rest))/binary>>
end.
-file("src/lightspeed/ops/contention_harness.gleam", 1145).
-spec max_loop(integer(), list(integer())) -> integer().
max_loop(Current_max, Values) ->
case Values of
[] ->
Current_max;
[Value | Rest] ->
max_loop(max_int(Current_max, Value), Rest)
end.
-file("src/lightspeed/ops/contention_harness.gleam", 1138).
-spec max_or_zero(list(integer())) -> integer().
max_or_zero(Values) ->
case Values of
[] ->
0;
[Value | Rest] ->
max_loop(Value, Rest)
end.
-file("src/lightspeed/ops/contention_harness.gleam", 1087).
-spec continuity_entries_all_met(list(continuity_entry())) -> boolean().
continuity_entries_all_met(Entries) ->
case Entries of
[] ->
true;
[Entry | Rest] ->
erlang:element(2, Entry) andalso continuity_entries_all_met(Rest)
end.
-file("src/lightspeed/ops/contention_harness.gleam", 951).
-spec evaluate_checkpoint_backend(
lightspeed@cluster@durable_session:persistence_backend(),
integer()
) -> continuity_entry().
evaluate_checkpoint_backend(Backend, Index) ->
Session_id = <<"m37-window-"/utf8,
(erlang:integer_to_binary(Index + 1))/binary>>,
Crashed = begin
_pipe = lightspeed@cluster@durable_session:start(
Session_id,
<<"node-a"/utf8>>,
<<"/window"/utf8>>,
Backend,
rehydrate,
0,
35,
1
),
_pipe@1 = lightspeed@cluster@durable_session:append_counter_delta(
_pipe,
1,
3
),
_pipe@2 = lightspeed@cluster@durable_session:append_counter_delta(
_pipe@1,
1,
5
),
_pipe@3 = lightspeed@cluster@durable_session:append_counter_delta(
_pipe@2,
1,
7
),
_pipe@4 = lightspeed@cluster@durable_session:append_counter_delta(
_pipe@3,
1,
9
),
_pipe@5 = lightspeed@cluster@durable_session:crash(
_pipe@4,
<<"boom"/utf8>>
),
lightspeed@cluster@durable_session:restart(_pipe@5, 500)
end,
Takeover = lightspeed@cluster@durable_session:request_takeover(
Crashed,
<<"node-b"/utf8>>,
2,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-b"/utf8>>,
2
),
510
),
{Recovered, Takeover_successful} = case Takeover of
{ok, Updated} ->
{Updated, true};
{error, _} ->
{Crashed, false}
end,
Reconnected = lightspeed@cluster@durable_session:reconnect(
Recovered,
rehydrate,
<<"/window"/utf8>>,
524
),
Continuity = lightspeed@cluster@durable_session:continuity_report(
Reconnected,
500,
524
),
{continuity_entry,
erlang:element(4, Continuity),
lightspeed@cluster@durable_session:backend_label(Backend),
Continuity,
Takeover_successful}.
-file("src/lightspeed/ops/contention_harness.gleam", 936).
-spec evaluate_checkpoint_entries(
list(lightspeed@cluster@durable_session:persistence_backend()),
integer(),
list(continuity_entry())
) -> list(continuity_entry()).
evaluate_checkpoint_entries(Backends, Index, Acc_rev) ->
case Backends of
[] ->
Acc_rev;
[Backend | Rest] ->
evaluate_checkpoint_entries(
Rest,
Index + 1,
[evaluate_checkpoint_backend(Backend, Index) | Acc_rev]
)
end.
-file("src/lightspeed/ops/contention_harness.gleam", 746).
-spec evaluate_checkpoint_replay_windows() -> {boolean(),
boolean(),
metrics(),
binary()}.
evaluate_checkpoint_replay_windows() ->
Entries = begin
_pipe = evaluate_checkpoint_entries(
lightspeed@cluster@durable_session:supported_backends(),
0,
[]
),
lists:reverse(_pipe)
end,
Met_all = continuity_entries_all_met(Entries),
Takeover_successes = begin
_pipe@1 = Entries,
_pipe@2 = gleam@list:filter(
_pipe@1,
fun(Entry) -> erlang:element(5, Entry) end
),
erlang:length(_pipe@2)
end,
Signatures = begin
_pipe@3 = Entries,
gleam@list:map(
_pipe@3,
fun(Entry@1) ->
<<<<(erlang:element(3, Entry@1))/binary, ":"/utf8>>/binary,
(lightspeed@cluster@durable_session:continuity_signature(
erlang:element(4, Entry@1)
))/binary>>
end
)
end,
Checkpoint_window_events = begin
_pipe@4 = Entries,
_pipe@5 = gleam@list:map(
_pipe@4,
fun(Entry@2) -> erlang:element(3, erlang:element(4, Entry@2)) end
),
max_or_zero(_pipe@5)
end,
Replay_window_ms = begin
_pipe@6 = Entries,
_pipe@7 = gleam@list:map(
_pipe@6,
fun(Entry@3) -> erlang:element(2, erlang:element(4, Entry@3)) end
),
max_or_zero(_pipe@7)
end,
Invariants_met = Met_all andalso (erlang:length(Entries) =:= 3),
Profile = {metrics,
0,
0,
0,
0,
Takeover_successes,
0,
0,
0,
0,
Checkpoint_window_events,
Replay_window_ms},
Passed = Invariants_met andalso (Checkpoint_window_events =< 1),
{Passed,
Invariants_met,
Profile,
<<<<<<<<<<"entries="/utf8,
(join_with(<<";"/utf8>>, Signatures))/binary>>/binary,
"|checkpoint_window="/utf8>>/binary,
(erlang:integer_to_binary(Checkpoint_window_events))/binary>>/binary,
"|replay_window_ms="/utf8>>/binary,
(erlang:integer_to_binary(Replay_window_ms))/binary>>}.
-file("src/lightspeed/ops/contention_harness.gleam", 828).
-spec apply_claim(claim_accumulator(), claim()) -> claim_accumulator().
apply_claim(Accumulator, Claim) ->
Queue_peak = max_int(
erlang:element(8, Accumulator),
erlang:element(5, Claim)
),
case lightspeed@cluster@durable_session:request_takeover(
erlang:element(2, Accumulator),
erlang:element(2, Claim),
erlang:element(3, Claim),
erlang:element(4, Claim),
erlang:element(6, Claim)
) of
{ok, Updated} ->
{claim_accumulator,
Updated,
erlang:element(3, Accumulator),
erlang:element(4, Accumulator),
erlang:element(5, Accumulator),
erlang:element(6, Accumulator) + 1,
erlang:element(7, Accumulator),
Queue_peak};
{error, {split_brain, _, _, _}} ->
{claim_accumulator,
erlang:element(2, Accumulator),
erlang:element(3, Accumulator) + 1,
erlang:element(4, Accumulator),
erlang:element(5, Accumulator),
erlang:element(6, Accumulator),
erlang:element(7, Accumulator) + 1,
Queue_peak};
{error, {stale_owner, _, _}} ->
{claim_accumulator,
erlang:element(2, Accumulator),
erlang:element(3, Accumulator),
erlang:element(4, Accumulator) + 1,
erlang:element(5, Accumulator),
erlang:element(6, Accumulator),
erlang:element(7, Accumulator) + 1,
Queue_peak};
{error, {invalid_token, _, _}} ->
{claim_accumulator,
erlang:element(2, Accumulator),
erlang:element(3, Accumulator),
erlang:element(4, Accumulator),
erlang:element(5, Accumulator) + 1,
erlang:element(6, Accumulator),
erlang:element(7, Accumulator) + 1,
Queue_peak}
end.
-file("src/lightspeed/ops/contention_harness.gleam", 818).
-spec run_claims_loop(claim_accumulator(), list(claim())) -> claim_accumulator().
run_claims_loop(Accumulator, Claims) ->
case Claims of
[] ->
Accumulator;
[Claim | Rest] ->
run_claims_loop(apply_claim(Accumulator, Claim), Rest)
end.
-file("src/lightspeed/ops/contention_harness.gleam", 800).
-spec run_claims(
lightspeed@cluster@durable_session:durable_session(),
list(claim())
) -> claim_accumulator().
run_claims(Session, Claims) ->
run_claims_loop({claim_accumulator, Session, 0, 0, 0, 0, 0, 0}, Claims).
-file("src/lightspeed/ops/contention_harness.gleam", 613).
-spec evaluate_takeover_queue_retry_pressure() -> {boolean(),
boolean(),
metrics(),
binary()}.
evaluate_takeover_queue_retry_pressure() ->
Session_id = <<"m37-queue"/utf8>>,
Base = begin
_pipe = lightspeed@cluster@durable_session:start(
Session_id,
<<"node-a"/utf8>>,
<<"/queue"/utf8>>,
{snapshot_journal, <<"snapshot"/utf8>>, <<"journal"/utf8>>, 2},
rehydrate,
0,
45,
1
),
_pipe@1 = lightspeed@cluster@durable_session:append_counter_delta(
_pipe,
5,
4
),
_pipe@2 = lightspeed@cluster@durable_session:crash(
_pipe@1,
<<"boom"/utf8>>
),
lightspeed@cluster@durable_session:restart(_pipe@2, 200)
end,
Claims = [{claim,
<<"node-b"/utf8>>,
2,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-b"/utf8>>,
2
),
5,
210},
{claim,
<<"node-c"/utf8>>,
2,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-c"/utf8>>,
2
),
5,
211},
{claim,
<<"node-a"/utf8>>,
1,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-a"/utf8>>,
1
),
4,
212},
{claim, <<"node-d"/utf8>>, 3, <<"bad-token"/utf8>>, 3, 213},
{claim,
<<"node-c"/utf8>>,
3,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-c"/utf8>>,
3
),
3,
214},
{claim,
<<"node-b"/utf8>>,
3,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-b"/utf8>>,
3
),
2,
215},
{claim,
<<"node-d"/utf8>>,
4,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-d"/utf8>>,
4
),
1,
216}],
Contested = run_claims(Base, Claims),
Reconnected = lightspeed@cluster@durable_session:reconnect(
erlang:element(2, Contested),
rehydrate,
<<"/queue"/utf8>>,
236
),
Continuity = lightspeed@cluster@durable_session:continuity_report(
Reconnected,
200,
236
),
Fence = lightspeed@cluster@durable_session:fence(Reconnected),
Snapshot = lightspeed@cluster@durable_session:snapshot(Reconnected),
Ownership_conflicts = (erlang:element(3, Contested) + erlang:element(
4,
Contested
))
+ erlang:element(5, Contested),
Invariants_met = ((((((erlang:element(3, Contested) =:= 2) andalso (erlang:element(
4,
Contested
)
=:= 1))
andalso (erlang:element(5, Contested) =:= 1))
andalso (erlang:element(6, Contested) =:= 3))
andalso (erlang:element(2, Fence) =:= <<"node-d"/utf8>>))
andalso (erlang:element(3, Fence) =:= 4))
andalso (erlang:element(4, Snapshot) =:= 5),
Profile = {metrics,
Ownership_conflicts,
erlang:element(3, Contested),
erlang:element(4, Contested),
erlang:element(5, Contested),
erlang:element(6, Contested),
0,
0,
erlang:element(8, Contested),
erlang:element(7, Contested),
erlang:element(3, Continuity),
erlang:element(2, Continuity)},
Passed = (Invariants_met andalso erlang:element(4, Continuity)) andalso lightspeed@cluster@durable_session:valid(
Reconnected
),
{Passed,
Invariants_met,
Profile,
<<<<<<<<<<<<<<<<<<<<<<<<<<"fence="/utf8,
(lightspeed@cluster@durable_session:fence_signature(
Fence
))/binary>>/binary,
"|split_brain="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(
3,
Contested
)
))/binary>>/binary,
"|stale_owner="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(4, Contested)
))/binary>>/binary,
"|invalid_token="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(5, Contested)
))/binary>>/binary,
"|queue_peak="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(8, Contested)
))/binary>>/binary,
"|retries="/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(7, Contested)))/binary>>/binary,
"|continuity="/utf8>>/binary,
(lightspeed@cluster@durable_session:continuity_signature(Continuity))/binary>>}.
-file("src/lightspeed/ops/contention_harness.gleam", 1134).
-spec p95_or_zero(list(integer())) -> integer().
p95_or_zero(Values) ->
max_or_zero(Values).
-file("src/lightspeed/ops/contention_harness.gleam", 1127).
-spec retries_from_queue_depth(integer()) -> integer().
retries_from_queue_depth(Queue_depth) ->
case Queue_depth =< 1 of
true ->
0;
false ->
Queue_depth - 1
end.
-file("src/lightspeed/ops/contention_harness.gleam", 895).
-spec apply_lease_renewal_sample(
binary(),
binary(),
renewal_sample(),
renewal_accumulator()
) -> renewal_accumulator().
apply_lease_renewal_sample(Session_id, Owner, Sample, Accumulator) ->
Epoch = erlang:element(3, Accumulator) + 1,
Now_ms = erlang:element(4, Accumulator) + erlang:element(2, Sample),
Queue_retry = retries_from_queue_depth(erlang:element(3, Sample)),
Queue_peak = max_int(
erlang:element(7, Accumulator),
erlang:element(3, Sample)
),
Token = lightspeed@cluster@durable_session:expected_token(
Session_id,
Owner,
Epoch
),
case lightspeed@cluster@durable_session:request_takeover(
erlang:element(2, Accumulator),
Owner,
Epoch,
Token,
Now_ms
) of
{ok, Updated} ->
{renewal_accumulator,
Updated,
Epoch,
Now_ms,
erlang:element(5, Accumulator) + 1,
erlang:element(6, Accumulator) + Queue_retry,
Queue_peak,
[erlang:element(2, Sample) | erlang:element(8, Accumulator)]};
{error, _} ->
{renewal_accumulator,
erlang:element(2, Accumulator),
erlang:element(3, Accumulator),
erlang:element(4, Accumulator),
erlang:element(5, Accumulator),
(erlang:element(6, Accumulator) + Queue_retry) + 1,
Queue_peak,
erlang:element(8, Accumulator)}
end.
-file("src/lightspeed/ops/contention_harness.gleam", 877).
-spec run_lease_renewals(
binary(),
binary(),
list(renewal_sample()),
renewal_accumulator()
) -> renewal_accumulator().
run_lease_renewals(Session_id, Owner, Samples, Accumulator) ->
case Samples of
[] ->
Accumulator;
[Sample | Rest] ->
run_lease_renewals(
Session_id,
Owner,
Rest,
apply_lease_renewal_sample(
Session_id,
Owner,
Sample,
Accumulator
)
)
end.
-file("src/lightspeed/ops/contention_harness.gleam", 532).
-spec evaluate_lease_renewal_contention() -> {boolean(),
boolean(),
metrics(),
binary()}.
evaluate_lease_renewal_contention() ->
Session_id = <<"m37-lease"/utf8>>,
Owner = <<"node-a"/utf8>>,
Base = lightspeed@cluster@durable_session:start(
Session_id,
Owner,
<<"/todos"/utf8>>,
{journal_only, <<"lease_journal"/utf8>>},
resume,
0,
40,
1
),
Samples = [{renewal_sample, 4, 1},
{renewal_sample, 6, 2},
{renewal_sample, 7, 2},
{renewal_sample, 5, 3},
{renewal_sample, 8, 2},
{renewal_sample, 6, 1},
{renewal_sample, 4, 2},
{renewal_sample, 7, 1}],
Renewal = run_lease_renewals(
Session_id,
Owner,
Samples,
{renewal_accumulator, Base, 1, 0, 0, 0, 0, []}
),
Fence = lightspeed@cluster@durable_session:fence(erlang:element(2, Renewal)),
Windows = lists:reverse(erlang:element(8, Renewal)),
Lease_p95 = p95_or_zero(Windows),
Sample_count = erlang:length(Samples),
Invariants_met = ((erlang:element(5, Renewal) =:= Sample_count) andalso (erlang:element(
2,
Fence
)
=:= Owner))
andalso (erlang:element(3, Fence) =:= (1 + Sample_count)),
Profile = {metrics,
0,
0,
0,
0,
erlang:element(5, Renewal),
Lease_p95,
erlang:element(7, Renewal),
erlang:element(7, Renewal),
erlang:element(6, Renewal),
0,
0},
Passed = Invariants_met andalso lightspeed@cluster@durable_session:valid(
erlang:element(2, Renewal)
),
{Passed,
Invariants_met,
Profile,
<<<<<<<<<<<<<<<<<<"fence="/utf8,
(lightspeed@cluster@durable_session:fence_signature(
Fence
))/binary>>/binary,
"|lease_p95_ms="/utf8>>/binary,
(erlang:integer_to_binary(Lease_p95))/binary>>/binary,
"|lease_queue_peak="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(7, Renewal)
))/binary>>/binary,
"|retries="/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(6, Renewal)))/binary>>/binary,
"|windows="/utf8>>/binary,
(join_with(
<<","/utf8>>,
gleam@list:map(Windows, fun erlang:integer_to_binary/1)
))/binary>>}.
-file("src/lightspeed/ops/contention_harness.gleam", 422).
-spec evaluate_ownership_fencing_contention() -> {boolean(),
boolean(),
metrics(),
binary()}.
evaluate_ownership_fencing_contention() ->
Session_id = <<"m37-fence"/utf8>>,
Base = lightspeed@cluster@durable_session:start(
Session_id,
<<"node-a"/utf8>>,
<<"/counter"/utf8>>,
{snapshot_journal, <<"snapshot"/utf8>>, <<"journal"/utf8>>, 2},
rehydrate,
0,
40,
1
),
Claims = [{claim,
<<"node-b"/utf8>>,
2,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-b"/utf8>>,
2
),
4,
10},
{claim,
<<"node-c"/utf8>>,
2,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-c"/utf8>>,
2
),
3,
11},
{claim,
<<"node-a"/utf8>>,
1,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-a"/utf8>>,
1
),
3,
12},
{claim, <<"node-d"/utf8>>, 3, <<"invalid-token"/utf8>>, 2, 13},
{claim,
<<"node-b"/utf8>>,
3,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-b"/utf8>>,
3
),
2,
14},
{claim,
<<"node-c"/utf8>>,
3,
lightspeed@cluster@durable_session:expected_token(
Session_id,
<<"node-c"/utf8>>,
3
),
1,
15}],
Result = run_claims(Base, Claims),
Fence = lightspeed@cluster@durable_session:fence(erlang:element(2, Result)),
Ownership_conflicts = (erlang:element(3, Result) + erlang:element(4, Result))
+ erlang:element(5, Result),
Invariants_met = (((((erlang:element(3, Result) =:= 2) andalso (erlang:element(
4,
Result
)
=:= 1))
andalso (erlang:element(5, Result) =:= 1))
andalso (erlang:element(6, Result) =:= 2))
andalso (erlang:element(2, Fence) =:= <<"node-b"/utf8>>))
andalso (erlang:element(3, Fence) =:= 3),
Profile = {metrics,
Ownership_conflicts,
erlang:element(3, Result),
erlang:element(4, Result),
erlang:element(5, Result),
erlang:element(6, Result),
0,
0,
erlang:element(8, Result),
erlang:element(7, Result),
0,
0},
Passed = Invariants_met andalso lightspeed@cluster@durable_session:valid(
erlang:element(2, Result)
),
{Passed,
Invariants_met,
Profile,
<<<<<<<<<<<<<<<<<<<<<<"fence="/utf8,
(lightspeed@cluster@durable_session:fence_signature(
Fence
))/binary>>/binary,
"|split_brain="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(3, Result)
))/binary>>/binary,
"|stale_owner="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(4, Result)
))/binary>>/binary,
"|invalid_token="/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(5, Result)))/binary>>/binary,
"|queue_peak="/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(8, Result)))/binary>>/binary,
"|retries="/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(7, Result)))/binary>>}.
-file("src/lightspeed/ops/contention_harness.gleam", 413).
-spec evaluate(scenario()) -> {boolean(), boolean(), metrics(), binary()}.
evaluate(Scenario) ->
case Scenario of
ownership_fencing_contention ->
evaluate_ownership_fencing_contention();
lease_renewal_contention ->
evaluate_lease_renewal_contention();
takeover_queue_retry_pressure ->
evaluate_takeover_queue_retry_pressure();
checkpoint_replay_windows ->
evaluate_checkpoint_replay_windows()
end.
-file("src/lightspeed/ops/contention_harness.gleam", 101).
?DOC(" Run one M37 scenario twice and require deterministic parity.\n").
-spec run_scenario(scenario()) -> scenario_outcome().
run_scenario(Scenario) ->
{First_passed, First_invariants, First_metrics, First_signature} = evaluate(
Scenario
),
{Second_passed, Second_invariants, Second_metrics, Second_signature} = evaluate(
Scenario
),
Deterministic = (((First_passed =:= Second_passed) andalso (First_invariants
=:= Second_invariants))
andalso (First_signature =:= Second_signature))
andalso (First_metrics =:= Second_metrics),
Passed = (First_passed andalso Second_passed) andalso Deterministic,
Invariants_met = First_invariants andalso Second_invariants,
{scenario_outcome,
Scenario,
Passed,
Deterministic,
Invariants_met,
First_signature,
First_metrics}.
-file("src/lightspeed/ops/contention_harness.gleam", 79).
?DOC(" Run all M37 scenarios and evaluate default contention budgets.\n").
-spec run_matrix() -> report().
run_matrix() ->
Outcomes = begin
_pipe = [ownership_fencing_contention,
lease_renewal_contention,
takeover_queue_retry_pressure,
checkpoint_replay_windows],
gleam@list:map(_pipe, fun run_scenario/1)
end,
Budget_results = evaluate_budget(Outcomes, default_budget()),
{report,
Outcomes,
Budget_results,
count_failed(Outcomes),
count_nondeterministic(Outcomes),
count_invariant_failures(Outcomes),
budget_failures(Budget_results)}.
-file("src/lightspeed/ops/contention_harness.gleam", 125).
?DOC(" M37 budget profile version label.\n").
-spec budget_version_label() -> binary().
budget_version_label() ->
<<"m37.budget.v"/utf8, (erlang:integer_to_binary(1))/binary>>.
-file("src/lightspeed/ops/contention_harness.gleam", 188).
?DOC(" Scenario label.\n").
-spec scenario_label(scenario()) -> binary().
scenario_label(Scenario) ->
case Scenario of
ownership_fencing_contention ->
<<"ownership_fencing_contention"/utf8>>;
lease_renewal_contention ->
<<"lease_renewal_contention"/utf8>>;
takeover_queue_retry_pressure ->
<<"takeover_queue_retry_pressure"/utf8>>;
checkpoint_replay_windows ->
<<"checkpoint_replay_windows"/utf8>>
end.
-file("src/lightspeed/ops/contention_harness.gleam", 198).
?DOC(" Stable pass/fail label.\n").
-spec pass_fail_label(scenario_outcome()) -> binary().
pass_fail_label(Outcome) ->
case erlang:element(3, Outcome) of
true ->
<<"pass"/utf8>>;
false ->
<<"fail"/utf8>>
end.
-file("src/lightspeed/ops/contention_harness.gleam", 206).
?DOC(" Scenario signature accessor.\n").
-spec signature(scenario_outcome()) -> binary().
signature(Outcome) ->
erlang:element(6, Outcome).
-file("src/lightspeed/ops/contention_harness.gleam", 211).
?DOC(" Scenario determinism accessor.\n").
-spec deterministic(scenario_outcome()) -> boolean().
deterministic(Outcome) ->
erlang:element(4, Outcome).
-file("src/lightspeed/ops/contention_harness.gleam", 216).
?DOC(" Scenario invariant accessor.\n").
-spec invariants_met(scenario_outcome()) -> boolean().
invariants_met(Outcome) ->
erlang:element(5, Outcome).
-file("src/lightspeed/ops/contention_harness.gleam", 221).
?DOC(" Scenario accessor.\n").
-spec scenario(scenario_outcome()) -> scenario().
scenario(Outcome) ->
erlang:element(2, Outcome).
-file("src/lightspeed/ops/contention_harness.gleam", 226).
?DOC(" Scenario profile accessor.\n").
-spec profile_metrics(scenario_outcome()) -> metrics().
profile_metrics(Outcome) ->
erlang:element(7, Outcome).
-file("src/lightspeed/ops/contention_harness.gleam", 231).
?DOC(" Report outcomes accessor.\n").
-spec outcomes(report()) -> list(scenario_outcome()).
outcomes(Report) ->
erlang:element(2, Report).
-file("src/lightspeed/ops/contention_harness.gleam", 236).
?DOC(" Report budget-results accessor.\n").
-spec budget_results(report()) -> list(budget_result()).
budget_results(Report) ->
erlang:element(3, Report).
-file("src/lightspeed/ops/contention_harness.gleam", 241).
?DOC(" Failed scenario count.\n").
-spec failed_scenarios(report()) -> integer().
failed_scenarios(Report) ->
erlang:element(4, Report).
-file("src/lightspeed/ops/contention_harness.gleam", 246).
?DOC(" Nondeterministic scenario count.\n").
-spec nondeterministic_failures(report()) -> integer().
nondeterministic_failures(Report) ->
erlang:element(5, Report).
-file("src/lightspeed/ops/contention_harness.gleam", 251).
?DOC(" Invariant failure count.\n").
-spec invariant_failures(report()) -> integer().
invariant_failures(Report) ->
erlang:element(6, Report).
-file("src/lightspeed/ops/contention_harness.gleam", 256).
?DOC(" Failed budget count.\n").
-spec failed_budgets(report()) -> integer().
failed_budgets(Report) ->
erlang:element(7, Report).
-file("src/lightspeed/ops/contention_harness.gleam", 261).
?DOC(" Stable metrics signature.\n").
-spec metrics_signature(metrics()) -> binary().
metrics_signature(Metrics) ->
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"conflicts="/utf8,
(erlang:integer_to_binary(
erlang:element(
2,
Metrics
)
))/binary>>/binary,
":split="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(
3,
Metrics
)
))/binary>>/binary,
":stale="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(
4,
Metrics
)
))/binary>>/binary,
":invalid="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(
5,
Metrics
)
))/binary>>/binary,
":takeovers="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(
6,
Metrics
)
))/binary>>/binary,
":lease_p95_ms="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(7, Metrics)
))/binary>>/binary,
":lease_queue_peak="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(8, Metrics)
))/binary>>/binary,
":takeover_queue_peak="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(9, Metrics)
))/binary>>/binary,
":retries="/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(10, Metrics)))/binary>>/binary,
":checkpoint_window="/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(11, Metrics)))/binary>>/binary,
":replay_window_ms="/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(12, Metrics)))/binary>>.
-file("src/lightspeed/ops/contention_harness.gleam", 287).
?DOC(" Stable report signature.\n").
-spec report_signature(report()) -> binary().
report_signature(Report) ->
Outcome_entries = gleam@list:map(
erlang:element(2, Report),
fun(Outcome) ->
<<<<<<<<<<<<<<<<<<<<(scenario_label(erlang:element(2, Outcome)))/binary,
"="/utf8>>/binary,
(pass_fail_label(Outcome))/binary>>/binary,
":deterministic="/utf8>>/binary,
(bool_label(erlang:element(4, Outcome)))/binary>>/binary,
":invariants="/utf8>>/binary,
(bool_label(erlang:element(5, Outcome)))/binary>>/binary,
":profile="/utf8>>/binary,
(metrics_signature(erlang:element(7, Outcome)))/binary>>/binary,
":"/utf8>>/binary,
(erlang:element(6, Outcome))/binary>>
end
),
Budget_entries = gleam@list:map(
erlang:element(3, Report),
fun(Result) ->
<<<<<<<<(scenario_label(erlang:element(2, Result)))/binary,
"="/utf8>>/binary,
(bool_label(erlang:element(3, Result)))/binary>>/binary,
":"/utf8>>/binary,
(erlang:element(4, Result))/binary>>
end
),
<<<<<<"outcomes="/utf8, (join_with(<<";"/utf8>>, Outcome_entries))/binary>>/binary,
"|budgets="/utf8>>/binary,
(join_with(<<";"/utf8>>, Budget_entries))/binary>>.
-file("src/lightspeed/ops/contention_harness.gleam", 318).
?DOC(" Deterministic snapshot signature for M37 drift gates.\n").
-spec snapshot_signature() -> binary().
snapshot_signature() ->
<<<<<<"m37.snapshot.v"/utf8, (erlang:integer_to_binary(1))/binary>>/binary,
"|"/utf8>>/binary,
(report_signature(run_matrix()))/binary>>.
-file("src/lightspeed/ops/contention_harness.gleam", 326).
?DOC(" Deterministic markdown report for M37 fixture scripts.\n").
-spec snapshot_report_markdown() -> binary().
snapshot_report_markdown() ->
Report = run_matrix(),
Failed = failed_scenarios(Report),
Nondeterministic = nondeterministic_failures(Report),
Failed_invariants = invariant_failures(Report),
Failed_budget_checks = failed_budgets(Report),
Status = case (((Failed =:= 0) andalso (Nondeterministic =:= 0)) andalso (Failed_invariants
=:= 0))
andalso (Failed_budget_checks =:= 0) of
true ->
<<"OK"/utf8>>;
false ->
<<"FAIL"/utf8>>
end,
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"# Contention Fixture Report\n\n"/utf8,
"snapshot_version: "/utf8>>/binary,
(erlang:integer_to_binary(
1
))/binary>>/binary,
"\n"/utf8>>/binary,
"budget_version: "/utf8>>/binary,
(budget_version_label(
))/binary>>/binary,
"\n"/utf8>>/binary,
"status: "/utf8>>/binary,
Status/binary>>/binary,
"\n"/utf8>>/binary,
"failed_scenarios: "/utf8>>/binary,
(erlang:integer_to_binary(
Failed
))/binary>>/binary,
"\n"/utf8>>/binary,
"nondeterministic_failures: "/utf8>>/binary,
(erlang:integer_to_binary(
Nondeterministic
))/binary>>/binary,
"\n"/utf8>>/binary,
"invariant_failures: "/utf8>>/binary,
(erlang:integer_to_binary(
Failed_invariants
))/binary>>/binary,
"\n"/utf8>>/binary,
"failed_budgets: "/utf8>>/binary,
(erlang:integer_to_binary(
Failed_budget_checks
))/binary>>/binary,
"\n\n"/utf8>>/binary,
"snapshot_signature: "/utf8>>/binary,
(snapshot_signature())/binary>>/binary,
"\n\n"/utf8>>/binary,
"report_signature: "/utf8>>/binary,
(report_signature(Report))/binary>>/binary,
"\n"/utf8>>.