Skip to content

Commit c20a54f

Browse files
committed
Fix protocol version negotiation issues with v5
Driver was automatically setting beta flag when using v5 protocol which causes issues when trying to connect to Cassandra versions that supported beta v5 like 3.11. Also, this patch makes the protocol version discovery process more resilient. Still not a long term solution since long term we should make the protocol version negotiation work like in the java driver. Patch by João Reis; reviewed by Lukasz Antoniak for CASSGO-88
1 parent a6e8291 commit c20a54f

File tree

4 files changed

+46
-8
lines changed

4 files changed

+46
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6565

6666
### Fixed
6767

68+
#### 2.0.0
69+
70+
- Do not set beta protocol flag when using v5 (CASSGO-88)
71+
6872
#### 2.0.0-rc1
6973

7074
- Cassandra version unmarshal fix (CASSGO-49)

conn.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1317,7 +1317,21 @@ func (c *Conn) execInternal(ctx context.Context, req frameBuilder, tracer Tracer
13171317
defer c.releaseStream(call)
13181318

13191319
if v := resp.framer.header.version.version(); v != c.version {
1320-
return nil, NewErrProtocol("unexpected protocol version in response: got %d expected %d", v, c.version)
1320+
errProtocol := NewErrProtocol("unexpected protocol version in response: got %d expected %d", v, c.version)
1321+
responseFrame, err := resp.framer.parseFrame()
1322+
if err != nil {
1323+
c.logger.Warning("Framer error while attempting to parse potential protocol error.",
1324+
newLogFieldError("err", err))
1325+
return nil, errProtocol
1326+
}
1327+
//goland:noinspection GoTypeAssertionOnErrors
1328+
errFrame, isErrFrame := responseFrame.(errorFrame)
1329+
if !isErrFrame || errFrame.Code() != ErrCodeProtocol {
1330+
return nil, errProtocol
1331+
}
1332+
return nil, NewErrProtocol("%w", &protocolError{
1333+
errFrame,
1334+
})
13211335
}
13221336

13231337
return resp.framer, nil

control.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,13 +204,34 @@ func shuffleHosts(hosts []*HostInfo) []*HostInfo {
204204

205205
// this is going to be version dependant and a nightmare to maintain :(
206206
var protocolSupportRe = regexp.MustCompile(`the lowest supported version is \d+ and the greatest is (\d+)$`)
207+
var betaProtocolRe = regexp.MustCompile(`Beta version of the protocol used \(.*\), but USE_BETA flag is unset`)
207208

208209
func parseProtocolFromError(err error) int {
210+
errStr := err.Error()
211+
212+
var errProtocol ErrProtocol
213+
if errors.As(err, &errProtocol) {
214+
err = errProtocol.error
215+
}
216+
209217
// I really wish this had the actual info in the error frame...
210-
matches := protocolSupportRe.FindAllStringSubmatch(err.Error(), -1)
218+
matches := betaProtocolRe.FindAllStringSubmatch(errStr, -1)
219+
if len(matches) == 1 {
220+
var protoErr *protocolError
221+
if errors.As(err, &protoErr) {
222+
version := protoErr.frame.Header().version.version()
223+
if version > 0 {
224+
return int(version - 1)
225+
}
226+
}
227+
return 0
228+
}
229+
230+
matches = protocolSupportRe.FindAllStringSubmatch(errStr, -1)
211231
if len(matches) != 1 || len(matches[0]) != 2 {
212-
if verr, ok := err.(*protocolError); ok {
213-
return int(verr.frame.Header().version.version())
232+
var protoErr *protocolError
233+
if errors.As(err, &protoErr) {
234+
return int(protoErr.frame.Header().version.version())
214235
}
215236
return 0
216237
}
@@ -223,11 +244,13 @@ func parseProtocolFromError(err error) int {
223244
return max
224245
}
225246

247+
const highestProtocolVersionSupported = 5
248+
226249
func (c *controlConn) discoverProtocol(hosts []*HostInfo) (int, error) {
227250
hosts = shuffleHosts(hosts)
228251

229252
connCfg := *c.session.connCfg
230-
connCfg.ProtoVersion = 5 // TODO: define maxProtocol
253+
connCfg.ProtoVersion = highestProtocolVersionSupported
231254

232255
handler := connErrorHandlerFn(func(c *Conn, err error, closed bool) {
233256
// we should never get here, but if we do it means we connected to a

frame.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,9 +393,6 @@ func newFramer(compressor Compressor, version byte, r *RegisteredTypes) *framer
393393
if compressor != nil {
394394
flags |= flagCompress
395395
}
396-
if version == protoVersion5 {
397-
flags |= flagBetaProtocol
398-
}
399396

400397
version &= protoVersionMask
401398

0 commit comments

Comments
 (0)