docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
43bccd08a8
commit
b2963105a8
+69
@@ -0,0 +1,69 @@
|
||||
# 조립된 경로에서 갱신과 원장 기록 사이에 있는 것
|
||||
// Still refreshed after execute, but the refresh is no longer what protects the run: the
|
||||
// heartbeat inside the context is. This one only proves the lease survived to the end, before
|
||||
// anything is written to the ledger under it.
|
||||
lock.refresh(template.maxTime());
|
||||
if (!migration.postcondition().isSatisfied(context, result)) {
|
||||
throw MongoOperationRejectedException.of(
|
||||
"migration.postcondition",
|
||||
"migration "
|
||||
+ migration.id()
|
||||
...
|
||||
result.resumePoint().ifPresent(checkpoint -> ledger.saveCheckpoint(checkpoint, lock.fence()));
|
||||
if (result.status() == MongoMigrationResult.Status.COMPLETED && !context.dryRun()) {
|
||||
ledger.recordApplied(
|
||||
migration.id(), migration.checksum(), context.operator(), clock.instant(), lock.fence());
|
||||
}
|
||||
|
||||
# 완료를 만드는 팩토리는 체크포인트를 남기지 않는다
|
||||
/** The migration finished. */
|
||||
public static MongoMigrationResult completed(long processedCount) {
|
||||
return new MongoMigrationResult(Status.COMPLETED, processedCount, null, "");
|
||||
}
|
||||
|
||||
/** The migration made progress and stored a checkpoint to resume from. */
|
||||
public static MongoMigrationResult incomplete(
|
||||
long processedCount, MongoMigrationCheckpoint checkpoint) {
|
||||
return new MongoMigrationResult(
|
||||
Status.INCOMPLETE, processedCount, Objects.requireNonNull(checkpoint, "checkpoint"), "");
|
||||
}
|
||||
|
||||
# 그 갱신이 던지는 것
|
||||
if (stillOwned != 1) {
|
||||
held = false;
|
||||
throw new IllegalStateException(
|
||||
"the migration lease was lost before it could be refreshed; another runner may have "
|
||||
+ "taken it after this one appeared to stall");
|
||||
}
|
||||
# 같은 인터페이스의 다른 잠금 구현이 같은 상황에 던지는 것
|
||||
public void refresh(Duration extension) {
|
||||
Objects.requireNonNull(extension, "extension");
|
||||
if (!held.get()) {
|
||||
throw MongoOperationRejectedException.of(
|
||||
"migration.lock", "the migration lease has been released and cannot be extended");
|
||||
}
|
||||
extend.accept(extension);
|
||||
|
||||
# 다른 원장 구현은 펜스 인자를 쓰지 않는다
|
||||
long fence) {
|
||||
recorded.put(
|
||||
Objects.requireNonNull(migrationId, "migrationId"),
|
||||
new AppliedMigration(migrationId, checksum, operator, appliedAt));
|
||||
}
|
||||
|
||||
# recordApplied 를 부르는 시험 전수
|
||||
MongoMigrationRunnerTest.java:23: ledger.recordApplied(
|
||||
MongoMigrationRunnerTest.java:40: ledger.recordApplied(
|
||||
MongoMigrationLaneTest.java:130: ledger.recordApplied(
|
||||
MongoMigrationLaneTest.java:227: ledger.recordApplied(id, new MongoMigrationChecksum("abc"), "operator", FIXED.instant(), 1L);
|
||||
MongoMigrationLaneTest.java:231: ledger.recordApplied(
|
||||
# 그중 실서버에서 두 번 부르는 시험이 단언하는 것
|
||||
() ->
|
||||
ledger.recordApplied(
|
||||
id, new MongoMigrationChecksum("abc"), "operator", FIXED.instant(), 1L))
|
||||
.as("the unique index, not the read-then-write check, is what makes this impossible")
|
||||
.isInstanceOf(RuntimeException.class);
|
||||
|
||||
# 고유 색인을 만드는 메서드를 부르는 곳 전수
|
||||
test/java/dev/caskeleton/adapter/outbound/mongo/migration/MongoMigrationLaneTest.java
|
||||
main/java/dev/caskeleton/adapter/outbound/mongo/migration/MongoCollectionMigrationLedger.java
|
||||
Reference in New Issue
Block a user