refactor(mtproto): sync redesign RPC replay ownership
This commit is contained in:
parent
7e0f9d1e62
commit
ac0566f779
28 changed files with 1304 additions and 343 deletions
|
|
@ -171,6 +171,10 @@ func notifySessionDestroyed(observer SessionLifecycleObserver, authKeyID [8]byte
|
|||
type SessionManager struct {
|
||||
mu sync.RWMutex
|
||||
bySession map[sessionKey]*Conn
|
||||
// logicalSessions owns MTProto resend state independently of physical Conn
|
||||
// generations. It is bounded by the Server-wide tracked-body budget and a
|
||||
// short offline retention window; ACK and destroy release bodies immediately.
|
||||
logicalSessions map[sessionKey]*logicalSession
|
||||
// claims owns the provisional -> active gap. A claimant is intentionally
|
||||
// absent from every push/online index until its required session control frame
|
||||
// is on the wire and PublishActivation validates the same owner.
|
||||
|
|
@ -188,6 +192,7 @@ type SessionManager struct {
|
|||
pending map[sessionKey][]queuedPush // updates-ready 前暂存的主动推送
|
||||
flushing map[sessionKey]bool // 置位时暂存正在排空的 session;排空完成前推送继续进 pending 保序
|
||||
pendingBudget *outboundTrackedBudget // 未就绪 session 暂存 encoded body 的进程级上限
|
||||
logicalSessionReleased func(sessionKey)
|
||||
|
||||
lifecycle SessionLifecycleObserver
|
||||
log *zap.Logger
|
||||
|
|
@ -200,6 +205,7 @@ func NewSessionManager(log *zap.Logger) *SessionManager {
|
|||
}
|
||||
return &SessionManager{
|
||||
bySession: make(map[sessionKey]*Conn),
|
||||
logicalSessions: make(map[sessionKey]*logicalSession),
|
||||
claims: make(map[sessionKey]*Conn),
|
||||
claimsByAuth: make(map[[8]byte]map[int64]*Conn),
|
||||
byAuthKey: make(map[[8]byte]map[int64]*Conn),
|
||||
|
|
@ -225,6 +231,12 @@ func (m *SessionManager) SetLifecycleObserver(observer SessionLifecycleObserver)
|
|||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
func (m *SessionManager) setLogicalSessionReleaseHook(hook func(sessionKey)) {
|
||||
m.mu.Lock()
|
||||
m.logicalSessionReleased = hook
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// SeedInheritedLayerForRawAuthKey supplies an auth-key-wide default to every
|
||||
// currently unknown active/provisional connection for rawAuthKeyID. Existing
|
||||
// inherited or explicit state is left untouched; only ordered invokeWithLayer
|
||||
|
|
@ -634,6 +646,7 @@ func (m *SessionManager) AbortActivation(c *Conn) {
|
|||
m.deletePendingLocked(key)
|
||||
delete(m.flushing, key)
|
||||
}
|
||||
m.markLogicalSessionOfflineLocked(key, time.Now())
|
||||
owned = true
|
||||
}
|
||||
m.mu.Unlock()
|
||||
|
|
@ -677,6 +690,7 @@ func (m *SessionManager) Unregister(c *Conn) {
|
|||
zap.Int("online", len(m.bySession)),
|
||||
)
|
||||
}
|
||||
m.markLogicalSessionOfflineLocked(key, time.Now())
|
||||
m.mu.Unlock()
|
||||
if observer != nil {
|
||||
observer.SessionOffline(c.authKeyID, c.sessionID, offlineUser, lastForUser)
|
||||
|
|
@ -692,6 +706,7 @@ func (m *SessionManager) DestroySessionForAuthKey(authKeyID [8]byte, sessionID i
|
|||
if !ok {
|
||||
if claim := m.claims[key]; claim != nil {
|
||||
m.retireClaimLocked(key, claim, true)
|
||||
outbound := m.destroyLogicalSessionLocked(key)
|
||||
m.mu.Unlock()
|
||||
if !forceCloseConnBatch([]*Conn{claim}, forceCloseBatchTimeout) {
|
||||
m.log.Warn("Claimed session close exceeded shared deadline",
|
||||
|
|
@ -699,15 +714,23 @@ func (m *SessionManager) DestroySessionForAuthKey(authKeyID [8]byte, sessionID i
|
|||
zap.Int64("session_id", sessionID),
|
||||
)
|
||||
}
|
||||
if outbound != nil {
|
||||
m.releaseLogicalSession(key, outbound)
|
||||
}
|
||||
notifySessionDestroyed(observer, authKeyID, sessionID)
|
||||
return true
|
||||
}
|
||||
m.deletePendingLocked(key)
|
||||
outbound := m.destroyLogicalSessionLocked(key)
|
||||
m.mu.Unlock()
|
||||
if outbound != nil {
|
||||
m.releaseLogicalSession(key, outbound)
|
||||
}
|
||||
notifySessionDestroyed(observer, authKeyID, sessionID)
|
||||
return false
|
||||
}
|
||||
offlineUser := m.retireConnLocked(c, true)
|
||||
outbound := m.destroyLogicalSessionLocked(key)
|
||||
lastForUser := offlineUser != 0 && len(m.byUser[offlineUser]) == 0
|
||||
m.log.Debug("Session destroyed",
|
||||
zap.String("auth_key_id", sessionKeyLog(authKeyID)),
|
||||
|
|
@ -721,6 +744,9 @@ func (m *SessionManager) DestroySessionForAuthKey(authKeyID [8]byte, sessionID i
|
|||
zap.Int64("session_id", sessionID),
|
||||
)
|
||||
}
|
||||
if outbound != nil {
|
||||
m.releaseLogicalSession(key, outbound)
|
||||
}
|
||||
if observer != nil && offlineUser != 0 {
|
||||
observer.SessionOffline(authKeyID, sessionID, offlineUser, lastForUser)
|
||||
}
|
||||
|
|
@ -815,6 +841,7 @@ func (m *SessionManager) bindAuthKeyLocked(c *Conn, key sessionKey, authKeyID [8
|
|||
removeBusinessAuthKeyIndex(m.byBusinessAuthKey, oldAuthKeyID, key)
|
||||
}
|
||||
c.SetBusinessAuthKeyID(authKeyID)
|
||||
m.bindLogicalSessionAuthKeyLocked(key, authKeyID)
|
||||
addBusinessAuthKeyIndex(m.byBusinessAuthKey, authKeyID, key, c)
|
||||
if changed {
|
||||
if oldUserID != 0 {
|
||||
|
|
@ -865,6 +892,7 @@ func (m *SessionManager) CloseSessionsForBusinessAuthKey(authKeyID [8]byte) int
|
|||
m.mu.Lock()
|
||||
var conns []*Conn
|
||||
var events []offlineEvent
|
||||
var logicalRelease []*logicalSession
|
||||
for key, c := range m.businessAuthKeyCandidatesLocked(authKeyID) {
|
||||
if !connUsesBusinessAuthKey(c, authKeyID) {
|
||||
continue
|
||||
|
|
@ -880,6 +908,14 @@ func (m *SessionManager) CloseSessionsForBusinessAuthKey(authKeyID [8]byte) int
|
|||
m.retireClaimLocked(key, c, true)
|
||||
conns = append(conns, c)
|
||||
}
|
||||
for key, logical := range m.logicalSessions {
|
||||
if logical == nil || (key.authKeyID != authKeyID &&
|
||||
(!logical.businessAuthResolved || logical.businessAuthKeyID != authKeyID)) {
|
||||
continue
|
||||
}
|
||||
delete(m.logicalSessions, key)
|
||||
logicalRelease = append(logicalRelease, logical)
|
||||
}
|
||||
observer := m.lifecycle
|
||||
if len(conns) > 0 {
|
||||
m.log.Debug("Force close sessions for revoked auth key",
|
||||
|
|
@ -894,6 +930,9 @@ func (m *SessionManager) CloseSessionsForBusinessAuthKey(authKeyID [8]byte) int
|
|||
zap.Int("sessions", len(conns)),
|
||||
)
|
||||
}
|
||||
for _, logical := range logicalRelease {
|
||||
m.releaseLogicalSession(logical.key, logical.outbound)
|
||||
}
|
||||
if observer != nil {
|
||||
for _, e := range events {
|
||||
observer.SessionOffline(e.key.authKeyID, e.key.sessionID, e.userID, e.last)
|
||||
|
|
@ -2567,6 +2606,7 @@ func (m *SessionManager) RunPendingSweeper(ctx context.Context, interval time.Du
|
|||
case <-ticker.C:
|
||||
}
|
||||
m.sweepStalePending()
|
||||
m.sweepLogicalSessions(time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue