Skip to content

Commit b05c3b9

Browse files
committed
kfake: support KIP-951, fix OffsetForLeaderEpoch
OffsetForLeaderEpoch was not actually correct; now, by searching for the next epoch, the logic is simpler.
1 parent 1ed02eb commit b05c3b9

4 files changed

Lines changed: 61 additions & 13 deletions

File tree

‎pkg/kfake/00_produce.go‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package kfake
22

33
import (
44
"hash/crc32"
5+
"net"
6+
"strconv"
57
"time"
68

79
"github.com/twmb/franz-go/pkg/kerr"
@@ -14,7 +16,7 @@ import (
1416
// * Multiple batches in one produce
1517
// * Compact
1618

17-
func init() { regKey(0, 3, 9) }
19+
func init() { regKey(0, 3, 10) }
1820

1921
func (c *Cluster) handleProduce(b *broker, kreq kmsg.Request) (kmsg.Response, error) {
2022
var (
@@ -46,13 +48,25 @@ func (c *Cluster) handleProduce(b *broker, kreq kmsg.Request) (kmsg.Response, er
4648
donet(t, errCode)
4749
}
4850
}
51+
var includeBrokers bool
4952
toresp := func() kmsg.Response {
5053
for topic, partitions := range tdone {
5154
st := kmsg.NewProduceResponseTopic()
5255
st.Topic = topic
5356
st.Partitions = partitions
5457
resp.Topics = append(resp.Topics, st)
5558
}
59+
if includeBrokers {
60+
for _, b := range c.bs {
61+
sb := kmsg.NewProduceResponseBroker()
62+
h, p, _ := net.SplitHostPort(b.ln.Addr().String())
63+
p32, _ := strconv.Atoi(p)
64+
sb.NodeID = b.node
65+
sb.Host = h
66+
sb.Port = int32(p32)
67+
resp.Brokers = append(resp.Brokers, sb)
68+
}
69+
}
5670
return resp
5771
}
5872

@@ -76,7 +90,10 @@ func (c *Cluster) handleProduce(b *broker, kreq kmsg.Request) (kmsg.Response, er
7690
continue
7791
}
7892
if pd.leader != b {
79-
donep(rt.Topic, rp, kerr.NotLeaderForPartition.Code)
93+
p := donep(rt.Topic, rp, kerr.NotLeaderForPartition.Code)
94+
p.CurrentLeader.LeaderID = pd.leader.node
95+
p.CurrentLeader.LeaderEpoch = pd.epoch
96+
includeBrokers = true
8097
continue
8198
}
8299

‎pkg/kfake/01_fetch.go‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package kfake
22

33
import (
4+
"net"
5+
"strconv"
46
"sync"
57
"time"
68

@@ -16,7 +18,7 @@ import (
1618
// * Out of range fetch causes early return
1719
// * Raw bytes of batch counts against wait bytes
1820

19-
func init() { regKey(1, 4, 13) }
21+
func init() { regKey(1, 4, 16) }
2022

2123
func (c *Cluster) handleFetch(creq *clientReq, w *watchFetch) (kmsg.Response, error) {
2224
var (
@@ -132,6 +134,21 @@ func (c *Cluster) handleFetch(creq *clientReq, w *watchFetch) (kmsg.Response, er
132134
return &st.Partitions[len(st.Partitions)-1]
133135
}
134136

137+
var includeBrokers bool
138+
defer func() {
139+
if includeBrokers {
140+
for _, b := range c.bs {
141+
sb := kmsg.NewFetchResponseBroker()
142+
h, p, _ := net.SplitHostPort(b.ln.Addr().String())
143+
p32, _ := strconv.Atoi(p)
144+
sb.NodeID = b.node
145+
sb.Host = h
146+
sb.Port = int32(p32)
147+
resp.Brokers = append(resp.Brokers, sb)
148+
}
149+
}
150+
}()
151+
135152
var batchesAdded int
136153
full:
137154
for _, rt := range req.Topics {
@@ -146,7 +163,10 @@ full:
146163
continue
147164
}
148165
if pd.leader != creq.cc.b {
149-
donep(rt.Topic, rt.TopicID, rp.Partition, kerr.NotLeaderForPartition.Code)
166+
p := donep(rt.Topic, rt.TopicID, rp.Partition, kerr.NotLeaderForPartition.Code)
167+
p.CurrentLeader.LeaderID = pd.leader.node
168+
p.CurrentLeader.LeaderEpoch = pd.epoch
169+
includeBrokers = true
150170
continue
151171
}
152172
sp := donep(rt.Topic, rt.TopicID, rp.Partition, 0)

‎pkg/kfake/23_offset_for_leader_epoch.go‎

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,24 @@ func (c *Cluster) handleOffsetForLeaderEpoch(b *broker, kreq kmsg.Request) (kmsg
7474
continue
7575
}
7676

77+
// If our epoch was bumped before anything was
78+
// produced, return the epoch and a start offset of 0.
79+
if len(pd.batches) == 0 {
80+
sp.LeaderEpoch = pd.epoch
81+
sp.EndOffset = 0
82+
if rp.LeaderEpoch > pd.epoch {
83+
sp.LeaderEpoch = -1
84+
sp.EndOffset = -1
85+
}
86+
continue
87+
}
88+
7789
// What is the largest epoch after the requested epoch?
90+
nextEpoch := rp.LeaderEpoch + 1
7891
idx, _ := sort.Find(len(pd.batches), func(idx int) int {
7992
batchEpoch := pd.batches[idx].epoch
8093
switch {
81-
case rp.LeaderEpoch <= batchEpoch:
94+
case nextEpoch <= batchEpoch:
8295
return -1
8396
default:
8497
return 1
@@ -92,19 +105,16 @@ func (c *Cluster) handleOffsetForLeaderEpoch(b *broker, kreq kmsg.Request) (kmsg
92105
continue
93106
}
94107

95-
// Requested epoch is before the LSO: return the requested
96-
// epoch and the LSO.
97-
if idx == 0 && pd.batches[0].epoch > rp.LeaderEpoch {
108+
// Next epoch is actually the first epoch: return the
109+
// requested epoch and the LSO.
110+
if idx == 0 {
98111
sp.LeaderEpoch = rp.LeaderEpoch
99112
sp.EndOffset = pd.logStartOffset
100113
continue
101114
}
102115

103-
// The requested epoch exists and is not the latest
104-
// epoch, we return the end offset being the first
105-
// offset of the next epoch.
106-
sp.LeaderEpoch = pd.batches[idx].epoch
107-
sp.EndOffset = pd.batches[idx+1].FirstOffset
116+
sp.LeaderEpoch = pd.batches[idx-1].epoch
117+
sp.EndOffset = pd.batches[idx].FirstOffset
108118
}
109119
}
110120
return resp, nil

‎pkg/kfake/cluster.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,7 @@ func (c *Cluster) MoveTopicPartition(topic string, partition int32, nodeID int32
958958
return
959959
}
960960
pd.leader = br
961+
pd.epoch++
961962
})
962963
return err
963964
}

0 commit comments

Comments
 (0)