merged with fixes
This commit is contained in:
parent
a9e758b712
commit
2f1818d656
176 changed files with 9000 additions and 907 deletions
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/iamxvbaba/td/tlprofile"
|
||||
"telesrv/internal/observability/dbtrace"
|
||||
"telesrv/internal/postresponse"
|
||||
"telesrv/internal/rpcresult"
|
||||
"telesrv/internal/store"
|
||||
)
|
||||
|
||||
|
|
@ -40,6 +41,7 @@ type connState struct {
|
|||
createdFloor int64
|
||||
seen map[int64]clientMsgRecord // 已处理的 client msg_id,用于幂等和 msgs_state_req
|
||||
order []int64
|
||||
orderHead int
|
||||
minSeen int64
|
||||
maxSeen int64
|
||||
// maxContentMsgID/maxContentSeqNo 是已接受 content 消息的 msg_id / seq_no 高水位,
|
||||
|
|
@ -116,7 +118,7 @@ var errActivationAuthKeyRejected = errors.New("activation auth key no longer exi
|
|||
// 直接复用 current.key/current.salt 解密。任何 provisional 在 claim 建立后、发 required
|
||||
// control 前都会最终回查 AuthKeyStore,使外部撤销与 activation 线性化。
|
||||
// plain 是 serveConn 持有的复用明文缓冲,frame 的 slice 仅在下一帧解密前有效。
|
||||
func (s *Server) handleEncrypted(ctx context.Context, tc transport.Conn, cs *connState, current *Conn, fetchedKey *store.AuthKeyData, b, plain *bin.Buffer) (*Conn, error) {
|
||||
func (s *Server) handleEncrypted(ctx context.Context, tc transport.Conn, cs *connState, current *Conn, remote string, fetchedKey *store.AuthKeyData, b, plain *bin.Buffer) (*Conn, error) {
|
||||
var key crypto.AuthKey
|
||||
var serverSalt int64
|
||||
var authKeyExpiresAt int
|
||||
|
|
@ -161,6 +163,8 @@ func (s *Server) handleEncrypted(ctx context.Context, tc transport.Conn, cs *con
|
|||
} else {
|
||||
current = s.newConn(tc, key, frame.sessionID, serverSalt)
|
||||
}
|
||||
// 记录对端 IP,供绑定设备授权时写入 authorizations.ip(admin 面板可见)。
|
||||
current.setRemoteAddrStr(remote)
|
||||
current.authKeyExpiresAt = authKeyExpiresAt
|
||||
// Same-session evidence is restored as explicit; auth-key metadata is only
|
||||
// an inherited default and can be corrected by the next invokeWithLayer.
|
||||
|
|
@ -904,7 +908,7 @@ func (s *Server) publishRPCResult(
|
|||
priority := rpcResultPriority(method, encoded)
|
||||
encoded.priority = priority
|
||||
if metrics, ok := s.metrics.(RPCResultMetrics); ok {
|
||||
metrics.RPCResultPrepared(method, priority.String(), encoded.uncompressedBytes, len(encoded.body), encoded.compressed)
|
||||
metrics.RPCResultPrepared(method, priority.String(), encoded.uncompressedBytes, encoded.wireSize(), encoded.compressed)
|
||||
}
|
||||
visible := encoded.compressed || priority == outboundPriorityCritical || priority == outboundPriorityBulk
|
||||
return priority, visible
|
||||
|
|
@ -916,21 +920,26 @@ func (s *Server) publishRPCResult(
|
|||
// re-execution hidden behind a local capacity error.
|
||||
retainForReplay := func(encoded *encodedOutboundMessage, admissionErr error) error {
|
||||
if s == nil || s.rpcResults == nil || c == nil || encoded == nil || reqMsgID == 0 {
|
||||
if encoded != nil {
|
||||
encoded.releaseBulkCredit()
|
||||
}
|
||||
return errors.New("rpc result receipt ledger is unavailable")
|
||||
}
|
||||
priority, visible := prepareEncoded(encoded)
|
||||
if owner != nil && !owner.HandOff() {
|
||||
encoded.releaseBulkCredit()
|
||||
return ErrRPCResultFlightInvalid
|
||||
}
|
||||
started := time.Now()
|
||||
encoded.markReplayable()
|
||||
encoded.releaseBulkCredit()
|
||||
// Complete may expose terminal execution only after the old connection
|
||||
// is irreversibly unable to accept another same-generation request.
|
||||
c.fenceUndeliveredRPCResult()
|
||||
s.completeRPCResult(c, reqMsgID, encoded, false)
|
||||
latency := time.Since(started)
|
||||
if metrics, ok := s.metrics.(RPCResultMetrics); ok {
|
||||
metrics.RPCResultDelivered(method, latency, len(encoded.body), admissionErr)
|
||||
metrics.RPCResultDelivered(method, latency, encoded.wireSize(), admissionErr)
|
||||
}
|
||||
resultLogLevel := zap.DebugLevel
|
||||
if visible {
|
||||
|
|
@ -941,14 +950,15 @@ func (s *Server) publishRPCResult(
|
|||
zap.String("method", method), zap.Int64("req_msg_id", reqMsgID),
|
||||
zap.Int64("delivered_req_msg_id", encoded.writtenRequestID()),
|
||||
zap.String("auth_key_id", c.authKeyHex), zap.Int64("session_id", c.sessionID),
|
||||
zap.Int("wire_bytes", len(encoded.body)), zap.Bool("gzip", encoded.compressed),
|
||||
zap.Int("wire_bytes", encoded.wireSize()), zap.Bool("gzip", encoded.compressed),
|
||||
zap.String("priority", priority.String()), zap.Error(admissionErr))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
encoded, reserved, retained, err := s.encodeRPCResultReservedWithHandoffContext(
|
||||
prepareCtx, c, reqMsgID, result, retainForReplay,
|
||||
methodPriority := rpcMethodPriority(method)
|
||||
encoded, reserved, retained, err := s.encodeRPCResultReservedWithPriorityAndHandoffContext(
|
||||
prepareCtx, c, reqMsgID, result, methodPriority, retainForReplay,
|
||||
)
|
||||
if retained {
|
||||
return err
|
||||
|
|
@ -958,11 +968,14 @@ func (s *Server) publishRPCResult(
|
|||
return err
|
||||
}
|
||||
if err != nil {
|
||||
if provider, ok := result.(interface{ exactRPCBulkCredit() *outboundBulkCredit }); ok {
|
||||
provider.exactRPCBulkCredit().release()
|
||||
}
|
||||
s.log.Warn("Encode RPC result failed; publishing INTERNAL",
|
||||
zap.String("method", method), zap.Int64("req_msg_id", reqMsgID), zap.Error(err))
|
||||
afterDelivered = nil
|
||||
encoded, reserved, retained, err = s.encodeRPCResultReservedWithHandoffContext(
|
||||
prepareCtx, c, reqMsgID, &mt.RPCError{ErrorCode: 500, ErrorMessage: "INTERNAL"}, retainForReplay,
|
||||
encoded, reserved, retained, err = s.encodeRPCResultReservedWithPriorityAndHandoffContext(
|
||||
prepareCtx, c, reqMsgID, &mt.RPCError{ErrorCode: 500, ErrorMessage: "INTERNAL"}, methodPriority, retainForReplay,
|
||||
)
|
||||
if retained {
|
||||
return err
|
||||
|
|
@ -973,6 +986,9 @@ func (s *Server) publishRPCResult(
|
|||
}
|
||||
}
|
||||
if encoded == nil || reserved == nil {
|
||||
if provider, ok := result.(interface{ exactRPCBulkCredit() *outboundBulkCredit }); ok {
|
||||
provider.exactRPCBulkCredit().release()
|
||||
}
|
||||
c.fenceUndeliveredRPCResult()
|
||||
return errors.New("rpc result encode completed without tracked retention")
|
||||
}
|
||||
|
|
@ -981,6 +997,7 @@ func (s *Server) publishRPCResult(
|
|||
defer reserved.release()
|
||||
priority, _ := prepareEncoded(encoded)
|
||||
if owner != nil && !owner.HandOff() {
|
||||
encoded.releaseBulkCredit()
|
||||
return ErrRPCResultFlightInvalid
|
||||
}
|
||||
|
||||
|
|
@ -989,7 +1006,7 @@ func (s *Server) publishRPCResult(
|
|||
latency := time.Since(egressStarted)
|
||||
deliveredReqMsgID := encoded.writtenRequestID()
|
||||
if metrics, ok := s.metrics.(RPCResultMetrics); ok {
|
||||
metrics.RPCResultDelivered(method, latency, len(encoded.body), deliveryErr)
|
||||
metrics.RPCResultDelivered(method, latency, encoded.wireSize(), deliveryErr)
|
||||
}
|
||||
if deliveryErr != nil {
|
||||
encoded.markReplayable()
|
||||
|
|
@ -1000,7 +1017,7 @@ func (s *Server) publishRPCResult(
|
|||
zap.String("method", method), zap.Int64("req_msg_id", reqMsgID),
|
||||
zap.Int64("delivered_req_msg_id", deliveredReqMsgID),
|
||||
zap.String("auth_key_id", c.authKeyHex), zap.Int64("session_id", c.sessionID),
|
||||
zap.Int("wire_bytes", len(encoded.body)), zap.Bool("gzip", encoded.compressed),
|
||||
zap.Int("wire_bytes", encoded.wireSize()), zap.Bool("gzip", encoded.compressed),
|
||||
zap.Error(deliveryErr))
|
||||
}
|
||||
return
|
||||
|
|
@ -1012,7 +1029,7 @@ func (s *Server) publishRPCResult(
|
|||
zap.String("method", method), zap.Int64("req_msg_id", reqMsgID),
|
||||
zap.Int64("delivered_req_msg_id", deliveredReqMsgID),
|
||||
zap.String("auth_key_id", c.authKeyHex), zap.Int64("session_id", c.sessionID),
|
||||
zap.Int("wire_bytes", len(encoded.body)), zap.Bool("gzip", encoded.compressed),
|
||||
zap.Int("wire_bytes", encoded.wireSize()), zap.Bool("gzip", encoded.compressed),
|
||||
zap.Duration("egress_latency", latency))
|
||||
}
|
||||
}
|
||||
|
|
@ -1026,7 +1043,7 @@ func (s *Server) publishRPCResult(
|
|||
if checked := s.log.Check(zap.DebugLevel, "RPC result admitted"); checked != nil {
|
||||
checked.Write(
|
||||
zap.String("method", method), zap.Int64("req_msg_id", reqMsgID),
|
||||
zap.Int("wire_bytes", len(encoded.body)), zap.Int("inner_bytes", encoded.uncompressedBytes),
|
||||
zap.Int("wire_bytes", encoded.wireSize()), zap.Int("inner_bytes", encoded.uncompressedBytes),
|
||||
zap.Bool("gzip", encoded.compressed), zap.String("priority", priority.String()))
|
||||
}
|
||||
return nil
|
||||
|
|
@ -1086,7 +1103,7 @@ func (s *Server) sendReplayedRPCResultWithHook(
|
|||
c.fenceUndeliveredRPCResult()
|
||||
return errors.New("nil replayed rpc_result")
|
||||
}
|
||||
attempt, reserved, err := c.cloneRPCResultForRequestReserved(encoded, encoded.reqMsgID, false)
|
||||
attempt, reserved, err := c.cloneRPCResultForRequestReservedContext(ctx, encoded, encoded.reqMsgID, false)
|
||||
if err != nil {
|
||||
c.failOutboundBudget(err)
|
||||
c.fenceUndeliveredRPCResult()
|
||||
|
|
@ -1222,6 +1239,19 @@ func (s *Server) encodeRPCResultReservedWithHandoffContext(
|
|||
reqMsgID int64,
|
||||
result bin.Encoder,
|
||||
handoff rpcResultRetentionHandoff,
|
||||
) (*encodedOutboundMessage, *outboundBodyReservation, bool, error) {
|
||||
return s.encodeRPCResultReservedWithPriorityAndHandoffContext(
|
||||
ctx, c, reqMsgID, result, outboundPriorityNormal, handoff,
|
||||
)
|
||||
}
|
||||
|
||||
func (s *Server) encodeRPCResultReservedWithPriorityAndHandoffContext(
|
||||
ctx context.Context,
|
||||
c *Conn,
|
||||
reqMsgID int64,
|
||||
result bin.Encoder,
|
||||
priority outboundPriority,
|
||||
handoff rpcResultRetentionHandoff,
|
||||
) (*encodedOutboundMessage, *outboundBodyReservation, bool, error) {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
|
|
@ -1237,7 +1267,10 @@ func (s *Server) encodeRPCResultReservedWithHandoffContext(
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
budget := c.outboundMessageBudget(encoded.typeID, false)
|
||||
if priority != outboundPriorityNormal {
|
||||
encoded.priority = priority
|
||||
}
|
||||
budget := c.outboundMessageBudgetForPriority(encoded.typeID, encoded.priority, false)
|
||||
bytes := len(encoded.body)
|
||||
if budget.reserve(bytes) {
|
||||
reserved = &outboundBodyReservation{budget: budget, bytes: bytes}
|
||||
|
|
@ -1286,6 +1319,14 @@ func (s *Server) encodeRPCResultWithoutSlot(ctx context.Context, c *Conn, reqMsg
|
|||
return nil, fmt.Errorf("bind exact layer rpc result: %w", err)
|
||||
}
|
||||
}
|
||||
var replaySource rpcresult.ReplaySource
|
||||
if provider, ok := result.(interface{ exactRPCReplaySource() rpcresult.ReplaySource }); ok {
|
||||
replaySource = provider.exactRPCReplaySource()
|
||||
}
|
||||
var bulkCredit *outboundBulkCredit
|
||||
if provider, ok := result.(interface{ exactRPCBulkCredit() *outboundBulkCredit }); ok {
|
||||
bulkCredit = provider.exactRPCBulkCredit()
|
||||
}
|
||||
// Encode the ordinary exact/no-gzip path directly behind the rpc_result
|
||||
// prefix. This avoids both the old generated Prepare snapshot and another
|
||||
// full-body copy merely to prepend the 12-byte envelope.
|
||||
|
|
@ -1303,9 +1344,14 @@ func (s *Server) encodeRPCResultWithoutSlot(ctx context.Context, c *Conn, reqMsg
|
|||
return nil, fmt.Errorf("%w: body=%d limit=%d", ErrOutboundMessageTooLarge, len(innerBody)+12, maxOutboundBodyBytes)
|
||||
}
|
||||
|
||||
wireInner, compressed, err := encodeAdaptiveRPCResultInner(ctx, nil, innerBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("compress rpc result: %w", err)
|
||||
wireInner := innerBody
|
||||
compressed := false
|
||||
if replaySource == nil {
|
||||
var err error
|
||||
wireInner, compressed, err = encodeAdaptiveRPCResultInner(ctx, nil, innerBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("compress rpc result: %w", err)
|
||||
}
|
||||
}
|
||||
if len(wireInner) > maxOutboundBodyBytes-12 {
|
||||
return nil, fmt.Errorf("%w: body=%d limit=%d", ErrOutboundMessageTooLarge, len(wireInner)+12, maxOutboundBodyBytes)
|
||||
|
|
@ -1322,6 +1368,7 @@ func (s *Server) encodeRPCResultWithoutSlot(ctx context.Context, c *Conn, reqMsg
|
|||
typeID: proto.ResultTypeID, body: body, reqMsgID: reqMsgID,
|
||||
compressed: compressed, uncompressedBytes: len(innerBody), delivery: newRPCResultDelivery(0),
|
||||
layer: layerBinding, layerInvariant: layerInvariantResult,
|
||||
replaySource: replaySource, innerDigest: sha256.Sum256(innerBody), logicalBytes: len(body), bulkCredit: bulkCredit,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -1620,18 +1667,23 @@ func (cs *connState) trackInbound(msgID int64, seqNo int32, content, service boo
|
|||
cs.maxContentSeqNo = seqNo
|
||||
}
|
||||
}
|
||||
cs.order = append(cs.order, msgID)
|
||||
var evicted int64
|
||||
if len(cs.order) < maxTrackedClientMsgIDs {
|
||||
cs.order = append(cs.order, msgID)
|
||||
} else {
|
||||
evicted = cs.order[cs.orderHead]
|
||||
cs.order[cs.orderHead] = msgID
|
||||
cs.orderHead = (cs.orderHead + 1) % len(cs.order)
|
||||
}
|
||||
if msgID < cs.minSeen {
|
||||
cs.minSeen = msgID
|
||||
}
|
||||
if msgID > cs.maxSeen {
|
||||
cs.maxSeen = msgID
|
||||
}
|
||||
if len(cs.order) > maxTrackedClientMsgIDs {
|
||||
oldest := cs.order[0]
|
||||
cs.order = cs.order[1:]
|
||||
delete(cs.seen, oldest)
|
||||
if oldest == cs.minSeen || oldest == cs.maxSeen {
|
||||
if evicted != 0 {
|
||||
delete(cs.seen, evicted)
|
||||
if evicted == cs.minSeen || evicted == cs.maxSeen {
|
||||
cs.recomputeRange()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue