Skip to content

Cassgo 100 - #23

Closed
worryg0d wants to merge 14 commits into
masterfrom
cassgo-100
Closed

worryg0d wants to merge 14 commits into
masterfrom
cassgo-100

Conversation

@worryg0d

Copy link
Copy Markdown
Owner

No description provided.

Copilot AI left a comment

Copy link
Copy Markdown

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 introduces a dedicated segment codec and integrates Native Protocol v5 “segment” framing into the connection read/write paths, refactoring existing frame/segment logic and moving related tests into a new test file.

Changes:

  • Added segmentCodec for encoding/decoding compressed and uncompressed segments (with CRC checks).
  • Updated Conn startup flow to switch to segment-based reader/writer after successful handshake for proto v5+.
  • Moved/expanded segment-related tests out of frame_test.go into segment_codec_test.go and updated affected integration/unit tests.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
segment_codec.go New segment encoding/decoding implementation with header/payload checksums and compression handling.
segment_codec_test.go New unit tests covering segment codec behaviors and edge cases.
frame.go Removes prior segment framing helpers from frame implementation.
frame_test.go Removes segment-related tests now covered by segment_codec_test.go.
conn.go Adds segmentReader/segmentWriter and switches to segment framing for proto v5+ after startup.
conn_test.go Updates tests for new recv signature and adds segmentWriter multi-frame test.
control.go Uses execInternal in place of removed exec.
cassandra_test.go Updates exec callsite, tweaks one session creation, and adjusts compression-related test queries/table names.

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

Comment thread cassandra_test.go Outdated
Comment thread cassandra_test.go Outdated
Comment thread segment_codec.go Outdated
Comment thread segment_codec_test.go
Comment thread conn.go
Comment on lines +2104 to +2107
req.resultChan <- writeResult{
n: totalWritten,
err: flushErr,
}

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

flushBigFrameImmediately reports totalWritten (sum of encoded segment bytes written) back to the caller. contextWriter.writeContext is required to report bytes written from the caller-provided buffer (p), so this can exceed len(req.data) and also breaks callers that interpret n==0 as "not written". Return len(req.data) on success (or 0 on failure), and only use segment-level byte counts internally/for logging.

Copilot uses AI. Check for mistakes.
Comment thread conn.go
Comment thread conn.go
Comment thread conn.go
Comment on lines +2056 to +2061
for _, req := range sw.writeRequests {
req.resultChan <- writeResult{
n: n,
err: nil,
}
}

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

flushCurrentSegment returns the segment write byte count n to every queued request. This violates the contextWriter contract (it must return bytes written from that request’s p, i.e., 0 <= n <= len(p)), and it breaks execInternal’s n==0 error handling. Return len(req.data) for each successfully queued frame (or track per-frame progress), and return 0 on segment-level failure.

Copilot uses AI. Check for mistakes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.


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

Comment thread conn.go Outdated
Comment on lines +1982 to +1989
select {
case <-ctx.Done():
return 0, ctx.Err()
case <-sw.quit:
return 0, ErrConnectionClosed
case result := <-resultChan:
return result.n, result.err
}

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

segmentWriter.writeContext can return ctx.Err() after the request has already been enqueued, but the flusher will still write that frame later. This breaks the contextWriter contract and can cause execInternal to release the stream (n==0) while the request is still sent, leading to responses on a reused stream ID. Ensure that once a request is queued it either (a) is guaranteed not to be written when returning ctx.Err(), or (b) writeContext waits for the queued write result (ignoring ctx) similar to writeCoalescer, or (c) supports canceling/removing the queued request before it is flushed.

