18. 크로스-샤드 비원자 읽기와 이체의 찢긴 스냅샷 (C#)
난이도 최상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 시나리오: 크로스-샤드 집계 읽기 (재화 총량 조회 / 안티치트 감사)
//
// 플레이어 자산은 샤드로 분산 저장된다: 지갑 잔액은 walletShard, 창고/거래중 물품
// 가치는 vaultShard 에 있다. 운영/안티치트 도구는 "플레이어 총 자산"을 두 샤드에서
// 각각 읽어 합산해 보고한다. 한편 거래 처리기는 지갑에서 차감해 창고로 옮기는
// 이체를 수행한다(두 샤드에 걸친 이동).
//
// 요구사항:
// - 총 자산 = walletShard 잔액 + vaultShard 가치. 이 합은 이체가 진행 중이어도
// "돈이 사라지거나 두 번 계산되지 않게" 일관되게 읽혀야 한다(불변식: 총액 보존).
// - 이체와 합산 조회는 서로 다른 노드에서 동시에 일어난다.
//
// 아래 코드의 (A)(B) 지점을 검토하라.
using System.Threading.Tasks;
public interface IShard
{
long ReadBalance(string playerId);
void Apply(string playerId, long delta); // 잔액에 delta 를 더함(음수 가능)
}
public sealed class AssetService
{
private readonly IShard _wallet;
private readonly IShard _vault;
public AssetService(IShard wallet, IShard vault) { _wallet = wallet; _vault = vault; }
// 감사 도구가 호출: 플레이어 총 자산 합산.
public long GetTotalAssets(string playerId)
{
long w = _wallet.ReadBalance(playerId); // (A)
long v = _vault.ReadBalance(playerId);
return w + v;
}
// 거래 처리기가 호출: 지갑 -> 창고로 amount 이동.
public void TransferWalletToVault(string playerId, long amount)
{
_wallet.Apply(playerId, -amount); // (B)
_vault.Apply(playerId, +amount);
}
} 결함 코드 · C++
// 시나리오: 크로스-샤드 집계 읽기 (재화 총량 조회 / 안티치트 감사) (C++)
//
// 플레이어 자산은 샤드로 분산 저장된다: 지갑 잔액은 walletShard, 창고/거래중 물품
// 가치는 vaultShard 에 있다. 감사 도구는 두 샤드에서 각각 읽어 총 자산을 합산한다.
// 거래 처리기는 지갑에서 차감해 창고로 옮기는 이체를 수행한다(두 샤드 이동).
//
// 요구사항:
// - 총 자산 = wallet 잔액 + vault 가치. 이 합은 이체 중에도 "돈이 사라지거나 두 번
// 계산되지 않게" 일관되게 읽혀야 한다(불변식: 총액 보존).
// - 이체와 합산 조회는 서로 다른 노드에서 동시에 일어난다.
//
// 아래 코드의 (A)(B) 지점을 검토하라.
#include <cstdint>
#include <string>
struct IShard {
virtual long long readBalance(const std::string& playerId) = 0;
virtual void apply(const std::string& playerId, long long delta) = 0; // 잔액에 delta
virtual ~IShard() = default;
};
class AssetService {
public:
AssetService(IShard& wallet, IShard& vault) : wallet_(wallet), vault_(vault) {}
// 감사 도구가 호출: 총 자산 합산.
long long getTotalAssets(const std::string& playerId) {
long long w = wallet_.readBalance(playerId); // (A)
long long v = vault_.readBalance(playerId);
return w + v;
}
// 거래 처리기가 호출: 지갑 -> 창고로 amount 이동.
void transferWalletToVault(const std::string& playerId, long long amount) {
wallet_.apply(playerId, -amount); // (B)
vault_.apply(playerId, +amount);
}
private:
IShard& wallet_;
IShard& vault_;
};
int main() { return 0; } 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.