Packages

kafka_ex_tc

0.12.1-11-debug
0.13.0 0.12.1 0.12.1-51-1 0.12.1-50-3 0.12.1-50-2 0.12.1-50-1 0.12.1-49-2 0.12.1-49-1 0.12.1-49-0 0.12.1-48-2 0.12.1-48-1 0.12.1-47-1 0.12.1-46-2 0.12.1-45-2 0.12.1-45-1 0.12.1-44-1 0.12.1-43-1 0.12.1-42-8 0.12.1-42-6 0.12.1-42-5 0.12.1-42-4 0.12.1-42-1 0.12.1-41-2 0.12.1-41-1 0.12.1-40-9 0.12.1-40-8 0.12.1-40-7 0.12.1-40-6 0.12.1-40-5 0.12.1-40-4 0.12.1-40-3 0.12.1-40-2 0.12.1-40-10 0.12.1-40-1 0.12.1-39-2 0.12.1-39-1 0.12.1-36-3 0.12.1-36-2 0.12.1-36-1 0.12.1-34-b 0.12.1-34-a 0.12.1-33-1 0.12.1-32-a1 0.12.1-29-s-3 0.12.1-29-s-2 0.12.1-29-s-1 0.12.1-28-rumble-1 0.12.1-27-2 0.12.1-27-1 0.12.1-26-rumble-2 0.12.1-26-rumble-1 0.12.1-26-dev-1 0.12.1-26-dev.1 0.12.1-26-3 0.12.1-26-2 0.12.1-26-1 0.12.1-25-s-8 0.12.1-25-s-7 0.12.1-25-s-6 0.12.1-25-s-5 0.12.1-25-s-4 0.12.1-25-s-3 0.12.1-25-s-2 0.12.1-25-s-1 0.12.1-25-dev-22 0.12.1-25-dev 0.12.1-24-2 0.12.1-24-1 0.12.1-22-poc-b-7 0.12.1-20-poc-b-6 0.12.1-20-poc-b-5 0.12.1-20-poc-b-4 0.12.1-20-poc-b-3 0.12.1-19-poc-b-3 0.12.1-19-poc-b-2 0.12.1-19-poc-b-1 0.12.1-19-poc-7 0.12.1-19-poc-6 0.12.1-19-poc-4 0.12.1-19-poc-3 0.12.1-19-poc-2 0.12.1-19-poc-1 0.12.1-19-poc 0.12.1-11-debug-1 0.12.1-11-debug 0.12.1-39 0.12.1-38.a 0.12.1-38 0.12.1-37.c 0.12.1-37.b 0.12.1-37.a 0.12.1-37.1 0.12.1-37 0.12.1-35.b 0.12.1-35.a 0.12.1-34 0.12.1-33 0.12.1-32 0.12.1-31 0.12.1-30 0.12.1-29 0.12.1-28 0.12.1-27 0.12.1-26 0.12.1-25 0.12.1-24 0.12.1-23 0.12.1-22.1 0.12.1-22 0.12.1-21 0.12.1-20 0.12.1-19 0.12.1-18 0.12.1-17 0.12.1-16 0.12.1-15 0.12.1-14 0.12.1-13 0.12.1-12 0.12.1-11 0.12.1-10 0.12.1-9 0.12.1-8 0.12.1-7 0.12.1-6 0.12.1-5 0.12.1-4 0.12.1-3 0.12.1-2 0.12.1-1

Kafka client for Elixir/Erlang.

Current section

Files

Jump to
kafka_ex_tc lib kafka_ex protocol fetch.ex
Raw

lib/kafka_ex/protocol/fetch.ex

