Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GODRIVER-3058 Centralize x-package Connection interface as a struct #1475

Merged
merged 16 commits into from
Mar 18, 2024

Conversation

prestonvasquez
Copy link
Collaborator

@prestonvasquez prestonvasquez commented Nov 17, 2023

GODRIVER-3058

Summary

Move all of the connection logic from interfaces in the driver package to the mnet package.

Background & Motivation

Context
The driver.Connection interface is returned by various functions in the x package, which is a pattern in conflict with the Go idiom of "accept interfaces, return structs" defined in the wiki . And generally violates the robustness principle.

More importantly, this change will allow us to centralize the usage of description.Server. If we were to migrate the description package to the internal package, then we could create a subset of the fields from description.Server that are required in the experimental API in the mnet package:

package mnet

type Server struct {
	Addr         address.Address
	WireVersion  *VersionRange
}

type Describer interface {
	Description() Server
	ID() string
	ServerConnectionID() *int64
	DriverConnectionID() int64
	Address() address.Address
	Stale() bool
}

Blank diagram

Functions that implement the Describer will need to change their signature to use mnet.Server and apply the internal analogue under the hood to the entailed methods.

@prestonvasquez prestonvasquez requested a review from a team as a code owner November 17, 2023 04:34
@prestonvasquez prestonvasquez requested review from qingyang-hu and removed request for a team November 17, 2023 04:34
@prestonvasquez prestonvasquez marked this pull request as draft November 17, 2023 04:34
@prestonvasquez prestonvasquez requested review from matthewdale and removed request for qingyang-hu and matthewdale November 17, 2023 04:34
@prestonvasquez prestonvasquez changed the title POC for decoupling Connection interface GODRIVER-3058 POC for decoupling Connection interface Nov 27, 2023
Copy link
Contributor

mongodb-drivers-pr-bot bot commented Nov 28, 2023

API Change Report

./x/mongo/driver

incompatible changes

Compressor: removed
Connection: removed
##CursorResponse.Connection: changed from PinnedConnection to *./x/mongo/driver/mnet.Connection
##ErrorProcessor.ProcessError: changed from func(error, Connection) ProcessErrorResult to func(error, ./x/mongo/driver/mnet.Describer) ProcessErrorResult
##Handshaker.FinishHandshake: changed from func(context.Context, Connection) error to func(context.Context, *./x/mongo/driver/mnet.Connection) error
##Handshaker.GetHandshakeInformation: changed from func(context.Context, ./mongo/address.Address, Connection) (HandshakeInformation, error) to func(context.Context, ./mongo/address.Address, *./x/mongo/driver/mnet.Connection) (HandshakeInformation, error)
##Operation.ExecuteExhaust: changed from func(context.Context, StreamerConnection) error to func(context.Context, *./x/mongo/driver/mnet.Connection) error
PinnedConnection: removed
##ResponseInfo.Connection: changed from Connection to ./x/mongo/driver/mnet.Connection
##Server.Connection: changed from func(context.Context) (Connection, error) to func(context.Context) (
./x/mongo/driver/mnet.Connection, error)
##SingleConnectionDeployment.C: changed from Connection to ./x/mongo/driver/mnet.Connection
##SingleConnectionDeployment.Connection: changed from func(context.Context) (Connection, error) to func(context.Context) (
./x/mongo/driver/mnet.Connection, error)
StreamerConnection: removed

./x/mongo/driver/auth

incompatible changes

##Config.Connection: changed from ./x/mongo/driver.Connection to *./x/mongo/driver/mnet.Connection
Config.Description: removed

./x/mongo/driver/drivertest

incompatible changes

(*ChannelConn).ReadWireMessage: removed
(*ChannelConn).WriteWireMessage: removed

compatible changes

(*ChannelConn).Read: added
(*ChannelConn).Write: added

./x/mongo/driver/mnet

compatible changes

package added

./x/mongo/driver/operation

incompatible changes

##(*Hello).FinishHandshake: changed from func(context.Context, ./x/mongo/driver.Connection) error to func(context.Context, *./x/mongo/driver/mnet.Connection) error
##(*Hello).GetHandshakeInformation: changed from func(context.Context, ./mongo/address.Address, ./x/mongo/driver.Connection) (./x/mongo/driver.HandshakeInformation, error) to func(context.Context, ./mongo/address.Address, *./x/mongo/driver/mnet.Connection) (./x/mongo/driver.HandshakeInformation, error)
##(*Hello).StreamResponse: changed from func(context.Context, ./x/mongo/driver.StreamerConnection) error to func(context.Context, *./x/mongo/driver/mnet.Connection) error

./x/mongo/driver/session

incompatible changes

LoadBalancedTransactionConnection.ReadWireMessage: removed
LoadBalancedTransactionConnection.WriteWireMessage: removed
##./x/mongo/driver/mnet.ReadWriteCloser.Read: added
##./x/mongo/driver/mnet.ReadWriteCloser.Write: added

./x/mongo/driver/topology

incompatible changes

(*Connection).ReadWireMessage: removed
(*Connection).WriteWireMessage: removed
##(Server).Connection: changed from func(context.Context) (./x/mongo/driver.Connection, error) to func(context.Context) (./x/mongo/driver/mnet.Connection, error)
##(*Server).ProcessError: changed from func(error, ./x/mongo/driver.Connection) ./x/mongo/driver.ProcessErrorResult to func(error, ./x/mongo/driver/mnet.Describer) ./x/mongo/driver.ProcessErrorResult

compatible changes

