19. 2단계 커밋 코디네이터 장애와 in-doubt 블로킹 (C#)

난이도 최상 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// 시나리오: 서로 다른 두 샤드에 있는 플레이어 간 아이템 교환을 원자적으로 처리하려고
// 2단계 커밋(2PC)을 쓴다. 코디네이터가 두 참여 샤드에 Prepare 를 보내 자원을 잠그고
// 찬성을 받으면 Commit 을 보낸다. 참여자는 Prepare 후 코디네이터의 결정을 기다린다.
//
// 요구사항:
//  - 교환은 원자적이어야 한다(양쪽 다 반영되거나 양쪽 다 취소).
//  - 코디네이터나 참여자가 임의 시점에 죽거나 재시작해도 자원이 영구히 잠기거나
//    한쪽만 반영되는 상태로 남으면 안 된다.
//  - 잠긴 자원은 유한 시간 안에 반드시 해소되어야 한다.
//
// 과제: Execute 와 참여자 흐름을 검토하고, 코디네이터/참여자가 특정 시점에 실패할 때
//       무엇이 잘못되는지, 어떤 조건에서 드러나는지, 어떻게 고칠지 설명하라. (A)(B)(C) 를 보라.

using System.Threading.Tasks;

public interface IParticipant
{
    Task<bool> Prepare(TxOp op);   // 자원 잠그고 찬성/반대 투표
    Task Commit(TxOp op);          // 반영 후 잠금 해제
    Task Abort(TxOp op);           // 취소 후 잠금 해제
}

public sealed class TwoPhaseCommitCoordinator
{
    private readonly IParticipant _a, _b;
    public TwoPhaseCommitCoordinator(IParticipant a, IParticipant b) { _a = a; _b = b; }

    public async Task<bool> Execute(TxOp op)
    {
        bool va = await _a.Prepare(op);
        bool vb = await _b.Prepare(op);                 // (A) 둘 다 찬성해야 진행
        if (!va || !vb) { await _a.Abort(op); await _b.Abort(op); return false; }

        await _a.Commit(op);                             // (B)
        await _b.Commit(op);                             // (C)
        return true;
    }
}

public sealed class TxOp { public long ItemId; public long FromChar; public long ToChar; }
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.