raft: add (*RawNode).WithProgress#10309
Conversation
|
CI failed due to what looks to be an unrelated flake: |
Codecov Report
@@ Coverage Diff @@
## master #10309 +/- ##
==========================================
+ Coverage 71.54% 71.71% +0.16%
==========================================
Files 391 391
Lines 36397 36406 +9
==========================================
+ Hits 26042 26107 +65
+ Misses 8538 8475 -63
- Partials 1817 1824 +7
Continue to review full report at Codecov.
|
raft/rawnode.go
Outdated
| // function and passes it a Status with a nil Progress field and pointers to the | ||
| // RawNode's internal Progress for its peers and learners, respectively. These | ||
| // must not be mutated or held on to past the next operation on the RawNode. | ||
| func (rn *RawNode) WithUnsafeStatus(visitor func(s Status, prs, learnerPRs map[uint64]*Progress)) { |
There was a problem hiding this comment.
I might just call this WithStatus. A With(func) method already implies a warning (at least to me) against using anything outside of its scope.
Exposing the prs and learnerPRs maps separately is unfortunate; this makes it harder for us to change the internal structure of things that are used to derive Status. It might be nice to define a struct (UnsafeStatus, reversing my previous paragraph?) that contains these things so that applications that don't need learners (for example) don't have their builds broken if there is an internal change there.
There was a problem hiding this comment.
Nathan suggested splitting the "status" and "progress" portions which I did and I think it turned out much nicer and avoids this problem as well. PTAL.
| } | ||
|
|
||
| s.HardState = r.hardState() | ||
| s.SoftState = *r.softState() |
There was a problem hiding this comment.
I think this is still hitting an allocation. Or maybe escape analysis is smart enough to avoid it?
There was a problem hiding this comment.
The benchmarks indicate that escape analysis is smart enough.
Calls to Status can be frequent and currently incur three heap allocations, but often the caller has no intention to hold on to the returned status. Add StatusWithoutProgress and WithProgress to allow avoiding heap allocations altogether. StatusWithoutProgress does what's on the tin and additionally returns a value (instead of a pointer) to avoid the associated heap allocation. By not returning a Progress map, it avoids all other allocations that Status incurs. To still introspect the Progress map, add WithProgress, which uses a simple visitor pattern. Add benchmarks to verify that this is indeed allocation free. ``` BenchmarkStatusProgress/members=1/Status-8 5000000 353 ns/op 784 B/op 3 allocs/op BenchmarkStatusProgress/members=1/Status-example-8 5000000 372 ns/op 784 B/op 3 allocs/op BenchmarkStatusProgress/members=1/StatusWithoutProgress-8 100000000 17.6 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=1/WithProgress-8 30000000 48.6 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=1/WithProgress-example-8 30000000 42.9 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=3/Status-8 5000000 395 ns/op 784 B/op 3 allocs/op BenchmarkStatusProgress/members=3/Status-example-8 3000000 449 ns/op 784 B/op 3 allocs/op BenchmarkStatusProgress/members=3/StatusWithoutProgress-8 100000000 18.7 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=3/WithProgress-8 20000000 78.1 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=3/WithProgress-example-8 20000000 70.7 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=5/Status-8 3000000 470 ns/op 784 B/op 3 allocs/op BenchmarkStatusProgress/members=5/Status-example-8 3000000 544 ns/op 784 B/op 3 allocs/op BenchmarkStatusProgress/members=5/StatusWithoutProgress-8 100000000 19.7 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=5/WithProgress-8 20000000 105 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=5/WithProgress-example-8 20000000 94.0 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=100/Status-8 100000 11903 ns/op 22663 B/op 12 allocs/op BenchmarkStatusProgress/members=100/Status-example-8 100000 13330 ns/op 22669 B/op 12 allocs/op BenchmarkStatusProgress/members=100/StatusWithoutProgress-8 50000000 20.9 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=100/WithProgress-8 1000000 1731 ns/op 0 B/op 0 allocs/op BenchmarkStatusProgress/members=100/WithProgress-example-8 1000000 1571 ns/op 0 B/op 0 allocs/op ```
e20d3be to
bd332b3
Compare
|
Ready for another look. I also added the benchmark results to the PR message. (TLDR is no allocs and faster). |
|
lgtm |
nvb
left a comment
There was a problem hiding this comment.
LGTM. The ProgressType enum was a good idea.
Calls to Status can be frequent and currently incur three heap
allocations, but often the caller has no intention to hold on to the
returned status.
Add StatusWithoutProgress and WithProgress to allow avoiding heap
allocations altogether. StatusWithoutProgress does what's on the
tin and additionally returns a value (instead of a pointer) to
avoid the associated heap allocation. By not returning a Progress
map, it avoids all other allocations that Status incurs.
To still introspect the Progress map, add WithProgress, which
uses a simple visitor pattern.
Add benchmarks to verify that this is indeed allocation free.