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
+64
@@ -0,0 +1,64 @@
|
||||
# 인터페이스가 적는 계약
|
||||
/**
|
||||
* Records a completed migration, only if the fence is still the current one.
|
||||
*
|
||||
* <p>Conditioned on the fence because the runner that wrote the batches may no longer be the
|
||||
* runner that owns the lease. A ledger entry from a superseded runner says a migration completed
|
||||
* when the work it describes was overwritten by the runner that replaced it.
|
||||
*
|
||||
* @param fence the acquisition token from {@link MongoMigrationLock#fence()}
|
||||
* @throws dev.caskeleton.adapter.outbound.mongo.api.error.MongoOperationRejectedException when a
|
||||
* newer acquisition exists
|
||||
*/
|
||||
void recordApplied(
|
||||
|
||||
# 구현이 하는 일
|
||||
requireCurrentFence(fence, "ledger entry for " + migrationId.value());
|
||||
ledger.insertOne(
|
||||
new Document(MIGRATION_ID, migrationId.value())
|
||||
.append("checksum", checksum.value())
|
||||
.append("operator", operator)
|
||||
.append("appliedAt", Date.from(appliedAt))
|
||||
.append("fence", fence));
|
||||
|
||||
# 그 구현이 부르는 검사와 그 검사의 javadoc
|
||||
/**
|
||||
* Refuses a write from an unfenced lease.
|
||||
*
|
||||
* <p>An unfenced lease cannot prove the writer is still the owner, and the whole point of the
|
||||
* ledger is that it says what actually happened.
|
||||
*/
|
||||
private static void requireCurrentFence(long fence, String what) {
|
||||
if (fence == MongoMigrationLock.UNFENCED) {
|
||||
throw MongoOperationRejectedException.of(
|
||||
"migration.fence",
|
||||
"refusing to write the "
|
||||
+ what
|
||||
|
||||
# 같은 파일의 saveCheckpoint 는 저장된 펜스를 조건으로 건다
|
||||
long replaced =
|
||||
checkpoints
|
||||
.replaceOne(
|
||||
Filters.and(
|
||||
Filters.eq(MIGRATION_ID, checkpoint.migrationId().value()),
|
||||
Filters.or(Filters.exists("fence", false), Filters.lte("fence", fence))),
|
||||
document,
|
||||
new ReplaceOptions().upsert(false))
|
||||
.getMatchedCount();
|
||||
|
||||
# 그리고 중복 키를 잡아 번역한다. 그렇게 된 이유가 주석에 있다
|
||||
// Nor was the refusal itself reachable. With `upsert(true)`, a superseded write matches nothing
|
||||
// and MongoDB attempts an insert, which the unique index on migrationId rejects — so a
|
||||
// superseded runner got a driver-level duplicate-key error instead of the sentence written for
|
||||
// it, and the branch meant to produce that sentence was dead.
|
||||
try {
|
||||
checkpoints.insertOne(document);
|
||||
} catch (MongoWriteException duplicate) {
|
||||
if (duplicate.getError().getCategory() != ErrorCategory.DUPLICATE_KEY) {
|
||||
throw duplicate;
|
||||
}
|
||||
// Either the checkpoint was already there and the fence filter excluded it, or another runner
|
||||
// inserted between the replace and this insert. Both are the same fact about this runner.
|
||||
throw MongoOperationRejectedException.of(
|
||||
"migration.fence",
|
||||
"a newer migration runner owns the lease; this runner's checkpoint write was refused");
|
||||
Reference in New Issue
Block a user