kafka-python 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kafka/__init__.py +34 -0
- kafka/__main__.py +5 -0
- kafka/admin/__init__.py +29 -0
- kafka/admin/__main__.py +5 -0
- kafka/admin/_acls.py +355 -0
- kafka/admin/_cluster.py +359 -0
- kafka/admin/_configs.py +479 -0
- kafka/admin/_groups.py +754 -0
- kafka/admin/_partitions.py +595 -0
- kafka/admin/_topics.py +281 -0
- kafka/admin/_transactions.py +450 -0
- kafka/admin/_users.py +194 -0
- kafka/admin/client.py +373 -0
- kafka/benchmarks/__init__.py +0 -0
- kafka/benchmarks/consumer_performance.py +138 -0
- kafka/benchmarks/load_example.py +109 -0
- kafka/benchmarks/producer_encode_path.py +201 -0
- kafka/benchmarks/producer_performance.py +161 -0
- kafka/benchmarks/profile_protocol.py +138 -0
- kafka/benchmarks/protocol_old_vs_new.py +447 -0
- kafka/benchmarks/record_batch_compose.py +77 -0
- kafka/benchmarks/record_batch_read.py +82 -0
- kafka/benchmarks/varint_speed.py +426 -0
- kafka/cli/__init__.py +36 -0
- kafka/cli/admin/__init__.py +117 -0
- kafka/cli/admin/acls/__init__.py +9 -0
- kafka/cli/admin/acls/common.py +76 -0
- kafka/cli/admin/acls/create.py +19 -0
- kafka/cli/admin/acls/delete.py +23 -0
- kafka/cli/admin/acls/describe.py +16 -0
- kafka/cli/admin/cluster/__init__.py +14 -0
- kafka/cli/admin/cluster/describe.py +11 -0
- kafka/cli/admin/cluster/describe_quorum.py +11 -0
- kafka/cli/admin/cluster/features.py +52 -0
- kafka/cli/admin/cluster/log_dirs.py +43 -0
- kafka/cli/admin/cluster/versions.py +33 -0
- kafka/cli/admin/configs/__init__.py +10 -0
- kafka/cli/admin/configs/alter.py +43 -0
- kafka/cli/admin/configs/common.py +17 -0
- kafka/cli/admin/configs/describe.py +30 -0
- kafka/cli/admin/configs/list.py +16 -0
- kafka/cli/admin/configs/reset.py +20 -0
- kafka/cli/admin/groups/__init__.py +16 -0
- kafka/cli/admin/groups/alter_offsets.py +30 -0
- kafka/cli/admin/groups/delete.py +11 -0
- kafka/cli/admin/groups/delete_offsets.py +29 -0
- kafka/cli/admin/groups/describe.py +11 -0
- kafka/cli/admin/groups/list.py +28 -0
- kafka/cli/admin/groups/list_offsets.py +29 -0
- kafka/cli/admin/groups/remove_members.py +40 -0
- kafka/cli/admin/groups/reset_offsets.py +139 -0
- kafka/cli/admin/partitions/__init__.py +21 -0
- kafka/cli/admin/partitions/alter_reassignments.py +37 -0
- kafka/cli/admin/partitions/create.py +27 -0
- kafka/cli/admin/partitions/delete_records.py +31 -0
- kafka/cli/admin/partitions/describe.py +36 -0
- kafka/cli/admin/partitions/elect_leaders.py +53 -0
- kafka/cli/admin/partitions/list_offsets.py +88 -0
- kafka/cli/admin/partitions/list_reassignments.py +35 -0
- kafka/cli/admin/topics/__init__.py +10 -0
- kafka/cli/admin/topics/create.py +13 -0
- kafka/cli/admin/topics/delete.py +19 -0
- kafka/cli/admin/topics/describe.py +18 -0
- kafka/cli/admin/topics/list.py +11 -0
- kafka/cli/admin/transactions/__init__.py +17 -0
- kafka/cli/admin/transactions/abort.py +38 -0
- kafka/cli/admin/transactions/describe.py +24 -0
- kafka/cli/admin/transactions/describe_producers.py +29 -0
- kafka/cli/admin/transactions/find_hanging.py +26 -0
- kafka/cli/admin/transactions/list.py +37 -0
- kafka/cli/admin/users/__init__.py +8 -0
- kafka/cli/admin/users/alter_user_scram_credentials.py +34 -0
- kafka/cli/admin/users/describe_user_scram_credentials.py +15 -0
- kafka/cli/common.py +95 -0
- kafka/cli/consumer/__init__.py +63 -0
- kafka/cli/producer/__init__.py +57 -0
- kafka/cluster.py +824 -0
- kafka/codec.py +325 -0
- kafka/consumer/__init__.py +5 -0
- kafka/consumer/__main__.py +5 -0
- kafka/consumer/fetcher.py +2012 -0
- kafka/consumer/group.py +1347 -0
- kafka/consumer/subscription_state.py +897 -0
- kafka/coordinator/__init__.py +0 -0
- kafka/coordinator/assignors/__init__.py +0 -0
- kafka/coordinator/assignors/abstract.py +90 -0
- kafka/coordinator/assignors/cooperative_sticky.py +167 -0
- kafka/coordinator/assignors/range.py +81 -0
- kafka/coordinator/assignors/roundrobin.py +101 -0
- kafka/coordinator/assignors/sticky/StickyAssignorUserData.json +37 -0
- kafka/coordinator/assignors/sticky/__init__.py +0 -0
- kafka/coordinator/assignors/sticky/partition_movements.py +149 -0
- kafka/coordinator/assignors/sticky/sorted_set.py +63 -0
- kafka/coordinator/assignors/sticky/sticky_assignor.py +665 -0
- kafka/coordinator/assignors/sticky/user_data.py +8 -0
- kafka/coordinator/base.py +1215 -0
- kafka/coordinator/consumer.py +1224 -0
- kafka/coordinator/heartbeat.py +82 -0
- kafka/coordinator/subscription.py +34 -0
- kafka/errors.py +1004 -0
- kafka/future.py +166 -0
- kafka/metrics/__init__.py +13 -0
- kafka/metrics/compound_stat.py +33 -0
- kafka/metrics/dict_reporter.py +81 -0
- kafka/metrics/kafka_metric.py +36 -0
- kafka/metrics/measurable.py +27 -0
- kafka/metrics/measurable_stat.py +13 -0
- kafka/metrics/metric_config.py +33 -0
- kafka/metrics/metric_name.py +105 -0
- kafka/metrics/metrics.py +261 -0
- kafka/metrics/metrics_reporter.py +53 -0
- kafka/metrics/quota.py +41 -0
- kafka/metrics/stat.py +19 -0
- kafka/metrics/stats/__init__.py +15 -0
- kafka/metrics/stats/avg.py +24 -0
- kafka/metrics/stats/count.py +17 -0
- kafka/metrics/stats/histogram.py +99 -0
- kafka/metrics/stats/max_stat.py +17 -0
- kafka/metrics/stats/min_stat.py +19 -0
- kafka/metrics/stats/percentile.py +14 -0
- kafka/metrics/stats/percentiles.py +75 -0
- kafka/metrics/stats/rate.py +118 -0
- kafka/metrics/stats/sampled_stat.py +99 -0
- kafka/metrics/stats/sensor.py +136 -0
- kafka/metrics/stats/total.py +15 -0
- kafka/net/__init__.py +19 -0
- kafka/net/compat.py +165 -0
- kafka/net/connection.py +593 -0
- kafka/net/http_connect.py +144 -0
- kafka/net/inet.py +122 -0
- kafka/net/manager.py +451 -0
- kafka/net/metrics.py +149 -0
- kafka/net/sasl/__init__.py +32 -0
- kafka/net/sasl/abc.py +28 -0
- kafka/net/sasl/gssapi.py +95 -0
- kafka/net/sasl/msk.py +245 -0
- kafka/net/sasl/oauth.py +98 -0
- kafka/net/sasl/plain.py +42 -0
- kafka/net/sasl/scram.py +135 -0
- kafka/net/sasl/sspi.py +111 -0
- kafka/net/selector.py +644 -0
- kafka/net/socks5.py +262 -0
- kafka/net/transport.py +415 -0
- kafka/net/wakeup_notifier.py +72 -0
- kafka/partitioner/__init__.py +8 -0
- kafka/partitioner/abc.py +8 -0
- kafka/partitioner/default.py +89 -0
- kafka/partitioner/sticky.py +109 -0
- kafka/producer/__init__.py +5 -0
- kafka/producer/__main__.py +5 -0
- kafka/producer/future.py +101 -0
- kafka/producer/kafka.py +1123 -0
- kafka/producer/producer_batch.py +192 -0
- kafka/producer/record_accumulator.py +647 -0
- kafka/producer/sender.py +884 -0
- kafka/producer/transaction_manager.py +1326 -0
- kafka/protocol/__init__.py +0 -0
- kafka/protocol/admin/__init__.py +29 -0
- kafka/protocol/admin/acl.py +83 -0
- kafka/protocol/admin/acl.pyi +375 -0
- kafka/protocol/admin/client_quotas.py +14 -0
- kafka/protocol/admin/client_quotas.pyi +265 -0
- kafka/protocol/admin/cluster.py +31 -0
- kafka/protocol/admin/cluster.pyi +620 -0
- kafka/protocol/admin/configs.py +22 -0
- kafka/protocol/admin/configs.pyi +437 -0
- kafka/protocol/admin/groups.py +24 -0
- kafka/protocol/admin/groups.pyi +261 -0
- kafka/protocol/admin/topics.py +53 -0
- kafka/protocol/admin/topics.pyi +982 -0
- kafka/protocol/admin/transactions.py +18 -0
- kafka/protocol/admin/transactions.pyi +311 -0
- kafka/protocol/admin/users.py +14 -0
- kafka/protocol/admin/users.pyi +223 -0
- kafka/protocol/api_data.py +125 -0
- kafka/protocol/api_header.py +55 -0
- kafka/protocol/api_key.py +97 -0
- kafka/protocol/api_message.py +277 -0
- kafka/protocol/broker_version_data.py +246 -0
- kafka/protocol/consumer/__init__.py +13 -0
- kafka/protocol/consumer/fetch.py +16 -0
- kafka/protocol/consumer/fetch.pyi +298 -0
- kafka/protocol/consumer/group.py +38 -0
- kafka/protocol/consumer/group.pyi +824 -0
- kafka/protocol/consumer/metadata.py +30 -0
- kafka/protocol/consumer/metadata.pyi +89 -0
- kafka/protocol/consumer/offsets.py +75 -0
- kafka/protocol/consumer/offsets.pyi +288 -0
- kafka/protocol/data_container.py +166 -0
- kafka/protocol/frame.py +30 -0
- kafka/protocol/generate_stubs.py +468 -0
- kafka/protocol/metadata/__init__.py +10 -0
- kafka/protocol/metadata/api_versions.py +41 -0
- kafka/protocol/metadata/api_versions.pyi +128 -0
- kafka/protocol/metadata/find_coordinator.py +19 -0
- kafka/protocol/metadata/find_coordinator.pyi +105 -0
- kafka/protocol/metadata/metadata.py +34 -0
- kafka/protocol/metadata/metadata.pyi +160 -0
- kafka/protocol/old/__init__.py +0 -0
- kafka/protocol/old/abstract.py +17 -0
- kafka/protocol/old/add_offsets_to_txn.py +54 -0
- kafka/protocol/old/add_partitions_to_txn.py +71 -0
- kafka/protocol/old/admin.py +1086 -0
- kafka/protocol/old/api.py +205 -0
- kafka/protocol/old/api_versions.py +133 -0
- kafka/protocol/old/commit.py +355 -0
- kafka/protocol/old/consumer_protocol.py +36 -0
- kafka/protocol/old/end_txn.py +53 -0
- kafka/protocol/old/fetch.py +408 -0
- kafka/protocol/old/find_coordinator.py +72 -0
- kafka/protocol/old/group.py +451 -0
- kafka/protocol/old/init_producer_id.py +42 -0
- kafka/protocol/old/list_offsets.py +186 -0
- kafka/protocol/old/metadata.py +290 -0
- kafka/protocol/old/offset_for_leader_epoch.py +133 -0
- kafka/protocol/old/produce.py +247 -0
- kafka/protocol/old/sasl_authenticate.py +38 -0
- kafka/protocol/old/sasl_handshake.py +39 -0
- kafka/protocol/old/struct.py +87 -0
- kafka/protocol/old/txn_offset_commit.py +73 -0
- kafka/protocol/old/types.py +440 -0
- kafka/protocol/parser.py +191 -0
- kafka/protocol/producer/__init__.py +7 -0
- kafka/protocol/producer/produce.py +17 -0
- kafka/protocol/producer/produce.pyi +197 -0
- kafka/protocol/producer/transaction.py +30 -0
- kafka/protocol/producer/transaction.pyi +663 -0
- kafka/protocol/sasl.py +52 -0
- kafka/protocol/sasl.pyi +126 -0
- kafka/protocol/schemas/__init__.py +7 -0
- kafka/protocol/schemas/fields/__init__.py +7 -0
- kafka/protocol/schemas/fields/array.py +127 -0
- kafka/protocol/schemas/fields/base.py +156 -0
- kafka/protocol/schemas/fields/codecs/__init__.py +12 -0
- kafka/protocol/schemas/fields/codecs/encode_buffer.py +82 -0
- kafka/protocol/schemas/fields/codecs/tagged_fields.py +109 -0
- kafka/protocol/schemas/fields/codecs/types.py +505 -0
- kafka/protocol/schemas/fields/codegen.py +40 -0
- kafka/protocol/schemas/fields/simple.py +127 -0
- kafka/protocol/schemas/fields/struct.py +357 -0
- kafka/protocol/schemas/fields/struct_array.py +142 -0
- kafka/protocol/schemas/load_json.py +42 -0
- kafka/protocol/schemas/resources/AddOffsetsToTxnRequest.json +40 -0
- kafka/protocol/schemas/resources/AddOffsetsToTxnResponse.json +35 -0
- kafka/protocol/schemas/resources/AddPartitionsToTxnRequest.json +65 -0
- kafka/protocol/schemas/resources/AddPartitionsToTxnResponse.json +60 -0
- kafka/protocol/schemas/resources/AlterClientQuotasRequest.json +47 -0
- kafka/protocol/schemas/resources/AlterClientQuotasResponse.json +41 -0
- kafka/protocol/schemas/resources/AlterConfigsRequest.json +43 -0
- kafka/protocol/schemas/resources/AlterConfigsResponse.json +39 -0
- kafka/protocol/schemas/resources/AlterPartitionReassignmentsRequest.json +42 -0
- kafka/protocol/schemas/resources/AlterPartitionReassignmentsResponse.json +47 -0
- kafka/protocol/schemas/resources/AlterReplicaLogDirsRequest.json +41 -0
- kafka/protocol/schemas/resources/AlterReplicaLogDirsResponse.json +41 -0
- kafka/protocol/schemas/resources/AlterUserScramCredentialsRequest.json +45 -0
- kafka/protocol/schemas/resources/AlterUserScramCredentialsResponse.json +35 -0
- kafka/protocol/schemas/resources/ApiVersionsRequest.json +34 -0
- kafka/protocol/schemas/resources/ApiVersionsResponse.json +79 -0
- kafka/protocol/schemas/resources/ConsumerProtocolAssignment.json +42 -0
- kafka/protocol/schemas/resources/ConsumerProtocolSubscription.json +49 -0
- kafka/protocol/schemas/resources/CreateAclsRequest.json +46 -0
- kafka/protocol/schemas/resources/CreateAclsResponse.json +37 -0
- kafka/protocol/schemas/resources/CreatePartitionsRequest.json +47 -0
- kafka/protocol/schemas/resources/CreatePartitionsResponse.json +41 -0
- kafka/protocol/schemas/resources/CreateTopicsRequest.json +65 -0
- kafka/protocol/schemas/resources/CreateTopicsResponse.json +72 -0
- kafka/protocol/schemas/resources/DeleteAclsRequest.json +46 -0
- kafka/protocol/schemas/resources/DeleteAclsResponse.json +59 -0
- kafka/protocol/schemas/resources/DeleteGroupsRequest.json +30 -0
- kafka/protocol/schemas/resources/DeleteGroupsResponse.json +36 -0
- kafka/protocol/schemas/resources/DeleteRecordsRequest.json +42 -0
- kafka/protocol/schemas/resources/DeleteRecordsResponse.json +43 -0
- kafka/protocol/schemas/resources/DeleteTopicsRequest.json +43 -0
- kafka/protocol/schemas/resources/DeleteTopicsResponse.json +52 -0
- kafka/protocol/schemas/resources/DescribeAclsRequest.json +43 -0
- kafka/protocol/schemas/resources/DescribeAclsResponse.json +55 -0
- kafka/protocol/schemas/resources/DescribeClientQuotasRequest.json +37 -0
- kafka/protocol/schemas/resources/DescribeClientQuotasResponse.json +47 -0
- kafka/protocol/schemas/resources/DescribeClusterRequest.json +35 -0
- kafka/protocol/schemas/resources/DescribeClusterResponse.json +56 -0
- kafka/protocol/schemas/resources/DescribeConfigsRequest.json +42 -0
- kafka/protocol/schemas/resources/DescribeConfigsResponse.json +69 -0
- kafka/protocol/schemas/resources/DescribeGroupsRequest.json +38 -0
- kafka/protocol/schemas/resources/DescribeGroupsResponse.json +74 -0
- kafka/protocol/schemas/resources/DescribeLogDirsRequest.json +38 -0
- kafka/protocol/schemas/resources/DescribeLogDirsResponse.json +65 -0
- kafka/protocol/schemas/resources/DescribeProducersRequest.json +32 -0
- kafka/protocol/schemas/resources/DescribeProducersResponse.json +55 -0
- kafka/protocol/schemas/resources/DescribeQuorumRequest.json +39 -0
- kafka/protocol/schemas/resources/DescribeQuorumResponse.json +82 -0
- kafka/protocol/schemas/resources/DescribeTopicPartitionsRequest.json +40 -0
- kafka/protocol/schemas/resources/DescribeTopicPartitionsResponse.json +66 -0
- kafka/protocol/schemas/resources/DescribeTransactionsRequest.json +27 -0
- kafka/protocol/schemas/resources/DescribeTransactionsResponse.json +52 -0
- kafka/protocol/schemas/resources/DescribeUserScramCredentialsRequest.json +30 -0
- kafka/protocol/schemas/resources/DescribeUserScramCredentialsResponse.json +45 -0
- kafka/protocol/schemas/resources/ElectLeadersRequest.json +41 -0
- kafka/protocol/schemas/resources/ElectLeadersResponse.json +45 -0
- kafka/protocol/schemas/resources/EndTxnRequest.json +43 -0
- kafka/protocol/schemas/resources/EndTxnResponse.json +41 -0
- kafka/protocol/schemas/resources/FetchRequest.json +125 -0
- kafka/protocol/schemas/resources/FetchResponse.json +124 -0
- kafka/protocol/schemas/resources/FindCoordinatorRequest.json +43 -0
- kafka/protocol/schemas/resources/FindCoordinatorResponse.json +58 -0
- kafka/protocol/schemas/resources/HeartbeatRequest.json +39 -0
- kafka/protocol/schemas/resources/HeartbeatResponse.json +35 -0
- kafka/protocol/schemas/resources/IncrementalAlterConfigsRequest.json +44 -0
- kafka/protocol/schemas/resources/IncrementalAlterConfigsResponse.json +38 -0
- kafka/protocol/schemas/resources/InitProducerIdRequest.json +50 -0
- kafka/protocol/schemas/resources/InitProducerIdResponse.json +47 -0
- kafka/protocol/schemas/resources/JoinGroupRequest.json +63 -0
- kafka/protocol/schemas/resources/JoinGroupResponse.json +69 -0
- kafka/protocol/schemas/resources/LeaveGroupRequest.json +47 -0
- kafka/protocol/schemas/resources/LeaveGroupResponse.json +47 -0
- kafka/protocol/schemas/resources/ListConfigResourcesRequest.json +31 -0
- kafka/protocol/schemas/resources/ListConfigResourcesResponse.json +37 -0
- kafka/protocol/schemas/resources/ListGroupsRequest.json +36 -0
- kafka/protocol/schemas/resources/ListGroupsResponse.json +49 -0
- kafka/protocol/schemas/resources/ListOffsetsRequest.json +72 -0
- kafka/protocol/schemas/resources/ListOffsetsResponse.json +71 -0
- kafka/protocol/schemas/resources/ListPartitionReassignmentsRequest.json +34 -0
- kafka/protocol/schemas/resources/ListPartitionReassignmentsResponse.json +46 -0
- kafka/protocol/schemas/resources/ListTransactionsRequest.json +40 -0
- kafka/protocol/schemas/resources/ListTransactionsResponse.json +42 -0
- kafka/protocol/schemas/resources/MetadataRequest.json +56 -0
- kafka/protocol/schemas/resources/MetadataResponse.json +101 -0
- kafka/protocol/schemas/resources/OffsetCommitRequest.json +76 -0
- kafka/protocol/schemas/resources/OffsetCommitResponse.json +71 -0
- kafka/protocol/schemas/resources/OffsetDeleteRequest.json +39 -0
- kafka/protocol/schemas/resources/OffsetDeleteResponse.json +42 -0
- kafka/protocol/schemas/resources/OffsetFetchRequest.json +76 -0
- kafka/protocol/schemas/resources/OffsetFetchResponse.json +107 -0
- kafka/protocol/schemas/resources/OffsetForLeaderEpochRequest.json +52 -0
- kafka/protocol/schemas/resources/OffsetForLeaderEpochResponse.json +51 -0
- kafka/protocol/schemas/resources/ProduceRequest.json +73 -0
- kafka/protocol/schemas/resources/ProduceResponse.json +96 -0
- kafka/protocol/schemas/resources/RequestHeader.json +44 -0
- kafka/protocol/schemas/resources/ResponseHeader.json +26 -0
- kafka/protocol/schemas/resources/SaslAuthenticateRequest.json +29 -0
- kafka/protocol/schemas/resources/SaslAuthenticateResponse.json +34 -0
- kafka/protocol/schemas/resources/SaslHandshakeRequest.json +31 -0
- kafka/protocol/schemas/resources/SaslHandshakeResponse.json +32 -0
- kafka/protocol/schemas/resources/SyncGroupRequest.json +56 -0
- kafka/protocol/schemas/resources/SyncGroupResponse.json +46 -0
- kafka/protocol/schemas/resources/TxnOffsetCommitRequest.json +68 -0
- kafka/protocol/schemas/resources/TxnOffsetCommitResponse.json +47 -0
- kafka/protocol/schemas/resources/UpdateFeaturesRequest.json +43 -0
- kafka/protocol/schemas/resources/UpdateFeaturesResponse.json +39 -0
- kafka/protocol/schemas/resources/WriteTxnMarkersRequest.json +49 -0
- kafka/protocol/schemas/resources/WriteTxnMarkersResponse.json +45 -0
- kafka/protocol/schemas/resources/__init__.py +0 -0
- kafka/record/__init__.py +3 -0
- kafka/record/_crc32c.py +161 -0
- kafka/record/abc.py +144 -0
- kafka/record/default_records.py +782 -0
- kafka/record/legacy_records.py +587 -0
- kafka/record/memory_records.py +255 -0
- kafka/record/util.py +135 -0
- kafka/serializer/__init__.py +4 -0
- kafka/serializer/abstract.py +20 -0
- kafka/serializer/default.py +16 -0
- kafka/serializer/json.py +17 -0
- kafka/serializer/wrapper.py +21 -0
- kafka/structs.py +69 -0
- kafka/util.py +159 -0
- kafka/vendor/__init__.py +0 -0
- kafka/version.py +1 -0
- kafka_python-3.0.0.dist-info/METADATA +319 -0
- kafka_python-3.0.0.dist-info/RECORD +373 -0
- kafka_python-3.0.0.dist-info/WHEEL +5 -0
- kafka_python-3.0.0.dist-info/entry_points.txt +2 -0
- kafka_python-3.0.0.dist-info/licenses/LICENSE +202 -0
- kafka_python-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# This class takes advantage of the fact that all formats v0, v1 and v2 of
|
|
2
|
+
# messages storage has the same byte offsets for Length and Magic fields.
|
|
3
|
+
# Lets look closely at what leading bytes all versions have:
|
|
4
|
+
#
|
|
5
|
+
# V0 and V1 (Offset is MessageSet part, other bytes are Message ones):
|
|
6
|
+
# Offset => Int64
|
|
7
|
+
# BytesLength => Int32
|
|
8
|
+
# CRC => Int32
|
|
9
|
+
# Magic => Int8
|
|
10
|
+
# ...
|
|
11
|
+
#
|
|
12
|
+
# V2:
|
|
13
|
+
# BaseOffset => Int64
|
|
14
|
+
# Length => Int32
|
|
15
|
+
# PartitionLeaderEpoch => Int32
|
|
16
|
+
# Magic => Int8
|
|
17
|
+
# ...
|
|
18
|
+
#
|
|
19
|
+
# So we can iterate over batches just by knowing offsets of Length. Magic is
|
|
20
|
+
# used to construct the correct class for Batch itself.
|
|
21
|
+
|
|
22
|
+
import struct
|
|
23
|
+
|
|
24
|
+
from kafka.errors import CorruptRecordError, IllegalStateError, UnsupportedVersionError
|
|
25
|
+
from kafka.record.abc import ABCRecords
|
|
26
|
+
from kafka.record.legacy_records import LegacyRecordBatch, LegacyRecordBatchBuilder
|
|
27
|
+
from kafka.record.default_records import DefaultRecordBatch, DefaultRecordBatchBuilder
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MemoryRecords(ABCRecords):
|
|
31
|
+
|
|
32
|
+
LENGTH_OFFSET = struct.calcsize(">q")
|
|
33
|
+
LOG_OVERHEAD = struct.calcsize(">qi")
|
|
34
|
+
MAGIC_OFFSET = struct.calcsize(">qii")
|
|
35
|
+
|
|
36
|
+
# Minimum space requirements for Record V0
|
|
37
|
+
MIN_SLICE = LOG_OVERHEAD + LegacyRecordBatch.RECORD_OVERHEAD_V0
|
|
38
|
+
|
|
39
|
+
__slots__ = ("_buffer", "_pos", "_next_slice", "_remaining_bytes")
|
|
40
|
+
|
|
41
|
+
def __init__(self, bytes_data):
|
|
42
|
+
self._buffer = bytes_data
|
|
43
|
+
self._pos = 0
|
|
44
|
+
# We keep one slice ahead so `has_next` will return very fast
|
|
45
|
+
self._next_slice = None
|
|
46
|
+
self._remaining_bytes = None
|
|
47
|
+
self._cache_next()
|
|
48
|
+
|
|
49
|
+
def size_in_bytes(self):
|
|
50
|
+
return len(self._buffer)
|
|
51
|
+
|
|
52
|
+
def valid_bytes(self):
|
|
53
|
+
# We need to read the whole buffer to get the valid_bytes.
|
|
54
|
+
# NOTE: in Fetcher we do the call after iteration, so should be fast
|
|
55
|
+
if self._remaining_bytes is None:
|
|
56
|
+
next_slice = self._next_slice
|
|
57
|
+
pos = self._pos
|
|
58
|
+
while self._remaining_bytes is None:
|
|
59
|
+
self._cache_next()
|
|
60
|
+
# Reset previous iterator position
|
|
61
|
+
self._next_slice = next_slice
|
|
62
|
+
self._pos = pos
|
|
63
|
+
return len(self._buffer) - self._remaining_bytes
|
|
64
|
+
|
|
65
|
+
# NOTE: we cache offsets here as kwargs for a bit more speed, as cPython
|
|
66
|
+
# will use LOAD_FAST opcode in this case
|
|
67
|
+
def _cache_next(self, len_offset=LENGTH_OFFSET, log_overhead=LOG_OVERHEAD):
|
|
68
|
+
buffer = self._buffer
|
|
69
|
+
buffer_len = len(buffer)
|
|
70
|
+
pos = self._pos
|
|
71
|
+
remaining = buffer_len - pos
|
|
72
|
+
if remaining < log_overhead:
|
|
73
|
+
# Will be re-checked in Fetcher for remaining bytes.
|
|
74
|
+
self._remaining_bytes = remaining
|
|
75
|
+
self._next_slice = None
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
length, = struct.unpack_from(
|
|
79
|
+
">i", buffer, pos + len_offset)
|
|
80
|
+
|
|
81
|
+
slice_end = pos + log_overhead + length
|
|
82
|
+
if slice_end > buffer_len:
|
|
83
|
+
# Will be re-checked in Fetcher for remaining bytes
|
|
84
|
+
self._remaining_bytes = remaining
|
|
85
|
+
self._next_slice = None
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
self._next_slice = memoryview(buffer)[pos: slice_end]
|
|
89
|
+
self._pos = slice_end
|
|
90
|
+
|
|
91
|
+
def has_next(self):
|
|
92
|
+
return self._next_slice is not None
|
|
93
|
+
|
|
94
|
+
# NOTE: same cache for LOAD_FAST as above
|
|
95
|
+
def next_batch(self, _min_slice=MIN_SLICE,
|
|
96
|
+
_magic_offset=MAGIC_OFFSET):
|
|
97
|
+
next_slice = self._next_slice
|
|
98
|
+
if next_slice is None:
|
|
99
|
+
return None
|
|
100
|
+
if len(next_slice) < _min_slice:
|
|
101
|
+
raise CorruptRecordError(
|
|
102
|
+
"Record size is less than the minimum record overhead "
|
|
103
|
+
"({})".format(_min_slice - self.LOG_OVERHEAD))
|
|
104
|
+
self._cache_next()
|
|
105
|
+
magic, = struct.unpack_from(">b", next_slice, _magic_offset)
|
|
106
|
+
if magic <= 1:
|
|
107
|
+
return LegacyRecordBatch(next_slice, magic)
|
|
108
|
+
else:
|
|
109
|
+
return DefaultRecordBatch(next_slice)
|
|
110
|
+
|
|
111
|
+
def __iter__(self):
|
|
112
|
+
return self
|
|
113
|
+
|
|
114
|
+
def __next__(self):
|
|
115
|
+
if not self.has_next():
|
|
116
|
+
raise StopIteration
|
|
117
|
+
return self.next_batch()
|
|
118
|
+
|
|
119
|
+
next = __next__
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class MemoryRecordsBuilder:
|
|
123
|
+
|
|
124
|
+
__slots__ = ("_builder", "_batch_size", "_buffer", "_next_offset", "_closed",
|
|
125
|
+
"_magic", "_bytes_written", "_producer_id", "_producer_epoch",
|
|
126
|
+
"_base_sequence")
|
|
127
|
+
|
|
128
|
+
def __init__(self, magic, compression_type, batch_size, offset=0,
|
|
129
|
+
transactional=False, producer_id=-1, producer_epoch=-1, base_sequence=-1):
|
|
130
|
+
assert magic in [0, 1, 2], "Not supported magic"
|
|
131
|
+
assert compression_type in [0, 1, 2, 3, 4], "Not valid compression type"
|
|
132
|
+
if magic >= 2:
|
|
133
|
+
assert not transactional or producer_id != -1, "Cannot write transactional messages without a valid producer ID"
|
|
134
|
+
assert producer_id == -1 or producer_epoch != -1, "Invalid negative producer epoch"
|
|
135
|
+
assert producer_id == -1 or base_sequence != -1, "Invalid negative sequence number used"
|
|
136
|
+
|
|
137
|
+
self._builder = DefaultRecordBatchBuilder(
|
|
138
|
+
magic=magic, compression_type=compression_type,
|
|
139
|
+
is_transactional=transactional, producer_id=producer_id,
|
|
140
|
+
producer_epoch=producer_epoch, base_sequence=base_sequence,
|
|
141
|
+
batch_size=batch_size)
|
|
142
|
+
self._producer_id = producer_id
|
|
143
|
+
self._producer_epoch = producer_epoch
|
|
144
|
+
self._base_sequence = base_sequence
|
|
145
|
+
else:
|
|
146
|
+
assert not transactional and producer_id == -1, "Idempotent messages are not supported for magic %s" % (magic,)
|
|
147
|
+
self._builder = LegacyRecordBatchBuilder(
|
|
148
|
+
magic=magic, compression_type=compression_type,
|
|
149
|
+
batch_size=batch_size)
|
|
150
|
+
self._producer_id = None
|
|
151
|
+
self._producer_epoch = None
|
|
152
|
+
self._base_sequence = None
|
|
153
|
+
self._batch_size = batch_size
|
|
154
|
+
self._buffer = None
|
|
155
|
+
|
|
156
|
+
self._next_offset = offset
|
|
157
|
+
self._closed = False
|
|
158
|
+
self._magic = magic
|
|
159
|
+
self._bytes_written = 0
|
|
160
|
+
|
|
161
|
+
def skip(self, offsets_to_skip):
|
|
162
|
+
# Exposed for testing compacted records
|
|
163
|
+
self._next_offset += offsets_to_skip
|
|
164
|
+
|
|
165
|
+
def append(self, timestamp, key, value, headers=None):
|
|
166
|
+
""" Append a message to the buffer.
|
|
167
|
+
|
|
168
|
+
Returns: RecordMetadata or None if unable to append
|
|
169
|
+
"""
|
|
170
|
+
if headers is None:
|
|
171
|
+
headers = []
|
|
172
|
+
if self._closed:
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
offset = self._next_offset
|
|
176
|
+
metadata = self._builder.append(offset, timestamp, key, value, headers)
|
|
177
|
+
# Return of None means there's no space to add a new message
|
|
178
|
+
if metadata is None:
|
|
179
|
+
return None
|
|
180
|
+
|
|
181
|
+
self._next_offset += 1
|
|
182
|
+
return metadata
|
|
183
|
+
|
|
184
|
+
def set_producer_state(self, producer_id, producer_epoch, base_sequence, is_transactional):
|
|
185
|
+
if self._magic < 2:
|
|
186
|
+
raise UnsupportedVersionError('Producer State requires Message format v2+')
|
|
187
|
+
elif self._closed:
|
|
188
|
+
# Sequence numbers are assigned when the batch is closed while the accumulator is being drained.
|
|
189
|
+
# If the resulting ProduceRequest to the partition leader failed for a retriable error, the batch will
|
|
190
|
+
# be re queued. In this case, we should not attempt to set the state again, since changing the pid and sequence
|
|
191
|
+
# once a batch has been sent to the broker risks introducing duplicates.
|
|
192
|
+
raise IllegalStateError("Trying to set producer state of an already closed batch. This indicates a bug on the client.")
|
|
193
|
+
self._builder.set_producer_state(producer_id, producer_epoch, base_sequence, is_transactional)
|
|
194
|
+
self._producer_id = producer_id
|
|
195
|
+
self._producer_epoch = producer_epoch
|
|
196
|
+
self._base_sequence = base_sequence
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def producer_id(self):
|
|
200
|
+
return self._producer_id
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def producer_epoch(self):
|
|
204
|
+
return self._producer_epoch
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def base_sequence(self):
|
|
208
|
+
return self._base_sequence
|
|
209
|
+
|
|
210
|
+
def records(self):
|
|
211
|
+
assert self._closed
|
|
212
|
+
return MemoryRecords(self._buffer)
|
|
213
|
+
|
|
214
|
+
def close(self):
|
|
215
|
+
# This method may be called multiple times on the same batch
|
|
216
|
+
# i.e., on retries
|
|
217
|
+
# we need to make sure we only close it out once
|
|
218
|
+
# otherwise compressed messages may be double-compressed
|
|
219
|
+
# see Issue 718
|
|
220
|
+
if not self._closed:
|
|
221
|
+
self._bytes_written = self._builder.size()
|
|
222
|
+
# Keep the buffer as bytearray to avoid a full-batch copy on
|
|
223
|
+
# close. Downstream consumers (MemoryRecords via memoryview and
|
|
224
|
+
# the protocol encoder via slice-assignment) handle bytearray
|
|
225
|
+
# without further copies.
|
|
226
|
+
self._buffer = self._builder.build()
|
|
227
|
+
if self._magic == 2:
|
|
228
|
+
self._producer_id = self._builder.producer_id
|
|
229
|
+
self._producer_epoch = self._builder.producer_epoch
|
|
230
|
+
self._base_sequence = self._builder.base_sequence
|
|
231
|
+
self._builder = None
|
|
232
|
+
self._closed = True
|
|
233
|
+
|
|
234
|
+
def size_in_bytes(self):
|
|
235
|
+
if not self._closed:
|
|
236
|
+
return self._builder.size()
|
|
237
|
+
else:
|
|
238
|
+
return len(self._buffer)
|
|
239
|
+
|
|
240
|
+
def compression_rate(self):
|
|
241
|
+
assert self._closed
|
|
242
|
+
return self.size_in_bytes() / self._bytes_written
|
|
243
|
+
|
|
244
|
+
def is_full(self):
|
|
245
|
+
if self._closed:
|
|
246
|
+
return True
|
|
247
|
+
else:
|
|
248
|
+
return self._builder.size() >= self._batch_size
|
|
249
|
+
|
|
250
|
+
def next_offset(self):
|
|
251
|
+
return self._next_offset
|
|
252
|
+
|
|
253
|
+
def buffer(self):
|
|
254
|
+
assert self._closed
|
|
255
|
+
return self._buffer
|
kafka/record/util.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import binascii
|
|
2
|
+
|
|
3
|
+
from kafka.record._crc32c import crc as crc32c_py
|
|
4
|
+
try:
|
|
5
|
+
from crc32c import crc32c as crc32c_c
|
|
6
|
+
except ImportError:
|
|
7
|
+
crc32c_c = None
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def encode_varint(value, write):
|
|
11
|
+
""" Encode an integer to a varint presentation. See
|
|
12
|
+
https://developers.google.com/protocol-buffers/docs/encoding?csw=1#varints
|
|
13
|
+
on how those can be produced.
|
|
14
|
+
|
|
15
|
+
Arguments:
|
|
16
|
+
value (int): Value to encode
|
|
17
|
+
write (function): Called per byte that needs to be writen
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
int: Number of bytes written
|
|
21
|
+
"""
|
|
22
|
+
value = (value << 1) ^ (value >> 63)
|
|
23
|
+
|
|
24
|
+
if value <= 0x7f: # 1 byte
|
|
25
|
+
write(value)
|
|
26
|
+
return 1
|
|
27
|
+
if value <= 0x3fff: # 2 bytes
|
|
28
|
+
write(0x80 | (value & 0x7f))
|
|
29
|
+
write(value >> 7)
|
|
30
|
+
return 2
|
|
31
|
+
if value <= 0x1fffff: # 3 bytes
|
|
32
|
+
write(0x80 | (value & 0x7f))
|
|
33
|
+
write(0x80 | ((value >> 7) & 0x7f))
|
|
34
|
+
write(value >> 14)
|
|
35
|
+
return 3
|
|
36
|
+
if value <= 0xfffffff: # 4 bytes
|
|
37
|
+
write(0x80 | (value & 0x7f))
|
|
38
|
+
write(0x80 | ((value >> 7) & 0x7f))
|
|
39
|
+
write(0x80 | ((value >> 14) & 0x7f))
|
|
40
|
+
write(value >> 21)
|
|
41
|
+
return 4
|
|
42
|
+
if value <= 0x7ffffffff: # 5 bytes
|
|
43
|
+
write(0x80 | (value & 0x7f))
|
|
44
|
+
write(0x80 | ((value >> 7) & 0x7f))
|
|
45
|
+
write(0x80 | ((value >> 14) & 0x7f))
|
|
46
|
+
write(0x80 | ((value >> 21) & 0x7f))
|
|
47
|
+
write(value >> 28)
|
|
48
|
+
return 5
|
|
49
|
+
else:
|
|
50
|
+
# Return to general algorithm
|
|
51
|
+
bits = value & 0x7f
|
|
52
|
+
value >>= 7
|
|
53
|
+
i = 0
|
|
54
|
+
while value:
|
|
55
|
+
write(0x80 | bits)
|
|
56
|
+
bits = value & 0x7f
|
|
57
|
+
value >>= 7
|
|
58
|
+
i += 1
|
|
59
|
+
write(bits)
|
|
60
|
+
return i
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def size_of_varint(value):
|
|
64
|
+
""" Number of bytes needed to encode an integer in variable-length format.
|
|
65
|
+
"""
|
|
66
|
+
value = (value << 1) ^ (value >> 63)
|
|
67
|
+
if value <= 0x7f:
|
|
68
|
+
return 1
|
|
69
|
+
if value <= 0x3fff:
|
|
70
|
+
return 2
|
|
71
|
+
if value <= 0x1fffff:
|
|
72
|
+
return 3
|
|
73
|
+
if value <= 0xfffffff:
|
|
74
|
+
return 4
|
|
75
|
+
if value <= 0x7ffffffff:
|
|
76
|
+
return 5
|
|
77
|
+
if value <= 0x3ffffffffff:
|
|
78
|
+
return 6
|
|
79
|
+
if value <= 0x1ffffffffffff:
|
|
80
|
+
return 7
|
|
81
|
+
if value <= 0xffffffffffffff:
|
|
82
|
+
return 8
|
|
83
|
+
if value <= 0x7fffffffffffffff:
|
|
84
|
+
return 9
|
|
85
|
+
return 10
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def decode_varint(buffer, pos=0):
|
|
89
|
+
""" Decode an integer from a varint presentation. See
|
|
90
|
+
https://developers.google.com/protocol-buffers/docs/encoding?csw=1#varints
|
|
91
|
+
on how those can be produced.
|
|
92
|
+
|
|
93
|
+
Arguments:
|
|
94
|
+
buffer (bytearray): buffer to read from.
|
|
95
|
+
pos (int): optional position to read from
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
(int, int): Decoded int value and next read position
|
|
99
|
+
"""
|
|
100
|
+
result = buffer[pos]
|
|
101
|
+
if not (result & 0x81):
|
|
102
|
+
return (result >> 1), pos + 1
|
|
103
|
+
if not (result & 0x80):
|
|
104
|
+
return (result >> 1) ^ (~0), pos + 1
|
|
105
|
+
|
|
106
|
+
result &= 0x7f
|
|
107
|
+
pos += 1
|
|
108
|
+
shift = 7
|
|
109
|
+
while 1:
|
|
110
|
+
b = buffer[pos]
|
|
111
|
+
result |= ((b & 0x7f) << shift)
|
|
112
|
+
pos += 1
|
|
113
|
+
if not (b & 0x80):
|
|
114
|
+
return ((result >> 1) ^ -(result & 1), pos)
|
|
115
|
+
shift += 7
|
|
116
|
+
if shift >= 64:
|
|
117
|
+
raise ValueError("Out of int64 range")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
_crc32c = crc32c_py
|
|
121
|
+
if crc32c_c is not None:
|
|
122
|
+
_crc32c = crc32c_c
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def calc_crc32c(memview, _crc32c=_crc32c):
|
|
126
|
+
""" Calculate CRC-32C (Castagnoli) checksum over a memoryview of data
|
|
127
|
+
"""
|
|
128
|
+
return _crc32c(memview)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def calc_crc32(memview):
|
|
132
|
+
""" Calculate simple CRC-32 checksum over a memoryview of data
|
|
133
|
+
"""
|
|
134
|
+
crc = binascii.crc32(memview) & 0xffffffff
|
|
135
|
+
return crc
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import List, Tuple, Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Serializer(ABC):
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def serialize(self, topic: str, headers: List[Tuple[str, bytes]], data: Any):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
def close(self):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Deserializer(ABC):
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def deserialize(self, topic: str, headers: List[Tuple[str, bytes]], data: bytes):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
def close(self):
|
|
20
|
+
pass
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from .abstract import Serializer, Deserializer
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DefaultSerializer(Serializer, Deserializer):
|
|
5
|
+
def __init__(self, encoding='utf-8'):
|
|
6
|
+
self.encoding = encoding
|
|
7
|
+
|
|
8
|
+
def serialize(self, topic, headers, data):
|
|
9
|
+
if type(data) in (bytes, bytearray, memoryview, type(None)):
|
|
10
|
+
return data
|
|
11
|
+
return data.encode(self.encoding)
|
|
12
|
+
|
|
13
|
+
def deserialize(self, topic, headers, data):
|
|
14
|
+
if data is None:
|
|
15
|
+
return None
|
|
16
|
+
return data.decode(self.encoding)
|
kafka/serializer/json.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from .abstract import Serializer, Deserializer
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class JsonSerializer(Serializer, Deserializer):
|
|
7
|
+
def serialize(self, topic, headers, data):
|
|
8
|
+
if data is None:
|
|
9
|
+
return None
|
|
10
|
+
s = json.dumps(data)
|
|
11
|
+
return super().serialize(topic, headers, s)
|
|
12
|
+
|
|
13
|
+
def deserialize(self, topic, headers, data):
|
|
14
|
+
if data is None:
|
|
15
|
+
return None
|
|
16
|
+
s = super().deserialize(topic, headers, data)
|
|
17
|
+
return json.loads(s)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .abstract import Deserializer, Serializer
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DeserializeWrapper(Deserializer):
|
|
5
|
+
def __init__(self, fn):
|
|
6
|
+
self.fn = fn
|
|
7
|
+
|
|
8
|
+
def deserialize(self, topic, headers, data):
|
|
9
|
+
if self.fn is None:
|
|
10
|
+
return data
|
|
11
|
+
return self.fn(data)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SerializeWrapper(Serializer):
|
|
15
|
+
def __init__(self, fn):
|
|
16
|
+
self.fn = fn
|
|
17
|
+
|
|
18
|
+
def serialize(self, topic, headers, data):
|
|
19
|
+
if self.fn is None:
|
|
20
|
+
return data
|
|
21
|
+
return self.fn(data)
|
kafka/structs.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
""" Other useful structs """
|
|
2
|
+
|
|
3
|
+
from collections import namedtuple
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
TopicPartition = namedtuple("TopicPartition",
|
|
7
|
+
["topic", "partition"])
|
|
8
|
+
TopicPartition.__doc__ = """A topic and partition tuple
|
|
9
|
+
|
|
10
|
+
Keyword Arguments:
|
|
11
|
+
topic (str): A topic name
|
|
12
|
+
partition (int): A partition id
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
TopicPartitionReplica = namedtuple("TopicPartitionReplica",
|
|
17
|
+
["topic", "partition", "broker_id"])
|
|
18
|
+
TopicPartitionReplica.__doc__ = """A topic / partition / broker replica tuple
|
|
19
|
+
|
|
20
|
+
Keyword Arguments:
|
|
21
|
+
topic (str): A topic name
|
|
22
|
+
partition (int): A partition id
|
|
23
|
+
broker_id (int): The node_id of the broker hosting the replica
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
OffsetAndMetadata = namedtuple("OffsetAndMetadata",
|
|
28
|
+
["offset", "metadata", "leader_epoch"], defaults=[None, '', -1])
|
|
29
|
+
OffsetAndMetadata.__doc__ = """Container for committed group offset data.
|
|
30
|
+
|
|
31
|
+
The Kafka offset commit API allows users to provide additional metadata
|
|
32
|
+
(in the form of a string) when an offset is committed. This can be useful
|
|
33
|
+
(for example) to store information about which node made the commit,
|
|
34
|
+
what time the commit was made, etc.
|
|
35
|
+
|
|
36
|
+
Keyword Arguments:
|
|
37
|
+
offset (int): The offset to be committed
|
|
38
|
+
metadata (str): Non-null metadata
|
|
39
|
+
leader_epoch (int): The last known epoch from the leader / broker
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
OffsetAndTimestamp = namedtuple("OffsetAndTimestamp",
|
|
44
|
+
["offset", "timestamp", "leader_epoch"])
|
|
45
|
+
OffsetAndTimestamp.__doc__ = """An offset and timestamp tuple
|
|
46
|
+
|
|
47
|
+
Keyword Arguments:
|
|
48
|
+
offset (int): An offset
|
|
49
|
+
timestamp (int): The timestamp associated to the offset
|
|
50
|
+
leader_epoch (int): The last known epoch from the leader / broker
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
ConsumerGroupMetadata = namedtuple("ConsumerGroupMetadata",
|
|
55
|
+
["group_id", "generation_id", "member_id", "group_instance_id"],
|
|
56
|
+
defaults=[-1, '', None])
|
|
57
|
+
ConsumerGroupMetadata.__doc__ = """A snapshot of a consumer's group membership (KIP-447).
|
|
58
|
+
|
|
59
|
+
Passed to KafkaProducer.send_offsets_to_transaction() so the broker can fence
|
|
60
|
+
stale consumer instances when committing offsets inside a transaction. The
|
|
61
|
+
broker uses member_id + generation_id + group_instance_id to verify the
|
|
62
|
+
producer is acting on behalf of the current group generation.
|
|
63
|
+
|
|
64
|
+
Keyword Arguments:
|
|
65
|
+
group_id (str): The consumer group id.
|
|
66
|
+
generation_id (int): The current generation id (-1 if unjoined).
|
|
67
|
+
member_id (str): The current member id ('' if unjoined).
|
|
68
|
+
group_instance_id (str): The static membership instance id, or None.
|
|
69
|
+
"""
|