Skip to content
New issue

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

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

Already on GitHub? # to your account

fix: Do not panic when using an unexpected cursor type #26165

Open
wants to merge 15 commits into
base: main-2.x
Choose a base branch
from

Conversation

devanbenz
Copy link

This PR is used to alleviate the erroneous panic we are seeing corresponding with #26142 There should not be a panic and instead we should be throwing an error.

This PR is used to alleviate the erroneous panic we are seeing
corresponding with #26142.
There should not be a panic and instead we should be throwing an error.
Copy link
Contributor

@davidby-influx davidby-influx left a comment

Choose a reason for hiding this comment

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

Still some panics left in the code, and error messages are cryptic.

panic(fmt.Sprintf("unreachable: %T", cur))
return nil, &errors2.Error{
Code: errors2.EInvalid,
Msg: fmt.Sprintf("unreachable: %s", arrayCursorType(cur)),
Copy link
Contributor

Choose a reason for hiding this comment

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

unreachable is a bad error message. Help the user out with something like unsupported array cursor type

panic(fmt.Sprintf("unreachable: %T", cur))
return nil, &errors2.Error{
Code: errors2.EInvalid,
Msg: fmt.Sprintf("unreachable: %s", arrayCursorType(cur)),
Copy link
Contributor

Choose a reason for hiding this comment

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

As above for error message.

panic(fmt.Sprintf("unreachable: %T", cur))
return nil, &errors2.Error{
Code: errors2.EInvalid,
Msg: fmt.Sprintf("unreachable: %s", arrayCursorType(cur)),
Copy link
Contributor

Choose a reason for hiding this comment

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

As above for error message

panic(fmt.Sprintf("unreachable: %T", cur))
return nil, &errors2.Error{
Code: errors2.EInvalid,
Msg: fmt.Sprintf("unreachable: %s", arrayCursorType(cur)),
Copy link
Contributor

Choose a reason for hiding this comment

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

As above.

panic(fmt.Sprintf("unsupported for aggregate min: %T", cur))
return nil, &errors2.Error{
Code: errors2.EInvalid,
Msg: fmt.Sprintf("unsupported for aggregate min: %s", arrayCursorType(cur)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, a better error message!

panic(fmt.Sprintf("unreachable: %T", cur))
return nil, &errors2.Error{
Code: errors2.EInvalid,
Msg: fmt.Sprintf("unreachable: %s", arrayCursorType(cur)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Better error message, see above.

panic(fmt.Sprintf("unreachable: %T", cur))
return nil, &errors2.Error{
Code: errors2.EInvalid,
Msg: fmt.Sprintf("unreachable: %s", arrayCursorType(cur)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Better error message, see suggestions above.

panic(fmt.Sprintf("unreachable: %T", cur))
return nil, &errors2.Error{
Code: errors2.EInvalid,
Msg: fmt.Sprintf("unreachable: %s", arrayCursorType(cur)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Better message

panic(fmt.Sprintf("unreachable: %T", cur))
return nil, &errors2.Error{
Code: errors2.EInvalid,
Msg: fmt.Sprintf("unreachable: %s", arrayCursorType(cur)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Better error message.

case datatypes.Aggregate_AggregateTypeMax:
return newWindowMaxArrayCursor(cursor, window), nil
return newWindowMaxArrayCursor(cursor, window)
case datatypes.Aggregate_AggregateTypeMean:
return newWindowMeanArrayCursor(cursor, window)
default:
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't panic in this default statement

Copy link
Contributor

Choose a reason for hiding this comment

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

See also panic on line 143. We should not panic for bad flux.

@devanbenz devanbenz marked this pull request as draft March 20, 2025 15:54
@devanbenz
Copy link
Author

Converting to draft as I make changes here.

@devanbenz devanbenz force-pushed the db/panic-at-the-cursor branch from 72977bc to c8ee812 Compare March 20, 2025 16:42
@@ -311,6 +314,7 @@ func (gi *groupIterator) handleRead(f func(flux.Table) error, rs storage.GroupRe
gc storage.GroupCursor
cur cursors.Cursor
table storageTable
err error
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be a separate declaration, because it is not a resource that much be closed if not nil on return.

@@ -121,7 +121,10 @@ func (g *groupResultSet) Next() GroupCursor {
// the time range of the query.
func (g *groupResultSet) seriesHasPoints(row *SeriesRow) bool {
// TODO(sgc): this is expensive. Storage engine must provide efficient time range queries of series keys.
cur := g.arrayCursors.createCursor(*row)
cur, err := g.arrayCursors.createCursor(*row)
Copy link
Contributor

Choose a reason for hiding this comment

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

So this is a lost error; unreported, never makes it out of this method scope. I'm not sure how to handle this, but because there is also a panic on line 148, you may need to return a (bool, error) from this method to get this error and the (soon-to-be-eliminated) panic out to the user.

Copy link
Contributor

@davidby-influx davidby-influx left a comment

Choose a reason for hiding this comment

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

A few notes on this draft.

cur = c.arrayCursors.createCursor(seriesRow)
cur, err = c.arrayCursors.createCursor(seriesRow)
if err != nil {
return nil, err
Copy link
Contributor

Choose a reason for hiding this comment

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

The other returns are (cur, err). Should we hand back the cur here (in case there is some clean-up necessary on it)? Or are we certain it is always nil if createCursor fails (which would be better).

Copy link
Author

Choose a reason for hiding this comment

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

cur here will be nil if the createCursor call fails.
This switch statement gets called during createCursor

func newWindowAggregateArrayCursor(ctx context.Context, agg *datatypes.Aggregate, window interval.Window, cursor cursors.Cursor) (cursors.Cursor, error) {
	if cursor == nil {
		return nil, nil
	}

	switch agg.Type {
	case datatypes.Aggregate_AggregateTypeCount:
		return newWindowCountArrayCursor(cursor, window)
	case datatypes.Aggregate_AggregateTypeSum:
		return newWindowSumArrayCursor(cursor, window)
	case datatypes.Aggregate_AggregateTypeFirst:
		return newWindowFirstArrayCursor(cursor, window)
	case datatypes.Aggregate_AggregateTypeLast:
		return newWindowLastArrayCursor(cursor, window)
	case datatypes.Aggregate_AggregateTypeMin:
		return newWindowMinArrayCursor(cursor, window)
	case datatypes.Aggregate_AggregateTypeMax:
		return newWindowMaxArrayCursor(cursor, window)
	case datatypes.Aggregate_AggregateTypeMean:
		return newWindowMeanArrayCursor(cursor, window)
	default:
		return nil, &errors2.Error{
			Code: errors2.EInvalid,
			Msg:  fmt.Sprintf("unsupported window aggregate cursor: %s", agg.Type),
		}
	}
}

Each of the newWindow...Cursor calls also has a switch statement that will bubble up nil for the cursor value as well.

@@ -119,7 +119,7 @@ func resultSetToString(wr io.Writer, rs reads.ResultSet, opts ...optionFn) {
for rs.Next() {
fmt.Fprint(wr, "series: ")
tagsToString(wr, rs.Tags())
cur := rs.Cursor()
cur, _ := rs.Cursor()
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmmm, not sure how important this is to fix....

At least add a comment.

Copy link
Author

Choose a reason for hiding this comment

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

Sounds good can do - I was actually planning on going back and adding in this error while I work on some tests for these changes to test capturing errors.

Copy link
Author

Choose a reason for hiding this comment

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

Taking a look at this code it looks like the tests that resultSetToString gets called in all have a nil cursor so the error will never bubble up in these tests. The continue here

is called in every test. I've added a comment.

@@ -257,7 +257,11 @@ func (s *Store) tagKeysWithFieldPredicate(ctx context.Context, mqAttrs *metaquer
rs := reads.NewFilteredResultSet(ctx, mqAttrs.start, mqAttrs.end, cur)
for rs.Next() {
func() {
c := rs.Cursor()
c, err := rs.Cursor()
Copy link
Contributor

Choose a reason for hiding this comment

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

Return the error out of this anonymous function; the top level function has an error return, so the plumbing is only local.

The rs.Next loop should halt on error (as opposed to continuing as is should for c == nil when there is no data.

@@ -623,7 +627,11 @@ func (s *Store) tagValuesSlow(ctx context.Context, mqAttrs *metaqueryAttributes,
rs := reads.NewFilteredResultSet(ctx, mqAttrs.start, mqAttrs.end, cur)
for rs.Next() {
func() {
c := rs.Cursor()
c, err := rs.Cursor()
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comments as in the similar code above.

@@ -764,7 +772,11 @@ func (s *Store) seriesCardinalityWithPredicateAndTime(ctx context.Context, shard
rs := reads.NewFilteredResultSet(ctx, start, end, cur)
for rs.Next() {
func() {
c := rs.Cursor()
c, err := rs.Cursor()
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

As above.

@devanbenz devanbenz marked this pull request as ready for review March 26, 2025 20:41
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
area/flux Issues related to the Flux query engine area/storage kind/bug team/edge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants