@@ -43,6 +43,24 @@ impl Default for Compression {
43
43
}
44
44
}
45
45
46
+ /// Which type of offset should be requested by [`PartitionClient::get_offset`].
47
+ ///
48
+ /// # Timestamp-based Queries
49
+ /// In theory the Kafka API would also support querying an offset based on a timestamp, but the behavior seems to be
50
+ /// semi-defined, unintuitive (even within Apache Kafka) and inconsistent between Apache Kafka and Redpanda. So we
51
+ /// decided to NOT expose this option.
52
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
53
+ pub enum OffsetAt {
54
+ /// Earliest existing record.
55
+ ///
56
+ /// This is NOT the earliest produced record but the earliest record that is still kept, i.e. the offset might
57
+ /// change if records are pruned by Kafka (retention policy) or if the are deleted.
58
+ Earliest ,
59
+
60
+ /// The latest existing record.
61
+ Latest ,
62
+ }
63
+
46
64
/// Many operations must be performed on the leader for a partition
47
65
///
48
66
/// Additionally a partition is the unit of concurrency within Kafka
@@ -110,7 +128,8 @@ impl PartitionClient {
110
128
///
111
129
/// # Error Handling
112
130
/// Fetching records outside the range known the to broker (marked by low and high watermark) will lead to a
113
- /// [`ServerError`](Error::ServerError) with [`OffsetOutOfRange`](ProtocolError::OffsetOutOfRange).
131
+ /// [`ServerError`](Error::ServerError) with [`OffsetOutOfRange`](ProtocolError::OffsetOutOfRange). You may use
132
+ /// [`get_offset`](Self::get_offset) to determine the offset range.
114
133
pub async fn fetch_records (
115
134
& self ,
116
135
offset : i64 ,
@@ -142,22 +161,23 @@ impl PartitionClient {
142
161
Ok ( ( records, partition. high_watermark . 0 ) )
143
162
}
144
163
145
- /// Get high watermark for this partition.
146
- pub async fn get_high_watermark ( & self ) -> Result < i64 > {
147
- let request = & build_list_offsets_request ( self . partition , & self . topic ) ;
164
+ /// Get offset for this partition.
165
+ ///
166
+ /// Note that the value returned by this method should be considered stale data, since:
167
+ ///
168
+ /// - **[`OffsetAt::Earliest`]:** Might be change at any time due to the Kafka retention policy or by
169
+ /// [deleting records](Self::delete_records).
170
+ /// - **[`OffsetAt::Latest`]:** Might be change at any time by [producing records](Self::produce).
171
+ pub async fn get_offset ( & self , at : OffsetAt ) -> Result < i64 > {
172
+ let request = & build_list_offsets_request ( self . partition , & self . topic , at) ;
148
173
149
- let partition = maybe_retry (
150
- & self . backoff_config ,
151
- self ,
152
- "get_high_watermark" ,
153
- || async move {
154
- let response = self . get ( ) . await ?. request ( & request) . await ?;
155
- process_list_offsets_response ( self . partition , & self . topic , response)
156
- } ,
157
- )
174
+ let partition = maybe_retry ( & self . backoff_config , self , "get_offset" , || async move {
175
+ let response = self . get ( ) . await ?. request ( & request) . await ?;
176
+ process_list_offsets_response ( self . partition , & self . topic , response)
177
+ } )
158
178
. await ?;
159
179
160
- extract_high_watermark ( partition)
180
+ extract_offset ( partition)
161
181
}
162
182
163
183
/// Delete records whose offset is smaller than the given offset.
@@ -585,16 +605,20 @@ fn extract_records(
585
605
Ok ( records)
586
606
}
587
607
588
- fn build_list_offsets_request ( partition : i32 , topic : & str ) -> ListOffsetsRequest {
608
+ fn build_list_offsets_request ( partition : i32 , topic : & str , at : OffsetAt ) -> ListOffsetsRequest {
609
+ let timestamp = match at {
610
+ OffsetAt :: Earliest => -2 ,
611
+ OffsetAt :: Latest => -1 ,
612
+ } ;
613
+
589
614
ListOffsetsRequest {
590
615
replica_id : NORMAL_CONSUMER ,
591
616
isolation_level : Some ( IsolationLevel :: ReadCommitted ) ,
592
617
topics : vec ! [ ListOffsetsRequestTopic {
593
618
name: String_ ( topic. to_owned( ) ) ,
594
619
partitions: vec![ ListOffsetsRequestPartition {
595
620
partition_index: Int32 ( partition) ,
596
- // latest offset
597
- timestamp: Int64 ( -1 ) ,
621
+ timestamp: Int64 ( timestamp) ,
598
622
max_num_offsets: Some ( Int32 ( 1 ) ) ,
599
623
} ] ,
600
624
} ] ,
@@ -636,7 +660,7 @@ fn process_list_offsets_response(
636
660
}
637
661
}
638
662
639
- fn extract_high_watermark ( partition : ListOffsetsResponsePartition ) -> Result < i64 > {
663
+ fn extract_offset ( partition : ListOffsetsResponsePartition ) -> Result < i64 > {
640
664
match (
641
665
partition. old_style_offsets . as_ref ( ) ,
642
666
partition. offset . as_ref ( ) ,
0 commit comments