From 2c38728eba7f415d0aeb519876b6e2bca717aba0 Mon Sep 17 00:00:00 2001 From: venkat1701 Date: Tue, 6 Oct 2026 04:07:24 +0530 Subject: [PATCH 1/7] feat(bench): add compaction live ratio and segment size options --compaction-live-ratio and --pages-per-segment set the matching engine options for HStore runs, so compaction behaviour can be compared across settings. --- benchmarks/src/main/java/io/hstore/bench/Comparison.java | 9 ++++++--- .../src/main/java/io/hstore/bench/HStoreStore.java | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/benchmarks/src/main/java/io/hstore/bench/Comparison.java b/benchmarks/src/main/java/io/hstore/bench/Comparison.java index 07593ada..11f0212b 100644 --- a/benchmarks/src/main/java/io/hstore/bench/Comparison.java +++ b/benchmarks/src/main/java/io/hstore/bench/Comparison.java @@ -1,6 +1,7 @@ package io.hstore.bench; import io.hstore.db.value.Json; +import io.hstore.engine.EngineOptions; import java.io.BufferedReader; import java.io.IOException; @@ -83,7 +84,7 @@ public static void main(String[] args) throws Exception { case "report" -> IO.println(Report.markdown(args)); default -> { IO.println(""" - usage: Comparison run --store hstore|hypergraphdb [--scale N] [--durability async|sync] [--threads N] [--history N] [--cache-mb N] --out FILE + usage: Comparison run --store hstore|hypergraphdb [--scale N] [--durability async|sync] [--threads N] [--history N] [--cache-mb N] [--compaction-live-ratio R] [--pages-per-segment N] --out FILE Comparison crash --store hstore|hypergraphdb --dir DIRECTORY (used by run; ingests until killed) Comparison report FILE... (runs of two stores; cells show the median and range)"""); System.exit(2); @@ -206,7 +207,9 @@ private static Store open(Map options, Path directory, boolean c boolean sync = options.getOrDefault("durability", "async").equals("sync"); long cacheBytes = Long.parseLong(options.getOrDefault("cache-mb", "0")) << 20; return switch (options.getOrDefault("store", "hstore")) { - case "hstore" -> new HStoreStore(directory, sync, Integer.parseInt(options.getOrDefault("history", "64")), cacheBytes, create); + case "hstore" -> new HStoreStore(directory, sync, Integer.parseInt(options.getOrDefault("history", "64")), cacheBytes, + Double.parseDouble(options.getOrDefault("compaction-live-ratio", String.valueOf(EngineOptions.defaults().compactionLiveRatio()))), + Integer.parseInt(options.getOrDefault("pages-per-segment", "0")), create); case "hypergraphdb" -> new HyperGraphDbStore(directory, sync, cacheBytes); case String other -> throw new IllegalArgumentException("unknown store " + other); }; @@ -228,7 +231,7 @@ private static Result recover(Map options, Dataset dataset) thro command.add(ProcessHandle.current().info().command().orElse("java")); command.addAll(ManagementFactory.getRuntimeMXBean().getInputArguments()); command.addAll(List.of("-cp", System.getProperty("java.class.path"), Comparison.class.getName(), "crash", "--dir", directory.toString())); - for (String option : List.of("store", "scale", "durability", "history", "cache-mb")) { + for (String option : List.of("store", "scale", "durability", "history", "cache-mb", "compaction-live-ratio", "pages-per-segment")) { if (options.containsKey(option)) { command.addAll(List.of("--" + option, options.get(option))); } diff --git a/benchmarks/src/main/java/io/hstore/bench/HStoreStore.java b/benchmarks/src/main/java/io/hstore/bench/HStoreStore.java index 66c70f51..2f42eede 100644 --- a/benchmarks/src/main/java/io/hstore/bench/HStoreStore.java +++ b/benchmarks/src/main/java/io/hstore/bench/HStoreStore.java @@ -38,14 +38,15 @@ final class HStoreStore implements Store { private final int cachedNodes; private final long cacheBytes; - HStoreStore(Path directory, boolean sync, int history, long cacheBytes, boolean create) { + HStoreStore(Path directory, boolean sync, int history, long cacheBytes, double liveRatio, int pagesPerSegment, boolean create) { this.directory = directory; this.history = history; this.cacheBytes = cacheBytes; EngineOptions engine = EngineOptions.defaults(); this.cachedNodes = cacheBytes > 0 ? Math.toIntExact(cacheBytes / engine.pageSize()) : CACHED_NODES; this.options = DatabaseOptions.defaults().withEngine(engine - .withDurability(sync ? Durability.SYNC : Durability.ASYNC).withCachedNodes(cachedNodes).withHistoryLimit(history)); + .withDurability(sync ? Durability.SYNC : Durability.ASYNC).withCachedNodes(cachedNodes).withHistoryLimit(history) + .withCompactionLiveRatio(liveRatio).withPagesPerSegment(pagesPerSegment > 0 ? pagesPerSegment : engine.pagesPerSegment())); this.database = HypergraphDatabase.open(directory, options); if (create) { database.write(writer -> { From da115a9a5c2087c7663c9e8799814bf13657f863 Mon Sep 17 00:00:00 2001 From: venkat1701 Date: Tue, 6 Oct 2026 04:35:11 +0530 Subject: [PATCH 2/7] feat(bench): run a full compaction in both adapters HStore calls StorageEngine.compact. JE runs cleanLog until it cleans nothing and then forces a checkpoint, which deletes the cleaned files. --- .../src/main/java/io/hstore/bench/HStoreStore.java | 5 +++++ .../main/java/io/hstore/bench/HyperGraphDbStore.java | 10 ++++++++++ benchmarks/src/main/java/io/hstore/bench/Store.java | 2 ++ 3 files changed, 17 insertions(+) diff --git a/benchmarks/src/main/java/io/hstore/bench/HStoreStore.java b/benchmarks/src/main/java/io/hstore/bench/HStoreStore.java index 2f42eede..7d8fd0df 100644 --- a/benchmarks/src/main/java/io/hstore/bench/HStoreStore.java +++ b/benchmarks/src/main/java/io/hstore/bench/HStoreStore.java @@ -216,6 +216,11 @@ public void flush() { database.engine().checkpoint(); } + @Override + public void compact() { + database.engine().compact(); + } + @Override public long bytesWritten() { EngineStats stats = database.engine().stats(); diff --git a/benchmarks/src/main/java/io/hstore/bench/HyperGraphDbStore.java b/benchmarks/src/main/java/io/hstore/bench/HyperGraphDbStore.java index 5d48958d..b6efe144 100644 --- a/benchmarks/src/main/java/io/hstore/bench/HyperGraphDbStore.java +++ b/benchmarks/src/main/java/io/hstore/bench/HyperGraphDbStore.java @@ -1,5 +1,6 @@ package io.hstore.bench; +import com.sleepycat.je.CheckpointConfig; import com.sleepycat.je.Durability; import com.sleepycat.je.Environment; import com.sleepycat.je.EnvironmentConfig; @@ -242,6 +243,15 @@ public void flush() { environment().sync(); } + @Override + public void compact() { + Environment environment = environment(); + while (environment.cleanLog() > 0) { + Thread.onSpinWait(); + } + environment.checkpoint(new CheckpointConfig().setForce(true)); + } + @Override public long bytesWritten() { EnvironmentStats stats = environment().getStats(new StatsConfig()); diff --git a/benchmarks/src/main/java/io/hstore/bench/Store.java b/benchmarks/src/main/java/io/hstore/bench/Store.java index 8287e8db..187a3663 100644 --- a/benchmarks/src/main/java/io/hstore/bench/Store.java +++ b/benchmarks/src/main/java/io/hstore/bench/Store.java @@ -55,6 +55,8 @@ default void reopen() { void flush(); + void compact(); + long bytesWritten(); Path directory(); From df0751a0922c4d0c0a47caefd9681d514105e543 Mon Sep 17 00:00:00 2001 From: venkat1701 Date: Tue, 6 Oct 2026 04:35:11 +0530 Subject: [PATCH 3/7] feat(bench): time commits while a full compaction runs After the churn, two 10 s windows of single-update commits on a fixed schedule: one without compaction and one with a full compaction starting 1 s in. disk.churned is now recorded at a reopen before them, and disk.compacted at the end. --- .../main/java/io/hstore/bench/Comparison.java | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/benchmarks/src/main/java/io/hstore/bench/Comparison.java b/benchmarks/src/main/java/io/hstore/bench/Comparison.java index 11f0212b..a6a2cad5 100644 --- a/benchmarks/src/main/java/io/hstore/bench/Comparison.java +++ b/benchmarks/src/main/java/io/hstore/bench/Comparison.java @@ -22,6 +22,7 @@ import java.util.function.IntToLongFunction; import java.util.function.LongSupplier; import java.util.function.Supplier; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.LockSupport; public final class Comparison { @@ -71,6 +72,9 @@ private interface Slice { private static final int MIXED_BATCH = 10; private static final int MIXED_UPDATES_PER_SECOND = 1_000; private static final int SAMPLES_PER_THREAD = 200_000; + private static final long COMPACTION_WINDOW_NANOS = 10_000_000_000L; + private static final long COMPACTION_DELAY_NANOS = 1_000_000_000L; + private static final long COMPACTION_INTERVAL_NANOS = 20_000_000L; private static final long SEED = 20_260_904L; private Comparison() { @@ -190,13 +194,18 @@ private static void run(Map options) throws Exception { })))); results.add(read("read.incidence.churned", "enumerate incidence sets after the deletes", nodes.length, (from, to) -> store.incidence(nodes, from, to), true)); + long[] churned = new long[1]; + store.reopen(() -> churned[0] = store.diskBytes()); + results.add(new Result("disk.churned", "bytes on disk after the deletes and a clean shutdown", churned[0], 1000.0, churned[0])); + results.add(compaction(store, dataset, false)); + results.add(compaction(store, dataset, true)); store.flush(); totals.put("bytesWritten", number(store.bytesWritten())); } finally { store.close(); } - long churned = store.diskBytes(); - results.add(new Result("disk.churned", "bytes on disk after the deletes and a clean shutdown", churned, 1000.0, churned)); + long compacted = store.diskBytes(); + results.add(new Result("disk.compacted", "bytes on disk after a full compaction and a clean shutdown", compacted, 1000.0, compacted)); results.add(recover(options, dataset)); write(out, store, scale, sync, threads, dataset, totals, results); results.forEach(result -> IO.println(" %-22s %,14.0f ops/s %,10.1f ms checksum %d" @@ -378,6 +387,59 @@ private static List mixed(Store store, Dataset dataset, int threads) thr return List.of(read, write); } + private static Result compaction(Store store, Dataset dataset, boolean compact) throws Exception { + int[] updates = dataset.updates(); + Reservoir commits = new Reservoir(SAMPLES_PER_THREAD, SEED); + AtomicReference failure = new AtomicReference<>(); + long[] compactNanos = new long[1]; + long before = store.bytesWritten(); + long diskBefore = store.diskBytes(); + JvmUsage usage = JvmUsage.now(); + long started = System.nanoTime(); + long deadline = started + COMPACTION_WINDOW_NANOS; + Thread compactor = Thread.ofPlatform().name("bench-compaction").start(() -> { + if (!compact) { + return; + } + LockSupport.parkNanos(started + COMPACTION_DELAY_NANOS - System.nanoTime()); + long begin = System.nanoTime(); + try { + store.compact(); + } catch (Throwable e) { + failure.set(e); + } + compactNanos[0] = System.nanoTime() - begin; + }); + int committed = 0; + for (int k = 0; ; k++) { + long intended = started + k * COMPACTION_INTERVAL_NANOS; + if (intended >= deadline && !compactor.isAlive()) { + break; + } + for (long wait = intended - System.nanoTime(); wait > 0; wait = intended - System.nanoTime()) { + LockSupport.parkNanos(wait); + } + int index = k % updates.length; + store.update(updates, index, index + 1, (compact ? 4_000_000 : 3_000_000) + k); + commits.add(System.nanoTime() - intended); + committed++; + } + compactor.join(); + if (failure.get() != null) { + throw new IllegalStateException("compaction failed", failure.get()); + } + double millis = (System.nanoTime() - started) / 1e6; + JvmUsage used = JvmUsage.now().since(usage); + store.flush(); + String schedule = "single-update commits at %d/s".formatted(1_000_000_000L / COMPACTION_INTERVAL_NANOS); + Result result = new Result(compact ? "compaction" : "compaction.baseline", + compact ? schedule + " while a full compaction runs" : schedule + " with no compaction, for comparison", + committed, millis, 0).using(used).with("latency", Reservoir.merge(commits).json()).with("checked", new Json.Bool(false)) + .with("bytesWritten", number(store.bytesWritten() - before)); + return compact ? result.with("compactionMillis", number(compactNanos[0] / 1_000_000)).with("reclaimed", number(diskBefore - store.diskBytes())) + : result; + } + private static Result concurrent(Store store, Dataset dataset, int threads) throws Exception { int[] probes = dataset.probeNodes(); try (ExecutorService pool = Executors.newFixedThreadPool(threads)) { From 6936dbcd849cadc579e9e15695fc6f90953737cb Mon Sep 17 00:00:00 2001 From: venkat1701 Date: Tue, 6 Oct 2026 04:35:11 +0530 Subject: [PATCH 4/7] feat(bench): report compaction time and space reclaimed Reclaimed space is the first measure where more is better, so its ratio is inverted, and negative sizes are printed as such. --- .../src/main/java/io/hstore/bench/Report.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/benchmarks/src/main/java/io/hstore/bench/Report.java b/benchmarks/src/main/java/io/hstore/bench/Report.java index a81eaab7..0f52df91 100644 --- a/benchmarks/src/main/java/io/hstore/bench/Report.java +++ b/benchmarks/src/main/java/io/hstore/bench/Report.java @@ -71,13 +71,15 @@ static String markdown(String[] args) { return out.toString(); } - private record Metric(String key, String name, boolean perOperation, boolean showZero, DoubleFunction format) { + private record Metric(String key, String name, boolean perOperation, boolean showZero, boolean higherIsBetter, DoubleFunction format) { } - private static final List METRICS = List.of(new Metric("bytesWritten", "bytes written per operation", true, false, Report::bytes), - new Metric("allocated", "heap allocated per operation", true, false, Report::bytes), - new Metric("gcMillis", "GC pause time", false, false, value -> "%,.0f ms".formatted(value)), - new Metric("lost", "acknowledged nodes lost", false, true, value -> "%,.0f".formatted(value))); + private static final List METRICS = List.of(new Metric("bytesWritten", "bytes written per operation", true, false, false, Report::bytes), + new Metric("allocated", "heap allocated per operation", true, false, false, Report::bytes), + new Metric("gcMillis", "GC pause time", false, false, false, value -> "%,.0f ms".formatted(value)), + new Metric("lost", "acknowledged nodes lost", false, true, false, value -> "%,.0f".formatted(value)), + new Metric("compactionMillis", "compaction time", false, true, false, value -> "%,.0f ms".formatted(value)), + new Metric("reclaimed", "disk space reclaimed", false, true, true, Report::bytes)); private static void resources(StringBuilder out, List subjects, List baselines) { List all = Stream.concat(subjects.stream(), baselines.stream()).toList(); @@ -90,7 +92,7 @@ private static void resources(StringBuilder out, List subjects, List b if (mine == 0 && theirs == 0 && !metric.showZero()) { continue; } - double ratio = theirs / mine; + double ratio = metric.higherIsBetter() ? (mine > 0 && theirs > 0 ? mine / theirs : Double.NaN) : theirs / mine; rows.append("| `%s` | %s | %s | %s | %s |%n".formatted(workload, metric.name(), metric.format().apply(mine), metric.format().apply(theirs), Double.isFinite(ratio) ? "**%.2f×**".formatted(ratio) : "n/a")); } @@ -127,10 +129,12 @@ private static double[] header(List runs, String key) { } private static String bytes(double value) { - if (value < 1024) { - return "%.0f B".formatted(value); + double size = Math.abs(value); + String sign = value < 0 ? "-" : ""; + if (size < 1024) { + return sign + "%.0f B".formatted(size); } - return value < 1 << 20 ? "%.1f KiB".formatted(value / 1024) : "%,.1f MiB".formatted(value / (1 << 20)); + return sign + (size < 1 << 20 ? "%.1f KiB".formatted(size / 1024) : "%,.1f MiB".formatted(size / (1 << 20))); } private static void latency(StringBuilder out, List subjects, List baselines) { From d470430e0daa1c78f260fdf5605acd4337bda4c9 Mon Sep 17 00:00:00 2001 From: venkat1701 Date: Tue, 6 Oct 2026 04:35:11 +0530 Subject: [PATCH 5/7] build(bench): pass segment size and live ratio through run.sh --- benchmarks/run.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/benchmarks/run.sh b/benchmarks/run.sh index b5e0a396..0bc2b67a 100755 --- a/benchmarks/run.sh +++ b/benchmarks/run.sh @@ -9,10 +9,18 @@ heap="${HEAP:-4g}" history="${HISTORY:-64}" runs="${RUNS:-3}" cache="${CACHE_MB:-0}" +segment="${PAGES_PER_SEGMENT:-0}" +ratio="${COMPACTION_LIVE_RATIO:-0.5}" results="results/scale-$scale-$durability-history-$history" if [ "$cache" != 0 ]; then results="$results-cache-$cache" fi +if [ "$segment" != 0 ]; then + results="$results-segment-$segment" +fi +if [ "$ratio" != 0.5 ]; then + results="$results-ratio-$ratio" +fi ../mvnw -q -f ../pom.xml -Pbenchmarks -DskipTests install classpath="target/classes:$(cat target/classpath.txt)" @@ -26,7 +34,7 @@ rm -rf "$results" && mkdir -p "$results" for run in $(seq 1 "$runs"); do for store in hstore hypergraphdb; do java "${jvm[@]}" io.hstore.bench.Comparison run --store "$store" --scale "$scale" --durability "$durability" \ - --threads "$threads" --history "$history" --cache-mb "$cache" --out "$results/$store-$run.json" + --threads "$threads" --history "$history" --cache-mb "$cache" --pages-per-segment "$segment" --compaction-live-ratio "$ratio" --out "$results/$store-$run.json" done done java "${jvm[@]}" io.hstore.bench.Comparison report "$results"/hstore-*.json "$results"/hypergraphdb-*.json | tee "$results/report.md" From a8fa280d53d157e6adbe6701a2f4f4d0907d0cff Mon Sep 17 00:00:00 2001 From: venkat1701 Date: Tue, 6 Oct 2026 04:35:12 +0530 Subject: [PATCH 6/7] docs(bench): describe the compaction workload --- docs/benchmarks.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/benchmarks.md b/docs/benchmarks.md index 87f3e80b..e5504397 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -62,6 +62,9 @@ taken from a common hyperedge (so co-membership counts are non-zero), and 20,000 | `churn.remove` | remove one member from each of 20,000 other hyperedges, 1,000 per transaction | `Writer.remove` | `graph.replace` with a new `HGPlainLink` (links are immutable) | | `read.incidence.churned` | `read.incidence` after the deletes | | | | `disk.churned` | bytes on disk after the deletes and a clean shutdown | | | +| `compaction.baseline` | single-update commits at 50/s for 10 s, no compaction | `Writer.set` | `graph.replace` | +| `compaction` | the same commits while a full compaction runs, starting 1 s in | `StorageEngine.compact` | `Environment.cleanLog` until it finds nothing, then a forced checkpoint | +| `disk.compacted` | bytes on disk after the compaction and a clean shutdown | | | | `recover` | open the store after the process ingesting into it was killed with SIGKILL | `HypergraphDatabase.open` | `HGEnvironment.get` | Read workloads run a warm-up pass over 10% of the probes before timing, except `read.incidence.cold`. @@ -93,6 +96,16 @@ the loaded store after a clean shutdown. The checksum of `read.incidence.churned both engines applied the same deletes. `disk.churned` shows whether the space came back: through compaction for HStore, and the log cleaner for JE. +**Compaction.** After the churn, `disk.churned` is recorded at a reopen, and then two 10 s windows run. In both, one +writer commits a single update every 20 ms on a fixed schedule, and each commit's latency is measured from when it +was scheduled. In `compaction`, the store also runs a full compaction starting 1 s in, and the window lasts until +the compaction has finished. HStore calls `StorageEngine.compact()`. JE calls `cleanLog()` until it cleans nothing, +then forces a checkpoint so the cleaned files are deleted. The latency table compares the two windows, and the +*Resources* table adds the compaction time and the space reclaimed (disk while open, before against after). That +figure can be negative when compaction frees less than the writer adds. HStore's default segments are 256 MiB, so +at scale 1 most data shares one or two segments. `--pages-per-segment` (`PAGES_PER_SEGMENT`) and +`--compaction-live-ratio` (`COMPACTION_LIVE_RATIO`) change HStore's settings for a run. + **Crash recovery.** `reopen` closes the store cleanly first. `recover` doesn't: 1. The run starts a second JVM (`Comparison crash`) with the same flags and classpath. It ingests nodes into a fresh directory and prints the count after every acknowledged commit. From 0dd89233fb26a1066169e5e94157d4fac73b762d Mon Sep 17 00:00:00 2001 From: venkat1701 Date: Sun, 11 Oct 2026 12:53:30 +0530 Subject: [PATCH 7/7] fix(bench): measure reclaimed space at a reopen on both sides HStore deletes a retired segment only once no older reader can need it, which often happens after compact() returns. Measuring the disk while open, right after the window, missed that space. Both sides of the figure now come from a reopen. The delay before compaction now loops until its deadline, and the two fixed-rate windows are left out of the main table, where their ratio only showed the schedule. --- .../main/java/io/hstore/bench/Comparison.java | 17 +++++++++++++---- .../src/main/java/io/hstore/bench/Report.java | 2 +- docs/benchmarks.md | 6 ++++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/benchmarks/src/main/java/io/hstore/bench/Comparison.java b/benchmarks/src/main/java/io/hstore/bench/Comparison.java index a6a2cad5..0fe77763 100644 --- a/benchmarks/src/main/java/io/hstore/bench/Comparison.java +++ b/benchmarks/src/main/java/io/hstore/bench/Comparison.java @@ -392,8 +392,11 @@ private static Result compaction(Store store, Dataset dataset, boolean compact) Reservoir commits = new Reservoir(SAMPLES_PER_THREAD, SEED); AtomicReference failure = new AtomicReference<>(); long[] compactNanos = new long[1]; + long[] diskBefore = new long[1]; + if (compact) { + store.reopen(() -> diskBefore[0] = store.diskBytes()); + } long before = store.bytesWritten(); - long diskBefore = store.diskBytes(); JvmUsage usage = JvmUsage.now(); long started = System.nanoTime(); long deadline = started + COMPACTION_WINDOW_NANOS; @@ -401,7 +404,9 @@ private static Result compaction(Store store, Dataset dataset, boolean compact) if (!compact) { return; } - LockSupport.parkNanos(started + COMPACTION_DELAY_NANOS - System.nanoTime()); + for (long wait = started + COMPACTION_DELAY_NANOS - System.nanoTime(); wait > 0; wait = started + COMPACTION_DELAY_NANOS - System.nanoTime()) { + LockSupport.parkNanos(wait); + } long begin = System.nanoTime(); try { store.compact(); @@ -436,8 +441,12 @@ private static Result compaction(Store store, Dataset dataset, boolean compact) compact ? schedule + " while a full compaction runs" : schedule + " with no compaction, for comparison", committed, millis, 0).using(used).with("latency", Reservoir.merge(commits).json()).with("checked", new Json.Bool(false)) .with("bytesWritten", number(store.bytesWritten() - before)); - return compact ? result.with("compactionMillis", number(compactNanos[0] / 1_000_000)).with("reclaimed", number(diskBefore - store.diskBytes())) - : result; + if (!compact) { + return result; + } + long[] diskAfter = new long[1]; + store.reopen(() -> diskAfter[0] = store.diskBytes()); + return result.with("compactionMillis", number(compactNanos[0] / 1_000_000)).with("reclaimed", number(diskBefore[0] - diskAfter[0])); } private static Result concurrent(Store store, Dataset dataset, int threads) throws Exception { diff --git a/benchmarks/src/main/java/io/hstore/bench/Report.java b/benchmarks/src/main/java/io/hstore/bench/Report.java index 0f52df91..9e0c2e2f 100644 --- a/benchmarks/src/main/java/io/hstore/bench/Report.java +++ b/benchmarks/src/main/java/io/hstore/bench/Report.java @@ -49,7 +49,7 @@ static String markdown(String[] args) { out.append("|---|---:|---:|---:|:---:|%n".formatted()); for (Map.Entry> entry : subject.results().entrySet()) { String workload = entry.getKey(); - if (baselines.stream().anyMatch(run -> !run.results().containsKey(workload))) { + if (workload.startsWith("compaction") || baselines.stream().anyMatch(run -> !run.results().containsKey(workload))) { continue; } boolean disk = workload.startsWith("disk"); diff --git a/docs/benchmarks.md b/docs/benchmarks.md index e5504397..c1ef8f5b 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -101,8 +101,10 @@ writer commits a single update every 20 ms on a fixed schedule, and each commit' was scheduled. In `compaction`, the store also runs a full compaction starting 1 s in, and the window lasts until the compaction has finished. HStore calls `StorageEngine.compact()`. JE calls `cleanLog()` until it cleans nothing, then forces a checkpoint so the cleaned files are deleted. The latency table compares the two windows, and the -*Resources* table adds the compaction time and the space reclaimed (disk while open, before against after). That -figure can be negative when compaction frees less than the writer adds. HStore's default segments are 256 MiB, so +*Resources* table adds the compaction time and the space reclaimed. Disk is measured at a reopen just before the +window and again at a reopen just after it, so segments that HStore only deletes once older readers are gone are +counted too. That figure can be negative when compaction frees less than the writer adds. The two windows run at a +fixed rate, so they are left out of the main table, where their ratio would always be about 1. HStore's default segments are 256 MiB, so at scale 1 most data shares one or two segments. `--pages-per-segment` (`PAGES_PER_SEGMENT`) and `--compaction-live-ratio` (`COMPACTION_LIVE_RATIO`) change HStore's settings for a run.