-
Notifications
You must be signed in to change notification settings - Fork 14
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
Handle zero chunk size #263
Conversation
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.
@moshaad7 per our conversation, let's get rid of the redundant check in posting.go now that you've handled it within this method.
Let's also get some clarity on what happens when we return an error
when we stumble into this situation.
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.
Per previous comment.
@moshaad7 check out the latest 2 stack traces shared here - blevesearch/bleve#1662 (comment) . It seems even if we handle the error case of chunkSize being zero prior to setting posting's attribute, you could run into divide by zero panics downstream on account of not updating the attribute in line 644 and 747 of posting.go which we'll need to handle as well. |
@abhinavdangeti I agree. func (i *PostingsIterator) nextDocNumAtOrAfter(...) {
...
if i.Actual == nil || !i.Actual.HasNext() {
return 0, false, nil
}
if i.postings == nil || i.postings == emptyPostingsList {
// couldn't find anything
return 0, false, nil
}
...
} A PostingsList can only pass these checks and cause panic if
I tried several flows, by writing test cases, to try to get into this state of PostingsList, I then wrote the blow test case to forcefully endup in the panic situation, and can see divide by zero, when the above two conditions met. func TestDictWithNilFstReader(t *testing.T) {
preAllocPl := &PostingsList{} // postings list with nil postings and zero chunkSize
// Add an item just to simulate a populated postings list
preAllocPl.postings = roaring.New()
preAllocPl.postings.Add(1000) // this will be cleared by postingsListInit
except := roaring.New()
except.Add(1000)
dict := &Dictionary{} // dictionary with nil fst reader
pl, err := dict.PostingsList([]byte("foo"), except, preAllocPl)
if err != nil {
t.Fatalf("expected nil error, got: %v", err)
}
// Add some more items to the postings list
// So now our PostingsList have non nil postings and 0 chunkSize
//
// Since fstReader is nil, this simulation isn't realistic
preAllocPl.postings.Add(1000)
preAllocPl.postings.Add(2000)
preAllocPl.postings.Add(3000)
if pl != nil {
iter := pl.Iterator(false, false, false, nil)
posting, err := iter.Next()
if err != nil {
t.Fatalf("expected nil error, got: %v", err)
}
t.Logf("posting: %+v", posting)
}
}
For now we can add chunkSize!=0 checks in this method to avoid getting into panic situation. |
adbb2d1
to
51b9ade
Compare
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.
@moshaad7 one question still stands though - if we report this error now (better than the panic of course), how is the situation dealt with by the caller(s)?
The existing implementation of the method getChunkSize(...) (uint64, error), in some cases, can return chunkSize==0 and err==nil. The onus is on the caller to check for such possibility and handle it properly. Callers often use the returned chunkSize as a divisor and a zero chunkSize lead to panic. see #209 This PR intends to update the method implementation to always return an error in case the returned chunkSize value is 0. That way caller need to only worry about error being non-nil. Callers which are ok with 0 chunkSize can check the returned error against ErrChunkSizeZero
51b9ade
to
3268000
Compare
As it stands today, the error returned will be trickled down all the way up to user (Query will fail). This is more of a product decision, I will need team's consensus before I implement this. But just to give the glimpse of what changes will be required, |
I'd like for one more review here from the team. |
The existing implementation of the method getChunkSize(...) (uint64, error), in some cases, can return chunkSize==0 and err==nil. The onus is on the caller to check for such possibility and handle it properly. Callers often use the returned chunkSize as a divisor and a zero chunkSize lead to panic. see #209 This PR intends to update the method implementation to always return an error in case the returned chunkSize value is 0. That way caller need to only worry about error being non-nil. Callers which are ok with 0 chunkSize can check the returned error against ErrChunkSizeZero
Backport of #263 + #270 --------- Co-authored-by: Abhinav Dangeti <[email protected]>
The existing implementation of the method
getChunkSize(...) (uint64, error), in some cases,
can return chunkSize==0 and err==nil.
The onus is on the caller to check for such possibility and handle it properly.
Callers often use the returned chunkSize as a divisor and a zero chunkSize lead to panic.
see #209
This PR intends to update the method implementation to always return an error in case the returned chunkSize value is 0.
That way caller need to only worry about error being non-nil.
Callers which are ok with 0 chunkSize can check the returned error against ErrChunkSizeZero