Skip to content
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

Fix endless chunk rewriting when db is idle - improvement #4000

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 29 additions & 10 deletions h2/src/main/org/h2/mvstore/RandomAccessStore.java
Expand Up @@ -43,7 +43,9 @@ public abstract class RandomAccessStore extends FileStore<SFChunk>

private long reservedLow;
private long reservedHigh;
private boolean stopIdleHousekeeping;

private boolean chunksRewritingIsPaused;
private int chunksFillRateAfterLastRewriting;

public RandomAccessStore(Map<String, Object> config) {
super(config);
Expand Down Expand Up @@ -702,10 +704,6 @@ private void shrinkIfPossible(int minPercent) {

@Override
protected void doHousekeeping(MVStore mvStore) throws InterruptedException {
boolean idle = isIdle();
if (idle && stopIdleHousekeeping) {
return;
}
int autoCommitMemory = mvStore.getAutoCommitMemory();
int fillRate = getFillRate();
if (isFragmented() && fillRate < getAutoCompactFillRate()) {
Expand All @@ -719,22 +717,43 @@ protected void doHousekeeping(MVStore mvStore) throws InterruptedException {
});
}

int chunksFillRate = getRewritableChunksFillRate();
int adjustedChunksFillRate = 100 - (100 - chunksFillRate) / 2;
int fillRateToCompare = isIdle() ? chunksFillRate : adjustedChunksFillRate;
int chunksFillRate = getChunksFillRate();
if (chunksRewritingIsPaused && !chunksRewritingMustBeResumed(chunksFillRate, chunksFillRateAfterLastRewriting)) {
// chunks rewriting remains paused
return;
}
chunksRewritingIsPaused = false;

int rewritableChunksFillRate = getRewritableChunksFillRate();
int adjustedChunksFillRate = 100 - (100 - rewritableChunksFillRate) / 2;
int fillRateToCompare = isIdle() ? rewritableChunksFillRate : adjustedChunksFillRate;
if (fillRateToCompare < getTargetFillRate()) {
mvStore.tryExecuteUnderStoreLock(() -> {
int writeLimit = autoCommitMemory;
if (!isIdle()) {
writeLimit /= 4;
}
if (rewriteChunks(writeLimit, isIdle() ? adjustedChunksFillRate : chunksFillRate)) {
boolean hasRewrittenChunks = rewriteChunks(writeLimit, isIdle() ? adjustedChunksFillRate : chunksFillRate);
if (hasRewrittenChunks) {
dropUnusedChunks();
}
chunksFillRateAfterLastRewriting = getChunksFillRate();
chunksRewritingIsPaused = chunksRewritingMustBePaused(hasRewrittenChunks, chunksFillRate, chunksFillRateAfterLastRewriting);
return true;
});
}
stopIdleHousekeeping = idle && getFillRate() <= fillRate && getRewritableChunksFillRate() <= chunksFillRate;
}

private boolean chunksRewritingMustBePaused(boolean hasRewrittenChunks, int chunksFillRateBeforeRewriting, int chunksFillRateAfterRewriting) {
// Pause chunks rewriting if there was no progress made by the last chunks rewrite
// This is to avoid endless chunks rewriting in certain cases (cf. issue #3909)
return hasRewrittenChunks && chunksFillRateAfterRewriting <= chunksFillRateBeforeRewriting;
}

private boolean chunksRewritingMustBeResumed(int currentChunksFillRate, int chunksFillRateAfterLastRewriting) {
// Since last chunks rewrite (and rewriting being in pause since then), if chunksFillRate has changed that probably
// means some user write operations were performed and chunks rewriting should be resumed/retried
return currentChunksFillRate != chunksFillRateAfterLastRewriting;
}

private int getTargetFillRate() {
Expand Down