1use crate::api::produce::RecordBatchHeader;
2use crate::codec::{DecodeLimits, Decoder, Encoder};
3use crate::error::{Error, Result};
4use crate::header::RequestHeader;
5use crate::record_batch::{decompress_record_batch_records_with_limit, RecordBatchCompression};
6
7pub const API_KEY: i16 = 1;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct FetchRequestV2 {
11 pub correlation_id: i32,
12 pub client_id: Option<String>,
13 pub replica_id: i32,
14 pub max_wait_ms: i32,
15 pub min_bytes: i32,
16 pub topics: Vec<FetchTopicV2>,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct FetchRequestV4 {
21 pub correlation_id: i32,
22 pub client_id: Option<String>,
23 pub replica_id: i32,
24 pub max_wait_ms: i32,
25 pub min_bytes: i32,
26 pub max_bytes: i32,
27 pub isolation_level: i8,
28 pub topics: Vec<FetchTopicV2>,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct FetchRequestV11 {
37 pub correlation_id: i32,
38 pub client_id: Option<String>,
39 pub replica_id: i32,
40 pub max_wait_ms: i32,
41 pub min_bytes: i32,
42 pub max_bytes: i32,
43 pub isolation_level: i8,
44 pub session_id: i32,
45 pub session_epoch: i32,
46 pub topics: Vec<FetchTopicV11>,
47 pub forgotten_topics: Vec<FetchForgottenTopicV11>,
48 pub rack_id: String,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct FetchRequestV12 {
54 pub correlation_id: i32,
55 pub client_id: Option<String>,
56 pub replica_id: i32,
57 pub max_wait_ms: i32,
58 pub min_bytes: i32,
59 pub max_bytes: i32,
60 pub isolation_level: i8,
61 pub session_id: i32,
62 pub session_epoch: i32,
63 pub topics: Vec<FetchTopicV12>,
64 pub forgotten_topics: Vec<FetchForgottenTopicV12>,
65 pub rack_id: String,
66}
67
68impl FetchRequestV12 {
69 pub fn encode(&self) -> Result<Vec<u8>> {
70 let mut encoder = Encoder::new();
71 RequestHeader {
72 api_key: API_KEY,
73 api_version: 12,
74 correlation_id: self.correlation_id,
75 client_id: self.client_id.clone(),
76 }
77 .encode_v2(&mut encoder)?;
78 encoder.write_i32(self.replica_id);
79 encoder.write_i32(self.max_wait_ms);
80 encoder.write_i32(self.min_bytes);
81 encoder.write_i32(self.max_bytes);
82 encoder.write_i8(self.isolation_level);
83 encoder.write_i32(self.session_id);
84 encoder.write_i32(self.session_epoch);
85 encoder.write_compact_array(Some(self.topics.as_slice()), |encoder, topic| {
86 topic.encode(encoder)
87 })?;
88 encoder.write_compact_array(Some(self.forgotten_topics.as_slice()), |encoder, topic| {
89 topic.encode(encoder)
90 })?;
91 encoder.write_compact_string(&self.rack_id)?;
92 encoder.write_empty_tagged_fields();
93 Ok(encoder.into_bytes())
94 }
95}
96
97#[derive(Debug, Clone, PartialEq, Eq)]
98pub struct FetchTopicV12 {
99 pub name: String,
100 pub partitions: Vec<FetchPartitionV12>,
101}
102
103impl FetchTopicV12 {
104 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
105 encoder.write_compact_string(&self.name)?;
106 encoder.write_compact_array(Some(self.partitions.as_slice()), |encoder, partition| {
107 partition.encode(encoder)
108 })?;
109 encoder.write_empty_tagged_fields();
110 Ok(())
111 }
112}
113
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct FetchPartitionV12 {
116 pub partition_index: i32,
117 pub current_leader_epoch: i32,
118 pub fetch_offset: i64,
119 pub last_fetched_epoch: i32,
120 pub log_start_offset: i64,
121 pub max_bytes: i32,
122}
123
124impl FetchPartitionV12 {
125 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
126 encoder.write_i32(self.partition_index);
127 encoder.write_i32(self.current_leader_epoch);
128 encoder.write_i64(self.fetch_offset);
129 encoder.write_i32(self.last_fetched_epoch);
130 encoder.write_i64(self.log_start_offset);
131 encoder.write_i32(self.max_bytes);
132 encoder.write_empty_tagged_fields();
133 Ok(())
134 }
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
138pub struct FetchForgottenTopicV12 {
139 pub name: String,
140 pub partitions: Vec<i32>,
141}
142
143impl FetchForgottenTopicV12 {
144 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
145 encoder.write_compact_string(&self.name)?;
146 encoder.write_compact_array(Some(self.partitions.as_slice()), |encoder, partition| {
147 encoder.write_i32(*partition);
148 Ok(())
149 })?;
150 encoder.write_empty_tagged_fields();
151 Ok(())
152 }
153}
154
155impl FetchRequestV11 {
156 pub fn encode(&self) -> Result<Vec<u8>> {
157 let mut encoder = Encoder::new();
158 RequestHeader {
159 api_key: API_KEY,
160 api_version: 11,
161 correlation_id: self.correlation_id,
162 client_id: self.client_id.clone(),
163 }
164 .encode_v1(&mut encoder)?;
165 encoder.write_i32(self.replica_id);
166 encoder.write_i32(self.max_wait_ms);
167 encoder.write_i32(self.min_bytes);
168 encoder.write_i32(self.max_bytes);
169 encoder.write_i8(self.isolation_level);
170 encoder.write_i32(self.session_id);
171 encoder.write_i32(self.session_epoch);
172 encoder.write_array(Some(self.topics.as_slice()), |encoder, topic| {
173 topic.encode(encoder)
174 })?;
175 encoder.write_array(Some(self.forgotten_topics.as_slice()), |encoder, topic| {
176 topic.encode(encoder)
177 })?;
178 encoder.write_string(&self.rack_id)?;
179 Ok(encoder.into_bytes())
180 }
181}
182
183#[derive(Debug, Clone, PartialEq, Eq)]
184pub struct FetchTopicV11 {
185 pub name: String,
186 pub partitions: Vec<FetchPartitionV11>,
187}
188
189impl FetchTopicV11 {
190 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
191 encoder.write_string(&self.name)?;
192 encoder.write_array(Some(self.partitions.as_slice()), |encoder, partition| {
193 partition.encode(encoder)
194 })
195 }
196}
197
198#[derive(Debug, Clone, PartialEq, Eq)]
199pub struct FetchPartitionV11 {
200 pub partition_index: i32,
201 pub current_leader_epoch: i32,
202 pub fetch_offset: i64,
203 pub log_start_offset: i64,
204 pub max_bytes: i32,
205}
206
207impl FetchPartitionV11 {
208 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
209 encoder.write_i32(self.partition_index);
210 encoder.write_i32(self.current_leader_epoch);
211 encoder.write_i64(self.fetch_offset);
212 encoder.write_i64(self.log_start_offset);
213 encoder.write_i32(self.max_bytes);
214 Ok(())
215 }
216}
217
218#[derive(Debug, Clone, PartialEq, Eq)]
219pub struct FetchForgottenTopicV11 {
220 pub name: String,
221 pub partitions: Vec<i32>,
222}
223
224impl FetchForgottenTopicV11 {
225 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
226 encoder.write_string(&self.name)?;
227 encoder.write_array(Some(self.partitions.as_slice()), |encoder, partition| {
228 encoder.write_i32(*partition);
229 Ok(())
230 })
231 }
232}
233
234impl FetchRequestV4 {
235 pub fn encode(&self) -> Result<Vec<u8>> {
236 let mut encoder = Encoder::new();
237 RequestHeader {
238 api_key: API_KEY,
239 api_version: 4,
240 correlation_id: self.correlation_id,
241 client_id: self.client_id.clone(),
242 }
243 .encode_v1(&mut encoder)?;
244 encoder.write_i32(self.replica_id);
245 encoder.write_i32(self.max_wait_ms);
246 encoder.write_i32(self.min_bytes);
247 encoder.write_i32(self.max_bytes);
248 encoder.write_i8(self.isolation_level);
249 encoder.write_array(Some(self.topics.as_slice()), |encoder, topic| {
250 topic.encode(encoder)
251 })?;
252 Ok(encoder.into_bytes())
253 }
254}
255
256impl FetchRequestV2 {
257 pub fn encode(&self) -> Result<Vec<u8>> {
258 let mut encoder = Encoder::new();
259 RequestHeader {
260 api_key: API_KEY,
261 api_version: 2,
262 correlation_id: self.correlation_id,
263 client_id: self.client_id.clone(),
264 }
265 .encode_v1(&mut encoder)?;
266 encoder.write_i32(self.replica_id);
267 encoder.write_i32(self.max_wait_ms);
268 encoder.write_i32(self.min_bytes);
269 encoder.write_array(Some(self.topics.as_slice()), |encoder, topic| {
270 topic.encode(encoder)
271 })?;
272 Ok(encoder.into_bytes())
273 }
274}
275
276#[derive(Debug, Clone, PartialEq, Eq)]
277pub struct FetchTopicV2 {
278 pub name: String,
279 pub partitions: Vec<FetchPartitionV2>,
280}
281
282impl FetchTopicV2 {
283 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
284 encoder.write_string(&self.name)?;
285 encoder.write_array(Some(self.partitions.as_slice()), |encoder, partition| {
286 partition.encode(encoder)
287 })
288 }
289}
290
291#[derive(Debug, Clone, PartialEq, Eq)]
292pub struct FetchPartitionV2 {
293 pub partition_index: i32,
294 pub fetch_offset: i64,
295 pub max_bytes: i32,
296}
297
298impl FetchPartitionV2 {
299 fn encode(&self, encoder: &mut Encoder) -> Result<()> {
300 encoder.write_i32(self.partition_index);
301 encoder.write_i64(self.fetch_offset);
302 encoder.write_i32(self.max_bytes);
303 Ok(())
304 }
305}
306
307#[derive(Debug, Clone, PartialEq, Eq)]
308pub struct FetchResponseV2 {
309 pub throttle_time_ms: i32,
310 pub responses: Vec<FetchTopicResponseV2>,
311}
312
313#[derive(Debug, Clone, PartialEq, Eq)]
314pub struct FetchResponseV4 {
315 pub throttle_time_ms: i32,
316 pub responses: Vec<FetchTopicResponseV4>,
317}
318
319#[derive(Debug, Clone, PartialEq, Eq)]
321pub struct FetchResponseV11 {
322 pub throttle_time_ms: i32,
323 pub error_code: i16,
324 pub session_id: i32,
325 pub responses: Vec<FetchTopicResponseV11>,
326}
327
328#[derive(Debug, Clone, PartialEq, Eq)]
330pub struct FetchResponseV12 {
331 pub throttle_time_ms: i32,
332 pub error_code: i16,
333 pub session_id: i32,
334 pub responses: Vec<FetchTopicResponseV12>,
335}
336
337impl FetchResponseV12 {
338 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
339 Ok(Self {
340 throttle_time_ms: decoder.read_i32()?,
341 error_code: decoder.read_i16()?,
342 session_id: decoder.read_i32()?,
343 responses: decoder
344 .read_compact_array("fetch responses", FetchTopicResponseV12::decode)?
345 .unwrap_or_default(),
346 })
347 .and_then(|response| {
348 decoder.read_tagged_fields()?;
349 Ok(response)
350 })
351 }
352}
353
354#[derive(Debug, Clone, PartialEq, Eq)]
355pub struct FetchTopicResponseV12 {
356 pub name: String,
357 pub partitions: Vec<FetchPartitionResponseV12>,
358}
359
360impl FetchTopicResponseV12 {
361 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
362 let name = decoder.read_compact_string()?;
363 let partitions = decoder
364 .read_compact_array(
365 "fetch partition responses",
366 FetchPartitionResponseV12::decode,
367 )?
368 .unwrap_or_default();
369 decoder.read_tagged_fields()?;
370 Ok(Self { name, partitions })
371 }
372}
373
374#[derive(Debug, Clone, PartialEq, Eq)]
375pub struct FetchPartitionResponseV12 {
376 pub partition_index: i32,
377 pub error_code: i16,
378 pub high_watermark: i64,
379 pub last_stable_offset: i64,
380 pub log_start_offset: i64,
381 pub aborted_transactions: Vec<AbortedTransactionV12>,
382 pub preferred_read_replica: i32,
383 pub records: Vec<MessageSetRecord>,
384}
385
386impl FetchPartitionResponseV12 {
387 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
388 let limits = decoder.limits();
389 let partition_index = decoder.read_i32()?;
390 let error_code = decoder.read_i16()?;
391 let high_watermark = decoder.read_i64()?;
392 let last_stable_offset = decoder.read_i64()?;
393 let log_start_offset = decoder.read_i64()?;
394 let aborted_transactions = decoder
395 .read_compact_array("aborted transactions", AbortedTransactionV12::decode)?
396 .unwrap_or_default();
397 let preferred_read_replica = decoder.read_i32()?;
398 let records = decoder
399 .read_compact_nullable_bytes()?
400 .map(|bytes| decode_message_set(&bytes, limits))
401 .transpose()?
402 .unwrap_or_default();
403 decoder.read_tagged_fields()?;
404 Ok(Self {
405 partition_index,
406 error_code,
407 high_watermark,
408 last_stable_offset,
409 log_start_offset,
410 aborted_transactions,
411 preferred_read_replica,
412 records,
413 })
414 }
415}
416
417#[derive(Debug, Clone, PartialEq, Eq)]
418pub struct AbortedTransactionV12 {
419 pub producer_id: i64,
420 pub first_offset: i64,
421}
422
423impl AbortedTransactionV12 {
424 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
425 let producer_id = decoder.read_i64()?;
426 let first_offset = decoder.read_i64()?;
427 decoder.read_tagged_fields()?;
428 Ok(Self {
429 producer_id,
430 first_offset,
431 })
432 }
433}
434
435impl FetchResponseV11 {
436 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
437 Ok(Self {
438 throttle_time_ms: decoder.read_i32()?,
439 error_code: decoder.read_i16()?,
440 session_id: decoder.read_i32()?,
441 responses: decoder
442 .read_array("fetch responses", FetchTopicResponseV11::decode)?
443 .unwrap_or_default(),
444 })
445 }
446}
447
448#[derive(Debug, Clone, PartialEq, Eq)]
449pub struct FetchTopicResponseV11 {
450 pub name: String,
451 pub partitions: Vec<FetchPartitionResponseV11>,
452}
453
454impl FetchTopicResponseV11 {
455 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
456 Ok(Self {
457 name: decoder.read_string()?,
458 partitions: decoder
459 .read_array(
460 "fetch partition responses",
461 FetchPartitionResponseV11::decode,
462 )?
463 .unwrap_or_default(),
464 })
465 }
466}
467
468#[derive(Debug, Clone, PartialEq, Eq)]
469pub struct FetchPartitionResponseV11 {
470 pub partition_index: i32,
471 pub error_code: i16,
472 pub high_watermark: i64,
473 pub last_stable_offset: i64,
474 pub log_start_offset: i64,
475 pub aborted_transactions: Vec<AbortedTransactionV4>,
476 pub preferred_read_replica: i32,
477 pub records: Vec<MessageSetRecord>,
478}
479
480impl FetchPartitionResponseV11 {
481 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
482 let limits = decoder.limits();
483 Ok(Self {
484 partition_index: decoder.read_i32()?,
485 error_code: decoder.read_i16()?,
486 high_watermark: decoder.read_i64()?,
487 last_stable_offset: decoder.read_i64()?,
488 log_start_offset: decoder.read_i64()?,
489 aborted_transactions: decoder
490 .read_array("aborted transactions", AbortedTransactionV4::decode)?
491 .unwrap_or_default(),
492 preferred_read_replica: decoder.read_i32()?,
493 records: decode_message_set(&decoder.read_bytes()?, limits)?,
494 })
495 }
496}
497
498impl FetchResponseV4 {
499 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
500 Ok(Self {
501 throttle_time_ms: decoder.read_i32()?,
502 responses: decoder
503 .read_array("fetch responses", FetchTopicResponseV4::decode)?
504 .unwrap_or_default(),
505 })
506 }
507}
508
509#[derive(Debug, Clone, PartialEq, Eq)]
510pub struct FetchTopicResponseV4 {
511 pub name: String,
512 pub partitions: Vec<FetchPartitionResponseV4>,
513}
514
515impl FetchTopicResponseV4 {
516 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
517 Ok(Self {
518 name: decoder.read_string()?,
519 partitions: decoder
520 .read_array(
521 "fetch partition responses",
522 FetchPartitionResponseV4::decode,
523 )?
524 .unwrap_or_default(),
525 })
526 }
527}
528
529#[derive(Debug, Clone, PartialEq, Eq)]
530pub struct FetchPartitionResponseV4 {
531 pub partition_index: i32,
532 pub error_code: i16,
533 pub high_watermark: i64,
534 pub last_stable_offset: i64,
535 pub aborted_transactions: Vec<AbortedTransactionV4>,
536 pub records: Vec<MessageSetRecord>,
537}
538
539impl FetchPartitionResponseV4 {
540 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
541 let limits = decoder.limits();
542 Ok(Self {
543 partition_index: decoder.read_i32()?,
544 error_code: decoder.read_i16()?,
545 high_watermark: decoder.read_i64()?,
546 last_stable_offset: decoder.read_i64()?,
547 aborted_transactions: decoder
548 .read_array("aborted transactions", AbortedTransactionV4::decode)?
549 .unwrap_or_default(),
550 records: decode_message_set(&decoder.read_bytes()?, limits)?,
551 })
552 }
553}
554
555#[derive(Debug, Clone, PartialEq, Eq)]
556pub struct AbortedTransactionV4 {
557 pub producer_id: i64,
558 pub first_offset: i64,
559}
560
561impl AbortedTransactionV4 {
562 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
563 Ok(Self {
564 producer_id: decoder.read_i64()?,
565 first_offset: decoder.read_i64()?,
566 })
567 }
568}
569
570impl FetchResponseV2 {
571 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
572 Ok(Self {
573 throttle_time_ms: decoder.read_i32()?,
574 responses: decoder
575 .read_array("fetch responses", FetchTopicResponseV2::decode)?
576 .unwrap_or_default(),
577 })
578 }
579}
580
581#[derive(Debug, Clone, PartialEq, Eq)]
582pub struct FetchTopicResponseV2 {
583 pub name: String,
584 pub partitions: Vec<FetchPartitionResponseV2>,
585}
586
587impl FetchTopicResponseV2 {
588 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
589 Ok(Self {
590 name: decoder.read_string()?,
591 partitions: decoder
592 .read_array(
593 "fetch partition responses",
594 FetchPartitionResponseV2::decode,
595 )?
596 .unwrap_or_default(),
597 })
598 }
599}
600
601#[derive(Debug, Clone, PartialEq, Eq)]
602pub struct FetchPartitionResponseV2 {
603 pub partition_index: i32,
604 pub error_code: i16,
605 pub high_watermark: i64,
606 pub records: Vec<MessageSetRecord>,
607}
608
609impl FetchPartitionResponseV2 {
610 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
611 let limits = decoder.limits();
612 Ok(Self {
613 partition_index: decoder.read_i32()?,
614 error_code: decoder.read_i16()?,
615 high_watermark: decoder.read_i64()?,
616 records: decode_message_set(&decoder.read_bytes()?, limits)?,
617 })
618 }
619}
620
621#[derive(Debug, Clone, PartialEq, Eq)]
622pub struct MessageSetRecord {
623 pub offset: i64,
624 pub timestamp_ms: i64,
625 pub key: Option<Vec<u8>>,
626 pub value: Option<Vec<u8>>,
627 pub headers: Vec<RecordBatchHeader>,
628 pub producer_id: Option<i64>,
629 pub transactional: bool,
630 pub control: bool,
631}
632
633fn decode_message_set(bytes: &[u8], limits: DecodeLimits) -> Result<Vec<MessageSetRecord>> {
634 let mut decoder = Decoder::with_limits(bytes, limits);
635 let mut records = Vec::new();
636
637 while decoder.remaining() >= 12 {
638 let offset = decoder.read_i64()?;
639 let message_size = decoder.read_i32()?;
640 if message_size < 0 {
641 return Err(Error::NegativeLength {
642 kind: "message",
643 length: message_size,
644 });
645 }
646 let message_size =
647 usize::try_from(message_size).map_err(|_| Error::LengthOverflow("message"))?;
648 if decoder.remaining() < message_size {
650 break;
651 }
652 let message = decoder.read_exact(message_size)?;
653 let decoded = decode_message_or_batch(offset, message, limits)?;
654 let total = records
655 .len()
656 .checked_add(decoded.len())
657 .ok_or(Error::LengthOverflow("fetch records"))?;
658 decoder.ensure_collection_length("fetch records", total)?;
659 records.extend(decoded);
660 }
661
662 Ok(records)
663}
664
665fn decode_message_or_batch(
666 offset: i64,
667 bytes: &[u8],
668 limits: DecodeLimits,
669) -> Result<Vec<MessageSetRecord>> {
670 match bytes.get(4).copied() {
671 Some(2) => decode_record_batch(offset, bytes, limits),
672 _ => Ok(vec![decode_message(offset, bytes, limits)?]),
673 }
674}
675
676fn decode_message(offset: i64, bytes: &[u8], limits: DecodeLimits) -> Result<MessageSetRecord> {
677 let mut decoder = Decoder::with_limits(bytes, limits);
678 let _crc = decoder.read_i32()?;
679 let magic = decoder.read_i8()?;
680 let _attributes = decoder.read_i8()?;
681 let timestamp_ms = match magic {
682 0 => -1,
683 1 => decoder.read_i64()?,
684 _ => {
685 return Err(Error::UnsupportedVersion {
686 kind: "message magic",
687 version: i16::from(magic),
688 })
689 }
690 };
691 let key = decoder.read_nullable_bytes()?;
692 let value = decoder.read_nullable_bytes()?;
693
694 Ok(MessageSetRecord {
695 offset,
696 timestamp_ms,
697 key,
698 value,
699 headers: Vec::new(),
700 producer_id: None,
701 transactional: false,
702 control: false,
703 })
704}
705
706fn decode_record_batch(
707 base_offset: i64,
708 bytes: &[u8],
709 limits: DecodeLimits,
710) -> Result<Vec<MessageSetRecord>> {
711 let mut decoder = Decoder::with_limits(bytes, limits);
712 let _partition_leader_epoch = decoder.read_i32()?;
713 let magic = decoder.read_i8()?;
714 if magic != 2 {
715 return Err(Error::UnsupportedVersion {
716 kind: "record batch magic",
717 version: i16::from(magic),
718 });
719 }
720 let _crc = decoder.read_i32()?;
721 let attributes = decoder.read_i16()?;
722 let compression = RecordBatchCompression::from_attributes(attributes)?;
723 let _last_offset_delta = decoder.read_i32()?;
724 let base_timestamp = decoder.read_i64()?;
725 let _max_timestamp = decoder.read_i64()?;
726 let producer_id = decoder.read_i64()?;
727 let _producer_epoch = decoder.read_i16()?;
728 let _base_sequence = decoder.read_i32()?;
729 let record_count = decoder.read_i32()?;
730 if record_count < 0 {
731 return Err(Error::NegativeLength {
732 kind: "record batch records",
733 length: record_count,
734 });
735 }
736
737 let record_count =
738 usize::try_from(record_count).map_err(|_| Error::LengthOverflow("record batch records"))?;
739 decoder.ensure_collection_length("record batch records", record_count)?;
740 let record_bytes = if compression.is_compressed() {
741 let compressed = decoder.read_exact(decoder.remaining())?;
742 decompress_record_batch_records_with_limit(
743 compression,
744 compressed,
745 limits.max_decompressed_record_bytes(),
746 )?
747 } else {
748 if decoder.remaining() > limits.max_decompressed_record_bytes() {
749 return Err(Error::LimitExceeded {
750 kind: "decompressed record batch bytes",
751 actual: decoder.remaining(),
752 max: limits.max_decompressed_record_bytes(),
753 });
754 }
755 decoder.read_exact(decoder.remaining())?.to_vec()
756 };
757 let mut record_decoder = Decoder::with_limits(&record_bytes, limits);
758 let mut records = Vec::with_capacity(record_count);
759 for _ in 0..record_count {
760 let record_length = record_decoder.read_varint()?;
761 if record_length < 0 {
762 return Err(Error::NegativeLength {
763 kind: "record",
764 length: record_length,
765 });
766 }
767 let record_length =
768 usize::try_from(record_length).map_err(|_| Error::LengthOverflow("record"))?;
769 let record_bytes = record_decoder.read_exact(record_length)?;
770 records.push(decode_record(
771 base_offset,
772 base_timestamp,
773 producer_id,
774 attributes,
775 record_bytes,
776 limits,
777 )?);
778 }
779
780 Ok(records)
781}
782
783fn decode_record(
784 base_offset: i64,
785 base_timestamp: i64,
786 producer_id: i64,
787 batch_attributes: i16,
788 bytes: &[u8],
789 limits: DecodeLimits,
790) -> Result<MessageSetRecord> {
791 let mut decoder = Decoder::with_limits(bytes, limits);
792 let _attributes = decoder.read_i8()?;
793 let timestamp_delta = decoder.read_varlong()?;
794 let offset_delta = decoder.read_varint()?;
795 let key = decoder.read_varint_nullable_bytes()?;
796 let value = decoder.read_varint_nullable_bytes()?;
797 let header_count = decoder.read_varint()?;
798 if header_count < 0 {
799 return Err(Error::NegativeLength {
800 kind: "record headers",
801 length: header_count,
802 });
803 }
804 let header_count =
805 usize::try_from(header_count).map_err(|_| Error::LengthOverflow("record headers"))?;
806 decoder.ensure_collection_length("record headers", header_count)?;
807 let mut headers = Vec::with_capacity(header_count);
808 for _ in 0..header_count {
809 let header_key =
810 String::from_utf8(decoder.read_varint_bytes()?).map_err(|_| Error::InvalidUtf8)?;
811 let header_value = decoder.read_varint_nullable_bytes()?;
812 headers.push(RecordBatchHeader::new(header_key, header_value));
813 }
814
815 Ok(MessageSetRecord {
816 offset: base_offset.saturating_add(i64::from(offset_delta)),
817 timestamp_ms: base_timestamp.saturating_add(timestamp_delta),
818 key,
819 value,
820 headers,
821 producer_id: (producer_id >= 0).then_some(producer_id),
822 transactional: batch_attributes & 0x10 != 0,
823 control: batch_attributes & 0x20 != 0,
824 })
825}
826
827#[cfg(test)]
828#[allow(clippy::unwrap_used)]
829mod tests {
830 use super::{
831 FetchPartitionV11, FetchPartitionV12, FetchPartitionV2, FetchRequestV11, FetchRequestV12,
832 FetchRequestV2, FetchRequestV4, FetchResponseV11, FetchResponseV12, FetchResponseV2,
833 FetchResponseV4, FetchTopicV11, FetchTopicV12, FetchTopicV2, MessageSetRecord,
834 RecordBatchHeader,
835 };
836 use crate::codec::{Decoder, Encoder};
837
838 #[test]
839 fn encodes_fetch_request_v2() {
840 let request = FetchRequestV2 {
841 correlation_id: 7,
842 client_id: Some("kafrust".to_owned()),
843 replica_id: -1,
844 max_wait_ms: 500,
845 min_bytes: 1,
846 topics: vec![FetchTopicV2 {
847 name: "orders".to_owned(),
848 partitions: vec![FetchPartitionV2 {
849 partition_index: 0,
850 fetch_offset: 42,
851 max_bytes: 1_048_576,
852 }],
853 }],
854 };
855
856 let bytes = request.encode().unwrap();
857 assert_eq!(&bytes[0..4], &[0, 1, 0, 2]);
858 assert!(bytes.len() > 40);
859 }
860
861 #[test]
862 fn encodes_fetch_request_v4() {
863 let request = FetchRequestV4 {
864 correlation_id: 8,
865 client_id: Some("kafrust".to_owned()),
866 replica_id: -1,
867 max_wait_ms: 500,
868 min_bytes: 1,
869 max_bytes: 1_048_576,
870 isolation_level: 0,
871 topics: vec![FetchTopicV2 {
872 name: "orders".to_owned(),
873 partitions: vec![FetchPartitionV2 {
874 partition_index: 0,
875 fetch_offset: 42,
876 max_bytes: 1_048_576,
877 }],
878 }],
879 };
880
881 let bytes = request.encode().unwrap();
882 assert_eq!(&bytes[0..4], &[0, 1, 0, 4]);
883 assert_eq!(&bytes[4..8], &[0, 0, 0, 8]);
884 assert!(bytes.len() > 45);
885 }
886
887 #[test]
888 fn encodes_fetch_request_v11_with_rack_and_fetch_session_fields() {
889 let request = FetchRequestV11 {
890 correlation_id: 9,
891 client_id: Some("kafrust".to_owned()),
892 replica_id: -1,
893 max_wait_ms: 500,
894 min_bytes: 1,
895 max_bytes: 1_048_576,
896 isolation_level: 1,
897 session_id: 0,
898 session_epoch: 0,
899 topics: vec![FetchTopicV11 {
900 name: "orders".to_owned(),
901 partitions: vec![FetchPartitionV11 {
902 partition_index: 0,
903 current_leader_epoch: -1,
904 fetch_offset: 42,
905 log_start_offset: -1,
906 max_bytes: 1_048_576,
907 }],
908 }],
909 forgotten_topics: Vec::new(),
910 rack_id: "rack-a".to_owned(),
911 };
912
913 let bytes = request.encode().unwrap();
914 let mut decoder = Decoder::new(&bytes);
915 assert_eq!(decoder.read_i16().unwrap(), 1);
916 assert_eq!(decoder.read_i16().unwrap(), 11);
917 assert_eq!(decoder.read_i32().unwrap(), 9);
918 assert_eq!(
919 decoder.read_nullable_string().unwrap().as_deref(),
920 Some("kafrust")
921 );
922 assert_eq!(decoder.read_i32().unwrap(), -1);
923 assert_eq!(decoder.read_i32().unwrap(), 500);
924 assert_eq!(decoder.read_i32().unwrap(), 1);
925 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
926 assert_eq!(decoder.read_i8().unwrap(), 1);
927 assert_eq!(decoder.read_i32().unwrap(), 0);
928 assert_eq!(decoder.read_i32().unwrap(), 0);
929 assert_eq!(decoder.read_i32().unwrap(), 1);
930 assert_eq!(decoder.read_string().unwrap(), "orders");
931 assert_eq!(decoder.read_i32().unwrap(), 1);
932 assert_eq!(decoder.read_i32().unwrap(), 0);
933 assert_eq!(decoder.read_i32().unwrap(), -1);
934 assert_eq!(decoder.read_i64().unwrap(), 42);
935 assert_eq!(decoder.read_i64().unwrap(), -1);
936 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
937 assert_eq!(decoder.read_i32().unwrap(), 0);
938 assert_eq!(decoder.read_string().unwrap(), "rack-a");
939 assert!(decoder.is_empty());
940 }
941
942 #[test]
943 fn decodes_fetch_response_v11_with_preferred_read_replica() {
944 let mut bytes = Encoder::new();
945 bytes.write_i32(3);
946 bytes.write_i16(0);
947 bytes.write_i32(17);
948 bytes.write_i32(1);
949 bytes.write_string("orders").unwrap();
950 bytes.write_i32(1);
951 bytes.write_i32(0);
952 bytes.write_i16(0);
953 bytes.write_i64(43);
954 bytes.write_i64(42);
955 bytes.write_i64(40);
956 bytes.write_i32(0);
957 bytes.write_i32(2);
958 bytes.write_bytes(&[]).unwrap();
959
960 let bytes = bytes.into_bytes();
961 let mut decoder = Decoder::new(&bytes);
962 let response = FetchResponseV11::decode_body(&mut decoder).unwrap();
963 let partition = &response.responses[0].partitions[0];
964
965 assert_eq!(response.throttle_time_ms, 3);
966 assert_eq!(response.session_id, 17);
967 assert_eq!(partition.log_start_offset, 40);
968 assert_eq!(partition.preferred_read_replica, 2);
969 assert!(partition.records.is_empty());
970 assert!(decoder.is_empty());
971 }
972
973 #[test]
974 fn encodes_fetch_request_v12_with_flexible_rack_fields() {
975 let request = FetchRequestV12 {
976 correlation_id: 10,
977 client_id: Some("kafrust".to_owned()),
978 replica_id: -1,
979 max_wait_ms: 500,
980 min_bytes: 1,
981 max_bytes: 1_048_576,
982 isolation_level: 1,
983 session_id: 0,
984 session_epoch: 0,
985 topics: vec![FetchTopicV12 {
986 name: "orders".to_owned(),
987 partitions: vec![FetchPartitionV12 {
988 partition_index: 0,
989 current_leader_epoch: -1,
990 fetch_offset: 42,
991 last_fetched_epoch: -1,
992 log_start_offset: -1,
993 max_bytes: 1_048_576,
994 }],
995 }],
996 forgotten_topics: Vec::new(),
997 rack_id: "rack-a".to_owned(),
998 };
999
1000 let bytes = request.encode().unwrap();
1001 let mut decoder = Decoder::new(&bytes);
1002 assert_eq!(decoder.read_i16().unwrap(), 1);
1003 assert_eq!(decoder.read_i16().unwrap(), 12);
1004 assert_eq!(decoder.read_i32().unwrap(), 10);
1005 assert_eq!(
1006 decoder.read_nullable_string().unwrap().as_deref(),
1007 Some("kafrust")
1008 );
1009 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1010 assert_eq!(decoder.read_i32().unwrap(), -1);
1011 assert_eq!(decoder.read_i32().unwrap(), 500);
1012 assert_eq!(decoder.read_i32().unwrap(), 1);
1013 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1014 assert_eq!(decoder.read_i8().unwrap(), 1);
1015 assert_eq!(decoder.read_i32().unwrap(), 0);
1016 assert_eq!(decoder.read_i32().unwrap(), 0);
1017 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
1018 assert_eq!(decoder.read_compact_string().unwrap(), "orders");
1019 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
1020 assert_eq!(decoder.read_i32().unwrap(), 0);
1021 assert_eq!(decoder.read_i32().unwrap(), -1);
1022 assert_eq!(decoder.read_i64().unwrap(), 42);
1023 assert_eq!(decoder.read_i32().unwrap(), -1);
1024 assert_eq!(decoder.read_i64().unwrap(), -1);
1025 assert_eq!(decoder.read_i32().unwrap(), 1_048_576);
1026 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1027 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1028 assert_eq!(decoder.read_unsigned_varint().unwrap(), 1);
1029 assert_eq!(decoder.read_compact_string().unwrap(), "rack-a");
1030 assert_eq!(decoder.read_unsigned_varint().unwrap(), 0);
1031 assert!(decoder.is_empty());
1032 }
1033
1034 #[test]
1035 fn decodes_fetch_response_v12_with_preferred_read_replica() {
1036 let mut bytes = Encoder::new();
1037 bytes.write_i32(3);
1038 bytes.write_i16(0);
1039 bytes.write_i32(17);
1040 bytes.write_unsigned_varint(2);
1041 bytes.write_compact_string("orders").unwrap();
1042 bytes.write_unsigned_varint(2);
1043 bytes.write_i32(0);
1044 bytes.write_i16(0);
1045 bytes.write_i64(43);
1046 bytes.write_i64(42);
1047 bytes.write_i64(40);
1048 bytes.write_unsigned_varint(2);
1049 bytes.write_i64(7);
1050 bytes.write_i64(40);
1051 bytes.write_unsigned_varint(0);
1052 bytes.write_i32(2);
1053 bytes.write_compact_nullable_bytes(Some(&[])).unwrap();
1054 bytes.write_unsigned_varint(0);
1055 bytes.write_unsigned_varint(0);
1056 bytes.write_unsigned_varint(0);
1057
1058 let bytes = bytes.into_bytes();
1059 let mut decoder = Decoder::new(&bytes);
1060 let response = FetchResponseV12::decode_body(&mut decoder).unwrap();
1061 let partition = &response.responses[0].partitions[0];
1062
1063 assert_eq!(response.throttle_time_ms, 3);
1064 assert_eq!(response.session_id, 17);
1065 assert_eq!(partition.log_start_offset, 40);
1066 assert_eq!(partition.preferred_read_replica, 2);
1067 assert_eq!(partition.aborted_transactions[0].producer_id, 7);
1068 assert!(partition.records.is_empty());
1069 assert!(decoder.is_empty());
1070 }
1071
1072 #[test]
1073 fn decodes_fetch_response_v4_with_aborted_transaction() {
1074 let mut bytes = Encoder::new();
1075 bytes.write_i32(0);
1076 bytes.write_i32(1);
1077 bytes.write_string("orders").unwrap();
1078 bytes.write_i32(1);
1079 bytes.write_i32(0);
1080 bytes.write_i16(0);
1081 bytes.write_i64(43);
1082 bytes.write_i64(42);
1083 bytes.write_i32(1);
1084 bytes.write_i64(7);
1085 bytes.write_i64(40);
1086 bytes.write_bytes(&[]).unwrap();
1087 let bytes = bytes.into_bytes();
1088
1089 let mut decoder = Decoder::new(&bytes);
1090 let response = FetchResponseV4::decode_body(&mut decoder).unwrap();
1091 let partition = &response.responses[0].partitions[0];
1092
1093 assert_eq!(partition.high_watermark, 43);
1094 assert_eq!(partition.last_stable_offset, 42);
1095 assert_eq!(partition.aborted_transactions[0].producer_id, 7);
1096 assert_eq!(partition.aborted_transactions[0].first_offset, 40);
1097 assert!(partition.records.is_empty());
1098 assert!(decoder.is_empty());
1099 }
1100
1101 #[test]
1102 fn decodes_fetch_response_v2_with_message_set() {
1103 let mut message = Encoder::new();
1104 message.write_i32(0);
1105 message.write_i8(1);
1106 message.write_i8(0);
1107 message.write_i64(123);
1108 message.write_nullable_bytes(Some(b"order-1")).unwrap();
1109 message.write_nullable_bytes(Some(b"created")).unwrap();
1110 let message = message.into_bytes();
1111
1112 let mut set = Encoder::new();
1113 set.write_i64(42);
1114 set.write_i32(i32::try_from(message.len()).unwrap());
1115 set.write_raw(&message);
1116 let set = set.into_bytes();
1117
1118 let mut bytes = Encoder::new();
1119 bytes.write_i32(0);
1120 bytes.write_i32(1);
1121 bytes.write_string("orders").unwrap();
1122 bytes.write_i32(1);
1123 bytes.write_i32(0);
1124 bytes.write_i16(0);
1125 bytes.write_i64(43);
1126 bytes.write_bytes(&set).unwrap();
1127 let bytes = bytes.into_bytes();
1128
1129 let mut decoder = Decoder::new(&bytes);
1130 let response = FetchResponseV2::decode_body(&mut decoder).unwrap();
1131 let record = MessageSetRecord {
1132 offset: 42,
1133 timestamp_ms: 123,
1134 key: Some(b"order-1".to_vec()),
1135 value: Some(b"created".to_vec()),
1136 headers: Vec::new(),
1137 producer_id: None,
1138 transactional: false,
1139 control: false,
1140 };
1141
1142 assert_eq!(response.throttle_time_ms, 0);
1143 assert_eq!(response.responses[0].partitions[0].high_watermark, 43);
1144 assert_eq!(response.responses[0].partitions[0].records, vec![record]);
1145 assert!(decoder.is_empty());
1146 }
1147
1148 #[test]
1149 fn decodes_fetch_response_v2_ignores_partial_trailing_message_set_entry() {
1150 let mut message = Encoder::new();
1151 message.write_i32(0);
1152 message.write_i8(1);
1153 message.write_i8(0);
1154 message.write_i64(123);
1155 message.write_nullable_bytes(Some(b"order-1")).unwrap();
1156 message.write_nullable_bytes(Some(b"created")).unwrap();
1157 let message = message.into_bytes();
1158
1159 let mut set = Encoder::new();
1160 set.write_i64(42);
1161 set.write_i32(i32::try_from(message.len()).unwrap());
1162 set.write_raw(&message);
1163 set.write_i64(-1);
1164 set.write_i32(61);
1165 set.write_raw(&[0; 22]);
1166 let set = set.into_bytes();
1167
1168 let mut bytes = Encoder::new();
1169 bytes.write_i32(0);
1170 bytes.write_i32(1);
1171 bytes.write_string("orders").unwrap();
1172 bytes.write_i32(1);
1173 bytes.write_i32(0);
1174 bytes.write_i16(0);
1175 bytes.write_i64(43);
1176 bytes.write_bytes(&set).unwrap();
1177 let bytes = bytes.into_bytes();
1178
1179 let mut decoder = Decoder::new(&bytes);
1180 let response = FetchResponseV2::decode_body(&mut decoder).unwrap();
1181
1182 assert_eq!(response.responses[0].partitions[0].records.len(), 1);
1183 assert_eq!(response.responses[0].partitions[0].records[0].offset, 42);
1184 assert!(decoder.is_empty());
1185 }
1186
1187 #[test]
1188 fn decodes_fetch_response_v2_with_record_batch() {
1189 let mut record = Vec::new();
1190 record.push(0);
1191 write_varlong(&mut record, 5);
1192 write_varint(&mut record, 0);
1193 write_varint(&mut record, 7);
1194 record.extend_from_slice(b"order-1");
1195 write_varint(&mut record, 7);
1196 record.extend_from_slice(b"created");
1197 write_varint(&mut record, 2);
1198 write_varint(&mut record, 6);
1199 record.extend_from_slice(b"source");
1200 write_varint(&mut record, 8);
1201 record.extend_from_slice(b"checkout");
1202 write_varint(&mut record, 9);
1203 record.extend_from_slice(b"tombstone");
1204 write_varint(&mut record, -1);
1205
1206 let mut batch = Encoder::new();
1207 batch.write_i32(0);
1208 batch.write_i8(2);
1209 batch.write_i32(0);
1210 batch.write_i16(0x10);
1211 batch.write_i32(0);
1212 batch.write_i64(1_000);
1213 batch.write_i64(1_005);
1214 batch.write_i64(7);
1215 batch.write_i16(-1);
1216 batch.write_i32(-1);
1217 batch.write_i32(1);
1218 let mut encoded_record = Vec::new();
1219 write_varint(&mut encoded_record, i32::try_from(record.len()).unwrap());
1220 encoded_record.extend_from_slice(&record);
1221 batch.write_raw(&encoded_record);
1222 let batch = batch.into_bytes();
1223
1224 let mut set = Encoder::new();
1225 set.write_i64(42);
1226 set.write_i32(i32::try_from(batch.len()).unwrap());
1227 set.write_raw(&batch);
1228 let set = set.into_bytes();
1229
1230 let mut bytes = Encoder::new();
1231 bytes.write_i32(0);
1232 bytes.write_i32(1);
1233 bytes.write_string("orders").unwrap();
1234 bytes.write_i32(1);
1235 bytes.write_i32(0);
1236 bytes.write_i16(0);
1237 bytes.write_i64(43);
1238 bytes.write_bytes(&set).unwrap();
1239 let bytes = bytes.into_bytes();
1240
1241 let mut decoder = Decoder::new(&bytes);
1242 let response = FetchResponseV2::decode_body(&mut decoder).unwrap();
1243 let record = MessageSetRecord {
1244 offset: 42,
1245 timestamp_ms: 1_005,
1246 key: Some(b"order-1".to_vec()),
1247 value: Some(b"created".to_vec()),
1248 headers: vec![
1249 RecordBatchHeader::new("source", Some(b"checkout".to_vec())),
1250 RecordBatchHeader::new("tombstone", None),
1251 ],
1252 producer_id: Some(7),
1253 transactional: true,
1254 control: false,
1255 };
1256
1257 assert_eq!(response.responses[0].partitions[0].records, vec![record]);
1258 assert!(decoder.is_empty());
1259 }
1260
1261 fn write_varint(output: &mut Vec<u8>, value: i32) {
1262 write_unsigned_varint(output, u64::from(((value << 1) ^ (value >> 31)) as u32));
1263 }
1264
1265 fn write_varlong(output: &mut Vec<u8>, value: i64) {
1266 write_unsigned_varint(output, ((value << 1) ^ (value >> 63)) as u64);
1267 }
1268
1269 fn write_unsigned_varint(output: &mut Vec<u8>, mut value: u64) {
1270 loop {
1271 let mut byte = (value & 0x7f) as u8;
1272 value >>= 7;
1273 if value != 0 {
1274 byte |= 0x80;
1275 }
1276 output.push(byte);
1277 if value == 0 {
1278 break;
1279 }
1280 }
1281 }
1282}