mirror of
https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka.git
synced 2025-11-03 12:07:57 +00:00
Add some documentation
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
include/cppkafka/config.h
|
||||||
@@ -35,11 +35,27 @@
|
|||||||
|
|
||||||
namespace cppkafka {
|
namespace cppkafka {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Represents a view of a buffer.
|
||||||
|
*
|
||||||
|
* This is only a view, hence you should convert the contents of a buffer into
|
||||||
|
* some other container if you want to store it somewhere.
|
||||||
|
*/
|
||||||
class Buffer {
|
class Buffer {
|
||||||
public:
|
public:
|
||||||
using DataType = unsigned char;
|
using DataType = unsigned char;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an empty buffer
|
||||||
|
*/
|
||||||
Buffer();
|
Buffer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a buffer from a pointer and a size
|
||||||
|
*
|
||||||
|
* \param data A pointer to some type of size 1
|
||||||
|
* \param size The size of the buffer
|
||||||
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Buffer(const T* data, size_t size)
|
Buffer(const T* data, size_t size)
|
||||||
: data_(reinterpret_cast<const DataType*>(data)), size_(size) {
|
: data_(reinterpret_cast<const DataType*>(data)), size_(size) {
|
||||||
@@ -51,9 +67,19 @@ public:
|
|||||||
Buffer& operator=(const Buffer&) = delete;
|
Buffer& operator=(const Buffer&) = delete;
|
||||||
Buffer& operator=(Buffer&&) = default;
|
Buffer& operator=(Buffer&&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the data pointer
|
||||||
|
*/
|
||||||
const DataType* get_data() const;
|
const DataType* get_data() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the size of the buffer
|
||||||
|
*/
|
||||||
size_t get_size() const;
|
size_t get_size() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the contents of the buffer into a string
|
||||||
|
*/
|
||||||
std::string as_string() const;
|
std::string as_string() const;
|
||||||
private:
|
private:
|
||||||
const DataType* data_;
|
const DataType* data_;
|
||||||
|
|||||||
@@ -34,19 +34,41 @@
|
|||||||
|
|
||||||
namespace cppkafka {
|
namespace cppkafka {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smart pointer which allows copying via a clone functor
|
||||||
|
*/
|
||||||
template <typename T, typename Deleter, typename Cloner>
|
template <typename T, typename Deleter, typename Cloner>
|
||||||
class ClonablePtr {
|
class ClonablePtr {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Creates an instance
|
||||||
|
*
|
||||||
|
* \param ptr The pointer to be wrapped
|
||||||
|
* \param deleter The deleter functor
|
||||||
|
* \param cloner The clone functor
|
||||||
|
*/
|
||||||
ClonablePtr(T* ptr, const Deleter& deleter, const Cloner& cloner)
|
ClonablePtr(T* ptr, const Deleter& deleter, const Cloner& cloner)
|
||||||
: handle_(ptr, deleter), cloner_(cloner) {
|
: handle_(ptr, deleter), cloner_(cloner) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Copies the given ClonablePtr
|
||||||
|
*
|
||||||
|
* Cloning will be done by invoking the Cloner type
|
||||||
|
*
|
||||||
|
* \param rhs The pointer to be copied
|
||||||
|
*/
|
||||||
ClonablePtr(const ClonablePtr& rhs)
|
ClonablePtr(const ClonablePtr& rhs)
|
||||||
: handle_(rhs.cloner_(rhs.handle_.get()), rhs.handle_.get_deleter()), cloner_(rhs.cloner_) {
|
: handle_(rhs.cloner_(rhs.handle_.get()), rhs.handle_.get_deleter()), cloner_(rhs.cloner_) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies and assigns the given pointer
|
||||||
|
*
|
||||||
|
* \param rhs The pointer to be copied
|
||||||
|
*/
|
||||||
ClonablePtr& operator=(const ClonablePtr& rhs) {
|
ClonablePtr& operator=(const ClonablePtr& rhs) {
|
||||||
handle_.reset(cloner_(rhs.handle_.get()));
|
handle_.reset(cloner_(rhs.handle_.get()));
|
||||||
return *this;
|
return *this;
|
||||||
@@ -56,6 +78,9 @@ public:
|
|||||||
ClonablePtr& operator=(ClonablePtr&&) = default;
|
ClonablePtr& operator=(ClonablePtr&&) = default;
|
||||||
~ClonablePtr() = default;
|
~ClonablePtr() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the internal pointer
|
||||||
|
*/
|
||||||
T* get() const {
|
T* get() const {
|
||||||
return handle_.get();
|
return handle_.get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,14 @@ class Producer;
|
|||||||
class Consumer;
|
class Consumer;
|
||||||
class KafkaHandleBase;
|
class KafkaHandleBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Represents a global configuration (rd_kafka_conf_t).
|
||||||
|
*
|
||||||
|
* This wraps an rdkafka configuration handle. It can safely be copied (will use
|
||||||
|
* rd_kafka_conf_dup under the hood) and moved.
|
||||||
|
*
|
||||||
|
* Some other overloads for Configuration::set are given via ConfigurationBase.
|
||||||
|
*/
|
||||||
class Configuration : public ConfigurationBase<Configuration> {
|
class Configuration : public ConfigurationBase<Configuration> {
|
||||||
public:
|
public:
|
||||||
using DeliveryReportCallback = std::function<void(Producer& producer, const Message&)>;
|
using DeliveryReportCallback = std::function<void(Producer& producer, const Message&)>;
|
||||||
@@ -69,29 +77,121 @@ public:
|
|||||||
|
|
||||||
using ConfigurationBase<Configuration>::set;
|
using ConfigurationBase<Configuration>::set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructs a Configuration object
|
||||||
|
*/
|
||||||
Configuration();
|
Configuration();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sets an attribute.
|
||||||
|
*
|
||||||
|
* This will call rd_kafka_conf_set under the hood
|
||||||
|
*
|
||||||
|
* \param name The name of the attribute
|
||||||
|
* \param value The value of the attribute
|
||||||
|
*/
|
||||||
void set(const std::string& name, const std::string& value);
|
void set(const std::string& name, const std::string& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the delivery report callback (invokes rd_kafka_conf_set_dr_msg_cb)
|
||||||
|
*/
|
||||||
void set_delivery_report_callback(DeliveryReportCallback callback);
|
void set_delivery_report_callback(DeliveryReportCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the offset commit callback (invokes rd_kafka_conf_set_offset_commit_cb)
|
||||||
|
*/
|
||||||
void set_offset_commit_callback(OffsetCommitCallback callback);
|
void set_offset_commit_callback(OffsetCommitCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the error callback (invokes rd_kafka_conf_set_error_cb)
|
||||||
|
*/
|
||||||
void set_error_callback(ErrorCallback callback);
|
void set_error_callback(ErrorCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the throttle callback (invokes rd_kafka_conf_set_throttle_cb)
|
||||||
|
*/
|
||||||
void set_throttle_callback(ThrottleCallback callback);
|
void set_throttle_callback(ThrottleCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the log callback (invokes rd_kafka_conf_set_log_cb)
|
||||||
|
*/
|
||||||
void set_log_callback(LogCallback callback);
|
void set_log_callback(LogCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the stats callback (invokes rd_kafka_conf_set_stats_cb)
|
||||||
|
*/
|
||||||
void set_stats_callback(StatsCallback callback);
|
void set_stats_callback(StatsCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the socket callback (invokes rd_kafka_conf_set_socket_cb)
|
||||||
|
*/
|
||||||
void set_socket_callback(SocketCallback callback);
|
void set_socket_callback(SocketCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the default topic configuration
|
||||||
|
*/
|
||||||
void set_default_topic_configuration(boost::optional<TopicConfiguration> config);
|
void set_default_topic_configuration(boost::optional<TopicConfiguration> config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true iff the given property name has been set
|
||||||
|
*/
|
||||||
bool has_property(const std::string& name) const;
|
bool has_property(const std::string& name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the rdkafka configuration handle
|
||||||
|
*/
|
||||||
rd_kafka_conf_t* get_handle() const;
|
rd_kafka_conf_t* get_handle() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an option value
|
||||||
|
*
|
||||||
|
* \throws ConfigOptionNotFound if the option is not present
|
||||||
|
*/
|
||||||
std::string get(const std::string& name) const;
|
std::string get(const std::string& name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the delivery report callback
|
||||||
|
*/
|
||||||
const DeliveryReportCallback& get_delivery_report_callback() const;
|
const DeliveryReportCallback& get_delivery_report_callback() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the offset commit callback
|
||||||
|
*/
|
||||||
const OffsetCommitCallback& get_offset_commit_callback() const;
|
const OffsetCommitCallback& get_offset_commit_callback() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the error callback
|
||||||
|
*/
|
||||||
const ErrorCallback& get_error_callback() const;
|
const ErrorCallback& get_error_callback() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the throttle callback
|
||||||
|
*/
|
||||||
const ThrottleCallback& get_throttle_callback() const;
|
const ThrottleCallback& get_throttle_callback() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the log callback
|
||||||
|
*/
|
||||||
const LogCallback& get_log_callback() const;
|
const LogCallback& get_log_callback() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the stats callback
|
||||||
|
*/
|
||||||
const StatsCallback& get_stats_callback() const;
|
const StatsCallback& get_stats_callback() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the socket callback
|
||||||
|
*/
|
||||||
const SocketCallback& get_socket_callback() const;
|
const SocketCallback& get_socket_callback() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the default topic configuration
|
||||||
|
*/
|
||||||
const boost::optional<TopicConfiguration>& get_default_topic_configuration() const;
|
const boost::optional<TopicConfiguration>& get_default_topic_configuration() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the default topic configuration
|
||||||
|
*/
|
||||||
boost::optional<TopicConfiguration>& get_default_topic_configuration();
|
boost::optional<TopicConfiguration>& get_default_topic_configuration();
|
||||||
private:
|
private:
|
||||||
static const std::unordered_set<std::string> VALID_EXTENSIONS;
|
static const std::unordered_set<std::string> VALID_EXTENSIONS;
|
||||||
|
|||||||
@@ -37,17 +37,25 @@ namespace cppkafka {
|
|||||||
template <typename Concrete>
|
template <typename Concrete>
|
||||||
class ConfigurationBase {
|
class ConfigurationBase {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Sets a bool value
|
||||||
|
*/
|
||||||
void set(const std::string& name, bool value) {
|
void set(const std::string& name, bool value) {
|
||||||
proxy_set(name, value ? "true" : "false");
|
proxy_set(name, value ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overload for any integral value
|
/**
|
||||||
|
* Sets a value of any integral value
|
||||||
|
*/
|
||||||
template <typename T,
|
template <typename T,
|
||||||
typename = typename std::enable_if<std::is_integral<T>::value>::type>
|
typename = typename std::enable_if<std::is_integral<T>::value>::type>
|
||||||
void set(const std::string& name, T value) {
|
void set(const std::string& name, T value) {
|
||||||
proxy_set(name, std::to_string(value));
|
proxy_set(name, std::to_string(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a cstring value
|
||||||
|
*/
|
||||||
void set(const std::string& name, const char* value) {
|
void set(const std::string& name, const char* value) {
|
||||||
proxy_set(name, value);
|
proxy_set(name, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,43 +41,266 @@ namespace cppkafka {
|
|||||||
|
|
||||||
class TopicConfiguration;
|
class TopicConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief High level kafka consumer class
|
||||||
|
*
|
||||||
|
* Wrapper for the high level consumer API provided by rdkafka. Most methods are just
|
||||||
|
* a one to one mapping to rdkafka functions.
|
||||||
|
*
|
||||||
|
* This class allows hooking up to assignments/revocations via callbacks.
|
||||||
|
*
|
||||||
|
* Semi-simple code showing how to use this class
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* // Create a configuration and set the group.id and zookeeper fields
|
||||||
|
* Configuration config;
|
||||||
|
* // This is only valid when using the zookeeper extension
|
||||||
|
* config.set("zookeeper", "127.0.0.1:2181");
|
||||||
|
* config.set("group.id", "foo");
|
||||||
|
*
|
||||||
|
* // Create a consumer
|
||||||
|
* Consumer consumer(config);
|
||||||
|
*
|
||||||
|
* // Set the assignment callback
|
||||||
|
* consumer.set_assignment_callback([&](vector<TopicPartition>& topic_partitions) {
|
||||||
|
* // Here you could fetch offsets and do something, altering the offsets on the
|
||||||
|
* // topic_partitions vector if needed
|
||||||
|
* cout << "Got assigned " << topic_partitions.count() << " partitions!" << endl;
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // Set the revocation callback
|
||||||
|
* consumer.set_revocation_callback([&](const vector<TopicPartition>& topic_partitions) {
|
||||||
|
* cout << topic_partitions.size() << " partitions revoked!" << endl;
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // Subscribe
|
||||||
|
* consumer.subscribe({ "my_topic" });
|
||||||
|
* while (true) {
|
||||||
|
* // Poll. This will optionally return a message. It's necessary to check if it's a valid
|
||||||
|
* // one before using it or bad things will happen
|
||||||
|
* Message msg = consumer.poll();
|
||||||
|
* if (msg) {
|
||||||
|
* // It's a valid message!
|
||||||
|
* if (msg.get_error() == 0) {
|
||||||
|
* // It's an actual message. Get the payload and print it to stdout
|
||||||
|
* cout << msg.get_payload().as_string() << endl;
|
||||||
|
* }
|
||||||
|
* else {
|
||||||
|
* // Is it an error notification
|
||||||
|
* // ...
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
class Consumer : public KafkaHandleBase {
|
class Consumer : public KafkaHandleBase {
|
||||||
public:
|
public:
|
||||||
using AssignmentCallback = std::function<void(TopicPartitionList&)>;
|
using AssignmentCallback = std::function<void(TopicPartitionList&)>;
|
||||||
using RevocationCallback = std::function<void(const TopicPartitionList&)>;
|
using RevocationCallback = std::function<void(const TopicPartitionList&)>;
|
||||||
using RebalanceErrorCallback = std::function<void(rd_kafka_resp_err_t)>;
|
using RebalanceErrorCallback = std::function<void(rd_kafka_resp_err_t)>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Creates an instance of a consumer.
|
||||||
|
*
|
||||||
|
* Note that the configuration *must contain* the group.id attribute set or this
|
||||||
|
* will throw.
|
||||||
|
*
|
||||||
|
* \param config The configuration to be used
|
||||||
|
*/
|
||||||
Consumer(Configuration config);
|
Consumer(Configuration config);
|
||||||
Consumer(const Consumer&) = delete;
|
Consumer(const Consumer&) = delete;
|
||||||
Consumer(Consumer&) = delete;
|
Consumer(Consumer&) = delete;
|
||||||
Consumer& operator=(const Consumer&) = delete;
|
Consumer& operator=(const Consumer&) = delete;
|
||||||
Consumer& operator=(Consumer&&) = delete;
|
Consumer& operator=(Consumer&&) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Closes and estroys the rdkafka handle
|
||||||
|
*
|
||||||
|
* This will call Consumer::close before destroying the handle
|
||||||
|
*/
|
||||||
~Consumer();
|
~Consumer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sets the topic/partition assignment callback
|
||||||
|
*
|
||||||
|
* The Consumer class will use rd_kafka_conf_set_rebalance_cb and will handle the
|
||||||
|
* rebalance, converting from rdkafka topic partition list handles into vector<TopicPartition>
|
||||||
|
* and executing the assignment/revocation/rebalance_error callbacks.
|
||||||
|
*
|
||||||
|
* \note You *do not need* to call Consumer::assign with the provided topic parttitions. This
|
||||||
|
* will be handled automatically by cppkafka.
|
||||||
|
*
|
||||||
|
* \param callback The topic/partition assignment callback
|
||||||
|
*/
|
||||||
void set_assignment_callback(AssignmentCallback callback);
|
void set_assignment_callback(AssignmentCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sets the topic/partition revocation callback
|
||||||
|
*
|
||||||
|
* The Consumer class will use rd_kafka_conf_set_rebalance_cb and will handle the
|
||||||
|
* rebalance, converting from rdkafka topic partition list handles into vector<TopicPartition>
|
||||||
|
* and executing the assignment/revocation/rebalance_error callbacks.
|
||||||
|
*
|
||||||
|
* \note You *do not need* to call Consumer::assign with an empty topic partition list or
|
||||||
|
* anything like that. That's handled automatically by cppkafka. This is just a notifitation
|
||||||
|
* so your application code can react to revocations
|
||||||
|
*
|
||||||
|
* \param callback The topic/partition revocation callback
|
||||||
|
*/
|
||||||
void set_revocation_callback(RevocationCallback callback);
|
void set_revocation_callback(RevocationCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sets the rebalance error callback
|
||||||
|
*
|
||||||
|
* The Consumer class will use rd_kafka_conf_set_rebalance_cb and will handle the
|
||||||
|
* rebalance, converting from rdkafka topic partition list handles into vector<TopicPartition>
|
||||||
|
* and executing the assignment/revocation/rebalance_error callbacks.
|
||||||
|
*
|
||||||
|
* \param callback The rebalance error callback
|
||||||
|
*/
|
||||||
void set_rebalance_error_callback(RebalanceErrorCallback callback);
|
void set_rebalance_error_callback(RebalanceErrorCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Subscribes to the given list of topics
|
||||||
|
*
|
||||||
|
* This translates to a call to rd_kafka_subscribe
|
||||||
|
*
|
||||||
|
* \param topics The topics to subscribe to
|
||||||
|
*/
|
||||||
void subscribe(const std::vector<std::string>& topics);
|
void subscribe(const std::vector<std::string>& topics);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Unsubscribes to the current subscription list
|
||||||
|
*
|
||||||
|
* This translates to a call to rd_kafka_unsubscribe
|
||||||
|
*/
|
||||||
void unsubscribe();
|
void unsubscribe();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sets the current topic/partition assignment
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_assign
|
||||||
|
*/
|
||||||
void assign(const TopicPartitionList& topic_partitions);
|
void assign(const TopicPartitionList& topic_partitions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Unassigns the current topic/partition assignment
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_assign using a null as the topic partition list
|
||||||
|
* parameter
|
||||||
|
*/
|
||||||
void unassign();
|
void unassign();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Closes the consumer session
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_consumer_close
|
||||||
|
*/
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Commits the given message synchronously
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_commit_message
|
||||||
|
*
|
||||||
|
* \param msg The message to be committed
|
||||||
|
*/
|
||||||
void commit(const Message& msg);
|
void commit(const Message& msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Commits the given message asynchronously
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_commit_message
|
||||||
|
*
|
||||||
|
* \param msg The message to be committed
|
||||||
|
*/
|
||||||
void async_commit(const Message& msg);
|
void async_commit(const Message& msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Commits the offsets on the given topic/partitions synchronously
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_commit
|
||||||
|
*
|
||||||
|
* \param topic_partitions The topic/partition list to be committed
|
||||||
|
*/
|
||||||
void commit(const TopicPartitionList& topic_partitions);
|
void commit(const TopicPartitionList& topic_partitions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Commits the offsets on the given topic/partitions asynchronously
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_commit
|
||||||
|
*
|
||||||
|
* \param topic_partitions The topic/partition list to be committed
|
||||||
|
*/
|
||||||
void async_commit(const TopicPartitionList& topic_partitions);
|
void async_commit(const TopicPartitionList& topic_partitions);
|
||||||
|
|
||||||
OffsetTuple get_offsets(const std::string& topic, int partition) const;
|
/**
|
||||||
|
* \brief Gets the minimum and maximum offsets for the given topic/partition
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_get_watermark_offsets
|
||||||
|
*
|
||||||
|
* \param topic_partition The topic/partition to get the offsets from
|
||||||
|
*/
|
||||||
|
OffsetTuple get_offsets(const TopicPartition& topic_partition) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Gets the offsets committed for the given topic/partition list
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_committed
|
||||||
|
*
|
||||||
|
* \param topic_partitions The topic/partition list to be queried
|
||||||
|
*/
|
||||||
TopicPartitionList get_offsets_committed(const TopicPartitionList& topic_partitions) const;
|
TopicPartitionList get_offsets_committed(const TopicPartitionList& topic_partitions) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Gets the offset positions for the given topic/partition list
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_position
|
||||||
|
*
|
||||||
|
* \param topic_partitions The topic/partition list to be queried
|
||||||
|
*/
|
||||||
TopicPartitionList get_offsets_position(const TopicPartitionList& topic_partitions) const;
|
TopicPartitionList get_offsets_position(const TopicPartitionList& topic_partitions) const;
|
||||||
TopicPartitionList get_subscription() const;
|
|
||||||
|
/**
|
||||||
|
* \brief Gets the current topic subscription
|
||||||
|
*
|
||||||
|
* This translates to a call to rd_kafka_subscription
|
||||||
|
*/
|
||||||
|
std::vector<std::string> get_subscription() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Gets the current topic/partition list assignment
|
||||||
|
*
|
||||||
|
* This translates to a call to rd_kafka_assignment
|
||||||
|
*/
|
||||||
TopicPartitionList get_assignment() const;
|
TopicPartitionList get_assignment() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Gets the group member id
|
||||||
|
*
|
||||||
|
* This translates to a call to rd_kafka_memberid
|
||||||
|
*/
|
||||||
std::string get_member_id() const;
|
std::string get_member_id() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Polls for new messages
|
||||||
|
*
|
||||||
|
* This will call rd_kafka_consumer_poll.
|
||||||
|
*
|
||||||
|
* Note that you need to call poll periodically as a keep alive mechanism, otherwise the broker
|
||||||
|
* will think this consumer is down and will trigger a rebalance (if using dynamic
|
||||||
|
* subscription).
|
||||||
|
*
|
||||||
|
* The returned message *might* be empty. If's necessary to check that it's a valid one before
|
||||||
|
* using it:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* Message msg = consumer.poll();
|
||||||
|
* if (msg) {
|
||||||
|
* // It's a valid message!
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
Message poll();
|
Message poll();
|
||||||
private:
|
private:
|
||||||
static void rebalance_proxy(rd_kafka_t *handle, rd_kafka_resp_err_t error,
|
static void rebalance_proxy(rd_kafka_t *handle, rd_kafka_resp_err_t error,
|
||||||
|
|||||||
@@ -36,6 +36,9 @@
|
|||||||
|
|
||||||
namespace cppkafka {
|
namespace cppkafka {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all cppkafka exceptions
|
||||||
|
*/
|
||||||
class Exception : public std::exception {
|
class Exception : public std::exception {
|
||||||
public:
|
public:
|
||||||
Exception(std::string message);
|
Exception(std::string message);
|
||||||
@@ -45,16 +48,25 @@ private:
|
|||||||
std::string message_;
|
std::string message_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration related error
|
||||||
|
*/
|
||||||
class ConfigException : public Exception {
|
class ConfigException : public Exception {
|
||||||
public:
|
public:
|
||||||
ConfigException(const std::string& config_name, const std::string& error);
|
ConfigException(const std::string& config_name, const std::string& error);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates a configuration option was not set
|
||||||
|
*/
|
||||||
class ConfigOptionNotFound : public Exception {
|
class ConfigOptionNotFound : public Exception {
|
||||||
public:
|
public:
|
||||||
ConfigOptionNotFound(const std::string& config_name);
|
ConfigOptionNotFound(const std::string& config_name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic rdkafka handle error
|
||||||
|
*/
|
||||||
class HandleException : public Exception {
|
class HandleException : public Exception {
|
||||||
public:
|
public:
|
||||||
HandleException(rd_kafka_resp_err_t error_code);
|
HandleException(rd_kafka_resp_err_t error_code);
|
||||||
@@ -64,6 +76,9 @@ private:
|
|||||||
rd_kafka_resp_err_t error_code_;
|
rd_kafka_resp_err_t error_code_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception when using zookeeper
|
||||||
|
*/
|
||||||
class ZookeeperException : public Exception {
|
class ZookeeperException : public Exception {
|
||||||
public:
|
public:
|
||||||
using Exception::Exception;
|
using Exception::Exception;
|
||||||
|
|||||||
@@ -44,13 +44,16 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#ifdef CPPKAFKA_HAVE_ZOOKEEPER
|
#ifdef CPPKAFKA_HAVE_ZOOKEEPER
|
||||||
#include "zookeeper/zookeeper_subscriber.h"
|
#include "zookeeper/zookeeper_subscription.h"
|
||||||
#endif // CPPKAFKA_HAVE_ZOOKEEPER
|
#endif // CPPKAFKA_HAVE_ZOOKEEPER
|
||||||
|
|
||||||
namespace cppkafka {
|
namespace cppkafka {
|
||||||
|
|
||||||
class Topic;
|
class Topic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for kafka consumer/producer
|
||||||
|
*/
|
||||||
class KafkaHandleBase {
|
class KafkaHandleBase {
|
||||||
public:
|
public:
|
||||||
using OffsetTuple = std::tuple<int64_t, int64_t>;
|
using OffsetTuple = std::tuple<int64_t, int64_t>;
|
||||||
@@ -61,20 +64,100 @@ public:
|
|||||||
KafkaHandleBase& operator=(const KafkaHandleBase&) = delete;
|
KafkaHandleBase& operator=(const KafkaHandleBase&) = delete;
|
||||||
KafkaHandleBase& operator=(KafkaHandleBase&&) = delete;
|
KafkaHandleBase& operator=(KafkaHandleBase&&) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Pauses consumption/production from the given topic/partition list
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_pause_partitions
|
||||||
|
*
|
||||||
|
* \param topic_partitions The topic/partition list to pause consuming/producing from/to
|
||||||
|
*/
|
||||||
void pause_partitions(const TopicPartitionList& topic_partitions);
|
void pause_partitions(const TopicPartitionList& topic_partitions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Resumes consumption/production from the given topic/partition list
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_resume_partitions
|
||||||
|
*
|
||||||
|
* \param topic_partitions The topic/partition list to resume consuming/producing from/to
|
||||||
|
*/
|
||||||
void resume_partitions(const TopicPartitionList& topic_partitions);
|
void resume_partitions(const TopicPartitionList& topic_partitions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sets the timeout for operations that require a timeout
|
||||||
|
*
|
||||||
|
* This timeout is applied to operations like polling, querying for offsets, etc
|
||||||
|
*
|
||||||
|
* \param timeout The timeout to be set
|
||||||
|
*/
|
||||||
void set_timeout(const std::chrono::milliseconds& timeout);
|
void set_timeout(const std::chrono::milliseconds& timeout);
|
||||||
|
|
||||||
OffsetTuple query_offsets(const std::string& topic, int partition) const;
|
/**
|
||||||
|
* \brief Queries the offset for the given topic/partition
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_query_watermark_offsets
|
||||||
|
*
|
||||||
|
* \param topic_partition The topic/partition to be queried
|
||||||
|
*/
|
||||||
|
OffsetTuple query_offsets(const TopicPartition& topic_partition) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the rdkafka handle
|
||||||
|
*/
|
||||||
rd_kafka_t* get_handle() const;
|
rd_kafka_t* get_handle() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Creates a topic handle
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_topic_new. This will use the default topic
|
||||||
|
* configuration provided in the Configuration object for this consumer/producer handle,
|
||||||
|
* if any.
|
||||||
|
*
|
||||||
|
* \param name The name of the topic to be created
|
||||||
|
*/
|
||||||
Topic get_topic(const std::string& name);
|
Topic get_topic(const std::string& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Creates a topic handle
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_topic_new.
|
||||||
|
*
|
||||||
|
* \param name The name of the topic to be created
|
||||||
|
* \param config The configuration to be used for the new topic
|
||||||
|
*/
|
||||||
Topic get_topic(const std::string& name, TopicConfiguration config);
|
Topic get_topic(const std::string& name, TopicConfiguration config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Gets metadata for brokers, topics, partitions, etc
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_metadata
|
||||||
|
*/
|
||||||
Metadata get_metadata() const;
|
Metadata get_metadata() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Gets general metadata but only fetches metadata for the given topic rather than
|
||||||
|
* all of them
|
||||||
|
*
|
||||||
|
* This translates into a call to rd_kafka_metadata
|
||||||
|
*
|
||||||
|
* \param topic The topic to fetch information for
|
||||||
|
*/
|
||||||
Metadata get_metadata(const Topic& topic) const;
|
Metadata get_metadata(const Topic& topic) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the kafka handle name
|
||||||
|
*/
|
||||||
std::string get_name() const;
|
std::string get_name() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the configured timeout.
|
||||||
|
*
|
||||||
|
* \sa KafkaHandleBase::set_timeout
|
||||||
|
*/
|
||||||
std::chrono::milliseconds get_timeout() const;
|
std::chrono::milliseconds get_timeout() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the handle's configuration
|
||||||
|
*/
|
||||||
const Configuration& get_configuration() const;
|
const Configuration& get_configuration() const;
|
||||||
protected:
|
protected:
|
||||||
KafkaHandleBase(Configuration config);
|
KafkaHandleBase(Configuration config);
|
||||||
@@ -99,7 +182,7 @@ private:
|
|||||||
std::mutex topic_configurations_mutex_;
|
std::mutex topic_configurations_mutex_;
|
||||||
#ifdef CPPKAFKA_HAVE_ZOOKEEPER
|
#ifdef CPPKAFKA_HAVE_ZOOKEEPER
|
||||||
// This could be an optional but apparently move construction is only supported as of 1.56
|
// This could be an optional but apparently move construction is only supported as of 1.56
|
||||||
std::unique_ptr<ZookeeperSubscriber> zookeeper_subscriber_;
|
std::unique_ptr<ZookeeperSubscription> zookeeper_subscription_;
|
||||||
#endif // CPPKAFKA_HAVE_ZOOKEEPER
|
#endif // CPPKAFKA_HAVE_ZOOKEEPER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -38,18 +38,52 @@
|
|||||||
|
|
||||||
namespace cppkafka {
|
namespace cppkafka {
|
||||||
|
|
||||||
class ZookeeperSubscriber;
|
class ZookeeperSubscription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Pool of zookeeper handles
|
||||||
|
*
|
||||||
|
* This class is used internally by cppkafka.
|
||||||
|
*/
|
||||||
class ZookeeperPool {
|
class ZookeeperPool {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Get singleton instance
|
||||||
|
*/
|
||||||
static ZookeeperPool& instance();
|
static ZookeeperPool& instance();
|
||||||
|
|
||||||
ZookeeperSubscriber subscribe(const std::string& endpoint,
|
/**
|
||||||
|
* Subscribe to the given endpoint
|
||||||
|
*
|
||||||
|
* \param endpoint The zookeeper endpoint to subscribe to
|
||||||
|
* \param receive_timeout The zookeeper receive timeout
|
||||||
|
* \param callback The callback to be executed on updates
|
||||||
|
*
|
||||||
|
* \return A ZookeeperSubscription that will auto-unsubscribe upon destruction
|
||||||
|
*/
|
||||||
|
ZookeeperSubscription subscribe(const std::string& endpoint,
|
||||||
std::chrono::milliseconds receive_timeout,
|
std::chrono::milliseconds receive_timeout,
|
||||||
ZookeeperWatcher::WatcherCallback callback);
|
ZookeeperWatcher::WatcherCallback callback);
|
||||||
void unsubscribe(const ZookeeperSubscriber& subscriber);
|
|
||||||
|
/**
|
||||||
|
* Unsubscribes from a previous subscription
|
||||||
|
*
|
||||||
|
* \param subscriber The subscriber return by a previous call to ZookeeperPool::subscribe
|
||||||
|
*/
|
||||||
|
void unsubscribe(const ZookeeperSubscription& subscriber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Gets the broker list for the given zookeeper endpoint
|
||||||
|
*
|
||||||
|
* Requires having previously called subscribe for this endpoint at least once.
|
||||||
|
*
|
||||||
|
* \param endpoint The endpoint for which to get the broker list
|
||||||
|
*/
|
||||||
std::string get_brokers(const std::string& endpoint);
|
std::string get_brokers(const std::string& endpoint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the amount of subscribers for the given zookeeper endpoint
|
||||||
|
*/
|
||||||
size_t get_subscriber_count(const std::string& endpoint) const;
|
size_t get_subscriber_count(const std::string& endpoint) const;
|
||||||
private:
|
private:
|
||||||
using WatchersMap = std::map<std::string, ZookeeperWatcher>;
|
using WatchersMap = std::map<std::string, ZookeeperWatcher>;
|
||||||
|
|||||||
@@ -27,29 +27,37 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CPPKAFKA_ZOOKEEPER_SUBSCRIBER_H
|
#ifndef CPPKAFKA_ZOOKEEPER_SUBSCRIPTION_H
|
||||||
#define CPPKAFKA_ZOOKEEPER_SUBSCRIBER_H
|
#define CPPKAFKA_ZOOKEEPER_SUBSCRIPTION_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace cppkafka {
|
namespace cppkafka {
|
||||||
|
|
||||||
class ZookeeperSubscriber {
|
/**
|
||||||
|
* \cond
|
||||||
|
*/
|
||||||
|
class ZookeeperSubscription {
|
||||||
public:
|
public:
|
||||||
ZookeeperSubscriber(std::string endpoint, std::string subscription_id);
|
ZookeeperSubscription(std::string endpoint, std::string subscription_id);
|
||||||
ZookeeperSubscriber(ZookeeperSubscriber&&) = default;
|
ZookeeperSubscription(ZookeeperSubscription&&) = default;
|
||||||
ZookeeperSubscriber(const ZookeeperSubscriber&) = delete;
|
ZookeeperSubscription(const ZookeeperSubscription&) = delete;
|
||||||
ZookeeperSubscriber& operator=(ZookeeperSubscriber&&);
|
ZookeeperSubscription& operator=(ZookeeperSubscription&&);
|
||||||
ZookeeperSubscriber& operator=(const ZookeeperSubscriber&) = delete;
|
ZookeeperSubscription& operator=(const ZookeeperSubscription&) = delete;
|
||||||
~ZookeeperSubscriber();
|
~ZookeeperSubscription();
|
||||||
|
|
||||||
const std::string& get_endpoint() const;
|
const std::string& get_endpoint() const;
|
||||||
|
|
||||||
const std::string& get_subscription_id() const;
|
const std::string& get_subscription_id() const;
|
||||||
private:
|
private:
|
||||||
std::string endpoint_;
|
std::string endpoint_;
|
||||||
std::string subscription_id_;
|
std::string subscription_id_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \endcond
|
||||||
|
*/
|
||||||
|
|
||||||
} // cppkafka
|
} // cppkafka
|
||||||
|
|
||||||
#endif // CPPKAFKA_ZOOKEEPER_SUBSCRIBER_H
|
#endif // CPPKAFKA_ZOOKEEPER_SUBSCRIPTION_H
|
||||||
@@ -40,6 +40,9 @@
|
|||||||
|
|
||||||
namespace cppkafka {
|
namespace cppkafka {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \cond
|
||||||
|
*/
|
||||||
class ZookeeperWatcher {
|
class ZookeeperWatcher {
|
||||||
public:
|
public:
|
||||||
static const std::chrono::milliseconds DEFAULT_RECEIVE_TIMEOUT;
|
static const std::chrono::milliseconds DEFAULT_RECEIVE_TIMEOUT;
|
||||||
@@ -73,6 +76,10 @@ private:
|
|||||||
size_t id_counter_{0};
|
size_t id_counter_{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \endcond
|
||||||
|
*/
|
||||||
|
|
||||||
} // cppkafka
|
} // cppkafka
|
||||||
|
|
||||||
#endif // CPPKAFKA_ZOOKEEPER_WATCHER_H
|
#endif // CPPKAFKA_ZOOKEEPER_WATCHER_H
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ if (ENABLE_ZOOKEEPER)
|
|||||||
set(ZOOKEEPER_SOURCES
|
set(ZOOKEEPER_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zookeeper/zookeeper_watcher.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/zookeeper/zookeeper_watcher.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zookeeper/zookeeper_pool.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/zookeeper/zookeeper_pool.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zookeeper/zookeeper_subscriber.cpp)
|
${CMAKE_CURRENT_SOURCE_DIR}/zookeeper/zookeeper_subscription.cpp)
|
||||||
# Add json library as include dir (header only)
|
# Add json library as include dir (header only)
|
||||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/json)
|
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/json)
|
||||||
set(SOURCES ${SOURCES} ${ZOOKEEPER_SOURCES})
|
set(SOURCES ${SOURCES} ${ZOOKEEPER_SOURCES})
|
||||||
|
|||||||
@@ -126,9 +126,11 @@ void Consumer::async_commit(const TopicPartitionList& topic_partitions) {
|
|||||||
commit(topic_partitions, true);
|
commit(topic_partitions, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
KafkaHandleBase::OffsetTuple Consumer::get_offsets(const string& topic, int partition) const {
|
KafkaHandleBase::OffsetTuple Consumer::get_offsets(const TopicPartition& topic_partition) const {
|
||||||
int64_t low;
|
int64_t low;
|
||||||
int64_t high;
|
int64_t high;
|
||||||
|
const string& topic = topic_partition.get_topic();
|
||||||
|
const int partition = topic_partition.get_partition();
|
||||||
rd_kafka_resp_err_t result = rd_kafka_get_watermark_offsets(get_handle(), topic.data(),
|
rd_kafka_resp_err_t result = rd_kafka_get_watermark_offsets(get_handle(), topic.data(),
|
||||||
partition, &low, &high);
|
partition, &low, &high);
|
||||||
check_error(result);
|
check_error(result);
|
||||||
@@ -152,12 +154,18 @@ Consumer::get_offsets_position(const TopicPartitionList& topic_partitions) const
|
|||||||
return convert(topic_list_handle);
|
return convert(topic_list_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
TopicPartitionList Consumer::get_subscription() const {
|
vector<string> Consumer::get_subscription() const {
|
||||||
rd_kafka_resp_err_t error;
|
rd_kafka_resp_err_t error;
|
||||||
rd_kafka_topic_partition_list_t* list = nullptr;
|
rd_kafka_topic_partition_list_t* list = nullptr;
|
||||||
error = rd_kafka_subscription(get_handle(), &list);
|
error = rd_kafka_subscription(get_handle(), &list);
|
||||||
check_error(error);
|
check_error(error);
|
||||||
return convert(make_handle(list));
|
|
||||||
|
auto handle = make_handle(list);
|
||||||
|
vector<string> output;
|
||||||
|
for (const auto& topic_partition : convert(handle)) {
|
||||||
|
output.push_back(topic_partition.get_topic());
|
||||||
|
}
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
TopicPartitionList Consumer::get_assignment() const {
|
TopicPartitionList Consumer::get_assignment() const {
|
||||||
|
|||||||
@@ -91,10 +91,12 @@ Topic KafkaHandleBase::get_topic(const string& name, TopicConfiguration config)
|
|||||||
return get_topic(name, rd_kafka_topic_conf_dup(handle));
|
return get_topic(name, rd_kafka_topic_conf_dup(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
KafkaHandleBase::OffsetTuple KafkaHandleBase::query_offsets(const string& topic,
|
KafkaHandleBase::OffsetTuple
|
||||||
int partition) const {
|
KafkaHandleBase::query_offsets(const TopicPartition& topic_partition) const {
|
||||||
int64_t low;
|
int64_t low;
|
||||||
int64_t high;
|
int64_t high;
|
||||||
|
const string& topic = topic_partition.get_topic();
|
||||||
|
const int partition = topic_partition.get_partition();
|
||||||
rd_kafka_resp_err_t result = rd_kafka_query_watermark_offsets(handle_.get(), topic.data(),
|
rd_kafka_resp_err_t result = rd_kafka_query_watermark_offsets(handle_.get(), topic.data(),
|
||||||
partition, &low, &high,
|
partition, &low, &high,
|
||||||
timeout_ms_.count());
|
timeout_ms_.count());
|
||||||
@@ -144,8 +146,8 @@ void KafkaHandleBase::set_handle(rd_kafka_t* handle) {
|
|||||||
rd_kafka_brokers_add(handle_.get(), brokers.data());
|
rd_kafka_brokers_add(handle_.get(), brokers.data());
|
||||||
rd_kafka_poll(handle_.get(), 10);
|
rd_kafka_poll(handle_.get(), 10);
|
||||||
};
|
};
|
||||||
ZookeeperSubscriber subscriber = pool.subscribe(endpoint, timeout, callback);
|
ZookeeperSubscription subscriber = pool.subscribe(endpoint, timeout, callback);
|
||||||
zookeeper_subscriber_.reset(new ZookeeperSubscriber(move(subscriber)));
|
zookeeper_subscription_.reset(new ZookeeperSubscription(move(subscriber)));
|
||||||
callback(pool.get_brokers(endpoint));
|
callback(pool.get_brokers(endpoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "zookeeper/zookeeper_pool.h"
|
#include "zookeeper/zookeeper_pool.h"
|
||||||
#include "zookeeper/zookeeper_subscriber.h"
|
#include "zookeeper/zookeeper_subscription.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
@@ -45,7 +45,7 @@ ZookeeperPool& ZookeeperPool::instance() {
|
|||||||
return the_instance;
|
return the_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZookeeperSubscriber ZookeeperPool::subscribe(const string& endpoint,
|
ZookeeperSubscription ZookeeperPool::subscribe(const string& endpoint,
|
||||||
milliseconds receive_timeout,
|
milliseconds receive_timeout,
|
||||||
ZookeeperWatcher::WatcherCallback callback) {
|
ZookeeperWatcher::WatcherCallback callback) {
|
||||||
lock_guard<mutex> _(watchers_mutex_);
|
lock_guard<mutex> _(watchers_mutex_);
|
||||||
@@ -55,10 +55,10 @@ ZookeeperSubscriber ZookeeperPool::subscribe(const string& endpoint,
|
|||||||
forward_as_tuple(endpoint, receive_timeout)).first;
|
forward_as_tuple(endpoint, receive_timeout)).first;
|
||||||
}
|
}
|
||||||
string id = iter->second.subscribe(move(callback));
|
string id = iter->second.subscribe(move(callback));
|
||||||
return ZookeeperSubscriber(endpoint, id);
|
return ZookeeperSubscription(endpoint, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZookeeperPool::unsubscribe(const ZookeeperSubscriber& subscriber) {
|
void ZookeeperPool::unsubscribe(const ZookeeperSubscription& subscriber) {
|
||||||
lock_guard<mutex> _(watchers_mutex_);
|
lock_guard<mutex> _(watchers_mutex_);
|
||||||
auto iter = watchers_.find(subscriber.get_endpoint());
|
auto iter = watchers_.find(subscriber.get_endpoint());
|
||||||
if (iter != watchers_.end()) {
|
if (iter != watchers_.end()) {
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
#include "zookeeper/zookeeper_subscriber.h"
|
|
||||||
#include "zookeeper/zookeeper_pool.h"
|
|
||||||
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
namespace cppkafka {
|
|
||||||
|
|
||||||
ZookeeperSubscriber::ZookeeperSubscriber(string endpoint, string subscription_id)
|
|
||||||
: endpoint_(move(endpoint)), subscription_id_(move(subscription_id)) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ZookeeperSubscriber::~ZookeeperSubscriber() {
|
|
||||||
ZookeeperPool::instance().unsubscribe(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
const string& ZookeeperSubscriber::get_endpoint() const {
|
|
||||||
return endpoint_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const string& ZookeeperSubscriber::get_subscription_id() const {
|
|
||||||
return subscription_id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // cppkafka
|
|
||||||
25
src/zookeeper/zookeeper_subscription.cpp
Normal file
25
src/zookeeper/zookeeper_subscription.cpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include "zookeeper/zookeeper_subscription.h"
|
||||||
|
#include "zookeeper/zookeeper_pool.h"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
namespace cppkafka {
|
||||||
|
|
||||||
|
ZookeeperSubscription::ZookeeperSubscription(string endpoint, string subscription_id)
|
||||||
|
: endpoint_(move(endpoint)), subscription_id_(move(subscription_id)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ZookeeperSubscription::~ZookeeperSubscription() {
|
||||||
|
ZookeeperPool::instance().unsubscribe(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const string& ZookeeperSubscription::get_endpoint() const {
|
||||||
|
return endpoint_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string& ZookeeperSubscription::get_subscription_id() const {
|
||||||
|
return subscription_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // cppkafka
|
||||||
@@ -130,12 +130,14 @@ TEST_F(ConsumerTest, AssignmentCallback) {
|
|||||||
}
|
}
|
||||||
EXPECT_EQ(1, runner.get_messages().size());
|
EXPECT_EQ(1, runner.get_messages().size());
|
||||||
|
|
||||||
|
EXPECT_EQ(vector<string>{ KAFKA_TOPIC }, consumer.get_subscription());
|
||||||
|
|
||||||
assignment = consumer.get_assignment();
|
assignment = consumer.get_assignment();
|
||||||
EXPECT_EQ(3, assignment.size());
|
EXPECT_EQ(3, assignment.size());
|
||||||
|
|
||||||
int64_t low;
|
int64_t low;
|
||||||
int64_t high;
|
int64_t high;
|
||||||
tie(low, high) = consumer.get_offsets(KAFKA_TOPIC, partition);
|
tie(low, high) = consumer.get_offsets({ KAFKA_TOPIC, partition });
|
||||||
EXPECT_GT(high, low);
|
EXPECT_GT(high, low);
|
||||||
EXPECT_EQ(high, runner.get_messages().back().get_offset() + 1);
|
EXPECT_EQ(high, runner.get_messages().back().get_offset() + 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ TEST_F(ProducerTest, OneMessageOnFixedPartition) {
|
|||||||
|
|
||||||
int64_t low;
|
int64_t low;
|
||||||
int64_t high;
|
int64_t high;
|
||||||
tie(low, high) = producer.query_offsets(KAFKA_TOPIC, partition);
|
tie(low, high) = producer.query_offsets({ KAFKA_TOPIC, partition });
|
||||||
EXPECT_GT(high, low);
|
EXPECT_GT(high, low);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user