-
Notifications
You must be signed in to change notification settings - Fork 624
HDDS-9967. Intermittent failure in TestOzoneRpcClientAbstract.testListSnapshot. #5970
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
Changes from 3 commits
2cb8bac
a226092
5202873
6709235
dee1298
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,7 @@ | |
| import java.util.NoSuchElementException; | ||
| import java.util.PriorityQueue; | ||
| import java.util.TreeMap; | ||
| import java.util.function.Predicate; | ||
|
|
||
| import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK; | ||
|
|
||
|
|
@@ -117,14 +118,17 @@ public static class DbTableIter<Value> implements | |
| ? extends Table.KeyValue<String, Value>> tableIterator; | ||
|
|
||
| private final Table<String, Value> table; | ||
| private HeapEntry currentKey; | ||
| private HeapEntry currentEntry; | ||
| private Predicate<String> doesKeyExistInCache; | ||
|
|
||
| DbTableIter(int entryIteratorId, Table<String, Value> table, | ||
| String prefixKey, String startKey) throws IOException { | ||
| String prefixKey, String startKey, | ||
| Predicate<String> doesKeyExistInCache) throws IOException { | ||
| this.entryIteratorId = entryIteratorId; | ||
| this.table = table; | ||
| this.tableIterator = table.iterator(prefixKey); | ||
| this.currentKey = null; | ||
| this.currentEntry = null; | ||
| this.doesKeyExistInCache = doesKeyExistInCache; | ||
|
|
||
| // only seek for the start key if the start key is lexicographically | ||
| // after the prefix key. For example | ||
|
|
@@ -141,11 +145,11 @@ public static class DbTableIter<Value> implements | |
| } | ||
|
|
||
| private void getNextKey() throws IOException { | ||
| while (tableIterator.hasNext() && currentKey == null) { | ||
| while (tableIterator.hasNext() && currentEntry == null) { | ||
| Table.KeyValue<String, Value> entry = tableIterator.next(); | ||
| String entryKey = entry.getKey(); | ||
| if (!KeyManagerImpl.isKeyInCache(entryKey, table)) { | ||
| currentKey = new HeapEntry(entryIteratorId, | ||
| if (!doesKeyExistInCache.test(entryKey)) { | ||
| currentEntry = new HeapEntry(entryIteratorId, | ||
| table.getName(), entryKey, entry.getValue()); | ||
| } | ||
| } | ||
|
|
@@ -157,13 +161,13 @@ public boolean hasNext() { | |
| } catch (IOException t) { | ||
| throw new UncheckedIOException(t); | ||
| } | ||
| return currentKey != null; | ||
| return currentEntry != null; | ||
| } | ||
|
|
||
| public HeapEntry next() { | ||
| if (hasNext()) { | ||
| HeapEntry ret = currentKey; | ||
| currentKey = null; | ||
| HeapEntry ret = currentEntry; | ||
| currentEntry = null; | ||
| return ret; | ||
| } | ||
| throw new NoSuchElementException(); | ||
|
|
@@ -186,15 +190,15 @@ public static class CacheIter<Value> | |
| private final String prefixKey; | ||
| private final String startKey; | ||
| private final String tableName; | ||
|
|
||
| private HeapEntry currentEntry; | ||
| private final int entryIteratorId; | ||
|
|
||
| CacheIter(int entryIteratorId, String tableName, | ||
| Iterator<Map.Entry<CacheKey<String>, | ||
| CacheValue<Value>>> cacheIter, String startKey, | ||
| String prefixKey) { | ||
| this.cacheKeyMap = new TreeMap<>(); | ||
|
|
||
| this.currentEntry = null; | ||
| this.startKey = startKey; | ||
| this.prefixKey = prefixKey; | ||
| this.tableName = tableName; | ||
|
|
@@ -236,14 +240,37 @@ private void populateCacheMap(Iterator<Map.Entry<CacheKey<String>, | |
| } | ||
| } | ||
|
|
||
| public boolean doesKeyExistInCache(String key) { | ||
| return cacheKeyMap.containsKey(key); | ||
| } | ||
|
|
||
| private void getNextKey() throws IOException { | ||
| while (cacheCreatedKeyIter.hasNext() && currentEntry == null) { | ||
| Map.Entry<String, Value> entry = cacheCreatedKeyIter.next(); | ||
| if (null == entry.getValue()) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
cacheKeyMap: This is used for 2 porpose,
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.
@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. |
||
| continue; | ||
| } | ||
| currentEntry = new HeapEntry(this.entryIteratorId, this.tableName, | ||
| entry.getKey(), entry.getValue()); | ||
| } | ||
| } | ||
|
|
||
| public boolean hasNext() { | ||
| return cacheCreatedKeyIter.hasNext(); | ||
| try { | ||
| getNextKey(); | ||
| } catch (IOException t) { | ||
| throw new UncheckedIOException(t); | ||
| } | ||
| return currentEntry != null; | ||
| } | ||
|
|
||
| public HeapEntry next() { | ||
| Map.Entry<String, Value> entry = cacheCreatedKeyIter.next(); | ||
| return new HeapEntry(this.entryIteratorId, this.tableName, | ||
| entry.getKey(), entry.getValue()); | ||
| if (hasNext()) { | ||
| HeapEntry ret = currentEntry; | ||
| currentEntry = null; | ||
| return ret; | ||
| } | ||
| throw new NoSuchElementException(); | ||
| } | ||
|
|
||
| public void close() { | ||
|
|
@@ -292,11 +319,13 @@ public static class MinHeapIterator implements ClosableIterator { | |
| try { | ||
| int iteratorId = 0; | ||
| for (Table table : tables) { | ||
| iterators.add(new CacheIter<>(iteratorId, table.getName(), | ||
| table.cacheIterator(), startKey, prefixKey)); | ||
| CacheIter cacheIter = new CacheIter<>(iteratorId, table.getName(), | ||
| table.cacheIterator(), startKey, prefixKey); | ||
| Predicate<String> doesKeyExistInCache = cacheIter::doesKeyExistInCache; | ||
| iterators.add(cacheIter); | ||
| iteratorId++; | ||
| iterators.add(new DbTableIter<>(iteratorId, table, prefixKey, | ||
| startKey)); | ||
| startKey, doesKeyExistInCache)); | ||
| iteratorId++; | ||
| } | ||
| } finally { | ||
|
|
||
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.
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();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 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.
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.
cacheCreatedKeyIter = cacheKeyMap.entrySet().stream().filter(e -> e.getValue() != null).iterator();This should not remove any element from the map.
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 @swamirishi is right.
doesKeyExistInCachechecks if key exist incacheKeyMapwhilecacheCreatedKeyItercan have filtered result.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.
yes, this filtering can be done while initializing iterator.
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.
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.