This is an automated email from the ASF dual-hosted git repository.
chia7712 pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/kafka.git
The following commit(s) were added to refs/heads/trunk by this push:
new 36a69b49c5b KAFKA-16937 Inline Time#waitObject to
ProducerMetadata#awaitUpdate (#22083)
36a69b49c5b is described below
commit 36a69b49c5b4bfdba775f54a9dc08bebde273081
Author: PoAn Yang <[email protected]>
AuthorDate: Mon Jul 27 12:19:44 2026 +0900
KAFKA-16937 Inline Time#waitObject to ProducerMetadata#awaitUpdate (#22083)
Inline `Time#waitObject` to `ProducerMetadata#awaitUpdate` and use
`Timer` in `ProducerMetadata#awaitUpdate`.
Reviewers: Chia-Ping Tsai <[email protected]>, Sean Quah
<[email protected]>
---
.../kafka/clients/producer/KafkaProducer.java | 7 +-
.../producer/internals/ProducerMetadata.java | 25 ++--
.../org/apache/kafka/common/utils/SystemTime.java | 20 ---
.../java/org/apache/kafka/common/utils/Time.java | 15 ++-
.../kafka/clients/producer/KafkaProducerTest.java | 142 +++++++++------------
.../producer/internals/ProducerMetadataTest.java | 12 +-
.../clients/producer/internals/SenderTest.java | 2 +-
.../producer/internals/TransactionManagerTest.java | 2 +-
.../apache/kafka/common/utils/MockTimeTest.java | 7 +-
.../apache/kafka/common/utils/SystemTimeTest.java | 25 ----
.../org/apache/kafka/common/utils/TimeTest.java | 15 +--
.../org/apache/kafka/common/utils/MockTime.java | 24 ----
.../apache/kafka/streams/TopologyTestDriver.java | 6 -
13 files changed, 108 insertions(+), 194 deletions(-)
diff --git
a/clients/src/main/java/org/apache/kafka/clients/producer/KafkaProducer.java
b/clients/src/main/java/org/apache/kafka/clients/producer/KafkaProducer.java
index b310020e125..cebd325f424 100644
--- a/clients/src/main/java/org/apache/kafka/clients/producer/KafkaProducer.java
+++ b/clients/src/main/java/org/apache/kafka/clients/producer/KafkaProducer.java
@@ -441,8 +441,7 @@ public class KafkaProducer<K, V> implements Producer<K, V> {
config.getLong(ProducerConfig.METADATA_MAX_AGE_CONFIG),
config.getLong(ProducerConfig.METADATA_MAX_IDLE_CONFIG),
logContext,
- clusterResourceListeners,
- Time.SYSTEM);
+ clusterResourceListeners);
this.metadata.bootstrap(addresses);
}
this.transactionManager = configureTransactionState(config,
logContext);
@@ -803,7 +802,7 @@ public class KafkaProducer<K, V> implements Producer<K, V> {
if (versionOpt.isEmpty()) return 0L;
sender.wakeup();
try {
- metadata.awaitUpdate(versionOpt.getAsInt(), maxBlockTimeMs);
+ metadata.awaitUpdate(versionOpt.getAsInt(),
time.timer(maxBlockTimeMs));
} catch (InterruptedException e) {
throw new InterruptException(e);
}
@@ -1274,7 +1273,7 @@ public class KafkaProducer<K, V> implements Producer<K,
V> {
int version = metadata.requestUpdateForTopic(topic);
sender.wakeup();
try {
- metadata.awaitUpdate(version, remainingWaitMs);
+ metadata.awaitUpdate(version, time.timer(remainingWaitMs));
} catch (TimeoutException ex) {
// Rethrow with original maxWaitMs to prevent logging
exception with remainingWaitMs
final String errorMessage = getErrorMessage(partitionsCount,
topic, partition, maxWaitMs);
diff --git
a/clients/src/main/java/org/apache/kafka/clients/producer/internals/ProducerMetadata.java
b/clients/src/main/java/org/apache/kafka/clients/producer/internals/ProducerMetadata.java
index 6945092c143..1e0d265e58d 100644
---
a/clients/src/main/java/org/apache/kafka/clients/producer/internals/ProducerMetadata.java
+++
b/clients/src/main/java/org/apache/kafka/clients/producer/internals/ProducerMetadata.java
@@ -18,11 +18,12 @@ package org.apache.kafka.clients.producer.internals;
import org.apache.kafka.clients.Metadata;
import org.apache.kafka.common.KafkaException;
+import org.apache.kafka.common.errors.TimeoutException;
import org.apache.kafka.common.internals.ClusterResourceListeners;
import org.apache.kafka.common.protocol.Errors;
import org.apache.kafka.common.requests.MetadataRequest;
import org.apache.kafka.common.requests.MetadataResponse;
-import org.apache.kafka.common.utils.Time;
+import org.apache.kafka.common.utils.Timer;
import org.apache.kafka.common.utils.internals.LogContext;
import org.slf4j.Logger;
@@ -44,7 +45,6 @@ public class ProducerMetadata extends Metadata {
private final Map<String, Long> topics = new ConcurrentHashMap<>();
private final Set<String> newTopics = new HashSet<>();
private final Logger log;
- private final Time time;
private Map<String, Errors> errors = null;
public ProducerMetadata(long refreshBackoffMs,
@@ -52,12 +52,10 @@ public class ProducerMetadata extends Metadata {
long metadataExpireMs,
long metadataIdleMs,
LogContext logContext,
- ClusterResourceListeners clusterResourceListeners,
- Time time) {
+ ClusterResourceListeners clusterResourceListeners)
{
super(refreshBackoffMs, refreshBackoffMaxMs, metadataExpireMs,
logContext, clusterResourceListeners);
this.metadataIdleMs = metadataIdleMs;
this.log = logContext.logger(ProducerMetadata.class);
- this.time = time;
}
@Override
@@ -153,14 +151,19 @@ public class ProducerMetadata extends Metadata {
/**
* Wait for metadata update until the current version is larger than the
last version we know of
*/
- public synchronized void awaitUpdate(final int lastVersion, final long
timeoutMs) throws InterruptedException {
- long currentTimeMs = time.milliseconds();
- long deadlineMs = currentTimeMs + timeoutMs < 0 ? Long.MAX_VALUE :
currentTimeMs + timeoutMs;
- time.waitObject(this, () -> {
+ public synchronized void awaitUpdate(final int lastVersion, final Timer
timer) throws InterruptedException {
+ while (true) {
// Throw fatal exceptions, if there are any. Recoverable topic
errors will be handled by the caller.
maybeThrowFatalException();
- return updateVersion() > lastVersion || isClosed();
- }, deadlineMs);
+ if (updateVersion() > lastVersion || isClosed())
+ break;
+
+ timer.update();
+ if (timer.isExpired())
+ throw new TimeoutException("Failed to update metadata after "
+ timer.timeoutMs() + " ms.");
+
+ wait(timer.remainingMs());
+ }
if (isClosed())
throw new KafkaException("Requested metadata update after close");
diff --git
a/clients/src/main/java/org/apache/kafka/common/utils/SystemTime.java
b/clients/src/main/java/org/apache/kafka/common/utils/SystemTime.java
index 524353507b7..f57cde65e32 100644
--- a/clients/src/main/java/org/apache/kafka/common/utils/SystemTime.java
+++ b/clients/src/main/java/org/apache/kafka/common/utils/SystemTime.java
@@ -16,10 +16,6 @@
*/
package org.apache.kafka.common.utils;
-import org.apache.kafka.common.errors.TimeoutException;
-
-import java.util.function.Supplier;
-
/**
* A time implementation that uses the system clock and sleep call. Use
`Time.SYSTEM` instead of creating an instance
* of this class.
@@ -46,22 +42,6 @@ class SystemTime implements Time {
Utils.sleep(ms);
}
- @Override
- public void waitObject(Object obj, Supplier<Boolean> condition, long
deadlineMs) throws InterruptedException {
- synchronized (obj) {
- while (true) {
- if (condition.get())
- return;
-
- long currentTimeMs = milliseconds();
- if (currentTimeMs >= deadlineMs)
- throw new TimeoutException("Condition not satisfied before
deadline");
-
- obj.wait(deadlineMs - currentTimeMs);
- }
- }
- }
-
private SystemTime() {
}
diff --git a/clients/src/main/java/org/apache/kafka/common/utils/Time.java
b/clients/src/main/java/org/apache/kafka/common/utils/Time.java
index b2277d24bac..500277dfef7 100644
--- a/clients/src/main/java/org/apache/kafka/common/utils/Time.java
+++ b/clients/src/main/java/org/apache/kafka/common/utils/Time.java
@@ -73,7 +73,20 @@ public interface Time {
*
* @throws org.apache.kafka.common.errors.TimeoutException if the timeout
expires before the condition is satisfied
*/
- void waitObject(Object obj, Supplier<Boolean> condition, long deadlineMs)
throws InterruptedException;
+ default void waitObject(Object obj, Supplier<Boolean> condition, long
deadlineMs) throws InterruptedException {
+ synchronized (obj) {
+ while (true) {
+ if (condition.get())
+ return;
+
+ long currentTimeMs = milliseconds();
+ if (currentTimeMs >= deadlineMs)
+ throw new
org.apache.kafka.common.errors.TimeoutException("Condition not satisfied before
deadline");
+
+ obj.wait(deadlineMs - currentTimeMs);
+ }
+ }
+ }
/**
* Get a timer which is bound to this time instance and expires after the
given timeout
diff --git
a/clients/src/test/java/org/apache/kafka/clients/producer/KafkaProducerTest.java
b/clients/src/test/java/org/apache/kafka/clients/producer/KafkaProducerTest.java
index 628caabb0cf..d2524fd2cf0 100644
---
a/clients/src/test/java/org/apache/kafka/clients/producer/KafkaProducerTest.java
+++
b/clients/src/test/java/org/apache/kafka/clients/producer/KafkaProducerTest.java
@@ -94,6 +94,7 @@ import
org.apache.kafka.common.telemetry.internals.ClientTelemetrySender;
import org.apache.kafka.common.utils.LogCaptureAppender;
import org.apache.kafka.common.utils.MockTime;
import org.apache.kafka.common.utils.Time;
+import org.apache.kafka.common.utils.Timer;
import org.apache.kafka.common.utils.internals.LogContext;
import org.apache.kafka.common.utils.internals.ProducerIdAndEpoch;
import org.apache.kafka.test.MockMetricsReporter;
@@ -128,7 +129,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -812,19 +812,19 @@ public class KafkaProducerTest {
// One request update for each empty cluster returned
verify(metadata, times(4)).requestUpdateForTopic(topic);
- verify(metadata, times(4)).awaitUpdate(anyInt(), anyLong());
+ verify(metadata, times(4)).awaitUpdate(anyInt(), any(Timer.class));
verify(metadata, times(5)).fetch();
// Should not request update for subsequent `send`
producer.send(record, null);
verify(metadata, times(4)).requestUpdateForTopic(topic);
- verify(metadata, times(4)).awaitUpdate(anyInt(), anyLong());
+ verify(metadata, times(4)).awaitUpdate(anyInt(), any(Timer.class));
verify(metadata, times(6)).fetch();
// Should not request update for subsequent `partitionsFor`
producer.partitionsFor(topic);
verify(metadata, times(4)).requestUpdateForTopic(topic);
- verify(metadata, times(4)).awaitUpdate(anyInt(), anyLong());
+ verify(metadata, times(4)).awaitUpdate(anyInt(), any(Timer.class));
verify(metadata, times(7)).fetch();
producer.close(Duration.ofMillis(0));
@@ -846,13 +846,13 @@ public class KafkaProducerTest {
// Verify the topic's metadata isn't requested since it's already
present.
verify(metadata, times(0)).requestUpdateForTopic(topic);
- verify(metadata, times(0)).awaitUpdate(anyInt(), anyLong());
+ verify(metadata, times(0)).awaitUpdate(anyInt(), any(Timer.class));
verify(metadata, times(1)).fetch();
// The metadata has been expired. Verify the producer requests the
topic's metadata.
producer.send(record, null);
verify(metadata, times(1)).requestUpdateForTopic(topic);
- verify(metadata, times(1)).awaitUpdate(anyInt(), anyLong());
+ verify(metadata, times(1)).awaitUpdate(anyInt(), any(Timer.class));
verify(metadata, times(3)).fetch();
producer.close(Duration.ofMillis(0));
@@ -888,7 +888,7 @@ public class KafkaProducerTest {
// For idempotence enabled case, the first metadata.fetch will be
called in Sender#maybeSendAndPollTransactionalRequest
Future<RecordMetadata> future = producer.send(record);
verify(metadata, times(4)).requestUpdateForTopic(topic);
- verify(metadata, times(4)).awaitUpdate(anyInt(), anyLong());
+ verify(metadata, times(4)).awaitUpdate(anyInt(), any(Timer.class));
verify(metadata, times(5)).fetch();
try {
assertInstanceOf(TimeoutException.class,
assertThrows(ExecutionException.class, future::get).getCause());
@@ -917,7 +917,7 @@ public class KafkaProducerTest {
// One request update if metadata is available but outdated for the
given record
producer.send(record);
verify(metadata, times(2)).requestUpdateForTopic(topic);
- verify(metadata, times(2)).awaitUpdate(anyInt(), anyLong());
+ verify(metadata, times(2)).awaitUpdate(anyInt(), any(Timer.class));
verify(metadata, times(3)).fetch();
producer.close(Duration.ofMillis(0));
@@ -955,7 +955,7 @@ public class KafkaProducerTest {
Future<RecordMetadata> future = producer.send(record);
verify(metadata, times(4)).requestUpdateForTopic(topic);
- verify(metadata, times(4)).awaitUpdate(anyInt(), anyLong());
+ verify(metadata, times(4)).awaitUpdate(anyInt(), any(Timer.class));
verify(metadata, times(5)).fetch();
try {
assertInstanceOf(TimeoutException.class,
assertThrows(ExecutionException.class, future::get).getCause());
@@ -968,16 +968,16 @@ public class KafkaProducerTest {
public void testTopicRefreshInMetadata() throws InterruptedException {
Map<String, Object> configs = new HashMap<>();
configs.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9999");
- configs.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, "600000");
+ configs.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, "3000");
// test under normal producer for simplicity
configs.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, false);
- long refreshBackoffMs = 500L;
- long refreshBackoffMaxMs = 5000L;
+ long refreshBackoffMs = 100L;
+ long refreshBackoffMaxMs = 500L;
long metadataExpireMs = 60000L;
long metadataIdleMs = 60000L;
- final Time time = new MockTime();
+ final Time time = Time.SYSTEM;
final ProducerMetadata metadata = new
ProducerMetadata(refreshBackoffMs, refreshBackoffMaxMs, metadataExpireMs,
metadataIdleMs,
- new LogContext(), new ClusterResourceListeners(), time);
+ new LogContext(), new ClusterResourceListeners());
final String topic = "topic";
try (KafkaProducer<String, String> producer = kafkaProducer(configs,
new StringSerializer(), new StringSerializer(), metadata, new
MockClient(time, metadata), null, time)) {
@@ -991,7 +991,6 @@ public class KafkaProducerTest {
MetadataResponse updateResponse =
RequestTestUtils.metadataUpdateWith("kafka-cluster", 1,
singletonMap(topic,
Errors.UNKNOWN_TOPIC_OR_PARTITION), emptyMap());
metadata.updateWithCurrentRequestVersion(updateResponse,
false, time.milliseconds());
- time.sleep(60 * 1000L);
}
});
t.start();
@@ -1003,42 +1002,32 @@ public class KafkaProducerTest {
}
@Test
- public void testTopicNotExistingInMetadata() throws InterruptedException {
+ public void testTopicNotExistingInMetadata() {
Map<String, Object> configs = new HashMap<>();
configs.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9999");
- configs.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, "30000");
- long refreshBackoffMs = 500L;
- long refreshBackoffMaxMs = 5000L;
+ configs.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, "2000");
+ configs.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, "false");
+ long refreshBackoffMs = 50L;
+ long refreshBackoffMaxMs = 500L;
long metadataExpireMs = 60000L;
long metadataIdleMs = 60000L;
- final Time time = new MockTime();
+ final Time time = Time.SYSTEM;
final ProducerMetadata metadata = new
ProducerMetadata(refreshBackoffMs, refreshBackoffMaxMs, metadataExpireMs,
metadataIdleMs,
- new LogContext(), new ClusterResourceListeners(), time);
+ new LogContext(), new ClusterResourceListeners());
final String topic = "topic";
+ MockClient client = new MockClient(time, metadata);
+ // Seed initial metadata, then update with the topic marked as
UNKNOWN_TOPIC_OR_PARTITION
+ client.updateMetadata(RequestTestUtils.metadataUpdateWith(1,
Map.of()));
+ MetadataResponse errorResponse =
RequestTestUtils.metadataUpdateWith("kafka-cluster", 1,
+ singletonMap(topic, Errors.UNKNOWN_TOPIC_OR_PARTITION),
emptyMap());
+ client.prepareMetadataUpdate(errorResponse);
try (KafkaProducer<String, String> producer = kafkaProducer(configs,
new StringSerializer(),
- new StringSerializer(), metadata, new MockClient(time,
metadata), null, time)) {
-
- Exchanger<Void> exchanger = new Exchanger<>();
+ new StringSerializer(), metadata, client, null, time)) {
- Thread t = new Thread(() -> {
- try {
- // Update the metadata with non-existing topic.
- MetadataResponse updateResponse =
RequestTestUtils.metadataUpdateWith("kafka-cluster", 1,
- singletonMap(topic,
Errors.UNKNOWN_TOPIC_OR_PARTITION), emptyMap());
- metadata.updateWithCurrentRequestVersion(updateResponse,
false, time.milliseconds());
- exchanger.exchange(null);
- while (!metadata.updateRequested())
- Thread.sleep(100);
- time.sleep(30 * 1000L);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
- t.start();
- exchanger.exchange(null);
+ // partitionsFor should time out via real wait() because the topic
has an error
+ // and the Sender keeps replaying the same error metadata.
Throwable throwable = assertThrows(TimeoutException.class, () ->
producer.partitionsFor(topic));
assertInstanceOf(UnknownTopicOrPartitionException.class,
throwable.getCause());
- t.join();
}
}
@@ -1046,48 +1035,42 @@ public class KafkaProducerTest {
public void testTopicExpiryInMetadata() throws InterruptedException {
Map<String, Object> configs = new HashMap<>();
configs.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9999");
- configs.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, "30000");
- long refreshBackoffMs = 500L;
- long refreshBackoffMaxMs = 5000L;
- long metadataExpireMs = 60000L;
- long metadataIdleMs = 60000L;
- final Time time = new MockTime();
+ configs.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, "2000");
+ configs.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, "false");
+ long refreshBackoffMs = 50L;
+ long refreshBackoffMaxMs = 500L;
+ long metadataExpireMs = 1000L;
+ long metadataIdleMs = 1000L;
+ final Time time = Time.SYSTEM;
final ProducerMetadata metadata = new
ProducerMetadata(refreshBackoffMs, refreshBackoffMaxMs, metadataExpireMs,
metadataIdleMs,
- new LogContext(), new ClusterResourceListeners(), time);
+ new LogContext(), new ClusterResourceListeners());
final String topic = "topic";
+ MockClient client = new MockClient(time, metadata);
+ // Seed initial metadata without the topic
+ client.updateMetadata(RequestTestUtils.metadataUpdateWith(1,
Map.of()));
+ // Queue a metadata response with the topic for the first
partitionsFor call
+ client.prepareMetadataUpdate(RequestTestUtils.metadataUpdateWith(1,
Map.of(topic, 1)));
+ // Queue a follow-up without the topic so that after consumption,
updateWithCurrentMetadata
+ // replays the empty response
+ client.prepareMetadataUpdate(RequestTestUtils.metadataUpdateWith(1,
Map.of()));
try (KafkaProducer<String, String> producer = kafkaProducer(configs,
new StringSerializer(),
- new StringSerializer(), metadata, new MockClient(time,
metadata), null, time)) {
+ new StringSerializer(), metadata, client, null, time)) {
- Exchanger<Void> exchanger = new Exchanger<>();
+ // First call should succeed — the queued metadata response
includes the topic
+ assertNotNull(producer.partitionsFor(topic));
- Thread t = new Thread(() -> {
- try {
- exchanger.exchange(null); // 1
- while (!metadata.updateRequested())
- Thread.sleep(100);
- MetadataResponse updateResponse =
RequestTestUtils.metadataUpdateWith(1, singletonMap(topic, 1));
- metadata.updateWithCurrentRequestVersion(updateResponse,
false, time.milliseconds());
- exchanger.exchange(null); // 2
- time.sleep(120 * 1000L);
+ // Wait for topic metadata to expire (metadataIdleMs = 1000ms)
+ Thread.sleep(1500);
- // Update the metadata again, but it should be expired at
this point.
- updateResponse = RequestTestUtils.metadataUpdateWith(1,
singletonMap(topic, 1));
- metadata.updateWithCurrentRequestVersion(updateResponse,
false, time.milliseconds());
- exchanger.exchange(null); // 3
- while (!metadata.updateRequested())
- Thread.sleep(100);
- time.sleep(30 * 1000L);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
- t.start();
- exchanger.exchange(null); // 1
- assertNotNull(producer.partitionsFor(topic));
- exchanger.exchange(null); // 2
- exchanger.exchange(null); // 3
+ // Force a metadata update so the Sender consumes the queued empty
response.
+ // This triggers retainTopic() which removes the expired topic
from the snapshot.
+ metadata.requestUpdate(true);
+ // Give the Sender time to process the update
+ Thread.sleep(500);
+
+ // partitionsFor should time out because the topic was expired and
the Sender
+ // now replays empty metadata. The real wait() timeout kicks in
after MAX_BLOCK_MS.
assertThrows(TimeoutException.class, () ->
producer.partitionsFor(topic));
- t.join();
}
}
@@ -2593,7 +2576,7 @@ public class KafkaProducerTest {
Time time = Time.SYSTEM;
MetadataResponse initialUpdateResponse =
RequestTestUtils.metadataUpdateWith(1, emptyMap());
ProducerMetadata metadata = new ProducerMetadata(0, 0, Long.MAX_VALUE,
Long.MAX_VALUE,
- new LogContext(), new ClusterResourceListeners(), time);
+ new LogContext(), new ClusterResourceListeners());
metadata.updateWithCurrentRequestVersion(initialUpdateResponse, false,
time.milliseconds());
MockClient client = new MockClient(time, metadata);
@@ -2749,7 +2732,7 @@ public class KafkaProducerTest {
private static ProducerMetadata newMetadata(long refreshBackoffMs, long
refreshBackoffMaxMs, long expirationMs) {
return new ProducerMetadata(refreshBackoffMs, refreshBackoffMaxMs,
expirationMs, DEFAULT_METADATA_IDLE_MS,
- new LogContext(), new ClusterResourceListeners(), Time.SYSTEM);
+ new LogContext(), new ClusterResourceListeners());
}
@Test
@@ -2800,8 +2783,7 @@ public class KafkaProducerTest {
configs.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG,
MockProducerInterceptor.class.getName());
configs.put(MockProducerInterceptor.APPEND_STRING_PROP, "something");
-
- Time time = new MockTime();
+ Time time = Time.SYSTEM;
ProducerMetadata producerMetadata = newMetadata(0, 0, Long.MAX_VALUE);
MockClient client = new MockClient(time, producerMetadata);
diff --git
a/clients/src/test/java/org/apache/kafka/clients/producer/internals/ProducerMetadataTest.java
b/clients/src/test/java/org/apache/kafka/clients/producer/internals/ProducerMetadataTest.java
index 01b202e29c8..559ab4d12d5 100644
---
a/clients/src/test/java/org/apache/kafka/clients/producer/internals/ProducerMetadataTest.java
+++
b/clients/src/test/java/org/apache/kafka/clients/producer/internals/ProducerMetadataTest.java
@@ -48,7 +48,7 @@ public class ProducerMetadataTest {
private final long refreshBackoffMaxMs = 1000;
private final long metadataExpireMs = 1000;
private final ProducerMetadata metadata = new
ProducerMetadata(refreshBackoffMs, refreshBackoffMaxMs, metadataExpireMs,
METADATA_IDLE_MS,
- new LogContext(), new ClusterResourceListeners(), Time.SYSTEM);
+ new LogContext(), new ClusterResourceListeners());
private final AtomicReference<Exception> backgroundError = new
AtomicReference<>();
@AfterEach
@@ -131,7 +131,7 @@ public class ProducerMetadataTest {
}
/**
- * Tests that {@link
org.apache.kafka.clients.producer.internals.ProducerMetadata#awaitUpdate(int,
long)} doesn't
+ * Tests that {@link
org.apache.kafka.clients.producer.internals.ProducerMetadata#awaitUpdate(int,
org.apache.kafka.common.utils.Timer)} doesn't
* wait forever with a max timeout value of 0
*
* @throws Exception
@@ -144,7 +144,7 @@ public class ProducerMetadataTest {
assertTrue(metadata.timeToNextUpdate(time) > 0, "No update needed.");
// first try with a max wait time of 0 and ensure that this returns
back without waiting forever
try {
- metadata.awaitUpdate(metadata.requestUpdate(true), 0);
+ metadata.awaitUpdate(metadata.requestUpdate(true),
Time.SYSTEM.timer(0));
fail("Wait on metadata update was expected to timeout, but it
didn't");
} catch (TimeoutException te) {
// expected
@@ -152,7 +152,7 @@ public class ProducerMetadataTest {
// now try with a higher timeout value once
final long twoSecondWait = 2000;
try {
- metadata.awaitUpdate(metadata.requestUpdate(true), twoSecondWait);
+ metadata.awaitUpdate(metadata.requestUpdate(true),
Time.SYSTEM.timer(twoSecondWait));
fail("Wait on metadata update was expected to timeout, but it
didn't");
} catch (TimeoutException te) {
// expected
@@ -215,7 +215,7 @@ public class ProducerMetadataTest {
@Test
public void testMetadataWaitAbortedOnFatalException() {
metadata.fatalError(new AuthenticationException("Fatal exception from
test"));
- assertThrows(AuthenticationException.class, () ->
metadata.awaitUpdate(0, 1000));
+ assertThrows(AuthenticationException.class, () ->
metadata.awaitUpdate(0, Time.SYSTEM.timer(1000)));
}
@Test
@@ -351,7 +351,7 @@ public class ProducerMetadataTest {
Thread thread = new Thread(() -> {
try {
while (metadata.fetch().partitionsForTopic(topic).isEmpty())
- metadata.awaitUpdate(metadata.requestUpdate(false),
maxWaitMs);
+ metadata.awaitUpdate(metadata.requestUpdate(false),
Time.SYSTEM.timer(maxWaitMs));
} catch (Exception e) {
backgroundError.set(e);
}
diff --git
a/clients/src/test/java/org/apache/kafka/clients/producer/internals/SenderTest.java
b/clients/src/test/java/org/apache/kafka/clients/producer/internals/SenderTest.java
index 3464f6e4ef0..61dcab8ef07 100644
---
a/clients/src/test/java/org/apache/kafka/clients/producer/internals/SenderTest.java
+++
b/clients/src/test/java/org/apache/kafka/clients/producer/internals/SenderTest.java
@@ -171,7 +171,7 @@ public class SenderTest {
private MockTime time = new MockTime();
private final int batchSize = 16 * 1024;
private final ProducerMetadata metadata = new ProducerMetadata(0, 0,
Long.MAX_VALUE, TOPIC_IDLE_MS,
- new LogContext(), new ClusterResourceListeners(), time);
+ new LogContext(), new ClusterResourceListeners());
private final ApiVersions apiVersions = new ApiVersions();
private MockClient client = new MockClient(time, metadata);
private Metrics metrics = null;
diff --git
a/clients/src/test/java/org/apache/kafka/clients/producer/internals/TransactionManagerTest.java
b/clients/src/test/java/org/apache/kafka/clients/producer/internals/TransactionManagerTest.java
index 849c31fff3f..97fe1913fa8 100644
---
a/clients/src/test/java/org/apache/kafka/clients/producer/internals/TransactionManagerTest.java
+++
b/clients/src/test/java/org/apache/kafka/clients/producer/internals/TransactionManagerTest.java
@@ -154,7 +154,7 @@ public class TransactionManagerTest {
private final LogContext logContext = new LogContext();
private final MockTime time = new MockTime();
private final ProducerMetadata metadata = new ProducerMetadata(0, 0,
Long.MAX_VALUE, Long.MAX_VALUE,
- logContext, new ClusterResourceListeners(), time);
+ logContext, new ClusterResourceListeners());
private final MockClient client = new MockClient(time, metadata);
private final ApiVersions apiVersions = new ApiVersions();
diff --git
a/clients/src/test/java/org/apache/kafka/common/utils/MockTimeTest.java
b/clients/src/test/java/org/apache/kafka/common/utils/MockTimeTest.java
index 88a18fe897c..784b2cadc1b 100644
--- a/clients/src/test/java/org/apache/kafka/common/utils/MockTimeTest.java
+++ b/clients/src/test/java/org/apache/kafka/common/utils/MockTimeTest.java
@@ -22,7 +22,7 @@ import org.junit.jupiter.api.Timeout;
import static org.junit.jupiter.api.Assertions.assertEquals;
@Timeout(120)
-public class MockTimeTest extends TimeTest {
+public class MockTimeTest {
@Test
public void testAdvanceClock() {
@@ -42,9 +42,4 @@ public class MockTimeTest extends TimeTest {
assertEquals(103, time.milliseconds());
assertEquals(104, time.milliseconds());
}
-
- @Override
- protected Time createTime() {
- return new MockTime();
- }
}
diff --git
a/clients/src/test/java/org/apache/kafka/common/utils/SystemTimeTest.java
b/clients/src/test/java/org/apache/kafka/common/utils/SystemTimeTest.java
deleted file mode 100644
index edc53d2293e..00000000000
--- a/clients/src/test/java/org/apache/kafka/common/utils/SystemTimeTest.java
+++ /dev/null
@@ -1,25 +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.kafka.common.utils;
-
-public class SystemTimeTest extends TimeTest {
-
- @Override
- protected Time createTime() {
- return Time.SYSTEM;
- }
-}
diff --git a/clients/src/test/java/org/apache/kafka/common/utils/TimeTest.java
b/clients/src/test/java/org/apache/kafka/common/utils/TimeTest.java
index 1ca630f81cd..e9d62cc3c5a 100644
--- a/clients/src/test/java/org/apache/kafka/common/utils/TimeTest.java
+++ b/clients/src/test/java/org/apache/kafka/common/utils/TimeTest.java
@@ -19,6 +19,7 @@ package org.apache.kafka.common.utils;
import org.apache.kafka.common.errors.TimeoutException;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -27,16 +28,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
-public abstract class TimeTest {
+@Timeout(120)
+public class TimeTest {
- protected abstract Time createTime();
+ private final Time time = Time.SYSTEM;
@Test
public void testWaitObjectTimeout() throws InterruptedException {
Object obj = new Object();
- Time time = createTime();
- long timeoutMs = 100;
- long deadlineMs = time.milliseconds() + timeoutMs;
+ long deadlineMs = time.milliseconds() + 100;
AtomicReference<Exception> caughtException = new AtomicReference<>();
Thread t = new Thread(() -> {
try {
@@ -47,7 +47,6 @@ public abstract class TimeTest {
});
t.start();
- time.sleep(timeoutMs);
t.join();
assertEquals(TimeoutException.class, caughtException.get().getClass());
@@ -56,9 +55,7 @@ public abstract class TimeTest {
@Test
public void testWaitObjectConditionSatisfied() throws InterruptedException
{
Object obj = new Object();
- Time time = createTime();
- long timeoutMs = 1000000000;
- long deadlineMs = time.milliseconds() + timeoutMs;
+ long deadlineMs = time.milliseconds() + 1000000000;
AtomicBoolean condition = new AtomicBoolean(false);
AtomicReference<Exception> caughtException = new AtomicReference<>();
Thread t = new Thread(() -> {
diff --git
a/clients/src/testFixtures/java/org/apache/kafka/common/utils/MockTime.java
b/clients/src/testFixtures/java/org/apache/kafka/common/utils/MockTime.java
index ccf3eec196e..5bb6505947c 100644
--- a/clients/src/testFixtures/java/org/apache/kafka/common/utils/MockTime.java
+++ b/clients/src/testFixtures/java/org/apache/kafka/common/utils/MockTime.java
@@ -16,12 +16,9 @@
*/
package org.apache.kafka.common.utils;
-import org.apache.kafka.common.errors.TimeoutException;
-
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.Supplier;
/**
* A clock that you can manually advance by calling sleep
@@ -86,27 +83,6 @@ public class MockTime implements Time {
tick();
}
- @Override
- public void waitObject(Object obj, Supplier<Boolean> condition, long
deadlineMs) throws InterruptedException {
- Listener listener = () -> {
- synchronized (obj) {
- obj.notify();
- }
- };
- listeners.add(listener);
- try {
- synchronized (obj) {
- while (milliseconds() < deadlineMs && !condition.get()) {
- obj.wait();
- }
- if (!condition.get())
- throw new TimeoutException("Condition not satisfied before
deadline");
- }
- } finally {
- listeners.remove(listener);
- }
- }
-
public void setCurrentTimeMs(long newMs) {
long oldMs = timeMs.getAndSet(newMs);
diff --git
a/streams/test-utils/src/main/java/org/apache/kafka/streams/TopologyTestDriver.java
b/streams/test-utils/src/main/java/org/apache/kafka/streams/TopologyTestDriver.java
index 54020c50de9..f491c03fb86 100644
---
a/streams/test-utils/src/main/java/org/apache/kafka/streams/TopologyTestDriver.java
+++
b/streams/test-utils/src/main/java/org/apache/kafka/streams/TopologyTestDriver.java
@@ -125,7 +125,6 @@ import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.Supplier;
import java.util.regex.Pattern;
import static
org.apache.kafka.streams.internals.StreamsConfigUtils.ProcessingMode.EXACTLY_ONCE_V2;
@@ -1361,11 +1360,6 @@ public class TopologyTestDriver implements Closeable {
timeMs.addAndGet(ms);
highResTimeNs.addAndGet(TimeUnit.MILLISECONDS.toNanos(ms));
}
-
- @Override
- public void waitObject(final Object obj, final Supplier<Boolean>
condition, final long timeoutMs) {
- throw new UnsupportedOperationException();
- }
}
static class KeyValueStoreFacade<K, V> extends
GenericReadOnlyKeyValueStoreFacade<K, ValueAndTimestamp<V>, V> implements
KeyValueStore<K, V> {