Skip to content

*: use per-stream Finished signal instead of shared sfin channel#45

Merged
shubhamdhama merged 1 commit into
stream-multiplexingfrom
shubham/use-stream-finished
Apr 7, 2026
Merged

*: use per-stream Finished signal instead of shared sfin channel#45
shubhamdhama merged 1 commit into
stream-multiplexingfrom
shubham/use-stream-finished

Conversation

@shubhamdhama
Copy link
Copy Markdown

Replace the shared sfin channel with stream.Finished(), giving each
stream its own completion signal. The shared channel worked for
single-stream-at-a-time. Per-stream signals are required for
multiplexing where multiple streams finish independently.

@shubhamdhama shubhamdhama force-pushed the shubham/simplify-manageStreams branch from 2b7433e to cf11131 Compare March 30, 2026 14:07
@shubhamdhama shubhamdhama force-pushed the shubham/use-stream-finished branch from 779b184 to 341397a Compare March 30, 2026 14:07
@shubhamdhama shubhamdhama force-pushed the shubham/simplify-manageStreams branch from cf11131 to b7ec558 Compare March 30, 2026 14:25
@shubhamdhama shubhamdhama force-pushed the shubham/use-stream-finished branch from 341397a to dcda07e Compare March 30, 2026 14:25
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates stream completion signaling to use the per-stream (*drpcstream.Stream).Finished() channel rather than a single shared “stream finished” channel, which is necessary for correct behavior when multiple streams can complete independently (multiplexing).

Changes:

  • Removed the shared sfin channel from drpcmanager.Manager and switched waiting logic to stream.Finished().
  • Removed fin plumbing from drpcstream.Stream construction and finish-path signaling.
  • Deleted GetStreamFin/SetStreamFin from internal stream options.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
internal/drpcopts/stream.go Removes accessors for the old shared finish channel in internal stream options.
drpcstream/stream.go Removes the stream-level fin channel and stops emitting to a shared finished notifier.
drpcmanager/manager.go Replaces waits on the shared sfin channel with waits on stream.Finished().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 20 to 28
// GetStreamTransport returns the drpc.Transport stored in the options.
func GetStreamTransport(opts *Stream) drpc.Transport { return opts.transport }

// SetStreamTransport sets the drpc.Transport stored in the options.
func SetStreamTransport(opts *Stream, tr drpc.Transport) { opts.transport = tr }

// GetStreamFin returns the chan<- struct{} stored in the options.
func GetStreamFin(opts *Stream) chan<- struct{} { return opts.fin }

// SetStreamFin sets the chan<- struct{} stored in the options.
func SetStreamFin(opts *Stream, fin chan<- struct{}) { opts.fin = fin }

// GetStreamKind returns the StreamKind stored in the options.
func GetStreamKind(opts *Stream) drpc.StreamKind { return opts.kind }

Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After removing GetStreamFin/SetStreamFin, the underlying fin chan<- struct{} field still remains in drpcopts.Stream (see internal/drpcopts/stream.go:14) but is now unreachable outside the package and has no remaining references in the repo. Consider deleting the fin field from drpcopts.Stream to avoid dead/unused internal state and confusion about how stream completion is signaled (now via (*drpcstream.Stream).Finished()).

Copilot uses AI. Check for mistakes.
@cthumuluru-crdb
Copy link
Copy Markdown

I don't believe this change is needed in mux world? The only reason s.fin is to signal that the active stream is complete and a new stream can be started but in mux world, we can have more than one streams active at any point of time. Its probably better you drop the use of sfin entirely.

Comment thread drpcstream/stream.go
if s.sigs.fin.Set(nil) {
s.log("FIN", func() string { return "" })
s.ctx.sig.Set(context.Canceled)
if s.fin != nil {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change semantically doesn't match with the current behavior. With s.fin() the caller is unblocked after s.fin <- struct{}{}.

With this change the caller is unblocked immediately after s.sigs.fin.Set(nil).

Copy link
Copy Markdown
Author

@shubhamdhama shubhamdhama Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[pp] we think we don't need checkFinished

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If above comments from chandra are true, then we will remove this later in multiplexing code. If it's actually needed then we need to revisit the semantic differnece here.

Comment thread drpcstream/stream.go
// checkFinished checks to see if the stream is terminated, and if so, sets the
// finished flag. This must be called after every read or write is complete, as
// well as when the stream becomes terminated.
func (s *Stream) checkFinished() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the main goal of checkFinished() appears to be to ensure the read/write/terminate of one stream happens before any admitting any other stream.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added to the list and will address in multiplexing

Copy link
Copy Markdown

@cthumuluru-crdb cthumuluru-crdb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see much use of checkFinished() in multiplexing world and I would expect that to be removed. Given that I'm now worried about the semantic difference this change brings to checkFinished(). This change looks good.

@shubhamdhama shubhamdhama force-pushed the shubham/simplify-manageStreams branch from b7ec558 to 4705799 Compare April 7, 2026 03:50
Base automatically changed from shubham/simplify-manageStreams to stream-multiplexing April 7, 2026 03:51
Replace the shared sfin channel with stream.Finished(), giving each
stream its own completion signal. The shared channel worked for
single-stream-at-a-time. Per-stream signals are required for
multiplexing where multiple streams finish independently.
@shubhamdhama shubhamdhama force-pushed the shubham/use-stream-finished branch from dcda07e to ce3c970 Compare April 7, 2026 03:52
@shubhamdhama shubhamdhama merged commit 3219dcf into stream-multiplexing Apr 7, 2026
@shubhamdhama shubhamdhama deleted the shubham/use-stream-finished branch April 7, 2026 03:54
shubhamdhama added a commit that referenced this pull request May 14, 2026
Squashed result of the upstream stream-multiplexing branch. See the
merged PRs for granular history:

- #39 drpcmanager: fix race between manageReader and stream creation
- #42 *: move frame assembly from reader to stream
- #43 *: extract PacketAssembler for frame-to-packet assembly
- #44 drpcmanager: replace manageStreams loop with per-stream goroutines
- #45 *: use per-stream Finished signal instead of shared sfin channel
- #46 drpcmanager: use atomic counter for client stream ID generation
- #47 drpcmanager: replace streamBuffer with a streams registry
- #51 drpc: enable stream multiplexing

A connection now runs multiple concurrent client and server streams
over a single transport. Frames carry stream IDs and are interleaved
on the wire by a shared MuxWriter. Each stream owns its own packet
ring buffer, Finished signal, and goroutine, and the manager tracks
live streams in an activeStreams registry.

New: drpcwire.MuxWriter, drpcwire.PacketAssembler,
drpcstream.ringBuffer, drpcmanager.activeStreams.

Removed: the drpccache package, drpcwire/writer (now MuxWriter),
drpcstream/pktbuf (now ringBuffer), drpcmanager/streambuf (now
activeStreams), drpcmanager.Options.InactivityTimeout, and the
drpcconn shared write buffer plus stats infrastructure (CollectStats,
Stats, drpcstats wiring).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants