1f2e74acca
- 完善 stream/bulk DataID 分配、预留和双向命名空间,修复并发打开及 dedicated/shared 回退时的 ID 冲突 - 将收发、回复、恢复任务和 sidecar 绑定原始会话与物理连接,防止重连后的旧消息误操作新连接 - 加强 close/reset 身份校验及实例移除检查,修复 dedicated attach 失败、通道引用和资源回收竞态 - 收紧批量发送器停止准入,确保在途入队完成后统一清理请求、缓冲区和等待者 - 修复 record 满队列死锁、取消时序号消耗及关闭竞态,确保关闭有界并返回真实错误 - 增加协商式 record 逻辑半关闭,保留反向 ACK;通过 reset 传递 RecordFailure,避免背压掩盖原始失败原因 - 补齐帧长度、批次数量、序号溢出和未确认窗口校验,提前拒绝超限数据并按字节预算拆批 - 为入站分发增加全局及单连接的条数、字节预算和阻塞背压,关闭时唤醒等待者,消除正常断连日志噪音 - 完善 bulk 窗口释放失败处理与传输诊断,补充并发、重连、背压、协议边界及真实 TCP 回归覆盖
1181 lines
32 KiB
Go
1181 lines
32 KiB
Go
package notify
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type BulkOpenRequest struct {
|
|
BulkID string
|
|
DataID uint64
|
|
FastPathVersion uint8
|
|
Range BulkRange
|
|
Metadata BulkMetadata
|
|
ReadTimeout time.Duration
|
|
WriteTimeout time.Duration
|
|
Dedicated bool
|
|
DedicatedLaneID uint32
|
|
AttachToken string
|
|
ChunkSize int
|
|
WindowBytes int
|
|
MaxInFlight int
|
|
}
|
|
|
|
type BulkOpenResponse struct {
|
|
BulkID string
|
|
DataID uint64
|
|
FastPathVersion uint8
|
|
Accepted bool
|
|
Dedicated bool
|
|
AttachToken string
|
|
TransportGeneration uint64
|
|
Error string
|
|
}
|
|
|
|
type BulkCloseRequest struct {
|
|
BulkID string
|
|
DataID uint64
|
|
Full bool
|
|
}
|
|
|
|
type BulkCloseResponse struct {
|
|
BulkID string
|
|
Accepted bool
|
|
Error string
|
|
}
|
|
|
|
type BulkResetRequest struct {
|
|
BulkID string
|
|
DataID uint64
|
|
Error string
|
|
}
|
|
|
|
type BulkResetResponse struct {
|
|
BulkID string
|
|
Accepted bool
|
|
Error string
|
|
}
|
|
|
|
type BulkReadyRequest struct {
|
|
BulkID string
|
|
DataID uint64
|
|
Error string
|
|
}
|
|
|
|
type BulkReadyResponse struct {
|
|
BulkID string
|
|
Accepted bool
|
|
Error string
|
|
}
|
|
|
|
type BulkReleaseRequest struct {
|
|
BulkID string
|
|
DataID uint64
|
|
Bytes int64
|
|
Chunks int
|
|
}
|
|
|
|
func bindClientBulkControl(c *ClientCommon) {
|
|
if c == nil {
|
|
return
|
|
}
|
|
c.SetLink(BulkOpenSignalKey, func(msg *Message) {
|
|
c.handleInboundBulkOpen(msg)
|
|
})
|
|
c.SetLink(BulkCloseSignalKey, func(msg *Message) {
|
|
c.handleInboundBulkClose(msg)
|
|
})
|
|
c.SetLink(BulkResetSignalKey, func(msg *Message) {
|
|
c.handleInboundBulkReset(msg)
|
|
})
|
|
c.SetLink(BulkReadySignalKey, func(msg *Message) {
|
|
c.handleInboundBulkReady(msg)
|
|
})
|
|
c.SetLink(BulkReleaseSignalKey, func(msg *Message) {
|
|
c.handleInboundBulkRelease(msg)
|
|
})
|
|
}
|
|
|
|
func bindServerBulkControl(s *ServerCommon) {
|
|
if s == nil {
|
|
return
|
|
}
|
|
s.SetLink(BulkOpenSignalKey, func(msg *Message) {
|
|
s.handleInboundBulkOpen(msg)
|
|
})
|
|
s.SetLink(BulkCloseSignalKey, func(msg *Message) {
|
|
s.handleInboundBulkClose(msg)
|
|
})
|
|
s.SetLink(BulkResetSignalKey, func(msg *Message) {
|
|
s.handleInboundBulkReset(msg)
|
|
})
|
|
s.SetLink(BulkReadySignalKey, func(msg *Message) {
|
|
s.handleInboundBulkReady(msg)
|
|
})
|
|
s.SetLink(BulkReleaseSignalKey, func(msg *Message) {
|
|
s.handleInboundBulkRelease(msg)
|
|
})
|
|
}
|
|
|
|
func bulkAcceptInfoFromClientBulk(bulk *bulkHandle) BulkAcceptInfo {
|
|
if bulk == nil {
|
|
return BulkAcceptInfo{}
|
|
}
|
|
return BulkAcceptInfo{
|
|
ID: bulk.ID(),
|
|
Range: bulk.Range(),
|
|
Metadata: bulk.Metadata(),
|
|
Dedicated: bulk.Dedicated(),
|
|
TransportGeneration: bulk.TransportGeneration(),
|
|
Bulk: bulk,
|
|
}
|
|
}
|
|
|
|
func bulkAcceptInfoFromServerBulk(bulk *bulkHandle, logical *LogicalConn, transport *TransportConn) BulkAcceptInfo {
|
|
if bulk == nil {
|
|
return BulkAcceptInfo{}
|
|
}
|
|
if logical == nil {
|
|
logical = bulk.LogicalConn()
|
|
}
|
|
if transport == nil {
|
|
transport = bulk.TransportConn()
|
|
}
|
|
return BulkAcceptInfo{
|
|
ID: bulk.ID(),
|
|
Range: bulk.Range(),
|
|
Metadata: bulk.Metadata(),
|
|
Dedicated: bulk.Dedicated(),
|
|
LogicalConn: logical,
|
|
TransportConn: transport,
|
|
TransportGeneration: bulk.TransportGeneration(),
|
|
Bulk: bulk,
|
|
}
|
|
}
|
|
|
|
func dispatchBulkAccept(handler func(BulkAcceptInfo) error, bulk *bulkHandle, info BulkAcceptInfo) error {
|
|
if bulk == nil {
|
|
return errBulkNotFound
|
|
}
|
|
if !bulk.acceptDispatchAllowed() {
|
|
if resetErr := bulk.resetErrSnapshot(); resetErr != nil {
|
|
return resetErr
|
|
}
|
|
err := transportDetachedErrorForTransport(bulk.TransportConn())
|
|
bulk.markReset(err)
|
|
return err
|
|
}
|
|
if !bulk.markAcceptDispatched() {
|
|
return nil
|
|
}
|
|
var dispatchErr error
|
|
defer func() {
|
|
bulk.finishAcceptDispatch(dispatchErr)
|
|
}()
|
|
if handler == nil {
|
|
dispatchErr = errBulkHandlerNotConfigured
|
|
bulk.markReset(dispatchErr)
|
|
return dispatchErr
|
|
}
|
|
if err := handler(info); err != nil {
|
|
dispatchErr = err
|
|
bulk.markReset(dispatchErr)
|
|
return dispatchErr
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *ClientCommon) clientBulkAcceptReadyNotifier(bulk *bulkHandle) func(error) {
|
|
route := bulk.clientSessionRouteSnapshot()
|
|
return func(readyErr error) {
|
|
if c == nil || bulk == nil {
|
|
return
|
|
}
|
|
req := BulkReadyRequest{
|
|
BulkID: bulk.ID(),
|
|
DataID: bulk.dataIDSnapshot(),
|
|
}
|
|
if readyErr != nil {
|
|
req.Error = readyErr.Error()
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), defaultBulkAcceptReadyTimeout)
|
|
defer cancel()
|
|
if _, err := sendBulkReadyClientAtRoute(ctx, c, route, req); err != nil && bulk.Context().Err() == nil {
|
|
bulk.markReset(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func sendBulkReadyServer(ctx context.Context, s *ServerCommon, logical *LogicalConn, transport *TransportConn, req BulkReadyRequest) error {
|
|
if s == nil {
|
|
return errBulkServerNil
|
|
}
|
|
if transport != nil {
|
|
_, err := sendBulkReadyServerTransport(ctx, s, transport, req)
|
|
return err
|
|
}
|
|
if logical == nil {
|
|
return errBulkLogicalConnNil
|
|
}
|
|
_, err := sendBulkReadyServerLogical(ctx, s, logical, req)
|
|
return err
|
|
}
|
|
|
|
func (s *ServerCommon) serverBulkAcceptReadyNotifier(bulk *bulkHandle, logical *LogicalConn, transport *TransportConn) func(error) {
|
|
return func(readyErr error) {
|
|
if s == nil || bulk == nil {
|
|
return
|
|
}
|
|
req := BulkReadyRequest{
|
|
BulkID: bulk.ID(),
|
|
DataID: bulk.dataIDSnapshot(),
|
|
}
|
|
if readyErr != nil {
|
|
req.Error = readyErr.Error()
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), defaultBulkAcceptReadyTimeout)
|
|
defer cancel()
|
|
if err := sendBulkReadyServer(ctx, s, logical, transport, req); err != nil && bulk.Context().Err() == nil {
|
|
bulk.markReset(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *ClientCommon) startClientBulkAcceptDispatch(bulk *bulkHandle) {
|
|
if c == nil || bulk == nil {
|
|
return
|
|
}
|
|
bulk.setAcceptNotify(c.clientBulkAcceptReadyNotifier(bulk))
|
|
go func() {
|
|
_ = c.dispatchClientBulkAccept(bulk)
|
|
}()
|
|
}
|
|
|
|
func (s *ServerCommon) startServerBulkAcceptDispatch(bulk *bulkHandle, logical *LogicalConn, transport *TransportConn) {
|
|
if s == nil || bulk == nil {
|
|
return
|
|
}
|
|
if logical == nil {
|
|
logical = bulk.LogicalConn()
|
|
}
|
|
if transport == nil {
|
|
transport = bulk.TransportConn()
|
|
}
|
|
bulk.setAcceptNotify(s.serverBulkAcceptReadyNotifier(bulk, logical, transport))
|
|
go func() {
|
|
_ = s.dispatchServerBulkAccept(bulk, logical, transport)
|
|
}()
|
|
}
|
|
|
|
func (c *ClientCommon) dispatchClientBulkAccept(bulk *bulkHandle) error {
|
|
if c == nil {
|
|
return errBulkClientNil
|
|
}
|
|
runtime := c.getBulkRuntime()
|
|
if runtime == nil {
|
|
return errBulkRuntimeNil
|
|
}
|
|
return dispatchBulkAccept(runtime.handlerSnapshot(), bulk, bulkAcceptInfoFromClientBulk(bulk))
|
|
}
|
|
|
|
func (s *ServerCommon) dispatchServerBulkAccept(bulk *bulkHandle, logical *LogicalConn, transport *TransportConn) error {
|
|
if s == nil {
|
|
return errBulkServerNil
|
|
}
|
|
runtime := s.getBulkRuntime()
|
|
if runtime == nil {
|
|
return errBulkRuntimeNil
|
|
}
|
|
return dispatchBulkAccept(runtime.handlerSnapshot(), bulk, bulkAcceptInfoFromServerBulk(bulk, logical, transport))
|
|
}
|
|
|
|
func (c *ClientCommon) handleInboundBulkOpen(msg *Message) {
|
|
req, err := decodeBulkOpenRequest(msg)
|
|
resp := BulkOpenResponse{
|
|
BulkID: req.BulkID,
|
|
DataID: req.DataID,
|
|
FastPathVersion: negotiateBulkFastPathVersion(req.FastPathVersion),
|
|
Dedicated: req.Dedicated,
|
|
}
|
|
if err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
route := msg.clientRoute
|
|
if !route.bound() {
|
|
route = c.clientSessionRouteSnapshot()
|
|
}
|
|
if err := c.ensureClientSessionRouteSendReady(route); err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if req.Dedicated {
|
|
if err := clientDedicatedBulkSupportError(c); err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
}
|
|
runtime := c.getBulkRuntime()
|
|
if runtime == nil {
|
|
resp.Error = errBulkRuntimeNil.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
scope := clientFileScope()
|
|
if existing, ok := runtime.lookup(scope, req.BulkID); ok && !existing.acceptsClientSessionRoute(route) {
|
|
existing.markReset(transportDetachedSessionEpochError())
|
|
}
|
|
if req.Dedicated && req.AttachToken == "" {
|
|
req.AttachToken = newBulkAttachToken()
|
|
}
|
|
resp.AttachToken = req.AttachToken
|
|
bulk := newBulkHandle(clientSessionRouteContext(route), runtime, scope, req, route.epoch, nil, nil, 0, clientBulkCloseSender(c), clientBulkResetSender(c), clientBulkDataSender(c, route), clientBulkWriteSender(c, route), clientBulkReleaseSender(c))
|
|
bulk.setClientSnapshotOwner(c)
|
|
bulk.setClientSessionRoute(route)
|
|
if req.Dedicated {
|
|
if err := c.retainBulkDedicatedLaneAtRoute(bulk.dedicatedLaneIDSnapshot(), route); err != nil {
|
|
// newBulkHandle starts its write/release workers before the lane
|
|
// retain can fail. Reset the unadopted candidate so those workers and
|
|
// its context are reclaimed; no lane lease was acquired yet.
|
|
bulk.markReset(err)
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
bulk.markDedicatedLaneReserved()
|
|
}
|
|
if err := runtime.adoptInbound(scope, bulk); err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if err := c.ensureClientSessionRouteSendReady(route); err != nil {
|
|
// Reattach may have won the race after the preflight check. Remove the
|
|
// just-registered handle before any handler or sidecar side effect.
|
|
runtime.remove(scope, bulk)
|
|
bulk.markReset(err)
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if req.Dedicated {
|
|
if err := c.attachDedicatedBulkSidecar(context.Background(), bulk); err != nil {
|
|
bulk.markReset(err)
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
resp.Accepted = true
|
|
resp.DataID = bulk.dataIDSnapshot()
|
|
resp.TransportGeneration = bulk.TransportGeneration()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
c.startClientBulkAcceptDispatch(bulk)
|
|
return
|
|
}
|
|
if err := c.dispatchClientBulkAccept(bulk); err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
resp.Accepted = true
|
|
resp.DataID = bulk.dataIDSnapshot()
|
|
resp.TransportGeneration = bulk.TransportGeneration()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
}
|
|
|
|
func (s *ServerCommon) handleInboundBulkOpen(msg *Message) {
|
|
req, err := decodeBulkOpenRequest(msg)
|
|
resp := BulkOpenResponse{
|
|
BulkID: req.BulkID,
|
|
DataID: req.DataID,
|
|
FastPathVersion: negotiateBulkFastPathVersion(req.FastPathVersion),
|
|
Dedicated: req.Dedicated,
|
|
}
|
|
if err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
runtime := s.getBulkRuntime()
|
|
if runtime == nil {
|
|
resp.Error = errBulkRuntimeNil.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
logical := messageLogicalConnSnapshot(msg)
|
|
if logical == nil {
|
|
resp.Error = errBulkLogicalConnNil.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
transport := messageTransportConnSnapshot(msg)
|
|
if transport != nil && !transport.IsCurrent() {
|
|
resp.Error = transportDetachedErrorForTransport(transport).Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if req.Dedicated {
|
|
if err := logicalDedicatedBulkSupportError(logical); err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if transport != nil {
|
|
if err := transportDedicatedBulkSupportError(transport); err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
scope := serverFileScope(logical)
|
|
if existing, ok := runtime.lookup(scope, req.BulkID); ok && !existing.acceptsTransportGeneration(transport) {
|
|
existing.markReset(transportDetachedGenerationMismatchError(existing.TransportGeneration(), transport))
|
|
}
|
|
if req.Dedicated && req.AttachToken == "" {
|
|
req.AttachToken = newBulkAttachToken()
|
|
}
|
|
resp.AttachToken = req.AttachToken
|
|
bulk := newBulkHandle(logical.stopContextSnapshot(), runtime, scope, req, 0, logical, transport, bulkTransportGeneration(logical, transport), serverBulkCloseSender(s, logical, transport), serverBulkResetSender(s, logical, transport), serverBulkDataSender(s, transport), serverBulkWriteSender(s, logical, transport), serverBulkReleaseSender(s, logical, transport))
|
|
if err := runtime.adoptInbound(scope, bulk); err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if transport != nil && !transport.IsCurrent() {
|
|
// Reattach may have won the race after the preflight check. Remove the
|
|
// just-registered handle before any handler or sidecar side effect.
|
|
runtime.remove(scope, bulk)
|
|
bulk.markReset(transportDetachedErrorForTransport(transport))
|
|
resp.Error = transportDetachedErrorForTransport(transport).Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
s.attachServerDedicatedSidecarIfExists(logical, bulk)
|
|
if runtime.handlerSnapshot() == nil {
|
|
bulk.markReset(errBulkHandlerNotConfigured)
|
|
resp.Error = errBulkHandlerNotConfigured.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if req.Dedicated {
|
|
resp.Accepted = true
|
|
resp.DataID = bulk.dataIDSnapshot()
|
|
resp.TransportGeneration = bulk.TransportGeneration()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
if bulk.dedicatedAttachedSnapshot() {
|
|
s.startServerBulkAcceptDispatch(bulk, logical, messageTransportConnSnapshot(msg))
|
|
}
|
|
return
|
|
}
|
|
if err := s.dispatchServerBulkAccept(bulk, logical, transport); err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
resp.Accepted = true
|
|
resp.DataID = bulk.dataIDSnapshot()
|
|
resp.TransportGeneration = bulk.TransportGeneration()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
}
|
|
|
|
func (c *ClientCommon) handleInboundBulkClose(msg *Message) {
|
|
req, err := decodeBulkCloseRequest(msg)
|
|
resp := BulkCloseResponse{BulkID: req.BulkID}
|
|
if err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
runtime := c.getBulkRuntime()
|
|
if runtime == nil {
|
|
resp.Error = errBulkRuntimeNil.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
bulk, ok := runtime.lookupControl(clientFileScope(), req.BulkID, req.DataID)
|
|
if !ok {
|
|
resp.Error = errBulkNotFound.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if !bulk.acceptsClientSessionRoute(msg.clientRoute) {
|
|
resp.Error = transportDetachedSessionEpochError().Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if req.Full {
|
|
bulk.markPeerClosed()
|
|
} else {
|
|
bulk.markRemoteClosed()
|
|
}
|
|
resp.Accepted = true
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
}
|
|
|
|
func (s *ServerCommon) handleInboundBulkClose(msg *Message) {
|
|
req, err := decodeBulkCloseRequest(msg)
|
|
resp := BulkCloseResponse{BulkID: req.BulkID}
|
|
if err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
runtime := s.getBulkRuntime()
|
|
if runtime == nil {
|
|
resp.Error = errBulkRuntimeNil.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
logical := messageLogicalConnSnapshot(msg)
|
|
scope := serverFileScope(logical)
|
|
bulk, ok := runtime.lookupControl(scope, req.BulkID, req.DataID)
|
|
if !ok {
|
|
resp.Error = errBulkNotFound.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if !bulk.acceptsTransportGeneration(messageTransportConnSnapshot(msg)) {
|
|
resp.Error = transportDetachedGenerationMismatchError(bulk.TransportGeneration(), messageTransportConnSnapshot(msg)).Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if req.Full {
|
|
bulk.markPeerClosed()
|
|
} else {
|
|
bulk.markRemoteClosed()
|
|
}
|
|
resp.Accepted = true
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
}
|
|
|
|
func (c *ClientCommon) handleInboundBulkReset(msg *Message) {
|
|
req, err := decodeBulkResetRequest(msg)
|
|
resp := BulkResetResponse{BulkID: req.BulkID}
|
|
if err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
runtime := c.getBulkRuntime()
|
|
if runtime == nil {
|
|
resp.Error = errBulkRuntimeNil.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
bulk, ok := runtime.lookupControl(clientFileScope(), req.BulkID, req.DataID)
|
|
if !ok {
|
|
resp.Error = errBulkNotFound.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if !bulk.acceptsClientSessionRoute(msg.clientRoute) {
|
|
resp.Error = transportDetachedSessionEpochError().Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if resp.BulkID == "" {
|
|
resp.BulkID = bulk.ID()
|
|
}
|
|
bulk.markReset(bulkResetError(bulkRemoteResetError(req.Error)))
|
|
resp.Accepted = true
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
}
|
|
|
|
func (c *ClientCommon) handleInboundBulkRelease(msg *Message) {
|
|
req, err := decodeBulkReleaseRequest(msg)
|
|
if err != nil {
|
|
return
|
|
}
|
|
runtime := c.getBulkRuntime()
|
|
if runtime == nil {
|
|
return
|
|
}
|
|
bulk, ok := runtime.lookupControl(clientFileScope(), req.BulkID, req.DataID)
|
|
if !ok {
|
|
return
|
|
}
|
|
if !bulk.acceptsClientSessionRoute(msg.clientRoute) {
|
|
return
|
|
}
|
|
bulk.releaseOutboundWindow(req.Bytes, req.Chunks)
|
|
}
|
|
|
|
func (c *ClientCommon) handleInboundBulkReady(msg *Message) {
|
|
req, err := decodeBulkReadyRequest(msg)
|
|
resp := BulkReadyResponse{BulkID: req.BulkID}
|
|
if err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
runtime := c.getBulkRuntime()
|
|
if runtime == nil {
|
|
resp.Error = errBulkRuntimeNil.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
bulk, ok := runtime.lookupControl(clientFileScope(), req.BulkID, req.DataID)
|
|
if !ok {
|
|
resp.Error = errBulkNotFound.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if !bulk.acceptsClientSessionRoute(msg.clientRoute) {
|
|
resp.Error = transportDetachedSessionEpochError().Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if resp.BulkID == "" {
|
|
resp.BulkID = bulk.ID()
|
|
}
|
|
readyErr := bulkReadyRemoteError(req.Error)
|
|
bulk.markAcceptReady(readyErr)
|
|
if readyErr != nil {
|
|
bulk.markReset(readyErr)
|
|
}
|
|
resp.Accepted = true
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
}
|
|
|
|
func (s *ServerCommon) handleInboundBulkReset(msg *Message) {
|
|
req, err := decodeBulkResetRequest(msg)
|
|
resp := BulkResetResponse{BulkID: req.BulkID}
|
|
if err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
runtime := s.getBulkRuntime()
|
|
if runtime == nil {
|
|
resp.Error = errBulkRuntimeNil.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
logical := messageLogicalConnSnapshot(msg)
|
|
scope := serverFileScope(logical)
|
|
bulk, ok := runtime.lookupControl(scope, req.BulkID, req.DataID)
|
|
if !ok {
|
|
resp.Error = errBulkNotFound.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
transport := messageTransportConnSnapshot(msg)
|
|
if !bulk.acceptsTransportGeneration(transport) {
|
|
resp.Error = transportDetachedGenerationMismatchError(bulk.TransportGeneration(), transport).Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if resp.BulkID == "" {
|
|
resp.BulkID = bulk.ID()
|
|
}
|
|
bulk.markReset(bulkResetError(bulkRemoteResetError(req.Error)))
|
|
resp.Accepted = true
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
}
|
|
|
|
func (s *ServerCommon) handleInboundBulkReady(msg *Message) {
|
|
req, err := decodeBulkReadyRequest(msg)
|
|
resp := BulkReadyResponse{BulkID: req.BulkID}
|
|
if err != nil {
|
|
resp.Error = err.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
runtime := s.getBulkRuntime()
|
|
if runtime == nil {
|
|
resp.Error = errBulkRuntimeNil.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
logical := messageLogicalConnSnapshot(msg)
|
|
scope := serverFileScope(logical)
|
|
bulk, ok := runtime.lookupControl(scope, req.BulkID, req.DataID)
|
|
if !ok {
|
|
resp.Error = errBulkNotFound.Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
transport := messageTransportConnSnapshot(msg)
|
|
if !bulk.acceptsTransportGeneration(transport) {
|
|
resp.Error = transportDetachedGenerationMismatchError(bulk.TransportGeneration(), transport).Error()
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
return
|
|
}
|
|
if resp.BulkID == "" {
|
|
resp.BulkID = bulk.ID()
|
|
}
|
|
readyErr := bulkReadyRemoteError(req.Error)
|
|
bulk.markAcceptReady(readyErr)
|
|
if readyErr != nil {
|
|
bulk.markReset(readyErr)
|
|
}
|
|
resp.Accepted = true
|
|
replyBulkControlIfNeeded(msg, resp)
|
|
}
|
|
|
|
func (s *ServerCommon) handleInboundBulkRelease(msg *Message) {
|
|
req, err := decodeBulkReleaseRequest(msg)
|
|
if err != nil {
|
|
return
|
|
}
|
|
runtime := s.getBulkRuntime()
|
|
if runtime == nil {
|
|
return
|
|
}
|
|
logical := messageLogicalConnSnapshot(msg)
|
|
scope := serverFileScope(logical)
|
|
bulk, ok := runtime.lookupControl(scope, req.BulkID, req.DataID)
|
|
if !ok {
|
|
return
|
|
}
|
|
if !bulk.acceptsTransportGeneration(messageTransportConnSnapshot(msg)) {
|
|
return
|
|
}
|
|
bulk.releaseOutboundWindow(req.Bytes, req.Chunks)
|
|
}
|
|
|
|
func replyBulkControlIfNeeded(msg *Message, value interface{}) {
|
|
if msg == nil || !requiresSignalReplyWait(msg.TransferMsg) {
|
|
return
|
|
}
|
|
_ = msg.ReplyObj(value)
|
|
}
|
|
|
|
func sendBulkOpenClient(ctx context.Context, c Client, req BulkOpenRequest) (BulkOpenResponse, error) {
|
|
if c == nil {
|
|
return BulkOpenResponse{}, errBulkClientNil
|
|
}
|
|
msg, err := c.SendObjCtx(ctx, BulkOpenSignalKey, req)
|
|
if err != nil {
|
|
return BulkOpenResponse{}, err
|
|
}
|
|
return decodeBulkOpenResponse(msg)
|
|
}
|
|
|
|
func sendBulkOpenClientAtRoute(ctx context.Context, c *ClientCommon, route clientSessionRoute, req BulkOpenRequest) (BulkOpenResponse, error) {
|
|
if c == nil {
|
|
return BulkOpenResponse{}, errBulkClientNil
|
|
}
|
|
msg, err := c.sendObjCtxAtRoute(ctx, route, BulkOpenSignalKey, req)
|
|
if err != nil {
|
|
return BulkOpenResponse{}, err
|
|
}
|
|
return decodeBulkOpenResponse(msg)
|
|
}
|
|
|
|
func sendBulkOpenServerLogical(ctx context.Context, s Server, logical *LogicalConn, req BulkOpenRequest) (BulkOpenResponse, error) {
|
|
if s == nil {
|
|
return BulkOpenResponse{}, errBulkServerNil
|
|
}
|
|
if logical == nil {
|
|
return BulkOpenResponse{}, errBulkLogicalConnNil
|
|
}
|
|
msg, err := s.SendObjCtxLogical(ctx, logical, BulkOpenSignalKey, req)
|
|
if err != nil {
|
|
return BulkOpenResponse{}, err
|
|
}
|
|
return decodeBulkOpenResponse(msg)
|
|
}
|
|
|
|
func sendBulkOpenServerTransport(ctx context.Context, s Server, transport *TransportConn, req BulkOpenRequest) (BulkOpenResponse, error) {
|
|
if s == nil {
|
|
return BulkOpenResponse{}, errBulkServerNil
|
|
}
|
|
if transport == nil {
|
|
return BulkOpenResponse{}, errBulkTransportNil
|
|
}
|
|
msg, err := s.SendObjCtxTransport(ctx, transport, BulkOpenSignalKey, req)
|
|
if err != nil {
|
|
return BulkOpenResponse{}, err
|
|
}
|
|
return decodeBulkOpenResponse(msg)
|
|
}
|
|
|
|
func sendBulkCloseClient(ctx context.Context, c Client, req BulkCloseRequest) (BulkCloseResponse, error) {
|
|
if c == nil {
|
|
return BulkCloseResponse{}, errBulkClientNil
|
|
}
|
|
msg, err := c.SendObjCtx(ctx, BulkCloseSignalKey, req)
|
|
if err != nil {
|
|
return BulkCloseResponse{}, err
|
|
}
|
|
return decodeBulkCloseResponse(msg)
|
|
}
|
|
|
|
func sendBulkCloseClientAtRoute(ctx context.Context, c *ClientCommon, route clientSessionRoute, req BulkCloseRequest) (BulkCloseResponse, error) {
|
|
if c == nil {
|
|
return BulkCloseResponse{}, errBulkClientNil
|
|
}
|
|
msg, err := c.sendObjCtxAtRoute(ctx, route, BulkCloseSignalKey, req)
|
|
if err != nil {
|
|
return BulkCloseResponse{}, err
|
|
}
|
|
return decodeBulkCloseResponse(msg)
|
|
}
|
|
|
|
func sendBulkCloseServerLogical(ctx context.Context, s Server, logical *LogicalConn, req BulkCloseRequest) (BulkCloseResponse, error) {
|
|
if s == nil {
|
|
return BulkCloseResponse{}, errBulkServerNil
|
|
}
|
|
if logical == nil {
|
|
return BulkCloseResponse{}, errBulkLogicalConnNil
|
|
}
|
|
msg, err := s.SendObjCtxLogical(ctx, logical, BulkCloseSignalKey, req)
|
|
if err != nil {
|
|
return BulkCloseResponse{}, err
|
|
}
|
|
return decodeBulkCloseResponse(msg)
|
|
}
|
|
|
|
func sendBulkCloseServerTransport(ctx context.Context, s Server, transport *TransportConn, req BulkCloseRequest) (BulkCloseResponse, error) {
|
|
if s == nil {
|
|
return BulkCloseResponse{}, errBulkServerNil
|
|
}
|
|
if transport == nil {
|
|
return BulkCloseResponse{}, errBulkTransportNil
|
|
}
|
|
msg, err := s.SendObjCtxTransport(ctx, transport, BulkCloseSignalKey, req)
|
|
if err != nil {
|
|
return BulkCloseResponse{}, err
|
|
}
|
|
return decodeBulkCloseResponse(msg)
|
|
}
|
|
|
|
func sendBulkResetClient(ctx context.Context, c Client, req BulkResetRequest) (BulkResetResponse, error) {
|
|
if c == nil {
|
|
return BulkResetResponse{}, errBulkClientNil
|
|
}
|
|
msg, err := c.SendObjCtx(ctx, BulkResetSignalKey, req)
|
|
if err != nil {
|
|
return BulkResetResponse{}, err
|
|
}
|
|
return decodeBulkResetResponse(msg)
|
|
}
|
|
|
|
func sendBulkResetClientAtRoute(ctx context.Context, c *ClientCommon, route clientSessionRoute, req BulkResetRequest) (BulkResetResponse, error) {
|
|
if c == nil {
|
|
return BulkResetResponse{}, errBulkClientNil
|
|
}
|
|
msg, err := c.sendObjCtxAtRoute(ctx, route, BulkResetSignalKey, req)
|
|
if err != nil {
|
|
return BulkResetResponse{}, err
|
|
}
|
|
return decodeBulkResetResponse(msg)
|
|
}
|
|
|
|
func sendBulkResetServerLogical(ctx context.Context, s Server, logical *LogicalConn, req BulkResetRequest) (BulkResetResponse, error) {
|
|
if s == nil {
|
|
return BulkResetResponse{}, errBulkServerNil
|
|
}
|
|
if logical == nil {
|
|
return BulkResetResponse{}, errBulkLogicalConnNil
|
|
}
|
|
msg, err := s.SendObjCtxLogical(ctx, logical, BulkResetSignalKey, req)
|
|
if err != nil {
|
|
return BulkResetResponse{}, err
|
|
}
|
|
return decodeBulkResetResponse(msg)
|
|
}
|
|
|
|
func sendBulkResetServerTransport(ctx context.Context, s Server, transport *TransportConn, req BulkResetRequest) (BulkResetResponse, error) {
|
|
if s == nil {
|
|
return BulkResetResponse{}, errBulkServerNil
|
|
}
|
|
if transport == nil {
|
|
return BulkResetResponse{}, errBulkTransportNil
|
|
}
|
|
msg, err := s.SendObjCtxTransport(ctx, transport, BulkResetSignalKey, req)
|
|
if err != nil {
|
|
return BulkResetResponse{}, err
|
|
}
|
|
return decodeBulkResetResponse(msg)
|
|
}
|
|
|
|
func sendBulkReleaseClient(ctx context.Context, c *ClientCommon, req BulkReleaseRequest) error {
|
|
return sendBulkReleaseClientAtRoute(ctx, c, c.clientSessionRouteSnapshot(), req)
|
|
}
|
|
|
|
func sendBulkReleaseClientAtRoute(ctx context.Context, c *ClientCommon, route clientSessionRoute, req BulkReleaseRequest) error {
|
|
if c == nil {
|
|
return errBulkClientNil
|
|
}
|
|
data, err := encode(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = c.sendWithContextTimeoutAtRoute(ctx, route, TransferMsg{
|
|
Key: BulkReleaseSignalKey,
|
|
Value: data,
|
|
Type: MSG_ASYNC,
|
|
}, 0)
|
|
return err
|
|
}
|
|
|
|
func sendBulkReleaseServerLogical(ctx context.Context, s *ServerCommon, logical *LogicalConn, req BulkReleaseRequest) error {
|
|
if s == nil {
|
|
return errBulkServerNil
|
|
}
|
|
if logical == nil {
|
|
return errBulkLogicalConnNil
|
|
}
|
|
data, err := encode(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = s.sendLogicalContext(ctx, logical, TransferMsg{
|
|
Key: BulkReleaseSignalKey,
|
|
Value: data,
|
|
Type: MSG_ASYNC,
|
|
}, 0)
|
|
return err
|
|
}
|
|
|
|
func sendBulkReleaseServerTransport(ctx context.Context, s *ServerCommon, transport *TransportConn, req BulkReleaseRequest) error {
|
|
if s == nil {
|
|
return errBulkServerNil
|
|
}
|
|
if transport == nil {
|
|
return errBulkTransportNil
|
|
}
|
|
data, err := encode(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = s.sendTransportContext(ctx, transport, TransferMsg{
|
|
Key: BulkReleaseSignalKey,
|
|
Value: data,
|
|
Type: MSG_ASYNC,
|
|
})
|
|
return err
|
|
}
|
|
|
|
func decodeBulkOpenRequest(msg *Message) (BulkOpenRequest, error) {
|
|
var req BulkOpenRequest
|
|
if msg == nil {
|
|
return BulkOpenRequest{}, errBulkIDEmpty
|
|
}
|
|
if err := msg.Value.Orm(&req); err != nil {
|
|
return BulkOpenRequest{}, err
|
|
}
|
|
req = normalizeBulkOpenRequest(req)
|
|
if req.BulkID == "" {
|
|
return BulkOpenRequest{}, errBulkIDEmpty
|
|
}
|
|
if !validBulkRange(req.Range) {
|
|
return BulkOpenRequest{}, errBulkRangeInvalid
|
|
}
|
|
return req, nil
|
|
}
|
|
|
|
func decodeBulkCloseRequest(msg *Message) (BulkCloseRequest, error) {
|
|
var req BulkCloseRequest
|
|
if msg == nil {
|
|
return BulkCloseRequest{}, errBulkIDEmpty
|
|
}
|
|
if err := msg.Value.Orm(&req); err != nil {
|
|
return BulkCloseRequest{}, err
|
|
}
|
|
if req.BulkID == "" {
|
|
return BulkCloseRequest{}, errBulkIDEmpty
|
|
}
|
|
return req, nil
|
|
}
|
|
|
|
func decodeBulkResetRequest(msg *Message) (BulkResetRequest, error) {
|
|
var req BulkResetRequest
|
|
if msg == nil {
|
|
return BulkResetRequest{}, errBulkIDEmpty
|
|
}
|
|
if err := msg.Value.Orm(&req); err != nil {
|
|
return BulkResetRequest{}, err
|
|
}
|
|
if req.BulkID == "" && req.DataID == 0 {
|
|
return BulkResetRequest{}, errBulkIDEmpty
|
|
}
|
|
return req, nil
|
|
}
|
|
|
|
func decodeBulkReleaseRequest(msg *Message) (BulkReleaseRequest, error) {
|
|
var req BulkReleaseRequest
|
|
if msg == nil {
|
|
return BulkReleaseRequest{}, errBulkIDEmpty
|
|
}
|
|
if err := msg.Value.Orm(&req); err != nil {
|
|
return BulkReleaseRequest{}, err
|
|
}
|
|
if req.BulkID == "" && req.DataID == 0 {
|
|
return BulkReleaseRequest{}, errBulkIDEmpty
|
|
}
|
|
if req.Bytes < 0 || req.Chunks < 0 {
|
|
return BulkReleaseRequest{}, errBulkRangeInvalid
|
|
}
|
|
return req, nil
|
|
}
|
|
|
|
func decodeBulkReadyRequest(msg *Message) (BulkReadyRequest, error) {
|
|
var req BulkReadyRequest
|
|
if msg == nil {
|
|
return BulkReadyRequest{}, errBulkIDEmpty
|
|
}
|
|
if err := msg.Value.Orm(&req); err != nil {
|
|
return BulkReadyRequest{}, err
|
|
}
|
|
if req.BulkID == "" && req.DataID == 0 {
|
|
return BulkReadyRequest{}, errBulkIDEmpty
|
|
}
|
|
return req, nil
|
|
}
|
|
|
|
func decodeBulkOpenResponse(msg Message) (BulkOpenResponse, error) {
|
|
var resp BulkOpenResponse
|
|
if err := msg.Value.Orm(&resp); err != nil {
|
|
return BulkOpenResponse{}, err
|
|
}
|
|
resp.FastPathVersion = normalizeBulkFastPathVersion(resp.FastPathVersion)
|
|
return resp, bulkControlResultError("open", resp.Accepted, resp.Error, nil)
|
|
}
|
|
|
|
func decodeBulkCloseResponse(msg Message) (BulkCloseResponse, error) {
|
|
var resp BulkCloseResponse
|
|
if err := msg.Value.Orm(&resp); err != nil {
|
|
return BulkCloseResponse{}, err
|
|
}
|
|
return resp, bulkControlResultError("close", resp.Accepted, resp.Error, nil)
|
|
}
|
|
|
|
func decodeBulkResetResponse(msg Message) (BulkResetResponse, error) {
|
|
var resp BulkResetResponse
|
|
if err := msg.Value.Orm(&resp); err != nil {
|
|
return BulkResetResponse{}, err
|
|
}
|
|
return resp, bulkControlResultError("reset", resp.Accepted, resp.Error, nil)
|
|
}
|
|
|
|
func decodeBulkReadyResponse(msg Message) (BulkReadyResponse, error) {
|
|
var resp BulkReadyResponse
|
|
if err := msg.Value.Orm(&resp); err != nil {
|
|
return BulkReadyResponse{}, err
|
|
}
|
|
return resp, bulkControlResultError("ready", resp.Accepted, resp.Error, nil)
|
|
}
|
|
|
|
func bulkControlResultError(op string, accepted bool, message string, callErr error) error {
|
|
if callErr != nil {
|
|
return callErr
|
|
}
|
|
if message != "" {
|
|
return bulkControlMessageError(message)
|
|
}
|
|
if accepted {
|
|
return nil
|
|
}
|
|
if op == "open" {
|
|
return errBulkRejected
|
|
}
|
|
return errors.New("bulk " + op + " rejected")
|
|
}
|
|
|
|
func bulkControlMessageError(message string) error {
|
|
if message == errTransportDetached.Error() || strings.HasPrefix(message, errTransportDetached.Error()+":") {
|
|
return errTransportDetached
|
|
}
|
|
switch message {
|
|
case errBulkNotFound.Error():
|
|
return errBulkNotFound
|
|
case errBulkAlreadyExists.Error():
|
|
return errBulkAlreadyExists
|
|
case errBulkHandlerNotConfigured.Error():
|
|
return errBulkHandlerNotConfigured
|
|
case errBulkLogicalConnNil.Error():
|
|
return errBulkLogicalConnNil
|
|
case errBulkTransportNil.Error():
|
|
return errBulkTransportNil
|
|
case errBulkRuntimeNil.Error():
|
|
return errBulkRuntimeNil
|
|
case errBulkIDEmpty.Error():
|
|
return errBulkIDEmpty
|
|
case errBulkRangeInvalid.Error():
|
|
return errBulkRangeInvalid
|
|
case errBulkDataIDEmpty.Error():
|
|
return errBulkDataIDEmpty
|
|
case errBulkDataIDExhausted.Error():
|
|
return errBulkDataIDExhausted
|
|
default:
|
|
return errors.New(message)
|
|
}
|
|
}
|
|
|
|
func bulkRemoteResetError(message string) error {
|
|
if message == "" {
|
|
return errBulkReset
|
|
}
|
|
return errors.New(message)
|
|
}
|
|
|
|
func bulkReadyRemoteError(message string) error {
|
|
if message == "" {
|
|
return nil
|
|
}
|
|
return bulkControlMessageError(message)
|
|
}
|
|
|
|
func sendBulkReadyClient(ctx context.Context, c Client, req BulkReadyRequest) (BulkReadyResponse, error) {
|
|
if c == nil {
|
|
return BulkReadyResponse{}, errBulkClientNil
|
|
}
|
|
msg, err := c.SendObjCtx(ctx, BulkReadySignalKey, req)
|
|
if err != nil {
|
|
return BulkReadyResponse{}, err
|
|
}
|
|
return decodeBulkReadyResponse(msg)
|
|
}
|
|
|
|
func sendBulkReadyClientAtRoute(ctx context.Context, c *ClientCommon, route clientSessionRoute, req BulkReadyRequest) (BulkReadyResponse, error) {
|
|
if c == nil {
|
|
return BulkReadyResponse{}, errBulkClientNil
|
|
}
|
|
msg, err := c.sendObjCtxAtRoute(ctx, route, BulkReadySignalKey, req)
|
|
if err != nil {
|
|
return BulkReadyResponse{}, err
|
|
}
|
|
return decodeBulkReadyResponse(msg)
|
|
}
|
|
|
|
func sendBulkReadyServerLogical(ctx context.Context, s Server, logical *LogicalConn, req BulkReadyRequest) (BulkReadyResponse, error) {
|
|
if s == nil {
|
|
return BulkReadyResponse{}, errBulkServerNil
|
|
}
|
|
if logical == nil {
|
|
return BulkReadyResponse{}, errBulkLogicalConnNil
|
|
}
|
|
msg, err := s.SendObjCtxLogical(ctx, logical, BulkReadySignalKey, req)
|
|
if err != nil {
|
|
return BulkReadyResponse{}, err
|
|
}
|
|
return decodeBulkReadyResponse(msg)
|
|
}
|
|
|
|
func sendBulkReadyServerTransport(ctx context.Context, s Server, transport *TransportConn, req BulkReadyRequest) (BulkReadyResponse, error) {
|
|
if s == nil {
|
|
return BulkReadyResponse{}, errBulkServerNil
|
|
}
|
|
if transport == nil {
|
|
return BulkReadyResponse{}, errBulkTransportNil
|
|
}
|
|
msg, err := s.SendObjCtxTransport(ctx, transport, BulkReadySignalKey, req)
|
|
if err != nil {
|
|
return BulkReadyResponse{}, err
|
|
}
|
|
return decodeBulkReadyResponse(msg)
|
|
}
|
|
|
|
func bulkTransportGeneration(logical *LogicalConn, transport *TransportConn) uint64 {
|
|
return streamTransportGeneration(logical, transport)
|
|
}
|