diff --git a/gradle.properties b/gradle.properties index 696d0adf15..033bb8ae88 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -org.gradle.jvmargs=-Xmx2g -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx2g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 org.gradle.java.installations.fromEnv=JDK_CI systemProp.sonar.gradle.skipCompile=true org.gradle.configuration-cache=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 18a6b29739..cbdb595058 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ bouncycastle = "1.70" cache2k = "2.6.1.Final" caffeine = "3.1.8" checker-framework = "3.42.0" -checkstyle = "10.12.6" +checkstyle = "10.12.7" coherence = "22.06.2" commons-collections4 = "4.4" commons-compress = "1.25.0" diff --git a/gradle/plugins/src/main/kotlin/ProjectExtensions.kt b/gradle/plugins/src/main/kotlin/ProjectExtensions.kt index 696ee185ce..9b1a69d39d 100644 --- a/gradle/plugins/src/main/kotlin/ProjectExtensions.kt +++ b/gradle/plugins/src/main/kotlin/ProjectExtensions.kt @@ -9,8 +9,8 @@ fun Project.version(major: Int, minor: Int, patch: Int, releaseBuild: Boolean) { } fun Project.javaExecJvmArgs(): List { - val jvmArgs = mutableListOf("-XX:+UseParallelGC", "-Xmx4g") val arguments = findProperty("jvmArgs") as String? + val jvmArgs = mutableListOf("-Xmx4g") if (arguments != null) { jvmArgs.addAll(arguments.split(",")) } diff --git a/gradle/plugins/src/main/kotlin/lifecycle/java-library-caffeine-conventions.gradle.kts b/gradle/plugins/src/main/kotlin/lifecycle/java-library-caffeine-conventions.gradle.kts index e56d9dc737..a1c4055d7f 100644 --- a/gradle/plugins/src/main/kotlin/lifecycle/java-library-caffeine-conventions.gradle.kts +++ b/gradle/plugins/src/main/kotlin/lifecycle/java-library-caffeine-conventions.gradle.kts @@ -88,10 +88,9 @@ tasks.withType().configureEach { "https://guava.dev/releases/${libs.versions.guava.get()}/api/docs/") if (project != project(":caffeine")) { - val caffeineJavadoc = project(":caffeine").tasks.named("javadoc") linksOffline("https://static.javadoc.io/$group/caffeine/$version/", - relativePath(caffeineJavadoc.get().destinationDir!!.path)) - dependsOn(caffeineJavadoc) + relativePath(project(":caffeine").layout.buildDirectory.dir("docs/javadoc"))) + dependsOn(":caffeine:javadoc") } } } diff --git a/simulator/build.gradle.kts b/simulator/build.gradle.kts index 937dbfcba9..484bc665ab 100644 --- a/simulator/build.gradle.kts +++ b/simulator/build.gradle.kts @@ -80,21 +80,15 @@ tasks.named("run").configure { } tasks.register("simulate") { - group = "Application" description = "Runs multiple simulations and generates an aggregate report" - dependsOn(tasks.processResources, tasks.compileJava) - classpath = sourceSets["main"].runtimeClasspath - systemProperties = caffeineSystemProperties() - defaultJvmArgs = javaExecJvmArgs() - outputs.upToDateWhen { false } + mainClass = "com.github.benmanes.caffeine.cache.simulator.Simulate" + configureSimulatorTask() } tasks.register("rewrite") { - group = "Application" description = "Rewrite traces into the format used by other simulators" - dependsOn(tasks.processResources, tasks.compileJava) - classpath = sourceSets["main"].runtimeClasspath - outputs.upToDateWhen { false } + mainClass = "com.github.benmanes.caffeine.cache.simulator.parser.Rewriter" + configureSimulatorTask() } eclipse.classpath.file.beforeMerged { @@ -104,81 +98,65 @@ eclipse.classpath.file.beforeMerged { } } -abstract class Simulate @Inject constructor(@Internal val external: ExecOperations, - @Internal val layout: ProjectLayout) : DefaultTask() { +fun JavaExec.configureSimulatorTask() { + group = "Application" + dependsOn(tasks.processResources, tasks.compileJava) + classpath(sourceSets["main"].runtimeClasspath) + systemProperties(caffeineSystemProperties()) + outputs.upToDateWhen { false } + jvmArgs(javaExecJvmArgs()) +} + +abstract class Simulate @Inject constructor( + @Internal val projectLayout: ProjectLayout) : JavaExec() { @Input @Option(option = "maximumSize", description = "The maximum sizes") - var maximumSize = "" + var maximumSize: List = emptyList() @Input @Option(option = "metric", description = "The metric to compare") var metric = "Hit Rate" @Input @Option(option = "theme", description = "The chart theme") var theme = "light" @Input @Option(option = "title", description = "The chart title") var title = "" - @get:Input - abstract val systemProperties: MapProperty - @get:Input - abstract val defaultJvmArgs: ListProperty - @get:InputFiles @get:Classpath - abstract val classpath: Property - @get:OutputDirectory - val reportDir = File(layout.buildDirectory.get().asFile, "/reports/$name") + @OutputDirectory + val reportDir = File(projectLayout.buildDirectory.get().asFile, "/reports/$name") @TaskAction - fun run() { - external.javaexec { - mainClass = "com.github.benmanes.caffeine.cache.simulator.Simulate" - systemProperties(this@Simulate.systemProperties.get()) - classpath(this@Simulate.classpath) - jvmArgs(defaultJvmArgs.get()) - - if (maximumSize.isNotEmpty()) { - args("--maximumSize", maximumSize) - } - args("--outputDir", reportDir) - args("--metric", metric) - args("--title", title) - args("--theme", theme) + override fun exec() { + if (maximumSize.isNotEmpty()) { + args("--maximumSize", maximumSize.joinToString(",")) } + args("--outputDir", reportDir) + args("--metric", metric) + args("--title", title) + args("--theme", theme) + super.exec() } } -abstract class Rewrite @Inject constructor(@Internal val external: ExecOperations) : DefaultTask() { - @Input @Optional @Option(option = "inputFiles", description = "The trace input files") +abstract class Rewrite : JavaExec() { + @Input @Option(option = "inputFiles", description = "The trace input files") var inputFiles: List = emptyList() - @get:Input @get:Optional @get:Option(option = "inputFormat", description = "The input format") - abstract val inputFormat: Property - @get:Input @get:Optional @get:Option(option = "outputFile", description = "The output file") - abstract val outputFile: Property - @get:Input @get:Optional @get:Option(option = "outputFormat", description = "The output format") - abstract val outputFormat: Property - @get:InputFiles @get:Classpath - abstract val classpath: Property + @Input @Option(option = "inputFormat", description = "The input format") + var inputFormat: String = "" + @Input @Option(option = "outputFile", description = "The output file") + var outputFile: String = "" + @Input @Option(option = "outputFormat", description = "The output format") + var outputFormat: String = "" @TaskAction - fun run() { - external.javaexec { - var help = true - classpath(this@Rewrite.classpath) - mainClass = "com.github.benmanes.caffeine.cache.simulator.parser.Rewriter" - if (inputFiles.isNotEmpty()) { - args("--inputFiles", inputFiles.joinToString(",")) - help = false - } - if (inputFormat.isPresent) { - args("--inputFormat", inputFormat.get()) - help = false - } - if (outputFile.isPresent) { - args("--outputFile", outputFile.get()) - help = false - } - if (outputFormat.isPresent) { - args("--outputFormat", outputFormat.get()) - help = false - } - if (help) { - args("--help") - } + override fun exec() { + if (inputFiles.isNotEmpty()) { + args("--inputFiles", inputFiles.joinToString(",")) + } + if (outputFormat.isNotEmpty()) { + args("--outputFormat", outputFormat) + } + if (inputFormat.isNotEmpty()) { + args("--inputFormat", inputFormat) + } + if (outputFile.isNotEmpty()) { + args("--outputFile", outputFile) } + super.exec() } } diff --git a/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/linked/SievePolicy.java b/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/linked/SievePolicy.java index b62bce9394..2c04bdc874 100644 --- a/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/linked/SievePolicy.java +++ b/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/linked/SievePolicy.java @@ -77,7 +77,7 @@ private void onHit(AccessEvent event, Node node) { node.weight = event.weight(); node.visited = true; - while (size >= maximumSize) { + while (size > maximumSize) { evict(); } } diff --git a/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/two_queue/S3FifoPolicy.java b/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/two_queue/S3FifoPolicy.java index 563d503dc7..1c80961ba4 100644 --- a/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/two_queue/S3FifoPolicy.java +++ b/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/two_queue/S3FifoPolicy.java @@ -41,7 +41,7 @@ * main region. The small and main regions uses an n-bit clock eviction policy. *

* This implementation is based on the code provided by the authors in their - * repository and the pseudo code in their + * repository and the pseudo code in their * paper FIFO queues are all you need for * cache eviction. It does not use any of the paper's proposed adaptations for space saving or * concurrency because that may impact the hit rate. An implementor is encouraged to use a more @@ -111,7 +111,7 @@ private void onHit(AccessEvent event, Node node, IntConsumer sizeAdjuster) { node.weight = event.weight(); policyStats.recordWeightedHit(event.weight()); - while ((sizeSmall + sizeMain) >= maximumSize) { + while ((sizeSmall + sizeMain) > maximumSize) { evict(); } } @@ -147,10 +147,12 @@ private Node insertSmall(long key, int weight) { return node; } - @CanIgnoreReturnValue - private Node insertGhost(long key, int weight) { + private void insertGhost(long key, int weight) { // Bound the number of non-resident entries. While not included in the paper's pseudo code, the // author's reference implementation adds a similar constraint to avoid uncontrolled growth. + if (weight > maxGhost) { + return; + } while ((sizeGhost + weight) > maxGhost) { evictFromGhost(); } @@ -159,11 +161,10 @@ private Node insertGhost(long key, int weight) { node.appendAtHead(sentinelGhost); dataGhost.put(key, node); sizeGhost += node.weight; - return node; } private void evict() { - if (sizeSmall >= maxSmall) { + if ((sizeSmall >= maxSmall) || dataMain.isEmpty()) { evictFromSmall(); } else { evictFromMain(); diff --git a/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/report/TextReporter.java b/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/report/TextReporter.java index 15d83c6585..c4c69b3d86 100644 --- a/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/report/TextReporter.java +++ b/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/report/TextReporter.java @@ -35,7 +35,6 @@ import com.github.benmanes.caffeine.cache.simulator.policy.PolicyStats.Metric; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSortedSet; import com.typesafe.config.Config; /** @@ -78,7 +77,7 @@ private ImmutableList getSortedStats(Collection result .filter(header -> header.toLowerCase(US).equals(settings.report().sortBy().toLowerCase(US))) .findAny().orElseThrow(() -> new IllegalArgumentException( "Unknown sort order: " + settings.report().sortBy())); - return ImmutableSortedSet.copyOf(comparator(sortBy), results).asList(); + return ImmutableList.sortedCopyOf(comparator(sortBy), results); } /** Returns the column headers in declaration order. */