Skip to content

Conversation

@devmadhuu
Copy link
Contributor

What changes were proposed in this pull request?

This PR fixes the Intermittent failure in TestOzoneRpcClientAbstract.testListSnapshot.

TestOzoneRpcClientAbstract.testListSnapshot creates 20 snapshots using createSnapshot API and asserts the count of same using listSnapshot API. This assertion of count fails intermittently.

listSnapshot API uses the org.apache.hadoop.ozone.om.ListIterator.MinHeapIterator which internally uses both CacheIterator and DBIterator and DBIterator had the logic of checking if rocks DB key is present in cache in org.apache.hadoop.ozone.om.ListIterator.DbTableIter#getNextKey, this checks the cache from table cache which may be intermittently flushed which makes the addition of duplicate entry in org.apache.hadoop.ozone.om.ListIterator.MinHeapIterator. So to fix this, we should use the pre-loaded keys in org.apache.hadoop.ozone.om.ListIterator.CacheIter#cacheKeyMap in org.apache.hadoop.ozone.om.ListIterator.CacheIter.

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-9967

How was this patch tested?

This patch is tested by repeated CI runs around 500 iterations and ZERO failure reported for this test case. Here is the green CI link.

@devmadhuu
Copy link
Contributor Author

@sumitagrawl @adoroszlai Pls review.

@adoroszlai adoroszlai added snapshot https://issues.apache.org/jira/browse/HDDS-6517 and removed test labels Jan 10, 2024
Copy link
Contributor

@hemantk-12 hemantk-12 left a comment

Choose a reason for hiding this comment

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

Thanks @devmadhuu for the patch and finding out the root cause.

Overall looks good to me, left some inline comments.

Copy link
Contributor

@sumitagrawl sumitagrawl left a comment

Choose a reason for hiding this comment

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

@devmadhuu thanks for working over this. Have few comments.
Additionally, can avoid returning null value in next() with some optimization.

Copy link
Contributor

@swamirishi swamirishi left a comment

Choose a reason for hiding this comment

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

Thanks for the patch @devmadhuu Overall the changes look good to me I had some nitpicky comment in the one place, check and see if it makes sense.

return cacheKeyMap.containsKey(key);
}

private void getNextKey() throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: instead of creating a new function, we can just remove null values when initializing the cacheCreatedKeyIterator.
cacheCreatedKeyIter = cacheKeyMap.entrySet().stream().filter(e -> e.getValue() != null).iterator();

Copy link
Contributor

Choose a reason for hiding this comment

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

We can not remove null value in cache iterator initialization as this is requried while checking db entry with cache if element is deleted or not (as deletion is marked with null value)
Optimization is done not to return null value while checking hasNext() or next(), so caller need not do check with null value.

Copy link
Contributor

Choose a reason for hiding this comment

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

cacheCreatedKeyIter = cacheKeyMap.entrySet().stream().filter(e -> e.getValue() != null).iterator();
This should not remove any element from the map.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think @swamirishi is right. doesKeyExistInCache checks if key exist in cacheKeyMap while cacheCreatedKeyIter can have filtered result.

Copy link
Contributor

Choose a reason for hiding this comment

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

yes, this filtering can be done while initializing iterator.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @hemantk-12 @swamirishi @sumitagrawl for review. This has been handled as per suggestion. Kindly re-review. Once changes finalized. I'll re-run the repeated CI run.

Copy link
Contributor

@hemantk-12 hemantk-12 left a comment

Choose a reason for hiding this comment

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

Overall looks good to me.

private final String startKey;
private final String tableName;

private HeapEntry currentKey;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: currentEntry and getCurrentEntry()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

CacheIter cacheIter = new CacheIter<>(iteratorId, table.getName(),
table.cacheIterator(), startKey, prefixKey);
Predicate<String> isKeyExistInCache = cacheIter::isKeyExistInCache;
Predicate<String> doesKeyExistInCache =
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: JFYI, now char limit is 120. It can be fit in one line. Configure/update your IDE with latest ozone-style.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok done.

Copy link
Contributor

@sumitagrawl sumitagrawl left a comment

Choose a reason for hiding this comment

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

@devmadhuu Overall looks good, have one minor comment

Copy link
Contributor

@sumitagrawl sumitagrawl left a comment

Choose a reason for hiding this comment

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

@devmadhuu LGTM +1