Copilot uses AI. Check for mistakes.
Comment thread conn.go
return
case req := <-sw.writeCh:
frame := req.data
if len(frame) > maxSegmentPayloadSize {

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

When a frame larger than maxSegmentPayloadSize arrives, runFlusher writes it immediately via flushBigFrameImmediately without first flushing any already-queued smaller frames. That can reorder writes on the connection (later big frame sent before earlier queued frames). Flush the current segment (if non-empty) and reset state before writing the big frame to preserve ordering.

Suggested change
if len(frame) > maxSegmentPayloadSize {
if len(frame) > maxSegmentPayloadSize {
if len(sw.writeRequests) > 0 {
sw.flushCurrentSegment()
sw.reset()
running = false
}

Copilot uses AI. Check for mistakes.
Comment thread conn.go Outdated
return fmt.Errorf("gocql: cluster schema versions not consistent: %+v", schemas)
}

// segmentWriter allows batching multiple frames into a signle segment before flushing them to the connection.

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

Typo in comment: "signle" should be "single".

Suggested change
// segmentWriter allows batching multiple frames into a signle segment before flushing them to the connection.
// segmentWriter allows batching multiple frames into a single segment before flushing them to the connection.

Copilot uses AI. Check for mistakes.
Comment thread conn_test.go Outdated
Comment on lines +1622 to +1650
// synced by doneReadCh
resultBuf := make([]byte, 0, 128)

go func() {
defer close(doneReadCh)
buf := make([]byte, 128)
n, err := server.Read(buf)
if err != nil && err != io.EOF {
t.Errorf("Failed to read segment: %v", err)
return
}
// Expected to read only a single segment with two frames inside
segmentCodec := newSegmentCodec(nil)
body, isSelfContained, err := segmentCodec.decode(bytes.NewReader(buf[:n]))
require.NoError(t, err)
require.True(t, isSelfContained)
resultBuf = append(resultBuf, body...)
}()

go func() {
sw.writeContext(context.Background(), []byte("one"))
}()

go func() {
sw.writeContext(context.Background(), []byte("two"))
}()

select {
case <-doneReadCh:

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

TestSegmentWriter_MultipleFrames reads from a real TCP connection with a single server.Read call and assumes it received an entire segment. TCP reads can be partial, making this test flaky. Consider decoding directly from the conn via segmentCodec.decode(server) (which uses io.ReadFull internally) or reading in a loop until the full segment is available; also capture/require errors returned by sw.writeContext in the writer goroutines so failures don't get silently ignored.

Suggested change
// synced by doneReadCh
resultBuf := make([]byte, 0, 128)
go func() {
defer close(doneReadCh)
buf := make([]byte, 128)
n, err := server.Read(buf)
if err != nil && err != io.EOF {
t.Errorf("Failed to read segment: %v", err)
return
}
// Expected to read only a single segment with two frames inside
segmentCodec := newSegmentCodec(nil)
body, isSelfContained, err := segmentCodec.decode(bytes.NewReader(buf[:n]))
require.NoError(t, err)
require.True(t, isSelfContained)
resultBuf = append(resultBuf, body...)
}()
go func() {
sw.writeContext(context.Background(), []byte("one"))
}()
go func() {
sw.writeContext(context.Background(), []byte("two"))
}()
select {
case <-doneReadCh:
writeErrCh := make(chan error, 2)
// synced by doneReadCh
resultBuf := make([]byte, 0, 128)
go func() {
defer close(doneReadCh)
// Expected to read only a single segment with two frames inside.
// Decode directly from the connection so partial reads are handled correctly.
segmentCodec := newSegmentCodec(nil)
body, isSelfContained, err := segmentCodec.decode(server)
require.NoError(t, err)
require.True(t, isSelfContained)
resultBuf = append(resultBuf, body...)
}()
go func() {
writeErrCh <- sw.writeContext(context.Background(), []byte("one"))
}()
go func() {
writeErrCh <- sw.writeContext(context.Background(), []byte("two"))
}()
select {
case <-doneReadCh:
require.NoError(t, <-writeErrCh)
require.NoError(t, <-writeErrCh)

Copilot uses AI. Check for mistakes.
Comment thread segment_codec.go Outdated
Comment on lines +1 to +5
// segment_codec.go

package gocql

import (

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

New Go source files in this repo typically include the ASF license header (and the historical Gocql BSD notice) at the top (e.g., frame.go:1-23, cluster.go:1-23). segment_codec.go currently lacks this header; please add the standard license block to keep licensing consistent.

Copilot uses AI. Check for mistakes.
Comment thread conn.go Outdated
Previously, the driver encoded each individual frame in a single segment despite segments ability to hold multiple frames.
This patch introduces a mechanism that allows driver collect multiple frames before encoding them as a batch.
To achieve this, segmentWriter was introduced.

Patch by Bohdan Siryk; reviewed by TBD for CASSGO-100
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.

2 participants