-
Notifications
You must be signed in to change notification settings - Fork 138
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
Flushless producer supporting both comparable and non comparable offsets #873
Changes from 1 commit
3a468e6
bf64205
33eebc2
1644f0c
062ba47
1ae2525
ade37ff
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 |
---|---|---|
|
@@ -5,11 +5,11 @@ | |
*/ | ||
package com.linkedin.datastream.server.callbackstatus; | ||
|
||
import java.util.ArrayDeque; | ||
import java.util.Collections; | ||
import java.util.Deque; | ||
import java.util.HashSet; | ||
import java.util.LinkedHashSet; | ||
import java.util.LinkedList; | ||
import java.util.Set; | ||
|
||
import org.slf4j.Logger; | ||
|
@@ -25,56 +25,71 @@ public class CallbackStatusWithNonComparableOffsets<T> extends CallbackStatus<T> | |
|
||
private static final Logger LOG = LoggerFactory.getLogger(CallbackStatusWithNonComparableOffsets.class); | ||
|
||
// the last checkpoint-ed record's offset | ||
protected T _currentCheckpoint = null; | ||
|
||
// Hashset storing all the records which are yet to be acked | ||
private final Set<T> _inFlight = Collections.synchronizedSet(new LinkedHashSet<>()); | ||
|
||
// Deque to store all the messages which are inflight until the last consumer checkpoint is made | ||
private final Deque<T> _inFlightUntilLastConsumerCheckpoint = new ArrayDeque<>(); | ||
// Deque to store all the messages which are inflight after the last consumer checkpoint is made | ||
private final Deque<T> _inFlightAfterLastConsumerCheckpoint = new LinkedList<>(); | ||
|
||
// Hashset storing all the records for which the ack is received | ||
private final Set<T> _acked = Collections.synchronizedSet(new HashSet<>()); | ||
|
||
// the last checkpoint-ed record's offset | ||
protected T _currentCheckpoint = null; | ||
|
||
/** | ||
* Get the latest checkpoint to be acked | ||
* @return <T> Type of the comparable checkpoint object internally used by the connector. | ||
*/ | ||
@Override | ||
public T getAckCheckpoint() { | ||
shrinandthakkar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return _currentCheckpoint; | ||
} | ||
|
||
/** | ||
* Get the count of the records which are in flight | ||
*/ | ||
@Override | ||
public long getInFlightCount() { | ||
return _inFlight.size(); | ||
} | ||
|
||
/** | ||
* Get all the messages which are in flight until the last checkpoint at consumer | ||
* Get the count of the records which are all acked from the producer | ||
*/ | ||
public long getinFlightUntilLastConsumerCheckpointCount() { | ||
return _inFlight.size(); | ||
} | ||
|
||
@Override | ||
public long getAckMessagesPastCheckpointCount() { | ||
return _acked.size(); | ||
} | ||
|
||
/** | ||
* Registers the given checkpoint by adding it to the deque of in-flight checkpoints. | ||
* @param checkpoint the checkpoint to register | ||
* @param checkpoint is the latest record acked by the producer of the underlying pub sub framework | ||
*/ | ||
@Override | ||
public synchronized void register(T checkpoint) { | ||
_inFlight.add(checkpoint); | ||
_inFlightUntilLastConsumerCheckpoint.offerLast(checkpoint); | ||
_inFlightAfterLastConsumerCheckpoint.offerLast(checkpoint); | ||
} | ||
|
||
/** | ||
* The checkpoint acknowledgement can be received out of order. So here, we track the checkpoints by adding | ||
* them in the _acked set and only update the _currentCheckpoint if a contiguous sequence of offsets are ack-ed | ||
* from the front of the queue. | ||
*/ | ||
@Override | ||
public synchronized void ack(T checkpoint) { | ||
// adding the checkpoint in the _acked set | ||
_acked.add(checkpoint); | ||
|
||
// removing the checkpoint from the _inFlight set as we got acknowledgement for this checkpoint from producer | ||
_inFlight.remove(checkpoint); | ||
while (!_inFlightUntilLastConsumerCheckpoint.isEmpty() && !_acked.isEmpty() && _acked.contains(_inFlightUntilLastConsumerCheckpoint.peekFirst())) { | ||
_currentCheckpoint = _inFlightUntilLastConsumerCheckpoint.pollFirst(); | ||
|
||
// Until a contiguous sequence of offsets are not ack-ed from the producer for all the consumed records, we can't | ||
// commit new checkpoint to consumer. This loops checks for that contiguous acked offsets. | ||
while (!_inFlightAfterLastConsumerCheckpoint.isEmpty() && !_acked.isEmpty() && _acked.contains( | ||
_inFlightAfterLastConsumerCheckpoint.peekFirst())) { | ||
_currentCheckpoint = _inFlightAfterLastConsumerCheckpoint.pollFirst(); | ||
|
||
if (!_acked.remove(_currentCheckpoint)) { | ||
LOG.error("Internal state error; could not remove checkpoint {}", _currentCheckpoint); | ||
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. Just curious: How will currentCheckpoints will look in case of non-comparable offsets? How will we debug the issues, i.e. stuck partitions? Offset numbers were easy to compare. 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. The checkpoints in non-comparable scenarios could be of byte type. |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,11 +6,16 @@ | |
package com.linkedin.datastream.server.callbackstatus; | ||
|
||
/** | ||
* Interface for CallbackStatus Factories | ||
* Factory implementation for Callback Status With Non Comparable Offsets | ||
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. nit: lower case for |
||
* @param <T> The type of the offset position that the underlying pub-sub system uses. | ||
*/ | ||
public class CallbackStatusWithNonComparableOffsetsFactory<T extends Comparable<T>> implements CallbackStatusFactory<T> { | ||
|
||
/** | ||
* Creates a callback status strategy that checkpoints the consumer offset on successful produce of that record | ||
* with non comparable offsets | ||
* @return CallbackStatus strategy construct | ||
*/ | ||
@Override | ||
public CallbackStatus<T> createCallbackStatusStrategy() { | ||
return new CallbackStatusWithNonComparableOffsets<T>(); | ||
|
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.
You can add verification as well here and save the object rather then saving the name and putting the onus on the caller to verify and throw exception.