-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
feat(db): optimize old rewards withdrawal #5406
Changes from 35 commits
686f45e
6b88acf
6f0488c
f0d7e01
41a8bc4
90c175a
1c3a0ad
66dcb82
aaaa8cd
8e64450
09b7d72
5b62a2e
b25d2f3
c70fd48
79c4895
38e48fd
309cf54
0435e58
6576d48
7a7bcfe
f0c38df
a7246e6
b47b18f
e255a40
4f831af
6c26b53
4fdfb46
6008ecc
74cd4fe
5bfc303
2c1861e
cd76dd3
320493a
2c5db36
6dff8d4
d85cce8
5d6f09c
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 |
---|---|---|
@@ -1,9 +1,77 @@ | ||
package org.tron.core.db.common.iterator; | ||
|
||
import com.google.common.collect.Iterators; | ||
import com.google.common.collect.UnmodifiableIterator; | ||
import com.google.common.primitives.Bytes; | ||
import java.io.Closeable; | ||
import java.util.Iterator; | ||
import java.util.Map.Entry; | ||
import java.util.NoSuchElementException; | ||
|
||
public interface DBIterator extends Iterator<Entry<byte[], byte[]>>, Closeable { | ||
public interface DBIterator extends Iterator<Entry<byte[], byte[]>>, AutoCloseable, Closeable { | ||
|
||
void seek(byte[] key); | ||
|
||
void seekToFirst(); | ||
|
||
void seekToLast(); | ||
|
||
default UnmodifiableIterator<Entry<byte[], byte[]>> prefixQueryAfterThat | ||
(byte[] key, byte[] afterThat) { | ||
this.seek(afterThat == null ? key : afterThat); | ||
return Iterators.filter(this, entry -> Bytes.indexOf(entry.getKey(), key) == 0); | ||
} | ||
|
||
/** | ||
* An iterator is either positioned at a key/value pair, or | ||
* not valid. This method returns true iff the iterator is valid. | ||
* | ||
* REQUIRES: iterator not closed | ||
* | ||
* @throws IllegalStateException if the iterator is closed. | ||
* @return an iterator is either positioned at a key/value pair | ||
*/ | ||
boolean valid(); | ||
|
||
/** | ||
* The underlying storage for | ||
* the returned slice is valid only until the next modification of | ||
* the iterator. | ||
* | ||
* REQUIRES: valid() && !closed | ||
* | ||
* @throws IllegalStateException if the iterator is closed. | ||
* @throws NoSuchElementException if the iterator is not valid. | ||
* | ||
* @return the key for the current entry | ||
*/ | ||
byte[] getKey(); | ||
|
||
/** | ||
* The underlying storage for | ||
* the returned slice is valid only until the next modification of | ||
* the iterator. | ||
* | ||
* REQUIRES: valid() && !closed | ||
* | ||
* @throws IllegalStateException if the iterator is closed. | ||
* @throws NoSuchElementException if the iterator is not valid. | ||
* | ||
* @return the value for the current entry | ||
*/ | ||
byte[] getValue(); | ||
|
||
/** | ||
* @throws IllegalStateException if the iterator is closed. | ||
*/ | ||
void checkState(); | ||
|
||
/** | ||
* @throws NoSuchElementException if the iterator is not valid. | ||
*/ | ||
default void checkValid() { | ||
if (!valid()) { | ||
throw new NoSuchElementException(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
import java.io.IOException; | ||
import java.util.Map.Entry; | ||
import java.util.NoSuchElementException; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.iq80.leveldb.DBIterator; | ||
|
||
|
@@ -13,20 +14,22 @@ public final class StoreIterator implements org.tron.core.db.common.iterator.DBI | |
private final DBIterator dbIterator; | ||
private boolean first = true; | ||
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. Is there a simpler way by just setting 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. Yes, that's exactly how it's handled. |
||
|
||
private boolean valid = true; | ||
private final AtomicBoolean close = new AtomicBoolean(false); | ||
|
||
public StoreIterator(DBIterator dbIterator) { | ||
this.dbIterator = dbIterator; | ||
} | ||
|
||
@Override | ||
public void close() throws IOException { | ||
dbIterator.close(); | ||
if (close.compareAndSet(false, true)) { | ||
dbIterator.close(); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean hasNext() { | ||
if (!valid) { | ||
if (close.get()) { | ||
return false; | ||
} | ||
|
||
|
@@ -39,8 +42,7 @@ public boolean hasNext() { | |
} | ||
|
||
if (!(hasNext = dbIterator.hasNext())) { // false is last item | ||
dbIterator.close(); | ||
valid = false; | ||
close(); | ||
} | ||
} catch (Exception e) { | ||
logger.error(e.getMessage(), e); | ||
|
@@ -51,7 +53,7 @@ public boolean hasNext() { | |
|
||
@Override | ||
public Entry<byte[], byte[]> next() { | ||
if (!valid) { | ||
if (close.get()) { | ||
throw new NoSuchElementException(); | ||
} | ||
return dbIterator.next(); | ||
|
@@ -61,4 +63,53 @@ public Entry<byte[], byte[]> next() { | |
public void remove() { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
public void seek(byte[] key) { | ||
checkState(); | ||
dbIterator.seek(key); | ||
this.first = false; | ||
} | ||
|
||
@Override | ||
public void seekToFirst() { | ||
checkState(); | ||
dbIterator.seekToFirst(); | ||
this.first = false; | ||
} | ||
|
||
@Override | ||
public void seekToLast() { | ||
checkState(); | ||
dbIterator.seekToLast(); | ||
this.first = false; | ||
} | ||
|
||
@Override | ||
public boolean valid() { | ||
checkState(); | ||
return dbIterator.hasNext(); | ||
} | ||
|
||
@Override | ||
public byte[] getKey() { | ||
checkState(); | ||
checkValid(); | ||
return dbIterator.peekNext().getKey(); | ||
} | ||
|
||
@Override | ||
public byte[] getValue() { | ||
checkState(); | ||
checkValid(); | ||
return dbIterator.peekNext().getValue(); | ||
} | ||
|
||
@Override | ||
public void checkState() { | ||
if (close.get()) { | ||
throw new IllegalStateException("iterator has been closed"); | ||
} | ||
} | ||
} | ||
|
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.
Here I have doubt, whether this iterator will still access all data in the database but just return the data that matched the filter.
If so, it will do a lot of useless read-op?
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.
Not All, iterates over all data after the prefix. I can't think of a better way for now. It takes 2 minutes to iterate the database.
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.
Use the default iterator and move the filter logic into
startRewardCal
, or re-implement a prefix iterator.Seems 2 minutes is not a big deal, depends on you
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.
Prefix does not work is fixed.