Skip to content

Commit a448d91

Browse files
authored
Merge pull request h2database#4273 from naive924/feat/compactThreads
SHUTDOWN COMPACT: parallel map copy (¼ cores default, override with h2.compactThreads)
2 parents c45413c + 6672123 commit a448d91

2 files changed

Lines changed: 35 additions & 22 deletions

File tree

h2/src/docsrc/html/changelog.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ <h1>Change Log</h1>
2121

2222
<h2>Next Version (unreleased)</h2>
2323
<ul>
24+
<li>PR #4273: SHUTDOWN COMPACT: parallel map copy (¼ cores default, override with h2.compactThreads)
25+
</li>
2426
<li>Issue #4263: Documentation: SET TRUNCATE_LARGE_LENGTH is broken
2527
</li>
2628
<li>Issue #4208: Lost update when attempting to atomically increment a value using SELECT FOR UPDATE

h2/src/main/org/h2/mvstore/MVStore.java

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
import java.util.Map;
1818
import java.util.Set;
1919
import java.util.concurrent.Callable;
20+
import java.util.concurrent.CompletableFuture;
2021
import java.util.concurrent.ConcurrentHashMap;
22+
import java.util.concurrent.ExecutorService;
23+
import java.util.concurrent.Executors;
2124
import java.util.concurrent.TimeUnit;
2225
import java.util.concurrent.atomic.AtomicBoolean;
2326
import java.util.concurrent.atomic.AtomicInteger;
@@ -404,28 +407,36 @@ private static void compact(MVStore source, MVStore target) {
404407
targetMeta.put(key, m.getValue());
405408
}
406409
}
407-
// We are going to cheat a little bit in the copyFrom() by employing "incomplete" pages,
408-
// which would be spared of saving, but save completed pages underneath,
409-
// and those may appear as dead (non-reachable).
410-
// That's why it is important to preserve all chunks
411-
// created in the process, especially if retention time
412-
// is set to a lower value, or even 0.
413-
for (String mapName : source.getMapNames()) {
414-
MVMap.Builder<Object, Object> mp = MVStoreTool.getGenericMapBuilder();
415-
// This is a hack to preserve chunks occupancy rate accounting.
416-
// It exposes design deficiency flaw in MVStore related to lack of
417-
// map's type metadata.
418-
// TODO: Introduce type metadata which will allow to open any store
419-
// TODO: without prior knowledge of keys / values types and map implementation
420-
// TODO: (MVMap vs MVRTreeMap, regular vs. singleWriter etc.)
421-
if (mapName.startsWith(TransactionStore.UNDO_LOG_NAME_PREFIX)) {
422-
mp.singleWriter();
423-
}
424-
MVMap<Object, Object> sourceMap = source.openMap(mapName, mp);
425-
MVMap<Object, Object> targetMap = target.openMap(mapName, mp);
426-
targetMap.copyFrom(sourceMap);
427-
targetMeta.put(MVMap.getMapKey(targetMap.getId()), sourceMeta.get(MVMap.getMapKey(sourceMap.getId())));
428-
}
410+
411+
int poolSize = Integer.getInteger("h2.compactThreads", Math.max(1, Runtime.getRuntime().availableProcessors() / 4));
412+
ExecutorService pool = Executors.newFixedThreadPool(poolSize);
413+
CompletableFuture.allOf(
414+
// We are going to cheat a little bit in the copyFrom() by employing "incomplete" pages,
415+
// which would be spared of saving, but save completed pages underneath,
416+
// and those may appear as dead (non-reachable).
417+
// That's why it is important to preserve all chunks
418+
// created in the process, especially if retention time
419+
// is set to a lower value, or even 0.
420+
source.getMapNames().stream().map(mapName ->
421+
CompletableFuture.runAsync(() -> {
422+
MVMap.Builder<Object, Object> mp = MVStoreTool.getGenericMapBuilder();
423+
// This is a hack to preserve chunks occupancy rate accounting.
424+
// It exposes design deficiency flaw in MVStore related to lack of
425+
// map's type metadata.
426+
// TODO: Introduce type metadata which will allow to open any store
427+
// TODO: without prior knowledge of keys / values types and map implementation
428+
// TODO: (MVMap vs MVRTreeMap, regular vs. singleWriter etc.)
429+
if (mapName.startsWith(TransactionStore.UNDO_LOG_NAME_PREFIX)) {
430+
mp.singleWriter();
431+
}
432+
MVMap<Object, Object> sourceMap = source.openMap(mapName, mp);
433+
MVMap<Object, Object> targetMap = target.openMap(mapName, mp);
434+
targetMap.copyFrom(sourceMap);
435+
targetMeta.put(MVMap.getMapKey(targetMap.getId()), sourceMeta.get(MVMap.getMapKey(sourceMap.getId())));
436+
}, pool)
437+
).toArray(CompletableFuture[]::new)
438+
).join();
439+
pool.shutdownNow();
429440
// this will end hacky mode of operation with incomplete pages
430441
// end ensure that all pages are saved
431442
target.commit();

0 commit comments

Comments
 (0)