defmodule KafkaEx.Protocol.Fetch do
alias KafkaEx.Protocol
alias KafkaEx.Compression
import KafkaEx.Protocol.Common
@moduledoc """
Implementation of the Kafka Fetch request and response APIs
"""
defmodule Request do
@moduledoc false
defstruct correlation_id: nil,
client_id: nil,
topic: nil,
partition: nil,
offset: nil,
wait_time: nil,
min_bytes: nil,
max_bytes: nil,
auto_commit: nil,
# NOTE api_version only used in new client
api_version: 0,
# NOTE offset_commit_api_version only used in new client with auto_commit
offset_commit_api_version: 0
@type t :: %Request{
correlation_id: integer,
client_id: binary,
topic: binary,
partition: integer,
offset: integer,
wait_time: integer,
min_bytes: integer,
max_bytes: integer,
api_version: integer,
offset_commit_api_version: integer
}
end
defmodule Response do
@moduledoc false
defstruct topic: nil, partitions: []
@type t :: %Response{topic: binary, partitions: list}
@spec partition_messages(list, binary, integer) :: map
def partition_messages(responses, topic, partition) do
response = Enum.find(responses, &(&1.topic == topic)) || %Response{}
Enum.find(response.partitions, &(&1.partition == partition))
end
end
defmodule Message do
@moduledoc false
defstruct attributes: 0,
crc: nil,
offset: nil,
key: nil,
value: nil,
topic: nil,
partition: nil,
timestamp: nil
@type t :: %Message{
attributes: integer,
crc: integer,
offset: integer,
key: binary,
value: binary,
topic: binary,
partition: integer,
# timestamp supported for `kafka_version: "kayrock"` ONLY
timestamp: integer
}
end
@spec create_request(Request.t()) :: binary
def create_request(fetch_request) do
KafkaEx.Protocol.create_request(
:fetch,
fetch_request.correlation_id,
fetch_request.client_id
) <>
<<
-1::32-signed,
fetch_request.wait_time::32-signed,
fetch_request.min_bytes::32-signed,
1::32-signed,
byte_size(fetch_request.topic)::16-signed,
fetch_request.topic::binary,
1::32-signed,
fetch_request.partition::32-signed,
fetch_request.offset::64,
fetch_request.max_bytes::32
>>
end
def parse_response(
<<_correlation_id::32-signed, topics_size::32-signed, rest::binary>>
) do
parse_topics(topics_size, rest, __MODULE__)
end
def parse_partitions(0, rest, partitions, _topic), do: {partitions, rest}
def parse_partitions(
partitions_size,
<<partition::32-signed, error_code::16-signed,
hw_mark_offset::64-signed, msg_set_size::32-signed,
msg_set_data::size(msg_set_size)-binary, rest::binary>>,
partitions,
topic
) do
{:ok, message_set, last_offset} =
parse_message_set([], msg_set_data, topic, partition)
parse_partitions(
partitions_size - 1,
rest,
[
%{
partition: partition,
error_code: Protocol.error(error_code),
hw_mark_offset: hw_mark_offset,
message_set: message_set,
last_offset: last_offset
}
| partitions
],
topic
)
end
defp parse_message_set([], <<>>, _topic, _partition) do
{:ok, [], nil}
end
defp parse_message_set(
list,
<<offset::64, msg_size::32, msg_data::size(msg_size)-binary,
rest::binary>>,
topic,
partition
) do
{:ok, message} =
parse_message(
%Message{offset: offset, topic: topic, partition: partition},
msg_data
)
parse_message_set(append_messages(message, list), rest, topic, partition)
end
defp parse_message_set([last | _] = list, _, _topic, _partition) do
{:ok, Enum.reverse(list), last.offset}
end
defp parse_message_set(
_,
<<offset::64, msg_size::32, partial_message_data::binary>>,
_topic,
_partition
)
when byte_size(partial_message_data) < msg_size do
raise RuntimeError,
"Insufficient data fetched at offset #{offset}. Message size is #{
msg_size
} but only received #{byte_size(partial_message_data)} bytes. Try increasing max_bytes."
end
# handles the single message case and the batch (compression) case
defp append_messages([], list) do
list
end
defp append_messages([message | messages], list) do
append_messages(messages, [message | list])
end
defp append_messages(message, list) do
[message | list]
end
defp parse_message(
%Message{} = message,
<<crc::32, _magic::8, attributes::8, rest::binary>>
) do
maybe_decompress(%{message | crc: crc, attributes: attributes}, rest)
end
defp maybe_decompress(%Message{attributes: 0} = message, rest) do
parse_key(message, rest)
end
defp maybe_decompress(
%Message{attributes: attributes, topic: topic, partition: partition},
rest
) do
<<-1::32-signed, value_size::32, value::size(value_size)-binary>> = rest
decompressed = Compression.decompress(attributes, value)
{:ok, msg_set, _offset} =
parse_message_set([], decompressed, topic, partition)
{:ok, msg_set}
end
defp parse_key(%Message{} = message, <<-1::32-signed, rest::binary>>) do
parse_value(%{message | key: nil}, rest)
end
defp parse_key(
%Message{} = message,
<<key_size::32, key::size(key_size)-binary, rest::binary>>
) do
parse_value(%{message | key: key}, rest)
end
defp parse_value(%Message{} = message, <<-1::32-signed>>) do
{:ok, %{message | value: nil}}
end
defp parse_value(
%Message{} = message,
<<value_size::32, value::size(value_size)-binary>>
) do
{:ok, %{message | value: value}}
end
end