wenxiangchao
3 天以前 b544d5cccd76735e034c8055918a50927b437474
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
using System;
using System.Threading;
using System.Threading.Tasks;
 
namespace Aging.ResourceContracts
{
    /// <summary>与现有 OwnerType 数值对齐:Production=0, Maintenance=1。</summary>
    public enum OwnerTypeV3 { Production = 0, Maintenance = 1 }
 
    /// <summary>MVP 相位:Free 可用 / Active 持有 / RecoveryRequired 过期待回收(INV-03)。</summary>
    public enum LeasePhase { Free = 0, Active = 1, RecoveryRequired = 2 }
 
    /// <summary>每资源一张租约凭证;栅栏=(AuthorityId, Epoch, ResourceKey, LeaseId, Generation)。</summary>
    public sealed class LeaseGrant
    {
        public string AuthorityId { get; }
        public string ResourceKey { get; }
        public string LeaseId { get; }
        public string OwnerId { get; }
        public OwnerTypeV3 OwnerType { get; }
        public long Epoch { get; }
        public long Generation { get; }
        public long ExpiresUtcMs { get; }
 
        public LeaseGrant(string authorityId, string resourceKey, string leaseId,
            string ownerId, OwnerTypeV3 ownerType, long epoch, long generation, long expiresUtcMs)
        {
            AuthorityId = authorityId; ResourceKey = resourceKey; LeaseId = leaseId;
            OwnerId = ownerId; OwnerType = ownerType; Epoch = epoch;
            Generation = generation; ExpiresUtcMs = expiresUtcMs;
        }
    }
 
    public sealed class AcquireRequest
    {
        public string OwnerId { get; set; } = "";
        public OwnerTypeV3 OwnerType { get; set; }
        /// <summary>boot_id + pid,同机进程区分。</summary>
        public string ProcessInstanceId { get; set; } = "";
        public string MachineName { get; set; } = Environment.MachineName;
        public int HostProcessId { get; set; } = System.Diagnostics.Process.GetCurrentProcess().Id;
        /// <summary>申请理由(维护会话填操作员与原因,进 lease_history)。</summary>
        public string Reason { get; set; } = "";
        /// <summary>Ordinals 升序、去重后申请(组申请 = 单事务全有全无)。</summary>
        public string[] ResourceKeys { get; set; } = new string[0];
        public int WaitTimeoutMs { get; set; } = 1000;
        public int TtlSeconds { get; set; } = 30;
    }
 
    public enum AcquireResultCode { Acquired, Reused, ConflictHeld, RecoveryBlocked, Timeout }
 
    public sealed class ConflictInfo
    {
        public string OwnerId { get; set; } = "";
        public OwnerTypeV3 OwnerType { get; set; }
        public string MachineName { get; set; } = "";
        public int HostProcessId { get; set; }
        public string Reason { get; set; } = "";
        public long ExpiresUtcMs { get; set; }
    }
 
    public sealed class AcquireOutcome
    {
        public AcquireResultCode Code { get; set; }
        public LeaseGrant[] Grants { get; set; } = new LeaseGrant[0];
        public ConflictInfo? Holder { get; set; }
        /// <summary>RecoveryBlocked 时指向 recovery_checkpoint 的键。</summary>
        public string? RecoveryCheckpointKey { get; set; }
    }
 
    /// <summary>租约协调器:仲裁域唯一入口。实现方:DbLeaseStore。</summary>
    public interface ILeaseCoordinator
    {
        /// <summary>权威域当前 epoch(重启后递增,旧 Grant 自动失效)。</summary>
        long CurrentEpoch { get; }
 
        AcquireOutcome Acquire(AcquireRequest request);
        /// <summary>同 LeaseId+Generation 续期;返回 false=已被回收/超越(本地须熔断)。</summary>
        bool Renew(LeaseGrant grant, int extendSeconds);
        bool Release(LeaseGrant grant, string note);
        ConflictInfo? ProbeConflict(string resourceKey);
        LeasePhase PhaseOf(string resourceKey);
        int SweepExpired();
        /// <summary>RecoveryRequired → Free:宿主完成读回探测后登记证据并放行。</summary>
        bool ApproveRecovery(string resourceKey, string readbackJson, string approvedBy);
        /// <summary>测试用:强制提升 epoch,使所有活跃 Grant 失效。</summary>
        void BumpEpochForTest(string reason);
    }
}