
seblegall
Distributed Services with Go - Method log.Read() fails reading Records
Hi,
I’m currently reading your book. By doing so, I like to rewrite the code by myself. It helps me to deeply understand how it works.
However, I found something strange in the log package, concerning the Read() func. Let’s see that with a test example :
In the log_test.go
file, the original test is :
func testAppendRead(t *testing.T, log *log.Log) {
append := &api.Record{
Value: []byte("hello world"),
}
off, err := log.Append(append)
require.NoError(t, err)
require.Equal(t, uint64(0), off)
read, err := log.Read(off)
require.NoError(t, err)
require.Equal(t, append, read)
}
In this test, we write 1 record and read it.
Let’s write 4 records and read them:
func testAppendRead(t *testing.T, log *log.Log) {
for i := 0; i < 5; i++ {
append := &api.Record{
Value: []byte(fmt.Sprintf("Hello World %d !", i)),
}
off, err := log.Append(append)
require.NoError(t, err)
require.Equal(t, uint64(i), off)
read, err := log.Read(off)
require.NoError(t, err)
require.Equal(t, append, read)
}
}
Here is what I get by running go test -v log_test.go
:
=== RUN TestLog
=== RUN TestLog/append_and_read_a_record_succeeds
TestLog/append_and_read_a_record_succeeds: log_test.go:48:
Error Trace: log_test.go:48
log_test.go:32
Error: Received unexpected error:
offset out of range: 2
Test: TestLog/append_and_read_a_record_succeeds
I’m not sure why it fails, but I have understood that, in a log, segments are ordered from the oldest to the newest. It means the oldest will have a base offset of 0 (for example), the second will have a base offset of 2.
But then, there is this code in the Read method :
var s *segment
for _, segment := range l.segments {
//The first segment we read is the oldest one. That is to say, the one
//with a base offset equals to 0, right?
if segment.baseOffset <= off {
s = segment
break
}
}
if s == nil || s.nextOffset <= off {
return nil, fmt.Errorf("offset out of range: %d", off)
}
If we try to read offset 3, by reading the first (oldest) segment in the loop, we will have: segment.baseOffset = 0 <= 3
However, the Record with the offset 3 is in the segment which baseOffset is 2.
Did I miss something?
Most Liked

travisjeffery
Hey, yeah it should be implemented like this:
func (l *Log) Read(off uint64) (*api.Record, error) {
l.mu.RLock()
defer l.mu.RUnlock()
var s *segment
for _, segment := range l.segments {
if segment.baseOffset <= off && off < segment.nextOffset {
s = segment
break
}
}
// START: before
if s == nil || s.nextOffset <= off {
return nil, fmt.Errorf("offset out of range: %d", off)
}
// END: before
return s.Read(off)
}
I fixed a ton of issues that will be in the next beta, which should be out either late this week or next week.
Popular Pragmatic Bookshelf topics







Modern Front-End Development for Rails - application does not start after run bin/setup (page xviii)



Other popular topics










Categories:
Sub Categories:
Popular Portals
- /elixir
- /rust
- /wasm
- /ruby
- /erlang
- /phoenix
- /keyboards
- /rails
- /js
- /python
- /security
- /go
- /swift
- /vim
- /clojure
- /emacs
- /java
- /haskell
- /onivim
- /svelte
- /typescript
- /crystal
- /c-plus-plus
- /kotlin
- /tailwind
- /gleam
- /react
- /ocaml
- /flutter
- /elm
- /vscode
- /ash
- /opensuse
- /centos
- /php
- /deepseek
- /html
- /zig
- /scala
- /textmate
- /sublime-text
- /debian
- /nixos
- /lisp
- /agda
- /react-native
- /kubuntu
- /arch-linux
- /revery
- /ubuntu
- /spring
- /django
- /manjaro
- /diversity
- /lua
- /nodejs
- /c
- /julia
- /slackware
- /markdown