-
Notifications
You must be signed in to change notification settings - Fork 588
HDDS-12742. Make RDBStoreAbstractIterator Return Reference-Counted KeyValues #8203
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 31 commits
30facb9
aab6ebc
5dd7460
e4bf8f7
9ab91c9
abe06ab
d215d4b
85c74b4
7d82a9e
ce6ab81
091e8ca
6bc5c86
1b394c2
7fdced2
f5b633b
1971a96
a33f265
0c3ae4f
fbe213b
71f9c28
5734027
99c508e
f16e1b9
86fe101
cfde81f
f825754
e4155a6
985d612
b98968b
78d33af
ed632a8
58f81cc
3f77cbe
1fecc85
deb0011
346a685
f6b651c
93c7f91
f81c116
7b37a29
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 |
|---|---|---|
|
|
@@ -21,6 +21,8 @@ | |
| import java.util.NoSuchElementException; | ||
| import java.util.function.Consumer; | ||
| import org.apache.hadoop.hdds.utils.db.managed.ManagedRocksIterator; | ||
| import org.apache.ratis.util.ReferenceCountedObject; | ||
| import org.apache.ratis.util.function.UncheckedAutoCloseableSupplier; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
|
|
@@ -30,30 +32,34 @@ | |
| * @param <RAW> the raw type. | ||
| */ | ||
| abstract class RDBStoreAbstractIterator<RAW> | ||
| implements TableIterator<RAW, Table.KeyValue<RAW, RAW>> { | ||
| implements TableIterator<RAW, RDBStoreAbstractIterator.AutoCloseableRawKeyValue<RAW>> { | ||
|
|
||
| private static final Logger LOG = | ||
| LoggerFactory.getLogger(RDBStoreAbstractIterator.class); | ||
|
|
||
| private final ManagedRocksIterator rocksDBIterator; | ||
| private final RDBTable rocksDBTable; | ||
| private Table.KeyValue<RAW, RAW> currentEntry; | ||
| private ReferenceCountedObject<RawKeyValue<RAW>> currentEntry; | ||
| private RawKeyValue<RAW> previousKeyValue; | ||
| // This is for schemas that use a fixed-length | ||
| // prefix for each key. | ||
| private final RAW prefix; | ||
| private Boolean hasNext; | ||
|
||
| private boolean closed; | ||
|
|
||
| RDBStoreAbstractIterator(ManagedRocksIterator iterator, RDBTable table, | ||
| RAW prefix) { | ||
| this.rocksDBIterator = iterator; | ||
| this.rocksDBTable = table; | ||
| this.prefix = prefix; | ||
| this.currentEntry = null; | ||
| this.hasNext = false; | ||
| this.closed = false; | ||
| this.previousKeyValue = null; | ||
sumitagrawl marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| /** @return the key for the current entry. */ | ||
| abstract RAW key(); | ||
|
|
||
| /** @return the {@link Table.KeyValue} for the current entry. */ | ||
| abstract Table.KeyValue<RAW, RAW> getKeyValue(); | ||
| abstract ReferenceCountedObject<RawKeyValue<RAW>> getKeyValue(); | ||
|
|
||
| /** Seek to the given key. */ | ||
| abstract void seek0(RAW key); | ||
|
|
@@ -78,32 +84,52 @@ final RAW getPrefix() { | |
|
|
||
| @Override | ||
| public final void forEachRemaining( | ||
| Consumer<? super Table.KeyValue<RAW, RAW>> action) { | ||
| Consumer<? super AutoCloseableRawKeyValue<RAW>> action) { | ||
| while (hasNext()) { | ||
| action.accept(next()); | ||
| AutoCloseableRawKeyValue<RAW> entry = next(); | ||
| action.accept(entry); | ||
| } | ||
| } | ||
|
|
||
| private void releaseEntry() { | ||
| if (currentEntry != null) { | ||
| currentEntry.release(); | ||
| } | ||
| currentEntry = null; | ||
| hasNext = null; | ||
| } | ||
|
|
||
| private void setCurrentEntry() { | ||
| if (rocksDBIterator.get().isValid()) { | ||
| boolean isValid = !closed && rocksDBIterator.get().isValid(); | ||
| if (isValid) { | ||
| currentEntry = getKeyValue(); | ||
| currentEntry.retain(); | ||
| } else { | ||
| currentEntry = null; | ||
| } | ||
| setHasNext(isValid, currentEntry); | ||
sumitagrawl marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| public void setHasNext(boolean isValid, ReferenceCountedObject<RawKeyValue<RAW>> entry) { | ||
| this.hasNext = isValid && (prefix == null || startsWithPrefix(entry.get().getKey())); | ||
| } | ||
|
|
||
| @Override | ||
| public final boolean hasNext() { | ||
| return rocksDBIterator.get().isValid() && | ||
| (prefix == null || startsWithPrefix(key())); | ||
| if (hasNext == null) { | ||
| setCurrentEntry(); | ||
| } | ||
| return hasNext; | ||
| } | ||
|
|
||
| @Override | ||
| public final Table.KeyValue<RAW, RAW> next() { | ||
| setCurrentEntry(); | ||
| if (currentEntry != null) { | ||
| public final AutoCloseableRawKeyValue<RAW> next() { | ||
| if (hasNext()) { | ||
| AutoCloseableRawKeyValue<RAW> entry = new AutoCloseableRawKeyValue<>(currentEntry); | ||
| this.previousKeyValue = currentEntry.get(); | ||
| rocksDBIterator.get().next(); | ||
|
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. rocksDbIterator.get().next() can also be moved to setCurrentEntry(), as we are getting next entry, updating hasNext flag together.
Contributor
Author
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. no we cannot do that. What about for the first entry. You shouldn't call next for the first entry in the iterator |
||
| return currentEntry; | ||
| releaseEntry(); | ||
| return entry; | ||
| } | ||
| throw new NoSuchElementException("RocksDB Store has no more elements"); | ||
| } | ||
|
|
@@ -115,7 +141,7 @@ public final void seekToFirst() { | |
| } else { | ||
| seek0(prefix); | ||
| } | ||
| setCurrentEntry(); | ||
| releaseEntry(); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -125,23 +151,28 @@ public final void seekToLast() { | |
| } else { | ||
| throw new UnsupportedOperationException("seekToLast: prefix != null"); | ||
| } | ||
| setCurrentEntry(); | ||
| releaseEntry(); | ||
| } | ||
|
|
||
| @Override | ||
| public final Table.KeyValue<RAW, RAW> seek(RAW key) { | ||
| public final AutoCloseableRawKeyValue<RAW> seek(RAW key) { | ||
| seek0(key); | ||
| releaseEntry(); | ||
| setCurrentEntry(); | ||
| return currentEntry; | ||
| // Current entry should be only closed when the next() and thus closing the returned entry should be a noop. | ||
| if (hasNext()) { | ||
| return new AutoCloseableRawKeyValue<>(currentEntry); | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| @Override | ||
| public final void removeFromDB() throws IOException { | ||
| if (rocksDBTable == null) { | ||
| throw new UnsupportedOperationException("remove"); | ||
| } | ||
| if (currentEntry != null) { | ||
| delete(currentEntry.getKey()); | ||
| if (previousKeyValue != null) { | ||
sumitagrawl marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| delete(previousKeyValue.getKey()); | ||
|
||
| } else { | ||
| LOG.info("Failed to removeFromDB: currentEntry == null"); | ||
| } | ||
|
|
@@ -150,5 +181,21 @@ public final void removeFromDB() throws IOException { | |
| @Override | ||
| public void close() { | ||
| rocksDBIterator.close(); | ||
| closed = true; | ||
| releaseEntry(); | ||
| } | ||
|
|
||
| public static final class AutoCloseableRawKeyValue<RAW> extends RawKeyValue<RAW> implements AutoCloseable { | ||
|
||
| private final UncheckedAutoCloseableSupplier<RawKeyValue<RAW>> keyValue; | ||
|
|
||
| private AutoCloseableRawKeyValue(ReferenceCountedObject<RawKeyValue<RAW>> kv) { | ||
|
||
| super(kv.get().getKey(), kv.get().getValue()); | ||
| this.keyValue = kv.retainAndReleaseOnClose(); | ||
| } | ||
|
|
||
| @Override | ||
| public void close() { | ||
| keyValue.close(); | ||
| } | ||
| } | ||
| } | ||
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.
default implementation can throw exception as not supported, no need to add for all cases.