# 인터페이스가 적는 계약 /** * Records a completed migration, only if the fence is still the current one. * *

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. * *

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");