Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a4e199f
Support configuring chunkingEnabled
BewareMyPower Dec 16, 2021
dfd069b
Add limitations when chunking is enabled
BewareMyPower Dec 16, 2021
97b7234
[WIP] serializeAndSendMessage
BewareMyPower Dec 20, 2021
69a911b
Pass TopicName instead of string to ProducerImpl's constructor
BewareMyPower Dec 21, 2021
4dcec9e
Send messages by chunks
BewareMyPower Dec 22, 2021
22b3453
Check whether the callback should be triggered in sendMessage
BewareMyPower Dec 22, 2021
644becb
Combine callback and releaseSemaphore
BewareMyPower Dec 23, 2021
4f2cd08
Wrap the send callback with stats update
BewareMyPower Dec 23, 2021
b97a896
Fix incorrect isValidProducerState
BewareMyPower Dec 23, 2021
82679fb
Fix checksum error when chunks are sent
BewareMyPower Dec 25, 2021
8386ee3
Add chunked configs from consumer
BewareMyPower Dec 30, 2021
74b6b6d
Support consuming chunks
BewareMyPower Dec 30, 2021
0b26aa7
Fix incorrect concanated payload size
BewareMyPower Dec 31, 2021
db5c2be
Add tests for chunking messages
BewareMyPower Jan 4, 2022
715c1f7
Fixed tests failure when compression is enabled
BewareMyPower Jan 4, 2022
007f542
Improve logs
BewareMyPower Jan 5, 2022
e654b6c
Refactor chunking related fields and fix memory error
BewareMyPower Jan 5, 2022
47b12b1
Fix comments
BewareMyPower Jan 5, 2022
c56fd2b
Add MapCache class
BewareMyPower Jan 5, 2022
ba92b2a
Use MapCache to refactor ConsumerImpl
BewareMyPower Jan 5, 2022
11a13a8
Verify the chunk cache is cleared
BewareMyPower Jan 5, 2022
58c144d
Fix chunked cache
BewareMyPower Jan 5, 2022
e893300
Fix CentOS 7 build
BewareMyPower Jan 5, 2022
1d91fb0
Fix Ubuntu 16.04 build failure
BewareMyPower Jan 5, 2022
def6a4d
Fix incompatibility with GTest 1.8.0
BewareMyPower Jan 5, 2022
acaef75
Fix tests
BewareMyPower Jan 6, 2022
5716961
Fix GCC 5.4 segmentation fault
BewareMyPower Jan 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions pulsar-client-cpp/include/pulsar/ConsumerConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,52 @@ class PULSAR_PUBLIC ConsumerConfiguration {
*/
int getPriorityLevel() const;

/**
* Consumer buffers chunk messages into memory until it receives all the chunks of the original message.
* While consuming chunk-messages, chunks from same message might not be contiguous in the stream and they
* might be mixed with other messages' chunks. so, consumer has to maintain multiple buffers to manage
* chunks coming from different messages. This mainly happens when multiple publishers are publishing
* messages on the topic concurrently or publisher failed to publish all chunks of the messages.
*
* eg: M1-C1, M2-C1, M1-C2, M2-C2
* Here, Messages M1-C1 and M1-C2 belong to original message M1, M2-C1 and M2-C2 belong to M2 message.
*
* Buffering large number of outstanding uncompleted chunked messages can create memory pressure and it
* can be guarded by providing this maxPendingChunkedMessage threshold. Once, consumer reaches this
* threshold, it drops the outstanding unchunked-messages by silently acking or asking broker to redeliver
* later by marking it unacked. See setAutoOldestChunkedMessageOnQueueFull.
*
* If it's zero, the pending chunked messages will not be limited.
*
* Default: 100
*
* @param maxPendingChunkedMessage the number of max pending chunked messages
*/
ConsumerConfiguration& setMaxPendingChunkedMessage(size_t maxPendingChunkedMessage);

/**
* The associated getter of setMaxPendingChunkedMessage
*/
size_t getMaxPendingChunkedMessage() const;

/**
* Buffering large number of outstanding uncompleted chunked messages can create memory pressure and it
* can be guarded by providing the maxPendingChunkedMessage threshold. See setMaxPendingChunkedMessage.
* Once, consumer reaches this threshold, it drops the outstanding unchunked-messages by silently acking
* if autoAckOldestChunkedMessageOnQueueFull is true else it marks them for redelivery.
*
* Default: false
*
* @param autoAckOldestChunkedMessageOnQueueFull whether to ack the discarded chunked message
*/
ConsumerConfiguration& setAutoOldestChunkedMessageOnQueueFull(
bool autoAckOldestChunkedMessageOnQueueFull);

/**
* The associated getter of setAutoOldestChunkedMessageOnQueueFull
*/
bool isAutoOldestChunkedMessageOnQueueFull() const;

friend class PulsarWrapper;

private:
Expand Down
28 changes: 28 additions & 0 deletions pulsar-client-cpp/include/pulsar/ProducerConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,34 @@ class PULSAR_PUBLIC ProducerConfiguration {
*/
ProducerConfiguration& setProperties(const std::map<std::string, std::string>& properties);

/**
* If message size is higher than allowed max publish-payload size by broker then enableChunking helps
* producer to split message into multiple chunks and publish them to broker separately in order. So, it
* allows client to successfully publish large size of messages in pulsar.
*
* Set it true to enable this feature. If so, you must disable batching (see setBatchingEnabled),
* otherwise the producer creation will fail.
*
* There are some other recommendations when it's enabled:
* 1. This features is right now only supported for non-shared subscription and persistent-topic.
* 2. It's better to reduce setMaxPendingMessages to avoid producer accupying large amount of memory by
* buffered messages.
* 3. Set message-ttl on the namespace to cleanup chunked messages. Sometimes due to broker-restart or
* publish time, producer might fail to publish entire large message. So, consumer will not be able to
* consume and ack those messages.
*
* Default: false
*
* @param chunkingEnabled whether chunking is enabled
* @return the ProducerConfiguration self
*/
ProducerConfiguration& setChunkingEnabled(bool chunkingEnabled);

/**
* The getter associated with setChunkingEnabled().
*/
bool isChunkingEnabled() const;

friend class PulsarWrapper;

private:
Expand Down
3 changes: 2 additions & 1 deletion pulsar-client-cpp/lib/BatchMessageContainerBase.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ Result BatchMessageContainerBase::createOpSendMsgHelper(OpSendMsg& opSendMsg,
return ResultMessageTooBig;
}

opSendMsg.msg_.impl_ = impl;
opSendMsg.metadata_ = impl->metadata;
opSendMsg.payload_ = impl->payload;
opSendMsg.sequenceId_ = impl->metadata.sequence_id();
opSendMsg.producerId_ = producerId_;
opSendMsg.timeout_ = TimeUtils::now() + milliseconds(producerConfig_.getSendTimeout());
Expand Down
10 changes: 6 additions & 4 deletions pulsar-client-cpp/lib/ClientConnection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1366,8 +1366,9 @@ void ClientConnection::sendMessage(const OpSendMsg& opSend) {
}

void ClientConnection::sendMessageInternal(const OpSendMsg& opSend) {
PairSharedBuffer buffer = Commands::newSend(outgoingBuffer_, outgoingCmd_, opSend.producerId_,
opSend.sequenceId_, getChecksumType(), opSend.msg_);
PairSharedBuffer buffer =
Commands::newSend(outgoingBuffer_, outgoingCmd_, opSend.producerId_, opSend.sequenceId_,
getChecksumType(), opSend.metadata_, opSend.payload_);

asyncWrite(buffer, customAllocWriteHandler(std::bind(&ClientConnection::handleSendPair,
shared_from_this(), std::placeholders::_1)));
Expand Down Expand Up @@ -1408,8 +1409,9 @@ void ClientConnection::sendPendingCommands() {
assert(any.type() == typeid(OpSendMsg));

const OpSendMsg& op = boost::any_cast<const OpSendMsg&>(any);
PairSharedBuffer buffer = Commands::newSend(outgoingBuffer_, outgoingCmd_, op.producerId_,
op.sequenceId_, getChecksumType(), op.msg_);
PairSharedBuffer buffer =
Commands::newSend(outgoingBuffer_, outgoingCmd_, op.producerId_, op.sequenceId_,
getChecksumType(), op.metadata_, op.payload_);

asyncWrite(buffer, customAllocWriteHandler(std::bind(&ClientConnection::handleSendPair,
shared_from_this(), std::placeholders::_1)));
Expand Down
6 changes: 5 additions & 1 deletion pulsar-client-cpp/lib/ClientImpl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <pulsar/ConsoleLoggerFactory.h>
#include <boost/algorithm/string/predicate.hpp>
#include <sstream>
#include <stdexcept>
#include <lib/HTTPLookupService.h>
#include <lib/TopicName.h>
#include <algorithm>
Expand Down Expand Up @@ -147,6 +148,9 @@ LookupServicePtr ClientImpl::getLookup() { return lookupServicePtr_; }

void ClientImpl::createProducerAsync(const std::string& topic, ProducerConfiguration conf,
CreateProducerCallback callback) {
if (conf.isChunkingEnabled() && conf.getBatchingEnabled()) {
throw std::invalid_argument("Batching and chunking of messages can't be enabled together");
}
TopicNamePtr topicName;
{
Lock lock(mutex_);
Expand Down Expand Up @@ -174,7 +178,7 @@ void ClientImpl::handleCreateProducer(const Result result, const LookupDataResul
producer = std::make_shared<PartitionedProducerImpl>(shared_from_this(), topicName,
partitionMetadata->getPartitions(), conf);
} else {
producer = std::make_shared<ProducerImpl>(shared_from_this(), topicName->toString(), conf);
producer = std::make_shared<ProducerImpl>(shared_from_this(), *topicName, conf);
}
producer->getProducerCreatedFuture().addListener(
std::bind(&ClientImpl::handleProducerCreated, shared_from_this(), std::placeholders::_1,
Expand Down
12 changes: 7 additions & 5 deletions pulsar-client-cpp/lib/Commands.cc
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,18 @@ SharedBuffer Commands::newConsumerStats(uint64_t consumerId, uint64_t requestId)
}

PairSharedBuffer Commands::newSend(SharedBuffer& headers, BaseCommand& cmd, uint64_t producerId,
uint64_t sequenceId, ChecksumType checksumType, const Message& msg) {
const proto::MessageMetadata& metadata = msg.impl_->metadata;
SharedBuffer& payload = msg.impl_->payload;

uint64_t sequenceId, ChecksumType checksumType,
const proto::MessageMetadata& metadata, const SharedBuffer& payload) {
cmd.set_type(BaseCommand::SEND);
CommandSend* send = cmd.mutable_send();
send->set_producer_id(producerId);
send->set_sequence_id(sequenceId);
if (metadata.has_num_messages_in_batch()) {
send->set_num_messages(metadata.num_messages_in_batch());
}
if (metadata.has_chunk_id()) {
send->set_is_chunk(true);
}

// / Wire format
// [TOTAL_SIZE] [CMD_SIZE][CMD] [MAGIC_NUMBER][CHECKSUM] [METADATA_SIZE][METADATA] [PAYLOAD]
Expand Down Expand Up @@ -199,7 +200,8 @@ PairSharedBuffer Commands::newSend(SharedBuffer& headers, BaseCommand& cmd, uint
int metadataStartIndex = checksumReaderIndex + checksumSize;
uint32_t metadataChecksum =
computeChecksum(0, headers.data() + metadataStartIndex, (writeIndex - metadataStartIndex));
uint32_t computedChecksum = computeChecksum(metadataChecksum, payload.data(), payload.writerIndex());
uint32_t computedChecksum =
computeChecksum(metadataChecksum, payload.data(), payload.readableBytes());
// set computed checksum
headers.setWriterIndex(checksumReaderIndex);
headers.writeUnsignedInt(computedChecksum);
Expand Down
3 changes: 2 additions & 1 deletion pulsar-client-cpp/lib/Commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ class Commands {
const std::string& listenerName);

static PairSharedBuffer newSend(SharedBuffer& headers, proto::BaseCommand& cmd, uint64_t producerId,
uint64_t sequenceId, ChecksumType checksumType, const Message& msg);
uint64_t sequenceId, ChecksumType checksumType,
const proto::MessageMetadata& metadata, const SharedBuffer& payload);

static SharedBuffer newSubscribe(const std::string& topic, const std::string& subscription,
uint64_t consumerId, uint64_t requestId,
Expand Down
17 changes: 17 additions & 0 deletions pulsar-client-cpp/lib/ConsumerConfiguration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -231,4 +231,21 @@ ConsumerConfiguration& ConsumerConfiguration::setKeySharedPolicy(KeySharedPolicy

KeySharedPolicy ConsumerConfiguration::getKeySharedPolicy() const { return impl_->keySharedPolicy; }

ConsumerConfiguration& ConsumerConfiguration::setMaxPendingChunkedMessage(size_t maxPendingChunkedMessage) {
impl_->maxPendingChunkedMessage = maxPendingChunkedMessage;
return *this;
}

size_t ConsumerConfiguration::getMaxPendingChunkedMessage() const { return impl_->maxPendingChunkedMessage; }

ConsumerConfiguration& ConsumerConfiguration::setAutoOldestChunkedMessageOnQueueFull(
bool autoAckOldestChunkedMessageOnQueueFull) {
impl_->autoAckOldestChunkedMessageOnQueueFull = autoAckOldestChunkedMessageOnQueueFull;
return *this;
}

bool ConsumerConfiguration::isAutoOldestChunkedMessageOnQueueFull() const {
return impl_->autoAckOldestChunkedMessageOnQueueFull;
}

} // namespace pulsar
2 changes: 2 additions & 0 deletions pulsar-client-cpp/lib/ConsumerConfigurationImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ struct ConsumerConfigurationImpl {
std::map<std::string, std::string> properties;
int priorityLevel{0};
KeySharedPolicy keySharedPolicy;
size_t maxPendingChunkedMessage{100};
bool autoAckOldestChunkedMessageOnQueueFull{false};
};
} // namespace pulsar
#endif /* LIB_CONSUMERCONFIGURATIONIMPL_H_ */
Loading