-
Notifications
You must be signed in to change notification settings - Fork 14.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KAFKA-17100: GlobalStreamThread#start should not busy-wait #16914
Changes from 2 commits
758a1b4
49930b3
143a185
7a9a300
5d45fdd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -29,7 +29,6 @@ | |||||
import org.apache.kafka.common.internals.KafkaFutureImpl; | ||||||
import org.apache.kafka.common.utils.LogContext; | ||||||
import org.apache.kafka.common.utils.Time; | ||||||
import org.apache.kafka.common.utils.Utils; | ||||||
import org.apache.kafka.streams.StreamsConfig; | ||||||
import org.apache.kafka.streams.errors.StreamsException; | ||||||
import org.apache.kafka.streams.processor.StateRestoreListener; | ||||||
|
@@ -45,9 +44,9 @@ | |||||
import java.util.HashSet; | ||||||
import java.util.Map; | ||||||
import java.util.Set; | ||||||
import java.util.concurrent.CountDownLatch; | ||||||
import java.util.concurrent.atomic.AtomicLong; | ||||||
|
||||||
import static org.apache.kafka.streams.processor.internals.GlobalStreamThread.State.CREATED; | ||||||
import static org.apache.kafka.streams.processor.internals.GlobalStreamThread.State.DEAD; | ||||||
import static org.apache.kafka.streams.processor.internals.GlobalStreamThread.State.PENDING_SHUTDOWN; | ||||||
import static org.apache.kafka.streams.processor.internals.GlobalStreamThread.State.RUNNING; | ||||||
|
@@ -72,6 +71,7 @@ public class GlobalStreamThread extends Thread { | |||||
private java.util.function.Consumer<Throwable> streamsUncaughtExceptionHandler; | ||||||
private volatile long fetchDeadlineClientInstanceId = -1; | ||||||
private volatile KafkaFutureImpl<Uuid> clientInstanceIdFuture = new KafkaFutureImpl<>(); | ||||||
private final CountDownLatch initializationLatch = new CountDownLatch(1); | ||||||
|
||||||
/** | ||||||
* The states that the global stream thread can be in | ||||||
|
@@ -175,6 +175,12 @@ private void setState(final State newState) { | |||||
} | ||||||
|
||||||
state = newState; | ||||||
|
||||||
// Question: Is this a good idea? Or should we spread the latch countdown to finally blocks | ||||||
// Count down the latch if transitioning from CREATED to any other state | ||||||
if (oldState == State.CREATED && newState != State.CREATED) { | ||||||
initializationLatch.countDown(); | ||||||
} | ||||||
} | ||||||
|
||||||
if (stateListener != null) { | ||||||
|
@@ -194,12 +200,6 @@ public boolean inErrorState() { | |||||
} | ||||||
} | ||||||
|
||||||
public boolean stillInitializing() { | ||||||
synchronized (stateLock) { | ||||||
return state.equals(CREATED); | ||||||
} | ||||||
} | ||||||
|
||||||
public GlobalStreamThread(final ProcessorTopology topology, | ||||||
final StreamsConfig config, | ||||||
final Consumer<byte[], byte[]> globalConsumer, | ||||||
|
@@ -453,11 +453,15 @@ private void closeStateConsumer(final StateConsumer stateConsumer, final boolean | |||||
@Override | ||||||
public synchronized void start() { | ||||||
super.start(); | ||||||
while (stillInitializing()) { | ||||||
Utils.sleep(1); | ||||||
if (startupException != null) { | ||||||
throw startupException; | ||||||
} | ||||||
try { | ||||||
initializationLatch.await(); | ||||||
} catch (final InterruptedException e) { | ||||||
currentThread().interrupt(); | ||||||
throw new IllegalStateException("Thread was interrupted during initialization", e); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a "new" exception, as the previous code would have just spun calling Utils.sleep and continuously throwing InterruptedExceptions. It's more informative than the other IllegalStateException thrown here, so this seems reasonable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
|
||||||
if (startupException != null) { | ||||||
throw startupException; | ||||||
} | ||||||
|
||||||
if (inErrorState()) { | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gharris1727 This works (all the tests pass), but I want to double-check it with you. The other alternative would be to count down in
finally
blocks across the class.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could make sense to have a finally block in the
initialize
method and callcountDown
inshutdown
, but the current implementation appears to have reasonable semantics.I have a weak feeling that counting down this latch is too much for the setState method to be doing, but at the same time pushing the latch management out into the calling code risks missing a (possibly future) call-site which transitions away from CREATED.
I think i would leave this to see what the Streams folks think about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @gharris1727 -- this is not the right place for this code. I am not 100% sure right now what the best place would be, but both
run()
orinitialize()
look like good candidates (maybeinitialize()
is better).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved the
countDown
logic to thefinally
block ofinitialize
. It sounds reasonable to me.