Skip to content

Commit

Permalink
online backup reliability improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
andreitokar committed Jul 4, 2024
1 parent 575302d commit 0bd1376
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 24 deletions.
12 changes: 8 additions & 4 deletions h2/src/main/org/h2/mvstore/FileStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentMap;
Expand Down Expand Up @@ -85,7 +86,7 @@ public abstract class FileStore<C extends Chunk<C>>
private static final int FORMAT_READ_MIN = 3;
private static final int FORMAT_READ_MAX = 3;

MVStore mvStore;
private MVStore mvStore;
private boolean closed;

/**
Expand Down Expand Up @@ -1357,7 +1358,8 @@ public boolean isSpaceReused() {
return true;
}

public void setReuseSpace(boolean reuseSpace) {
public boolean setReuseSpace(boolean reuseSpace) {
return isSpaceReused();
}

protected final void store() {
Expand Down Expand Up @@ -1876,7 +1878,7 @@ private static <C extends Chunk<C>> HashSet<Integer> createIdSet(Iterable<C> toC
return set;
}

public void executeFileStoreOperation(Runnable operation) {
public <T> T executeFileStoreOperation(Callable<T> operation) {
// because serializationExecutor is a single-threaded one and
// all task submissions to it are done under storeLock,
// it is guaranteed, that upon this dummy task completion
Expand All @@ -1888,7 +1890,9 @@ public void executeFileStoreOperation(Runnable operation) {
// are done under serializationLock, and upon this dummy task completion
// it will be no pending / in-progress task here
Utils.flushExecutor(bufferSaveExecutor);
operation.run();
return operation.call();
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
serializationLock.unlock();
}
Expand Down
12 changes: 8 additions & 4 deletions h2/src/main/org/h2/mvstore/MVStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -915,11 +915,13 @@ public boolean hasUnsavedChanges() {
return fileStore != null && fileStore.hasChangesSince(lastStoredVersion);
}

public void executeFilestoreOperation(Runnable operation) {
public <T> T executeFilestoreOperation(Callable<T> operation) {
T result = null;
storeLock.lock();
try {
checkNotClosed();
fileStore.executeFileStoreOperation(operation);
result = fileStore.executeFileStoreOperation(operation);
return result;
} catch (MVStoreException e) {
panic(e);
} catch (Throwable e) {
Expand All @@ -928,6 +930,7 @@ public void executeFilestoreOperation(Runnable operation) {
} finally {
unlockAndCheckPanicCondition();
}
return result;
}

<R> R tryExecuteUnderStoreLock(Callable<R> operation) throws InterruptedException {
Expand Down Expand Up @@ -1107,9 +1110,10 @@ public boolean isSpaceReused() {
* than the write operations).
*
* @param reuseSpace the new value
* @return previous state of the flag
*/
public void setReuseSpace(boolean reuseSpace) {
fileStore.setReuseSpace(reuseSpace);
public boolean setReuseSpace(boolean reuseSpace) {
return executeFilestoreOperation(() -> fileStore.setReuseSpace(reuseSpace));
}

public int getRetentionTime() {
Expand Down
15 changes: 10 additions & 5 deletions h2/src/main/org/h2/mvstore/RandomAccessStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,10 @@ public boolean isSpaceReused() {
}

@Override
public void setReuseSpace(boolean reuseSpace) {
public boolean setReuseSpace(boolean reuseSpace) {
boolean current = this.reuseSpace;
this.reuseSpace = reuseSpace;
return current;
}

@Override
Expand Down Expand Up @@ -470,15 +472,18 @@ public void compactMoveChunks(int targetFillRate, long moveSize, MVStore mvStore
} finally {
saveChunkLock.unlock();
}
return null;
});
}
}

private void compactMoveChunks(long moveSize) {
long start = getFirstFree() / FileStore.BLOCK_SIZE;
Iterable<SFChunk> chunksToMove = findChunksToMove(start, moveSize);
if (chunksToMove != null) {
compactMoveChunks(chunksToMove);
if (isSpaceReused()) {
long start = getFirstFree() / FileStore.BLOCK_SIZE;
Iterable<SFChunk> chunksToMove = findChunksToMove(start, moveSize);
if (chunksToMove != null) {
compactMoveChunks(chunksToMove);
}
}
}

Expand Down
28 changes: 17 additions & 11 deletions h2/src/main/org/h2/mvstore/SingleFileStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -231,20 +231,26 @@ protected long getAfterLastBlock_() {

@Override
public void backup(ZipOutputStream out) throws IOException {
boolean before = isSpaceReused();
setReuseSpace(false);
String f = correctFileName(FilePath.get(getFileName()).toRealPath().getName());
out.putNextEntry(new ZipEntry(f));
FileChannel in = originalFileChannel != null ? originalFileChannel : fileChannel;
MVStore mvStore = getMvStore();
boolean before = mvStore.setReuseSpace(false);
try {
backupFile(out, getFileName(), originalFileChannel != null ? originalFileChannel : fileChannel);

IOUtils.copy(in, out);

mvStore.executeFilestoreOperation(() -> {
try {
IOUtils.copy(in, out);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return null;
});
} finally {
setReuseSpace(before);
mvStore.setReuseSpace(before);
}
}

private static void backupFile(ZipOutputStream out, String fileName, FileChannel in) throws IOException {
String f = FilePath.get(fileName).toRealPath().getName();
f = correctFileName(f);
out.putNextEntry(new ZipEntry(f));
IOUtils.copy(in, out);
out.closeEntry();
}

Expand Down

0 comments on commit 0bd1376

Please sign in to comment.