-
Notifications
You must be signed in to change notification settings - Fork 164
Fix[MQB]: stop catchup before reaching common iterator #1046
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
base: main
Are you sure you want to change the base?
Conversation
| bsls::TimeInterval* delay, | ||
| mqbi::StorageIterator* reader, | ||
| mqbi::StorageIterator* start, | ||
| const bdlb::Variant<bsls::Types::Uint64, bmqt::MessageGUID>& stop) |
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.
As discussed with @dorjesinpo, I will try to find a way to provide stop without building a Variant object. Template arg might work well, however, there might be cleaner ways to refactor the code
678098
left a comment
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.
Counter thing introduces a multi-threading bug
77e816f to
75ad47e
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.
Build 3170 of commit 75ad47e has completed with FAILURE
| // cannot erase the GUID because of the d_iterator | ||
|
|
||
| if (d_iterator->second.numElements() == 0) { | ||
| if (message().numElements() == 0) { |
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.
message() accessor now checks that !atEnd(), the same check happens at line 124. It means that the same thing is being checked twice during removeCurrentElement call
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.
Correct. We can remove the assert in message() if we want to. Everywhere it is called, there is the same (duplicate) check prior to the call. But, it looks safer to keep the assert. If we want optimization, we can do something about asserts maybe.
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.
const PushStream::Message& message() const is a protected API, we fully control how to use it from within this class. All its usages are visible and easy to review.
I think it's worth to add checks where we use the class from external code but it's not worth to check any action in internal API, if we have trust in object's state due to the checks that were already performed.
| clearCache(); | ||
|
|
||
| if (d_iterator->second.numElements() == 0) { | ||
| if (message().numElements() == 0) { |
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.
!atEnd is checked twice now during advance call
| if (d_currentOrdinal > appOrdinal) { | ||
| d_currentOrdinal = 0; | ||
| d_currentElement = d_iterator->second.front(); | ||
| d_currentElement = message().d_appMessages.front(); |
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.
!atEnd is checked twice now in this function
| mqbblp::PushStreamIterator* d_start; | ||
| mqbblp::PushStreamIterator* d_stop; |
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.
| mqbblp::PushStreamIterator* d_start; | |
| mqbblp::PushStreamIterator* d_stop; | |
| mqbblp::PushStreamIterator* d_start_p; | |
| mqbblp::PushStreamIterator* d_stop_p; |
| mqbi::StorageIterator* d_start; | ||
| mqbi::StorageIterator* d_stop; |
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.
| mqbi::StorageIterator* d_start; | |
| mqbi::StorageIterator* d_stop; | |
| mqbi::StorageIterator* d_start_p; | |
| mqbi::StorageIterator* d_stop_p; |
| , d_stop(stop) | ||
| , d_doAdvance(false) | ||
| { | ||
| // NOTHING |
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.
| // NOTHING | |
| // PRECONDITIONS | |
| BSLS_ASSERT_SAFE(d_start_p); | |
| BSLS_ASSERT_SAFE(d_end_p); |
Signed-off-by: dorjesinpo <[email protected]>
Signed-off-by: dorjesinpo <[email protected]>
75ad47e to
8912eb8
Compare
Signed-off-by: dorjesinpo <[email protected]>
8912eb8 to
c080fc3
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.
Build 3175 of commit c080fc3 has completed with FAILURE
678098
left a comment
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.
A couple more comments
| /// Return number of Elements in the list | ||
| unsigned int numElements() const; | ||
|
|
||
| bsls::Types::Uint64 sequenceNumber() const; |
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.
Is there a reason to keep data signed and accessor unsigned? Let's keep both unsigned?
| // cannot erase the GUID because of the d_iterator | ||
|
|
||
| if (d_iterator->second.numElements() == 0) { | ||
| if (message().numElements() == 0) { |
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.
const PushStream::Message& message() const is a protected API, we fully control how to use it from within this class. All its usages are visible and easy to review.
I think it's worth to add checks where we use the class from external code but it's not worth to check any action in internal API, if we have trust in object's state due to the checks that were already performed.
| return 0; | ||
| } | ||
|
|
||
| if (!d_stop_p->atEnd()) { |
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.
We only advance d_start_p. This means that the result of d_stop_p->atEnd() never changes unless we pass a pointer to the same mqbi::StorageIterator:
VirtualIterator iter(start_p, start_p);
In this case we will return 0 on line 206 and never reach the check if (!d_stop_p->atEnd()) {
It is possible to compute d_stop_p->sequenceNumber() just once in constructor:
const bsls::Types::Uint64 d_stopSequenceNumber;
VirtualIterator(mqbblp::PushStreamIterator* start,
mqbblp::PushStreamIterator* stop)
: d_start_p(start)
, d_stopSequenceNumber((stop && !stop->atEnd()) ? stop->sequenceNumber() : bsl::numeric_limits<bsls::Types::Uint64>::max())
, d_doAdvance(false)
{
// PRECONDITIONS
BSLS_ASSERT_SAFE(d_start_p);
}
And simplify the condition:
if (d_stopSequenceNumber <= d_start_p->sequenceNumber()) {
return 0;
}
Note that when we call next() multiple times, we always check 2 if conditions, after this change we will only check 1.
| } | ||
|
|
||
| if (!d_stop_p->atEnd()) { | ||
| if (d_start_p->guid() == d_stop_p->guid()) { |
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.
Same here. When we call next() multiple times we always check these 2 conditions. We can just cache MessageGuid and check one:
if (d_start_p->guid() == d_stopGuid) {
return 0;
}
| // this prevents file set from closing possibly for a very long time. | ||
| // Make sure to invalidate any cached data within this iterator after use. | ||
| // TODO: refactor iterators to remove cached data. | ||
| d_start_p->clearCache(); |
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.
Don't we need to do the same for RelayQueueEngine::VirtualIterator?
When
RelayQueueEnginecallscatchUpfor a single App, the PushStream may have a gap resulting in the App first element being behind common iterator.A solution is to introduce a seqeunce number (only for PushStream messages)
For
RootQueueEngine,catchUpstill can rely on comparing current guid against the common iterator.Since both engines use the same
mqbi::StorageIteratorinterface, the duality is expressed asbdlb::Variant<bsls::Types::Uint64, bmqt::MessageGUID>