@@ -673,6 +673,17 @@ where
673
673
674
674
records
675
675
}
676
+ #[ cfg( feature = "compression-zstd" ) ]
677
+ RecordBatchCompression :: Zstd => {
678
+ use zstd:: Decoder ;
679
+
680
+ let mut decoder = Decoder :: new ( reader) ?;
681
+ let records = Self :: read_records ( & mut decoder, is_control, n_records) ?;
682
+
683
+ ensure_eof ( & mut decoder, "Data left in zstd block" ) ?;
684
+
685
+ records
686
+ }
676
687
#[ allow( unreachable_patterns) ]
677
688
_ => {
678
689
return Err ( ReadError :: Malformed (
@@ -843,6 +854,14 @@ where
843
854
844
855
writer. write_all ( & output[ ..len] ) ?;
845
856
}
857
+ #[ cfg( feature = "compression-zstd" ) ]
858
+ RecordBatchCompression :: Zstd => {
859
+ use zstd:: Encoder ;
860
+
861
+ let mut encoder = Encoder :: new ( writer, 0 ) ?;
862
+ Self :: write_records ( & mut encoder, self . records ) ?;
863
+ encoder. finish ( ) ?;
864
+ }
846
865
#[ allow( unreachable_patterns) ]
847
866
_ => {
848
867
return Err ( WriteError :: Malformed (
@@ -1114,6 +1133,56 @@ mod tests {
1114
1133
assert_eq ! ( actual2, expected) ;
1115
1134
}
1116
1135
1136
+ #[ cfg( feature = "compression-zstd" ) ]
1137
+ #[ test]
1138
+ fn test_decode_fixture_zstd ( ) {
1139
+ // This data was obtained by watching rdkafka.
1140
+ let data = [
1141
+ b"\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x5d \x00 \x00 \x00 \x00 " . to_vec ( ) ,
1142
+ b"\x02 \xa1 \x6e \x4e \x95 \x00 \x04 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x7e \xbf " . to_vec ( ) ,
1143
+ b"\x78 \xf3 \xad \x00 \x00 \x01 \x7e \xbf \x78 \xf3 \xad \xff \xff \xff \xff \xff " . to_vec ( ) ,
1144
+ b"\xff \xff \xff \xff \xff \xff \xff \xff \xff \x00 \x00 \x00 \x01 \x28 \xb5 \x2f " . to_vec ( ) ,
1145
+ b"\xfd \x00 \x58 \x1d \x01 \x00 \xe8 \xfc \x01 \x00 \x00 \x00 \xc8 \x01 \x78 \x16 " . to_vec ( ) ,
1146
+ b"\x68 \x65 \x6c \x6c \x6f \x20 \x6b \x61 \x66 \x6b \x61 \x02 \x06 \x66 \x6f \x6f " . to_vec ( ) ,
1147
+ b"\x06 \x62 \x61 \x72 \x01 \x00 \x20 \x05 \x5c " . to_vec ( ) ,
1148
+ ]
1149
+ . concat ( ) ;
1150
+
1151
+ let actual = RecordBatch :: read ( & mut Cursor :: new ( data) ) . unwrap ( ) ;
1152
+ let expected = RecordBatch {
1153
+ base_offset : 0 ,
1154
+ partition_leader_epoch : 0 ,
1155
+ last_offset_delta : 0 ,
1156
+ first_timestamp : 1643889882029 ,
1157
+ max_timestamp : 1643889882029 ,
1158
+ producer_id : -1 ,
1159
+ producer_epoch : -1 ,
1160
+ base_sequence : -1 ,
1161
+ records : ControlBatchOrRecords :: Records ( vec ! [ Record {
1162
+ timestamp_delta: 0 ,
1163
+ offset_delta: 0 ,
1164
+ key: Some ( vec![ b'x' ; 100 ] ) ,
1165
+ value: Some ( b"hello kafka" . to_vec( ) ) ,
1166
+ headers: vec![ RecordHeader {
1167
+ key: "foo" . to_owned( ) ,
1168
+ value: b"bar" . to_vec( ) ,
1169
+ } ] ,
1170
+ } ] ) ,
1171
+ compression : RecordBatchCompression :: Zstd ,
1172
+ is_transactional : false ,
1173
+ timestamp_type : RecordBatchTimestampType :: CreateTime ,
1174
+ } ;
1175
+ assert_eq ! ( actual, expected) ;
1176
+
1177
+ let mut data2 = vec ! [ ] ;
1178
+ actual. write ( & mut data2) . unwrap ( ) ;
1179
+
1180
+ // don't compare if the data is equal because compression encoder might work slightly differently, use another
1181
+ // roundtrip instead
1182
+ let actual2 = RecordBatch :: read ( & mut Cursor :: new ( data2) ) . unwrap ( ) ;
1183
+ assert_eq ! ( actual2, expected) ;
1184
+ }
1185
+
1117
1186
#[ test]
1118
1187
fn test_decode_fixture_null_key ( ) {
1119
1188
// This data was obtained by watching rdkafka driven by IOx.
0 commit comments