diff --git a/api/v1/create_statefulset_jvmspec_test.go b/api/v1/create_statefulset_jvmspec_test.go index 05628c1c..9588a35b 100644 --- a/api/v1/create_statefulset_jvmspec_test.go +++ b/api/v1/create_statefulset_jvmspec_test.go @@ -221,7 +221,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollector(t *testing.T) { spec := coh.CoherenceResourceSpec{ JVM: &coh.JVMSpec{ Gc: &coh.JvmGarbageCollectorSpec{ - Collector: stringPtr("G1"), + Collector: stringPtr("ZGC"), }, }, } @@ -230,7 +230,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollector(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "G1"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "ZGC"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/docs/jvm/040_gc.adoc b/docs/jvm/040_gc.adoc index f490b358..da013b37 100644 --- a/docs/jvm/040_gc.adoc +++ b/docs/jvm/040_gc.adoc @@ -61,13 +61,16 @@ If different GC logging arguments are required then the relevant JVM arguments c The garbage collector to use can be set using the `jvm.gc.collector` field. This field can be set to either `G1`, `CMS` or `Parallel` (the field is case-insensitive, invalid values will be silently ignored). -The default collector set, if none has been specified, will be `G1`. + +The default collector set, if none has been specified, will be whatever is the default for the JVM being used. |==== | Parameter | JVM Argument Set | `G1` | `-XX:+UseG1GC` | `CMS` | `-XX:+UseConcMarkSweepGC` | `Parallel` | `-XX:+UseParallelGC` +| `Serial` | `-XX:+UseSerialGC` +| `ZGC` | `-XX:+UseZGC` |==== For example: @@ -80,9 +83,15 @@ metadata: spec: jvm: gc: - collector: "G1" + collector: "ZGC" ---- -The example above will add `-XX:+UseG1GC` to the command line. +The example above will add `-XX:+UseZGC` to the command line. + +[NOTE] +==== +The JVM only allows a single `-XX:Use****` option that sets the garbage collector to use, so the collector should not be +specified in both the `spec.jvm.gc.collector` field, and in the `spec.jvm.args` field. +==== === Adding Arbitrary GC Args diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 4ad08cf5..b7276941 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -426,12 +426,16 @@ func configureCommand(details *run_details.RunDetails) error { gc := strings.ToLower(details.Getenv(v1.EnvVarJvmGcCollector)) switch { - case gc == "" || gc == "g1": + case gc == "g1": details.AddMemoryOption("-XX:+UseG1GC") case gc == "cms": details.AddMemoryOption("-XX:+UseConcMarkSweepGC") case gc == "parallel": details.AddMemoryOption("-XX:+UseParallelGC") + case gc == "serial": + details.AddMemoryOption("-XX:+UseSerialGC") + case gc == "zgc": + details.AddMemoryOption("-XX:+UseZGC") } maxRAM := details.Getenv(v1.EnvVarJvmMaxRAM) diff --git a/pkg/runner/runner_jvm_test.go b/pkg/runner/runner_jvm_test.go index 8f94b16e..96912fc0 100644 --- a/pkg/runner/runner_jvm_test.go +++ b/pkg/runner/runner_jvm_test.go @@ -265,6 +265,72 @@ func TestJvmGarbageCollectorParallel(t *testing.T) { g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } +func TestJvmGarbageCollectorSerial(t *testing.T) { + g := NewGomegaWithT(t) + + d := &coh.Coherence{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: coh.CoherenceStatefulSetResourceSpec{ + CoherenceResourceSpec: coh.CoherenceResourceSpec{ + JVM: &coh.JVMSpec{ + Gc: &coh.JvmGarbageCollectorSpec{ + Collector: ptr.To("serial"), + }, + }, + }, + }, + } + + expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseSerialGC") + verifyConfigFilesWithArgs(t, d, expectedArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + + e, err := ExecuteWithArgsAndNewViper(env, args) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(e).NotTo(BeNil()) + g.Expect(e.OsCmd).NotTo(BeNil()) + + g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+UseG1GC"), "-XX:+UseSerialGC") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) +} + +func TestJvmGarbageCollectorZGC(t *testing.T) { + g := NewGomegaWithT(t) + + d := &coh.Coherence{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: coh.CoherenceStatefulSetResourceSpec{ + CoherenceResourceSpec: coh.CoherenceResourceSpec{ + JVM: &coh.JVMSpec{ + Gc: &coh.JvmGarbageCollectorSpec{ + Collector: ptr.To("zgc"), + }, + }, + }, + }, + } + + expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseZGC") + verifyConfigFilesWithArgs(t, d, expectedArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + + e, err := ExecuteWithArgsAndNewViper(env, args) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(e).NotTo(BeNil()) + g.Expect(e.OsCmd).NotTo(BeNil()) + + g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+UseG1GC"), "-XX:+UseZGC") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) +} + func TestJvmGarbageCollectorLoggingTrue(t *testing.T) { g := NewGomegaWithT(t) diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 1a8604fd..32d9464f 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -217,7 +217,6 @@ func AppendCommonExpectedNonServerArgs(args []string, role string) []string { "-Dcoherence.operator.diagnostics.dir=/coherence-operator/jvm/unknown/unknown", "-XX:HeapDumpPath=/coherence-operator/jvm/unknown/unknown/heap-dumps/unknown-unknown.hprof", "-Dcoherence.operator.can.resume.services=true", - "-XX:+UseG1GC", "-Dcoherence.ttl=0", "-XX:+UnlockDiagnosticVMOptions", "-XX:ErrorFile=/coherence-operator/jvm/unknown/unknown/hs-err-unknown-unknown.log",