fix: close stream adaptive gaps and switch notify to stario v0.1.1
- make stream fast path honor adaptive soft payload limits end-to-end - split oversized fast-stream payloads into sequential frames before batching - use adaptive soft cap when encoding stream batch payloads - move timeout-like error detection into production code for adaptive tx - tune notify FrameReader read size explicitly to avoid throughput regression - drop local stario replace and depend on released b612.me/stario v0.1.1
This commit is contained in:
+370
-43
@@ -7,22 +7,25 @@ import (
|
||||
)
|
||||
|
||||
type BulkOpenRequest struct {
|
||||
BulkID string
|
||||
DataID uint64
|
||||
Range BulkRange
|
||||
Metadata BulkMetadata
|
||||
ReadTimeout time.Duration
|
||||
WriteTimeout time.Duration
|
||||
Dedicated bool
|
||||
AttachToken string
|
||||
ChunkSize int
|
||||
WindowBytes int
|
||||
MaxInFlight int
|
||||
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
|
||||
@@ -53,6 +56,18 @@ type BulkResetResponse struct {
|
||||
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
|
||||
@@ -73,6 +88,9 @@ func bindClientBulkControl(c *ClientCommon) {
|
||||
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)
|
||||
})
|
||||
@@ -91,14 +109,188 @@ func bindServerBulkControl(s *ServerCommon) {
|
||||
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.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) {
|
||||
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 := sendBulkReadyClient(ctx, c, 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 {
|
||||
if _, err := sendBulkReadyServerTransport(ctx, s, transport, req); err == nil {
|
||||
return nil
|
||||
} else if !errors.Is(err, errTransportDetached) && !errors.Is(err, errBulkTransportNil) {
|
||||
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, Dedicated: req.Dedicated}
|
||||
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)
|
||||
@@ -133,13 +325,6 @@ func (c *ClientCommon) handleInboundBulkOpen(msg *Message) {
|
||||
replyBulkControlIfNeeded(msg, resp)
|
||||
return
|
||||
}
|
||||
handler := runtime.handlerSnapshot()
|
||||
if handler == nil {
|
||||
bulk.markReset(errBulkHandlerNotConfigured)
|
||||
resp.Error = errBulkHandlerNotConfigured.Error()
|
||||
replyBulkControlIfNeeded(msg, resp)
|
||||
return
|
||||
}
|
||||
if req.Dedicated {
|
||||
if err := c.attachDedicatedBulkSidecar(context.Background(), bulk); err != nil {
|
||||
bulk.markReset(err)
|
||||
@@ -147,17 +332,14 @@ func (c *ClientCommon) handleInboundBulkOpen(msg *Message) {
|
||||
replyBulkControlIfNeeded(msg, resp)
|
||||
return
|
||||
}
|
||||
resp.Accepted = true
|
||||
resp.DataID = bulk.dataIDSnapshot()
|
||||
resp.TransportGeneration = bulk.TransportGeneration()
|
||||
replyBulkControlIfNeeded(msg, resp)
|
||||
c.startClientBulkAcceptDispatch(bulk)
|
||||
return
|
||||
}
|
||||
info := BulkAcceptInfo{
|
||||
ID: bulk.ID(),
|
||||
Range: bulk.Range(),
|
||||
Metadata: bulk.Metadata(),
|
||||
Dedicated: bulk.Dedicated(),
|
||||
TransportGeneration: bulk.TransportGeneration(),
|
||||
Bulk: bulk,
|
||||
}
|
||||
if err := handler(info); err != nil {
|
||||
bulk.markReset(err)
|
||||
if err := c.dispatchClientBulkAccept(bulk); err != nil {
|
||||
resp.Error = err.Error()
|
||||
replyBulkControlIfNeeded(msg, resp)
|
||||
return
|
||||
@@ -170,7 +352,12 @@ func (c *ClientCommon) handleInboundBulkOpen(msg *Message) {
|
||||
|
||||
func (s *ServerCommon) handleInboundBulkOpen(msg *Message) {
|
||||
req, err := decodeBulkOpenRequest(msg)
|
||||
resp := BulkOpenResponse{BulkID: req.BulkID, DataID: req.DataID, Dedicated: req.Dedicated}
|
||||
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)
|
||||
@@ -218,25 +405,24 @@ func (s *ServerCommon) handleInboundBulkOpen(msg *Message) {
|
||||
replyBulkControlIfNeeded(msg, resp)
|
||||
return
|
||||
}
|
||||
handler := runtime.handlerSnapshot()
|
||||
if handler == nil {
|
||||
s.attachServerDedicatedSidecarIfExists(logical, bulk)
|
||||
if runtime.handlerSnapshot() == nil {
|
||||
bulk.markReset(errBulkHandlerNotConfigured)
|
||||
resp.Error = errBulkHandlerNotConfigured.Error()
|
||||
replyBulkControlIfNeeded(msg, resp)
|
||||
return
|
||||
}
|
||||
info := BulkAcceptInfo{
|
||||
ID: bulk.ID(),
|
||||
Range: bulk.Range(),
|
||||
Metadata: bulk.Metadata(),
|
||||
Dedicated: bulk.Dedicated(),
|
||||
LogicalConn: logical,
|
||||
TransportConn: transport,
|
||||
TransportGeneration: bulk.TransportGeneration(),
|
||||
Bulk: bulk,
|
||||
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 := handler(info); err != nil {
|
||||
bulk.markReset(err)
|
||||
if err := s.dispatchServerBulkAccept(bulk, logical, transport); err != nil {
|
||||
resp.Error = err.Error()
|
||||
replyBulkControlIfNeeded(msg, resp)
|
||||
return
|
||||
@@ -357,6 +543,41 @@ func (c *ClientCommon) handleInboundBulkRelease(msg *Message) {
|
||||
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.lookup(clientFileScope(), req.BulkID)
|
||||
if !ok && req.DataID != 0 {
|
||||
bulk, ok = runtime.lookupByDataID(clientFileScope(), req.DataID)
|
||||
}
|
||||
if !ok {
|
||||
resp.Error = errBulkNotFound.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}
|
||||
@@ -390,6 +611,43 @@ func (s *ServerCommon) handleInboundBulkReset(msg *Message) {
|
||||
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.lookup(scope, req.BulkID)
|
||||
if !ok && req.DataID != 0 {
|
||||
bulk, ok = runtime.lookupByDataID(scope, req.DataID)
|
||||
}
|
||||
if !ok {
|
||||
resp.Error = errBulkNotFound.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 {
|
||||
@@ -625,11 +883,26 @@ func decodeBulkReleaseRequest(msg *Message) (BulkReleaseRequest, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -649,6 +922,14 @@ func decodeBulkResetResponse(msg Message) (BulkResetResponse, error) {
|
||||
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
|
||||
@@ -697,6 +978,52 @@ func bulkRemoteResetError(message string) error {
|
||||
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 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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user