-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
fix: copy names from mmapped memory before closing iterator #22040
Conversation
c4ca240
to
2171e57
Compare
This fix ensures that memory-mapped files are not released before pointers into them are copied into heap memory. MeasurementNamesByExpr() and MeasurementNamesByPredicate() can cause panics by copying memory from mmapped files that have been released. The functions they call use iterators to files which are closed (releasing the mmapped files) before the memory is safely copied to the heap. closes #22000
4aa6578
to
b6ccacc
Compare
tsdb/index.go
Outdated
return | ||
} | ||
|
||
ls, lsfi, err := exprToSlice(e.LHS) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lsfi.ToSlice()
gives ls
right? Why name both?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because ToSlice() can fail on none-slice-based iterators.
tsdb/index.go
Outdated
if e.Op == influxql.OR { | ||
return bytesutil.Union(lhs, rhs), nil | ||
return newFileMeasurementSliceIterator(bytesutil.Union(ls, rs), mis), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly it might be clearer if this read like:
newFileMeasurementSliceIterator(bytesutil.Union(lsfi.UnsafeToSlice(), rsfi.UnsafeToSlice), MeasurementIterators{lsfi, rsfi})
Also would it be clearer to name MeasurementIterators
as MeasurementIteratorClosers
?
@@ -968,6 +988,46 @@ func (itr *measurementSliceIterator) Next() (name []byte, err error) { | |||
return name, nil | |||
} | |||
|
|||
func (itr *measurementSliceIterator) ToSlice() [][]byte { | |||
return itr.names |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having both ToSlice
and Next
on the same object seems prone to accident...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe if it was named RemainingAsSlice
or something that suggests it is part of the iteration interface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UnderlyingSlice() is the new name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, UnderlyingSlice still hints to me that the slice is the whole thing instead of eaten away at by Next
, but ok.
|
||
mitr, err := is.measurementIterator() | ||
if err != nil { | ||
return nil, err | ||
} else if mitr == nil { | ||
return nil, nil | ||
} | ||
defer mitr.Close() | ||
defer func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've recently seen a pattern using sync.Once
to do this sort of thing, and I like it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.g.:
// early:
once sync.Once{}
defer once.Do(mitr.Close)
//later
var toReturn ...
once.Do(func(){
toReturn = newFileMeasurementSliceIterator(names, MeasurementIterators{mitr}), nil
})
return toReturn
So you're guaranteed just one of either the close or the delegation of the close succeeds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment doesn't need to be taken for the PR, just an observation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this pattern won't work here, because the initial defer once.Do(mitr.Close)
will be called first, before the close on the toReturn
. And that's what is causing the panic; a close on the iterator before the data is read out. But it's a nice pattern for other places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm - I think it would work, here's a playground example. But not necessary here. https://play.golang.org/p/35qO7UPTOyG
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see; Once works differently than a similar construct I used in another language; my mistake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comments
Mostly naming comments. |
@@ -1422,24 +1471,24 @@ func (is IndexSet) measurementNamesByExpr(auth query.FineAuthorizer, expr influx | |||
case *influxql.ParenExpr: | |||
return is.measurementNamesByExpr(auth, e.Expr) | |||
default: | |||
return nil, fmt.Errorf("Invalid measurement expression %#v", expr) | |||
return nil, fmt.Errorf("invalid measurement expression %#v", expr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -949,6 +949,11 @@ func (a MeasurementIterators) Close() (err error) { | |||
return err | |||
} | |||
|
|||
type MeasurementSliceIterator interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is much nicer than ToSlice
as a free function.
Ugh - you hit a new flaky test, I have a PR up to fix: #22038 |
This fix ensures that memory-mapped files are not released before pointers into them are copied into heap memory. MeasurementNamesByExpr() and MeasurementNamesByPredicate() can cause panics by copying memory from mmapped files that have been released. The functions they call use iterators to files which are closed (releasing the mmapped files) before the memory is safely copied to the heap. closes #22000 (cherry picked from commit a989f8f)
This fix ensures that memory-mapped files are not released before pointers into them are copied into heap memory. MeasurementNamesByExpr() and MeasurementNamesByPredicate() can cause panics by copying memory from mmapped files that have been released. The functions they call use iterators to files which are closed (releasing the mmapped files) before the memory is safely copied to the heap. closes #22000 (cherry picked from commit a989f8f)
This fix ensures that memory-mapped files are not released before pointers into them are copied into heap memory. MeasurementNamesByExpr() and MeasurementNamesByPredicate() can cause panics by copying memory from mmapped files that have been released. The functions they call use iterators to files which are closed (releasing the mmapped files) before the memory is safely copied to the heap. closes #22000 (cherry picked from commit a989f8f)
…22058) This fix ensures that memory-mapped files are not released before pointers into them are copied into heap memory. MeasurementNamesByExpr() and MeasurementNamesByPredicate() can cause panics by copying memory from mmapped files that have been released. The functions they call use iterators to files which are closed (releasing the mmapped files) before the memory is safely copied to the heap. closes #22000 (cherry picked from commit a989f8f) Closes #22001
…22059) This fix ensures that memory-mapped files are not released before pointers into them are copied into heap memory. MeasurementNamesByExpr() and MeasurementNamesByPredicate() can cause panics by copying memory from mmapped files that have been released. The functions they call use iterators to files which are closed (releasing the mmapped files) before the memory is safely copied to the heap. closes #22000 (cherry picked from commit a989f8f) closes #22002
…22060) This fix ensures that memory-mapped files are not released before pointers into them are copied into heap memory. MeasurementNamesByExpr() and MeasurementNamesByPredicate() can cause panics by copying memory from mmapped files that have been released. The functions they call use iterators to files which are closed (releasing the mmapped files) before the memory is safely copied to the heap. closes #22000 (cherry picked from commit a989f8f) closes #22003
…ta#22040) This fix ensures that memory-mapped files are not released before pointers into them are copied into heap memory. MeasurementNamesByExpr() and MeasurementNamesByPredicate() can cause panics by copying memory from mmapped files that have been released. The functions they call use iterators to files which are closed (releasing the mmapped files) before the memory is safely copied to the heap. closes influxdata#22000
…ta#22040) This fix ensures that memory-mapped files are not released before pointers into them are copied into heap memory. MeasurementNamesByExpr() and MeasurementNamesByPredicate() can cause panics by copying memory from mmapped files that have been released. The functions they call use iterators to files which are closed (releasing the mmapped files) before the memory is safely copied to the heap. closes influxdata#22000
This fix ensures that memory-mapped files are not released
before pointers into them are copied into heap memory.
MeasurementNamesByExpr() and MeasurementNamesByPredicate() can
cause panics by copying memory from mmapped files that have been
released. The functions they call use iterators to files which
are closed (releasing the mmapped files) before the memory is
safely copied to the heap.
closes #22000