This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-7452-3b19f76cc357788c5dd47f2f87aa50ce9e476fe6 in repository https://gitbox.apache.org/repos/asf/texera.git
commit 4b526eb26afcce34467d50b6ff597f4f06642dde Author: Xinyuan Lin <[email protected]> AuthorDate: Sat Aug 15 02:01:18 2026 +0000 chore(amber): remove the unused EmptyReplayLogger (#7452) ### What changes were proposed in this PR? Deletes `EmptyReplayLogger` and its spec — a no-op `ReplayLogger` that nothing in the engine ever constructs. Pure deletion, no behaviour change: **−171 lines**. The live null object for log replay sits one layer up, at the manager. `EmptyReplayLogManagerImpl` inherits the `ReplayLogManager` trait's non-logging `withFaultTolerant`, so it never needs a logger at all: ``` ReplayLogManager.scala:51 -> EmptyReplayLogManagerImpl (no-op manager, live) ReplayLogManager.scala:109 -> new ReplayLoggerImpl() (the only ReplayLogger built in main) EmptyReplayLogger (never instantiated) ``` `69b7f9bc1` (#2230) added `ReplayLogger`, `ReplayLoggerImpl`, `EmptyReplayLogger` and `ReplayLogManager` in a single commit, so nothing ever moved layers — `EmptyReplayLogger` was unwired from the day it landed. No configuration selects a logger class by name either, so there is no path that revives it. > Reviewer note: the abstract base `ReplayLogger` is **not** touched — `ReplayLoggerImpl` extends it and is unaffected. It does end up with a single subclass and no declared-type site once this lands, so collapsing it is tracked separately in #7673; that one edits live code, while this PR stays a pure dead-code deletion. `EmptyReplayLogger` acquired unit tests during the 2026 coverage work (#5554), which is why it currently looks live; the spec covers this class and nothing else. ### Any related issues, documentation, discussions? Closes #7449 ### How was this PR tested? Existing tests only — this PR adds none, since it removes code and the spec that covered it. Locally, from the repo root with Java 17: - `sbt "WorkflowExecutionService/Test/compile"` — success. Verification, re-runnable by a reviewer: ``` git grep -n EmptyReplayLogger # only the two deleted files git grep -n "extends ReplayLogger" -- amber/src/main # ReplayLoggerImpl remains git log -S "new EmptyReplayLogger" --all # only the #5554 spec commits ``` ### Was this PR authored or co-authored using generative AI tooling? Generated-by: Claude Code (Claude Opus 5) --- .../architecture/logreplay/EmptyReplayLogger.scala | 41 ------- .../logreplay/EmptyReplayLoggerSpec.scala | 130 --------------------- 2 files changed, 171 deletions(-) diff --git a/amber/src/main/scala/org/apache/texera/amber/engine/architecture/logreplay/EmptyReplayLogger.scala b/amber/src/main/scala/org/apache/texera/amber/engine/architecture/logreplay/EmptyReplayLogger.scala deleted file mode 100644 index 74be96acdb..0000000000 --- a/amber/src/main/scala/org/apache/texera/amber/engine/architecture/logreplay/EmptyReplayLogger.scala +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.texera.amber.engine.architecture.logreplay - -import org.apache.texera.amber.core.virtualidentity.{ - ChannelIdentity, - EmbeddedControlMessageIdentity -} -import org.apache.texera.amber.engine.common.ambermessage.WorkflowFIFOMessage - -class EmptyReplayLogger extends ReplayLogger { - - override def drainCurrentLogRecords(step: Long): Array[ReplayLogRecord] = { - Array.empty - } - - def markAsReplayDestination(id: EmbeddedControlMessageIdentity): Unit = {} - - override def logCurrentStepWithMessage( - step: Long, - channelId: ChannelIdentity, - msg: Option[WorkflowFIFOMessage] - ): Unit = {} -} diff --git a/amber/src/test/scala/org/apache/texera/amber/engine/architecture/logreplay/EmptyReplayLoggerSpec.scala b/amber/src/test/scala/org/apache/texera/amber/engine/architecture/logreplay/EmptyReplayLoggerSpec.scala deleted file mode 100644 index ccd7fde8f9..0000000000 --- a/amber/src/test/scala/org/apache/texera/amber/engine/architecture/logreplay/EmptyReplayLoggerSpec.scala +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.texera.amber.engine.architecture.logreplay - -import org.apache.texera.amber.core.virtualidentity.{ - ActorVirtualIdentity, - ChannelIdentity, - EmbeddedControlMessageIdentity -} -import org.scalatest.flatspec.AnyFlatSpec - -class EmptyReplayLoggerSpec extends AnyFlatSpec { - - // --------------------------------------------------------------------------- - // Fixtures - // --------------------------------------------------------------------------- - - private val channelId: ChannelIdentity = - ChannelIdentity(ActorVirtualIdentity("from"), ActorVirtualIdentity("to"), isControl = false) - private val ecmId: EmbeddedControlMessageIdentity = EmbeddedControlMessageIdentity("test-ecm") - - // --------------------------------------------------------------------------- - // drainCurrentLogRecords — always empty - // --------------------------------------------------------------------------- - - "EmptyReplayLogger.drainCurrentLogRecords" should - "return an empty Array[ReplayLogRecord] regardless of the step argument" in { - val logger = new EmptyReplayLogger - val r0 = logger.drainCurrentLogRecords(0L) - val r1 = logger.drainCurrentLogRecords(1L) - val rMax = logger.drainCurrentLogRecords(Long.MaxValue) - val rNeg = logger.drainCurrentLogRecords(-1L) - assert(r0.isEmpty) - assert(r1.isEmpty) - assert(rMax.isEmpty) - assert(rNeg.isEmpty) - } - - it should "return a non-null array (callers iterate it without null-checking)" in { - val logger = new EmptyReplayLogger - val r = logger.drainCurrentLogRecords(42L) - assert(r != null) - assert(r.length == 0) - } - - it should "return arrays whose element type is ReplayLogRecord (compile-time enforced)" in { - // If a future refactor accidentally widened the return type to - // `Array[AnyRef]`, this would fail to typecheck. Pin the contract. - val logger = new EmptyReplayLogger - val r: Array[ReplayLogRecord] = logger.drainCurrentLogRecords(0L) - assert(r.length == 0) - } - - // --------------------------------------------------------------------------- - // markAsReplayDestination — no-op - // --------------------------------------------------------------------------- - - "EmptyReplayLogger.markAsReplayDestination" should - "accept any EmbeddedControlMessageIdentity without throwing" in { - val logger = new EmptyReplayLogger - logger.markAsReplayDestination(ecmId) // must not throw - // Calling twice with the same id is still a no-op. - logger.markAsReplayDestination(ecmId) - succeed - } - - it should "leave drainCurrentLogRecords output untouched (no internal buffer accumulates)" in { - val logger = new EmptyReplayLogger - logger.markAsReplayDestination(ecmId) - logger.markAsReplayDestination(EmbeddedControlMessageIdentity("another")) - assert(logger.drainCurrentLogRecords(0L).isEmpty) - } - - // --------------------------------------------------------------------------- - // logCurrentStepWithMessage — no-op - // --------------------------------------------------------------------------- - - "EmptyReplayLogger.logCurrentStepWithMessage" should - "accept any (step, channelId, msg) triple without throwing" in { - val logger = new EmptyReplayLogger - logger.logCurrentStepWithMessage(0L, channelId, msg = None) - logger.logCurrentStepWithMessage(1L, channelId, msg = None) - logger.logCurrentStepWithMessage(Long.MaxValue, channelId, msg = None) - succeed - } - - it should "tolerate a None msg argument (the null-object's job is to absorb every call)" in { - val logger = new EmptyReplayLogger - logger.logCurrentStepWithMessage(7L, channelId, msg = None) - // Verify nothing was queued in the process. - assert(logger.drainCurrentLogRecords(7L).isEmpty) - } - - it should "leave drainCurrentLogRecords output empty even after many calls" in { - val logger = new EmptyReplayLogger - (1L to 100L).foreach(i => logger.logCurrentStepWithMessage(i, channelId, msg = None)) - assert(logger.drainCurrentLogRecords(100L).isEmpty) - } - - // --------------------------------------------------------------------------- - // ReplayLogger trait conformance - // --------------------------------------------------------------------------- - // - // The null-object pattern requires EmptyReplayLogger to be a drop-in for - // ReplayLogger callers — pin the upcast. - - "EmptyReplayLogger" should "be usable through the ReplayLogger interface" in { - val logger: ReplayLogger = new EmptyReplayLogger - logger.logCurrentStepWithMessage(0L, channelId, msg = None) - logger.markAsReplayDestination(ecmId) - assert(logger.drainCurrentLogRecords(0L).isEmpty) - } -}