@devmadhuu
Copy link
Contributor Author

@swamirishi @hemantk-12 Kindly re-review.

private void getNextKey() throws IOException {
while (cacheCreatedKeyIter.hasNext() && currentKey == null) {
Map.Entry<String, Value> entry = cacheCreatedKeyIter.next();
if (null == entry.getValue()) {
Copy link
Contributor

@swamirishi swamirishi Jan 16, 2024

Choose a reason for hiding this comment

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

@sumitagrawl @devmadhuu I am surely missing something here. Correct me if I am wrong, we are doing a continue here as per this statement which will skip the null value here. So all I am asking is when we are initializing cacheCreatedKeyIter can we skip null values? The key would be still there in the cacheKeyMap. It will make this code much simpler.

Copy link
Contributor

Choose a reason for hiding this comment

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

@sumitagrawl @devmadhuu I am surely missing something here. Correct me if I am wrong, we are doing a continue here as per this statement which will skip the null value here. So all I am asking is when we are initializing cacheCreatedKeyIter can we skip null values? The key would be still there in the cacheKeyMap. It will make this code much simpler.

cacheKeyMap: This is used for 2 porpose,

  1. check if latest update available in cache compared to DB,
  • Value if not null: latest value from cache
  • Value if null: represent data is deleted and dbIterator check for this also

Now if we remove null value while initialize, then how DBIterator knows if keys are deleted? So this is required if key is deleted to skip from db iterator and hence we need this information.

  1. retrieve data in getNextKey() to caller.
    Here, null value is not required to be returned while iterator, so we can skip as above.

@swamirishi I think this will help to understand why we can not remove null value during initialization. else if any key deleted, this can not be know via dbIterator (as may not yet flushed to db with delete) and may give deleted key details to user.

Copy link
Contributor

@hemantk-12 hemantk-12 left a comment

Choose a reason for hiding this comment

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

LGTM+1.

Copy link
Contributor

@swamirishi swamirishi left a comment

Choose a reason for hiding this comment

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

I have a minor nitpicky comment on the iterator initialization. You can make the changes if you feel it is good.

return cacheKeyMap.containsKey(key);
}

private void getNextKey() throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

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

cacheCreatedKeyIter = cacheKeyMap.entrySet().stream().filter(e -> e.getValue() != null).iterator();
This should not remove any element from the map.

@sumitagrawl
Copy link
Contributor

I have a minor nitpicky comment on the iterator initialization. You can make the changes if you feel it is good.

I think above explaination gives why null value key is requried and help to avoid returning key which is deleted in cache.

@devmadhuu
Copy link
Contributor Author

@sumitagrawl @swamirishi Pls re-review.

@devmadhuu
Copy link
Contributor Author

I have a minor nitpicky comment on the iterator initialization. You can make the changes if you feel it is good.

Thanks @swamirishi for your review. Changes done as suggested. Kindly re-review.

Copy link
Contributor

@sumitagrawl sumitagrawl left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@hemantk-12 hemantk-12 left a comment

Choose a reason for hiding this comment

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

Thanks @devmadhuu for the patch and incorporating the review comments.

LGTM.

@adoroszlai adoroszlai added test and removed test labels Jan 17, 2024
@adoroszlai adoroszlai requested a review from swamirishi January 17, 2024 19:47
Copy link
Contributor

@swamirishi swamirishi left a comment

Choose a reason for hiding this comment

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

@devmadhuu Thanks for the changes LGTM

@adoroszlai adoroszlai merged commit fa98426 into apache:master Jan 17, 2024
@adoroszlai
Copy link
Contributor

Thanks @devmadhuu for the patch, @hemantk-12, @sumitagrawl, @swamirishi for the review.

adoroszlai pushed a commit to adoroszlai/ozone that referenced this pull request Sep 25, 2025
…tSnapshot. (apache#5970)

(cherry picked from commit fa98426)
(cherry picked from commit 42e8540f3f3fcfadfbc4e66579fa2465a2eb3725)
swamirishi pushed a commit to swamirishi/ozone that referenced this pull request Dec 3, 2025
…ract.testListSnapshot. (apache#5970)

(cherry picked from commit fa98426)
Change-Id: Id59434644bfb9bbbeb2515dd4ecdd1bdad90fef7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

snapshot https://issues.apache.org/jira/browse/HDDS-6517

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants