diff --git a/h2/src/main/org/h2/mvstore/FileStore.java b/h2/src/main/org/h2/mvstore/FileStore.java index 957ed056c4..949736503a 100644 --- a/h2/src/main/org/h2/mvstore/FileStore.java +++ b/h2/src/main/org/h2/mvstore/FileStore.java @@ -423,7 +423,7 @@ public final void setAutoCommitDelay(int millis) { stopBackgroundThread(millis >= 0); // start the background thread if needed if (millis > 0 && mvStore.isOpen()) { - int sleep = Math.max(1, millis / 10); + int sleep = Math.max(10, millis / 3); BackgroundWriterThread t = new BackgroundWriterThread(this, sleep, toString()); if (backgroundWriterThread.compareAndSet(null, t)) { t.start(); @@ -622,7 +622,7 @@ protected final boolean hasPersistentData() { } protected final boolean isIdle() { - return autoCompactLastFileOpCount == getWriteCount() + getReadCount(); + return autoCompactLastFileOpCount >= getWriteCount() + getReadCount(); } protected final void setLastChunk(C last) { @@ -1835,7 +1835,8 @@ void writeInBackground() { mvStore.tryCommit(); } doHousekeeping(mvStore); - autoCompactLastFileOpCount = getWriteCount() + getReadCount(); + // less than 10 I/O operations will still count as "idle" + autoCompactLastFileOpCount = getWriteCount() + getReadCount() + 10; } } catch (InterruptedException ignore) { } catch (Throwable e) { diff --git a/h2/src/main/org/h2/mvstore/FreeSpaceBitSet.java b/h2/src/main/org/h2/mvstore/FreeSpaceBitSet.java index f0fff58cc1..23fd5512bb 100644 --- a/h2/src/main/org/h2/mvstore/FreeSpaceBitSet.java +++ b/h2/src/main/org/h2/mvstore/FreeSpaceBitSet.java @@ -145,10 +145,8 @@ private int allocate(int blocks, int reservedLow, int reservedHigh, boolean allo int freeBlocks = end - start; if (end < 0 || freeBlocks >= blocks) { if ((reservedHigh < 0 || start < reservedHigh) && start + blocks > reservedLow) { // overlap detected - if (reservedHigh < 0) { - start = getAfterLastBlock(); - end = -1; - } else { + if (reservedHigh >= 0) { + freeBlocksTotal += freeBlocks; i = reservedHigh; continue; } diff --git a/h2/src/main/org/h2/mvstore/RandomAccessStore.java b/h2/src/main/org/h2/mvstore/RandomAccessStore.java index e69737f45d..745e3b2af7 100644 --- a/h2/src/main/org/h2/mvstore/RandomAccessStore.java +++ b/h2/src/main/org/h2/mvstore/RandomAccessStore.java @@ -703,15 +703,17 @@ private void shrinkIfPossible(int minPercent) { @Override protected void doHousekeeping(MVStore mvStore) throws InterruptedException { boolean idle = isIdle(); + int rewritableChunksFillRate = getRewritableChunksFillRate(); if (idle && stopIdleHousekeeping) { return; } int autoCommitMemory = mvStore.getAutoCommitMemory(); - int fillRate = getFillRate(); - if (isFragmented() && fillRate < getAutoCompactFillRate()) { + int fileFillRate = getFillRate(); + long chunksTotalSize = size() * fileFillRate / 100; + if (isFragmented() && fileFillRate < getAutoCompactFillRate()) { mvStore.tryExecuteUnderStoreLock(() -> { int moveSize = 2 * autoCommitMemory; - if (isIdle()) { + if (idle) { moveSize *= 4; } compactMoveChunks(101, moveSize, mvStore); @@ -719,29 +721,35 @@ protected void doHousekeeping(MVStore mvStore) throws InterruptedException { }); } - int chunksFillRate = getRewritableChunksFillRate(); - int adjustedChunksFillRate = 100 - (100 - chunksFillRate) / 2; - int fillRateToCompare = isIdle() ? chunksFillRate : adjustedChunksFillRate; - if (fillRateToCompare < getTargetFillRate()) { + int chunksFillRate = getChunksFillRate(); + int adjustedUpFillRate = 50 + rewritableChunksFillRate / 2; + int fillRateToCompare = idle ? rewritableChunksFillRate : adjustedUpFillRate; + if (fillRateToCompare < getTargetFillRate(idle)) { + int targetFillRate = idle ? adjustedUpFillRate : rewritableChunksFillRate; mvStore.tryExecuteUnderStoreLock(() -> { int writeLimit = autoCommitMemory; - if (!isIdle()) { + if (!idle) { writeLimit /= 4; } - if (rewriteChunks(writeLimit, isIdle() ? adjustedChunksFillRate : chunksFillRate)) { + if (rewriteChunks(writeLimit, targetFillRate)) { dropUnusedChunks(); } return true; }); } - stopIdleHousekeeping = idle && getFillRate() <= fillRate && getRewritableChunksFillRate() <= chunksFillRate; + stopIdleHousekeeping = false; + if (idle) { + int currentChunksFillRate = getChunksFillRate(); + long currentTotalChunksSize = size() * getFillRate() / 100; + stopIdleHousekeeping = currentTotalChunksSize > chunksTotalSize || currentTotalChunksSize == chunksTotalSize && currentChunksFillRate <= chunksFillRate; + } } - private int getTargetFillRate() { + private int getTargetFillRate(boolean idle) { int targetRate = getAutoCompactFillRate(); // use a lower fill rate if there were any file operations since the last time - if (!isIdle()) { - targetRate /= 2; + if (!idle) { + targetRate = targetRate * targetRate / 100; } return targetRate; }