(*Connection).Read: added
(*Connection).Write: added

@prestonvasquez prestonvasquez changed the title GODRIVER-3058 POC for decoupling Connection interface GODRIVER-3058 Centralize x-package Connection interface as a struct Nov 28, 2023
@prestonvasquez prestonvasquez changed the title GODRIVER-3058 Centralize x-package Connection interface as a struct GODRIVER-3058 (POC) Centralize x-package Connection interface as a struct Nov 28, 2023
@prestonvasquez prestonvasquez marked this pull request as ready for review November 28, 2023 19:15
x/mongo/driver/mnet/connection.go Outdated Show resolved Hide resolved
x/mongo/driver/mnet/connection.go Show resolved Hide resolved
@prestonvasquez prestonvasquez changed the title GODRIVER-3058 (POC) Centralize x-package Connection interface as a struct GODRIVER-3058 Centralize x-package Connection interface as a struct Jan 18, 2024
func newProcessErrorTestConn(wireVersion *description.VersionRange, stale bool) *processErrorTestConn {
return &processErrorTestConn{
func newProcessErrorTestConn(t *testing.T, wireVersion *description.VersionRange, stale bool) *mnet.Connection {
t.Helper()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there a reason to call t.Helper here? Typically the purpose is to allow failed test assertions to point to a more relevant line number, but t is not used to make any assertions in this function.

Comment on lines 19 to 27
type WireMessageReader interface {
Read(ctx context.Context) ([]byte, error)
}

// WireMessageWriter represents a Connection where server operations can be
// written to.
type WireMessageWriter interface {
Write(ctx context.Context, wm []byte) error
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: These interfaces are only used in WireMessageReadWriteCloser. Consider putting the Read and Write method definitions in that interface instead.


// WireMessageReadWriteCloser represents a Connection where server operations
// can read from, written to, and closed.
type WireMessageReadWriteCloser interface {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Since mnet is dedicated to MongoDB connections, the WireMessage in WireMessageReadWriteCloser is redundant. Consider condensing the type name to ReadWriteCloser.

Comment on lines +110 to +112
if describer, ok := component.(Describer); ok {
conn.Describer = describer
}
Copy link
Collaborator

@matthewdale matthewdale Feb 7, 2024

Choose a reason for hiding this comment

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

For all of the other interfaces (Streamer, Compressor, etc), code that calls the associated methods performs nil checks first. However, code that calls the Describer methods do not perform nil checks and just assumes it's available. That's a valid assumption for now, but could break unexpectedly.

There are a few options to fix that:

  1. Make the minimum interface be the union of WireMessageReadWriteCloser and Describer.
  2. Add nil checks to all the calls to Describer methods.
  3. Add wrapper methods for all the Describer method calls that handle the nil case. For example:
func (c *Connection) Description() description.Server {
	if c.describer == nil {
		return description.Server{}
	}
	return c.describer.Description()
}

Copy link
Collaborator Author

@prestonvasquez prestonvasquez Feb 21, 2024

Choose a reason for hiding this comment

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

I think unioning is the best solution if we are certain that objects need to describe the connection for which they are establishing. However, a Describer is a pretty complicated interface which makes constructing a connection more strict. For robustness, the other two solutions also seem like a good idea. What are your thoughts?

Copy link
Collaborator

@matthewdale matthewdale Feb 28, 2024

Choose a reason for hiding this comment

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

I think 3. is probably the best change because it's easy and enables simpler connection implementations.

Edit: I see you went with option 1. We should keep that implementation for now because it should prevent bugs caused by a missing Description method, which is the main issue. These are internal APIs, so we can simplify things in the future without breaking changes.

Copy link
Collaborator

@matthewdale matthewdale left a comment

Choose a reason for hiding this comment

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

Looks good! 👍

@@ -76,26 +75,15 @@ func (s TransactionState) String() string {
}
}

var _ mnet.Pinner = (LoadBalancedTransactionConnection)(nil)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: This seems redundant because the interface description below includes mnet.Pinner. Consider removing it.

if !ok {
refConn := info.Connection.Pinner
if refConn == nil {
//debug.PrintStack()
return CursorResponse{}, fmt.Errorf("expected Connection used to establish a cursor to implement PinnedConnection, but got %T", info.Connection)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Make error message more correct.

Suggested change
return CursorResponse{}, fmt.Errorf("expected Connection used to establish a cursor to implement PinnedConnection, but got %T", info.Connection)
return CursorResponse{}, fmt.Errorf("expected Connection used to establish a cursor (type %T) to to support pinning, but it does not", info.Connection)

if !ok {
refConn := info.Connection.Pinner
if refConn == nil {
//debug.PrintStack()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Remove commented-out code.

Suggested change
//debug.PrintStack()

@@ -499,7 +501,8 @@ func (bc *BatchCursor) getOperationDeployment() Deployment {
// handled for these commands in this mode.
type loadBalancedCursorDeployment struct {
errorProcessor ErrorProcessor
conn PinnedConnection
//conn PinnedConnection
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Remove commented-out code.

Suggested change
//conn PinnedConnection

Copy link
Collaborator

@qingyang-hu qingyang-hu left a comment

Choose a reason for hiding this comment

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

LGTM once the commented-out lines are cleared.

@prestonvasquez prestonvasquez merged commit 7237136 into mongodb:master Mar 18, 2024
27 of 33 checks passed
@prestonvasquez prestonvasquez deleted the connection-poc branch March 18, 2024 22:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority-3-low Low Priority PR for Review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants