fix: sync protocol and discussion stability fixes
This commit is contained in:
parent
9f73dc20da
commit
aa21bd04e1
43 changed files with 7258 additions and 503 deletions
|
|
@ -30,11 +30,14 @@ type rpcResultCacheEntry struct {
|
|||
expiresAt time.Time
|
||||
}
|
||||
|
||||
// rpcResultCache 缓存已回发的 rpc_result(按 auth_key+session+req_msg_id),用于
|
||||
// 跨连接重放重复请求。encodedOutboundMessage 构造后不可变(push fan-out 与 pending
|
||||
// resend 均依赖该契约),因此 Get/Put 直接共享指针,不做防御性拷贝。
|
||||
// rpcResultCache 缓存已有交付证明的 rpc_result(按 auth_key+session+req_msg_id),
|
||||
// 用于跨连接重放重复请求。Put 的调用方必须先证明结果已物理写出,或原 logical Conn
|
||||
// 已不可逆 fenced;绝不能发布“Conn 仍 current/open 但结果尚未上 wire”的完成态。
|
||||
// encodedOutboundMessage 构造后不可变(push fan-out 与 pending resend 均依赖该契约),
|
||||
// 因此 Get/Put 直接共享指针,不做防御性拷贝。
|
||||
type rpcResultCache struct {
|
||||
shards [rpcResultCacheShards]rpcResultCacheShard
|
||||
shards [rpcResultCacheShards]rpcResultCacheShard
|
||||
flightLimit rpcResultFlightLimit
|
||||
}
|
||||
|
||||
type rpcResultCacheShard struct {
|
||||
|
|
@ -46,13 +49,25 @@ type rpcResultCacheShard struct {
|
|||
bytes int
|
||||
order *list.List
|
||||
byKey map[rpcResultCacheKey]*list.Element
|
||||
// pending is deliberately independent from the completed-result order/byKey
|
||||
// cache. In-flight owners and waiters must not disappear when completed
|
||||
// results expire or are trimmed under entry/byte pressure.
|
||||
pending map[rpcResultCacheKey]*rpcResultFlight
|
||||
}
|
||||
|
||||
func newRPCResultCache(now func() time.Time) *rpcResultCache {
|
||||
return newRPCResultCacheWithFlightLimit(now, rpcResultFlightDefaultMaxPending)
|
||||
}
|
||||
|
||||
func newRPCResultCacheWithFlightLimit(now func() time.Time, maxPending int) *rpcResultCache {
|
||||
if now == nil {
|
||||
now = time.Now
|
||||
}
|
||||
if maxPending <= 0 {
|
||||
maxPending = rpcResultFlightDefaultMaxPending
|
||||
}
|
||||
c := &rpcResultCache{}
|
||||
c.flightLimit.max = int64(maxPending)
|
||||
for i := range c.shards {
|
||||
s := &c.shards[i]
|
||||
s.now = now
|
||||
|
|
@ -61,6 +76,7 @@ func newRPCResultCache(now func() time.Time) *rpcResultCache {
|
|||
s.maxBytes = rpcResultCacheMaxBytes / rpcResultCacheShards
|
||||
s.order = list.New()
|
||||
s.byKey = make(map[rpcResultCacheKey]*list.Element)
|
||||
s.pending = make(map[rpcResultCacheKey]*rpcResultFlight)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
|
@ -102,28 +118,32 @@ func (c *rpcResultCache) Put(authKeyID [8]byte, sessionID, reqMsgID int64, encod
|
|||
key := rpcResultCacheKey{authKeyID: authKeyID, sessionID: sessionID, reqMsgID: reqMsgID}
|
||||
s := c.shard(key)
|
||||
size := len(encoded.body)
|
||||
if s.maxBytes > 0 && size > s.maxBytes {
|
||||
return
|
||||
}
|
||||
cacheable := s.maxBytes <= 0 || size <= s.maxBytes
|
||||
now := s.now()
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.expireLocked(now)
|
||||
if elem, ok := s.byKey[key]; ok {
|
||||
s.removeElement(elem)
|
||||
if cacheable {
|
||||
s.expireLocked(now)
|
||||
if elem, ok := s.byKey[key]; ok {
|
||||
s.removeElement(elem)
|
||||
}
|
||||
entry := &rpcResultCacheEntry{
|
||||
key: key,
|
||||
encoded: encoded,
|
||||
size: size,
|
||||
expiresAt: now.Add(s.ttl),
|
||||
}
|
||||
elem := s.order.PushBack(entry)
|
||||
s.byKey[key] = elem
|
||||
s.bytes += size
|
||||
s.trimLocked()
|
||||
}
|
||||
entry := &rpcResultCacheEntry{
|
||||
key: key,
|
||||
encoded: encoded,
|
||||
size: size,
|
||||
expiresAt: now.Add(s.ttl),
|
||||
}
|
||||
elem := s.order.PushBack(entry)
|
||||
s.byKey[key] = elem
|
||||
s.bytes += size
|
||||
s.trimLocked()
|
||||
// Resolve the independent in-flight entry only after the completed cache has
|
||||
// been published. Waiters awakened by this close can therefore immediately
|
||||
// observe either the shared encoded result or the completed Get entry.
|
||||
c.completeRPCResultFlightLocked(s, key, encoded)
|
||||
}
|
||||
|
||||
func (s *rpcResultCacheShard) expireLocked(now time.Time) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue