rdma: size publications to session capacity and preserve committed PUT facts

Size the publication queue from the configured session limit instead
of a fixed depth with an overflow semaphore: each session publishes
exactly one terminal record, so the queue can never fill and native
callbacks hand off without waiting. Remove the semaphore fallback.

Admit verification failures under the shutdown barrier so an
authentication publication cannot land after the sinks close. Give
the metrics manager a lifetime independent of the gateway context so
shutdown drain updates are counted, and pass the captured bucket
explicitly so RC datapoints appear in bucket-filtered metrics.

Track reservations by claim generation: release and publication
validate the generation, so a stale claim cannot consume a newer
owner's record. Install the reservation cleanup defer immediately
after acquisition so a panic during authorization cannot orphan it.

Preserve committed PUT facts independent of the native finalizer:
when the backend object exists, record the commit, keep the
committed byte count on the error publication, and still emit the
object-created event.
This commit is contained in:
Jihyeon Gim
2026-09-09 13:16:52 +09:00
parent d3e45fdb41
commit 55c82f5e4e
8 changed files with 240 additions and 115 deletions
+16 -7
View File
@@ -174,12 +174,13 @@ type SessionInfo struct {
// unblock), waits for every entered call to leave, then tears the
// server down; it is idempotent and safe from any goroutine.
type RCSvc struct {
srv *C.rc_server
closing atomic.Bool
ops atomic.Int64
once sync.Once
ctx context.Context
cancel context.CancelFunc
srv *C.rc_server
closing atomic.Bool
ops atomic.Int64
once sync.Once
ctx context.Context
cancel context.CancelFunc
maxSessions uint32
}
// Context returns the service-lifetime context. Handlers bind
@@ -188,6 +189,14 @@ func (s *RCSvc) Context() context.Context {
return s.ctx
}
// MaxSessions reports the configured global session limit. The
// operational publication pipeline sizes its queue against it:
// each session publishes exactly one terminal record, so a queue
// this deep can never fill.
func (s *RCSvc) MaxSessions() uint32 {
return s.maxSessions
}
// rcLogSink receives every diagnostic line the C server emits.
// It is stateless and process-global on purpose: the sink must be
// valid from init through destroy, independent of any single
@@ -263,7 +272,7 @@ func Init(opts DeviceOpts) (*RCSvc, error) {
}
installLogSink(srv, opts.Debug)
ctx, cancel := context.WithCancel(context.Background())
return &RCSvc{srv: srv, ctx: ctx, cancel: cancel}, nil
return &RCSvc{srv: srv, ctx: ctx, cancel: cancel, maxSessions: opts.MaxSessions}, nil
}
// TryEnter admits a request into the service. It returns false once