use of org.apache.pulsar.broker.service.Consumer in project incubator-pulsar by apache.
the class CompactorSubscription method acknowledgeMessage.
@Override
public void acknowledgeMessage(PositionImpl position, AckType ackType, Map<String, Long> properties) {
checkArgument(ackType == AckType.Cumulative);
checkArgument(properties.containsKey(Compactor.COMPACTED_TOPIC_LEDGER_PROPERTY));
long compactedLedgerId = properties.get(Compactor.COMPACTED_TOPIC_LEDGER_PROPERTY);
if (log.isDebugEnabled()) {
log.debug("[{}][{}] Cumulative ack on compactor subscription {}", topicName, subName, position);
}
CompletableFuture<Void> future = new CompletableFuture<>();
cursor.asyncMarkDelete(position, properties, new MarkDeleteCallback() {
@Override
public void markDeleteComplete(Object ctx) {
if (log.isDebugEnabled()) {
log.debug("[{}][{}] Mark deleted messages until position on compactor subscription {}", topicName, subName, position);
}
future.complete(null);
}
@Override
public void markDeleteFailed(ManagedLedgerException exception, Object ctx) {
// TODO: cut consumer connection on markDeleteFailed
if (log.isDebugEnabled()) {
log.debug("[{}][{}] Failed to mark delete for position on compactor subscription {}", topicName, subName, ctx, exception);
}
}
}, null);
if (topic.getManagedLedger().isTerminated() && cursor.getNumberOfEntriesInBacklog() == 0) {
// Notify all consumer that the end of topic was reached
dispatcher.getConsumers().forEach(Consumer::reachedEndOfTopic);
}
// Once properties have been persisted, we can notify the compacted topic to use
// the new ledger
future.thenAccept((v) -> compactedTopic.newCompactedLedger(position, compactedLedgerId));
}
use of org.apache.pulsar.broker.service.Consumer in project incubator-pulsar by apache.
the class PersistentDispatcherMultipleConsumers method readEntriesComplete.
@Override
public synchronized void readEntriesComplete(List<Entry> entries, Object ctx) {
ReadType readType = (ReadType) ctx;
int start = 0;
int entriesToDispatch = entries.size();
if (readType == ReadType.Normal) {
havePendingRead = false;
} else {
havePendingReplayRead = false;
}
if (readBatchSize < MaxReadBatchSize) {
int newReadBatchSize = Math.min(readBatchSize * 2, MaxReadBatchSize);
if (log.isDebugEnabled()) {
log.debug("[{}] Increasing read batch size from {} to {}", name, readBatchSize, newReadBatchSize);
}
readBatchSize = newReadBatchSize;
}
readFailureBackoff.reduceToHalf();
if (shouldRewindBeforeReadingOrReplaying && readType == ReadType.Normal) {
// All consumers got disconnected before the completion of the read operation
entries.forEach(Entry::release);
cursor.rewind();
shouldRewindBeforeReadingOrReplaying = false;
readMoreEntries();
return;
}
if (log.isDebugEnabled()) {
log.debug("[{}] Distributing {} messages to {} consumers", name, entries.size(), consumerList.size());
}
long totalMessagesSent = 0;
long totalBytesSent = 0;
while (entriesToDispatch > 0 && totalAvailablePermits > 0 && isAtleastOneConsumerAvailable()) {
Consumer c = getNextConsumer();
if (c == null) {
// Do nothing, cursor will be rewind at reconnection
log.info("[{}] rewind because no available consumer found from total {}", name, consumerList.size());
entries.subList(start, entries.size()).forEach(Entry::release);
cursor.rewind();
return;
}
// round-robin dispatch batch size for this consumer
int messagesForC = Math.min(Math.min(entriesToDispatch, c.getAvailablePermits()), MaxRoundRobinBatchSize);
if (messagesForC > 0) {
// remove positions first from replay list first : sendMessages recycles entries
if (readType == ReadType.Replay) {
entries.subList(start, start + messagesForC).forEach(entry -> {
messagesToReplay.remove(entry.getLedgerId(), entry.getEntryId());
});
}
SendMessageInfo sentMsgInfo = c.sendMessages(entries.subList(start, start + messagesForC));
long msgSent = sentMsgInfo.getTotalSentMessages();
start += messagesForC;
entriesToDispatch -= messagesForC;
totalAvailablePermits -= msgSent;
totalMessagesSent += sentMsgInfo.getTotalSentMessages();
totalBytesSent += sentMsgInfo.getTotalSentMessageBytes();
}
}
// acquire message-dispatch permits for already delivered messages
if (serviceConfig.isDispatchThrottlingOnNonBacklogConsumerEnabled() || !cursor.isActive()) {
topic.getDispatchRateLimiter().tryDispatchPermit(totalMessagesSent, totalBytesSent);
}
if (entriesToDispatch > 0) {
if (log.isDebugEnabled()) {
log.debug("[{}] No consumers found with available permits, storing {} positions for later replay", name, entries.size() - start);
}
entries.subList(start, entries.size()).forEach(entry -> {
messagesToReplay.add(entry.getLedgerId(), entry.getEntryId());
entry.release();
});
}
readMoreEntries();
}
use of org.apache.pulsar.broker.service.Consumer in project incubator-pulsar by apache.
the class PersistentDispatcherSingleActiveConsumer method readMoreEntries.
@Override
protected void readMoreEntries(Consumer consumer) {
// so skip reading more entries if currently there is no active consumer.
if (null == consumer) {
return;
}
int availablePermits = consumer.getAvailablePermits();
if (availablePermits > 0) {
if (!consumer.isWritable()) {
// If the connection is not currently writable, we issue the read request anyway, but for a single
// message. The intent here is to keep use the request as a notification mechanism while avoiding to
// read and dispatch a big batch of messages which will need to wait before getting written to the
// socket.
availablePermits = 1;
}
int messagesToRead = Math.min(availablePermits, readBatchSize);
// threshold: then schedule the read after MESSAGE_RATE_BACKOFF_MS
if (serviceConfig.isDispatchThrottlingOnNonBacklogConsumerEnabled() || !cursor.isActive()) {
DispatchRateLimiter rateLimiter = topic.getDispatchRateLimiter();
if (rateLimiter.isDispatchRateLimitingEnabled()) {
if (!rateLimiter.hasMessageDispatchPermit()) {
if (log.isDebugEnabled()) {
log.debug("[{}] message-read exceeded message-rate {}/{}, schedule after a {}", name, rateLimiter.getDispatchRateOnMsg(), rateLimiter.getDispatchRateOnByte(), MESSAGE_RATE_BACKOFF_MS);
}
topic.getBrokerService().executor().schedule(() -> {
Consumer currentConsumer = ACTIVE_CONSUMER_UPDATER.get(this);
if (currentConsumer != null && !havePendingRead) {
readMoreEntries(currentConsumer);
} else {
if (log.isDebugEnabled()) {
log.info("[{}] Skipping read retry: Current Consumer {}, havePendingRead {}", topic.getName(), currentConsumer, havePendingRead);
}
}
}, MESSAGE_RATE_BACKOFF_MS, TimeUnit.MILLISECONDS);
return;
} else {
// if dispatch-rate is in msg then read only msg according to available permit
long availablePermitsOnMsg = rateLimiter.getAvailableDispatchRateLimitOnMsg();
if (availablePermitsOnMsg > 0) {
messagesToRead = Math.min(messagesToRead, (int) availablePermitsOnMsg);
}
}
}
}
// Schedule read
if (log.isDebugEnabled()) {
log.debug("[{}-{}] Schedule read of {} messages", name, consumer, messagesToRead);
}
havePendingRead = true;
if (consumer.readCompacted()) {
topic.compactedTopic.asyncReadEntriesOrWait(cursor, messagesToRead, this, consumer);
} else {
cursor.asyncReadEntriesOrWait(messagesToRead, this, consumer);
}
} else {
if (log.isDebugEnabled()) {
log.debug("[{}-{}] Consumer buffer is full, pause reading", name, consumer);
}
}
}
use of org.apache.pulsar.broker.service.Consumer in project incubator-pulsar by apache.
the class PersistentDispatcherSingleActiveConsumer method readEntriesComplete.
@Override
public synchronized void readEntriesComplete(final List<Entry> entries, Object obj) {
Consumer readConsumer = (Consumer) obj;
if (log.isDebugEnabled()) {
log.debug("[{}-{}] Got messages: {}", name, readConsumer, entries.size());
}
havePendingRead = false;
if (readBatchSize < MaxReadBatchSize) {
int newReadBatchSize = Math.min(readBatchSize * 2, MaxReadBatchSize);
if (log.isDebugEnabled()) {
log.debug("[{}-{}] Increasing read batch size from {} to {}", name, readConsumer, readBatchSize, newReadBatchSize);
}
readBatchSize = newReadBatchSize;
}
readFailureBackoff.reduceToHalf();
Consumer currentConsumer = ACTIVE_CONSUMER_UPDATER.get(this);
if (currentConsumer == null || readConsumer != currentConsumer) {
// re-issue the read request for the new consumer
if (log.isDebugEnabled()) {
log.debug("[{}] rewind because no available consumer found", name);
}
entries.forEach(Entry::release);
cursor.rewind();
if (currentConsumer != null) {
readMoreEntries(currentConsumer);
}
} else {
SendMessageInfo sentMsgInfo = currentConsumer.sendMessages(entries);
final long totalMessagesSent = sentMsgInfo.getTotalSentMessages();
final long totalBytesSent = sentMsgInfo.getTotalSentMessageBytes();
sentMsgInfo.getChannelPromse().addListener(future -> {
if (future.isSuccess()) {
// acquire message-dispatch permits for already delivered messages
if (serviceConfig.isDispatchThrottlingOnNonBacklogConsumerEnabled() || !cursor.isActive()) {
topic.getDispatchRateLimiter().tryDispatchPermit(totalMessagesSent, totalBytesSent);
}
// Schedule a new read batch operation only after the previous batch has been written to the socket
synchronized (PersistentDispatcherSingleActiveConsumer.this) {
Consumer newConsumer = ACTIVE_CONSUMER_UPDATER.get(this);
if (newConsumer != null && !havePendingRead) {
readMoreEntries(newConsumer);
} else {
if (log.isDebugEnabled()) {
log.debug("[{}-{}] Ignoring write future complete. consumerAvailable={} havePendingRead={}", name, newConsumer, newConsumer != null, havePendingRead);
}
}
}
}
});
}
}
use of org.apache.pulsar.broker.service.Consumer in project incubator-pulsar by apache.
the class PersistentDispatcherSingleActiveConsumer method readEntriesFailed.
@Override
public synchronized void readEntriesFailed(ManagedLedgerException exception, Object ctx) {
havePendingRead = false;
Consumer c = (Consumer) ctx;
long waitTimeMillis = readFailureBackoff.next();
if (exception instanceof NoMoreEntriesToReadException) {
if (cursor.getNumberOfEntriesInBacklog() == 0) {
// Topic has been terminated and there are no more entries to read
// Notify the consumer only if all the messages were already acknowledged
consumers.forEach(Consumer::reachedEndOfTopic);
}
} else if (!(exception instanceof TooManyRequestsException)) {
log.error("[{}-{}] Error reading entries at {} : {} - Retrying to read in {} seconds", name, c, cursor.getReadPosition(), exception.getMessage(), waitTimeMillis / 1000.0);
} else {
if (log.isDebugEnabled()) {
log.debug("[{}-{}] Got throttled by bookies while reading at {} : {} - Retrying to read in {} seconds", name, c, cursor.getReadPosition(), exception.getMessage(), waitTimeMillis / 1000.0);
}
}
checkNotNull(c);
// Reduce read batch size to avoid flooding bookies with retries
readBatchSize = 1;
topic.getBrokerService().executor().schedule(() -> {
synchronized (PersistentDispatcherSingleActiveConsumer.this) {
Consumer currentConsumer = ACTIVE_CONSUMER_UPDATER.get(this);
// we should retry the read if we have an active consumer and there is no pending read
if (currentConsumer != null && !havePendingRead) {
if (log.isDebugEnabled()) {
log.debug("[{}-{}] Retrying read operation", name, c);
}
readMoreEntries(currentConsumer);
} else {
log.info("[{}-{}] Skipping read retry: Current Consumer {}, havePendingRead {}", name, c, currentConsumer, havePendingRead);
}
}
}, waitTimeMillis, TimeUnit.MILLISECONDS);
}
Aggregations