6
6
import java .util .HashSet ;
7
7
import java .util .Map ;
8
8
import java .util .Set ;
9
+ import java .util .stream .Collectors ;
9
10
import lombok .Getter ;
10
11
import lombok .extern .slf4j .Slf4j ;
11
12
import org .apache .commons .lang3 .mutable .MutableLong ;
12
13
import org .apache .kafka .clients .consumer .Consumer ;
13
14
import org .apache .kafka .common .TopicPartition ;
15
+ import org .apache .kafka .common .errors .UnsupportedVersionException ;
14
16
15
17
@ Slf4j
16
18
@ Getter
@@ -34,7 +36,7 @@ class OffsetsInfo {
34
36
35
37
OffsetsInfo (Consumer <?, ?> consumer , Collection <TopicPartition > targetPartitions ) {
36
38
this .consumer = consumer ;
37
- this .beginOffsets = consumer . beginningOffsets ( targetPartitions );
39
+ this .beginOffsets = firstOffsetsForPolling ( consumer , targetPartitions );
38
40
this .endOffsets = consumer .endOffsets (targetPartitions );
39
41
endOffsets .forEach ((tp , endOffset ) -> {
40
42
var beginningOffset = beginOffsets .get (tp );
@@ -46,6 +48,28 @@ class OffsetsInfo {
46
48
});
47
49
}
48
50
51
+
52
+ private Map <TopicPartition , Long > firstOffsetsForPolling (Consumer <?, ?> consumer ,
53
+ Collection <TopicPartition > partitions ) {
54
+ try {
55
+ // we try to use offsetsForTimes() to find earliest offsets, since for
56
+ // some topics (like compacted) beginningOffsets() ruturning 0 offsets
57
+ // even when effectively first offset can be very high
58
+ var offsets = consumer .offsetsForTimes (
59
+ partitions .stream ().collect (Collectors .toMap (p -> p , p -> 0L ))
60
+ );
61
+ // result of offsetsForTimes() can be null, if message version < 0.10.0
62
+ if (offsets .entrySet ().stream ().noneMatch (e -> e .getValue () == null )) {
63
+ return offsets .entrySet ().stream ()
64
+ .collect (Collectors .toMap (Map .Entry ::getKey , e -> e .getValue ().offset ()));
65
+ }
66
+ } catch (UnsupportedOperationException | UnsupportedVersionException e ) {
67
+ // offsetsForTimes() not supported
68
+ }
69
+ //falling back to beginningOffsets() if offsetsForTimes() not supported
70
+ return consumer .beginningOffsets (partitions );
71
+ }
72
+
49
73
boolean assignedPartitionsFullyPolled () {
50
74
for (var tp : consumer .assignment ()) {
51
75
Preconditions .checkArgument (endOffsets .containsKey (tp ));
0 commit comments