Closed darkweak closed 1 year ago
I'm unable to reproduce.
I wrapped your example in this program:
package main
import (
"github.com/buraksezer/olric"
"github.com/buraksezer/olric/config"
)
func main() {
olricInstance := config.New("local")
db, err := olric.New(olricInstance)
if err != nil {
panic(err)
}
go func() {
_ = db.Start()
}()
}
And I did go run -race main.go
.
The program printing and ended successfully.
2022/12/14 11:04:42 [INFO] Olric 0.5.0 on darwin/arm64 go1.19.4 => olric.go:319
Hey, @tidwall I have prepared a sample for you. If you run the following code snippet by enabling the race detector, you will see the problem. I would greatly appreciate any help.
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/buraksezer/olric"
"github.com/buraksezer/olric/config"
)
func main() {
// Sample for Olric v0.5.x
// Deployment scenario: embedded-member
// This creates a single-node Olric cluster. It's good enough for experimenting.
// config.New returns a new config.Config with sane defaults. Available values for env:
// local, lan, wan
c := config.New("local")
// Callback function. It's called when this node is ready to accept connections.
ctx, cancel := context.WithCancel(context.Background())
c.Started = func() {
defer cancel()
log.Println("[INFO] Olric is ready to accept connections")
}
// Create a new Olric instance.
db, err := olric.New(c)
if err != nil {
log.Fatalf("Failed to create Olric instance: %v", err)
}
// Start the instance. It will form a single-node cluster.
go func() {
// Call Start at background. It's a blocker call.
err = db.Start()
if err != nil {
log.Fatalf("olric.Start returned an error: %v", err)
}
}()
<-ctx.Done()
// In embedded-member scenario, you can use the EmbeddedClient. It implements
// the Client interface.
e := db.NewEmbeddedClient()
dm, err := e.NewDMap("bucket-of-arbitrary-items")
if err != nil {
log.Fatalf("olric.NewDMap returned an error: %v", err)
}
ctx, cancel = context.WithCancel(context.Background())
// Magic starts here!
fmt.Println("##")
fmt.Println("Simple Put/Get on a DMap instance:")
err = dm.Put(ctx, "my-key", "Olric Rocks!")
if err != nil {
log.Fatalf("Failed to call Put: %v", err)
}
gr, err := dm.Get(ctx, "my-key")
if err != nil {
log.Fatalf("Failed to call Get: %v", err)
}
// Olric uses the Redis serialization format.
value, err := gr.String()
if err != nil {
log.Fatalf("Failed to read Get response: %v", err)
}
fmt.Println("Response for my-key:", value)
fmt.Println("##")
// Don't forget the call Shutdown when you want to leave the cluster.
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err = db.Shutdown(ctx)
if err != nil {
log.Printf("Failed to shutdown Olric: %v", err)
}
}
2023/01/11 23:45:39 [INFO] Olric 0.5.0 on darwin/arm64 go1.19.4 => olric.go:319
2023/01/11 23:45:39 [INFO] Join completed. Synced with 0 initial nodes => discovery.go:59
2023/01/11 23:45:39 [INFO] Routing table has been pushed by 192.168.1.45:3320 => operations.go:86
2023/01/11 23:45:39 [INFO] The cluster coordinator has been bootstrapped => discovery.go:42
2023/01/11 23:45:39 [INFO] Memberlist bindAddr: 192.168.1.45, bindPort: 3322 => routingtable.go:413
2023/01/11 23:45:39 [INFO] Cluster coordinator: 192.168.1.45:3320 => routingtable.go:414
2023/01/11 23:45:39 [INFO] Node name in the cluster: 192.168.1.45:3320 => olric.go:380
2023/01/11 23:45:39 [INFO] Olric bindAddr: 192.168.1.45, bindPort: 3320 => olric.go:386
2023/01/11 23:45:39 [INFO] Replication count is 1 => olric.go:388
2023/01/11 23:45:39 [INFO] Olric is ready to accept connections
##
Simple Put/Get on a DMap instance:
Response for my-key: Olric Rocks!
##
2023/01/11 23:45:39 [INFO] Broadcasting a leave message => discovery.go:295
==================
WARNING: DATA RACE
Read at 0x00c00056e028 by goroutine 17:
github.com/tidwall/redcon.(*Writer).Flush()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:651 +0x34
github.com/tidwall/redcon.(*conn).Close()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:459 +0x3c
github.com/tidwall/redcon.serve.func1.1()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:338 +0xcc
github.com/tidwall/redcon.serve.func1()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:341 +0x50
runtime.deferreturn()
/usr/local/go/src/runtime/panic.go:476 +0x30
github.com/tidwall/redcon.(*Server).Serve()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:311 +0x14c
github.com/buraksezer/olric/internal/server.(*Server).ListenAndServe()
/Users/buraksezer/go/pkg/mod/github.com/buraksezer/olric@v0.5.0/internal/server/server.go:189 +0x5a8
github.com/buraksezer/olric.(*Olric).Start.func1()
/Users/buraksezer/go/pkg/mod/github.com/buraksezer/olric@v0.5.0/olric.go:324 +0x40
golang.org/x/sync/errgroup.(*Group).Go.func1()
/Users/buraksezer/go/pkg/mod/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/errgroup/errgroup.go:57 +0x74
Previous write at 0x00c00056e028 by goroutine 34:
github.com/tidwall/redcon.(*Writer).Flush()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:654 +0xa0
github.com/tidwall/redcon.handle.func2()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:438 +0x17c
github.com/tidwall/redcon.handle()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:442 +0x7c
github.com/tidwall/redcon.serve.func2()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:378 +0x40
Goroutine 17 (running) created at:
golang.org/x/sync/errgroup.(*Group).Go()
/Users/buraksezer/go/pkg/mod/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/errgroup/errgroup.go:54 +0xd8
github.com/buraksezer/olric.(*Olric).Start()
/Users/buraksezer/go/pkg/mod/github.com/buraksezer/olric@v0.5.0/olric.go:323 +0x20c
main.main.func2()
/Users/buraksezer/GolandProjects/redcon61/main.go:39 +0x34
Goroutine 34 (running) created at:
github.com/tidwall/redcon.serve()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:378 +0x690
github.com/tidwall/redcon.(*Server).Serve()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:311 +0x14c
github.com/buraksezer/olric/internal/server.(*Server).ListenAndServe()
/Users/buraksezer/go/pkg/mod/github.com/buraksezer/olric@v0.5.0/internal/server/server.go:189 +0x5a8
github.com/buraksezer/olric.(*Olric).Start.func1()
/Users/buraksezer/go/pkg/mod/github.com/buraksezer/olric@v0.5.0/olric.go:324 +0x40
golang.org/x/sync/errgroup.(*Group).Go.func1()
/Users/buraksezer/go/pkg/mod/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/errgroup/errgroup.go:57 +0x74
==================
==================
WARNING: DATA RACE
Read at 0x00c00056e010 by goroutine 17:
github.com/tidwall/redcon.(*Writer).Flush()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:654 +0x4c
github.com/tidwall/redcon.(*conn).Close()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:459 +0x3c
github.com/tidwall/redcon.serve.func1.1()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:338 +0xcc
github.com/tidwall/redcon.serve.func1()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:341 +0x50
runtime.deferreturn()
/usr/local/go/src/runtime/panic.go:476 +0x30
github.com/tidwall/redcon.(*Server).Serve()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:311 +0x14c
github.com/buraksezer/olric/internal/server.(*Server).ListenAndServe()
/Users/buraksezer/go/pkg/mod/github.com/buraksezer/olric@v0.5.0/internal/server/server.go:189 +0x5a8
github.com/buraksezer/olric.(*Olric).Start.func1()
/Users/buraksezer/go/pkg/mod/github.com/buraksezer/olric@v0.5.0/olric.go:324 +0x40
golang.org/x/sync/errgroup.(*Group).Go.func1()
/Users/buraksezer/go/pkg/mod/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/errgroup/errgroup.go:57 +0x74
Previous write at 0x00c00056e010 by goroutine 34:
github.com/tidwall/redcon.(*Writer).Flush()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:658 +0x15c
github.com/tidwall/redcon.handle.func2()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:438 +0x17c
github.com/tidwall/redcon.handle()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:442 +0x7c
github.com/tidwall/redcon.serve.func2()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:378 +0x40
Goroutine 17 (running) created at:
golang.org/x/sync/errgroup.(*Group).Go()
/Users/buraksezer/go/pkg/mod/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/errgroup/errgroup.go:54 +0xd8
github.com/buraksezer/olric.(*Olric).Start()
/Users/buraksezer/go/pkg/mod/github.com/buraksezer/olric@v0.5.0/olric.go:323 +0x20c
main.main.func2()
/Users/buraksezer/GolandProjects/redcon61/main.go:39 +0x34
Goroutine 34 (running) created at:
github.com/tidwall/redcon.serve()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:378 +0x690
github.com/tidwall/redcon.(*Server).Serve()
/Users/buraksezer/go/pkg/mod/github.com/tidwall/redcon@v1.6.0/redcon.go:311 +0x14c
github.com/buraksezer/olric/internal/server.(*Server).ListenAndServe()
/Users/buraksezer/go/pkg/mod/github.com/buraksezer/olric@v0.5.0/internal/server/server.go:189 +0x5a8
github.com/buraksezer/olric.(*Olric).Start.func1()
/Users/buraksezer/go/pkg/mod/github.com/buraksezer/olric@v0.5.0/olric.go:324 +0x40
golang.org/x/sync/errgroup.(*Group).Go.func1()
/Users/buraksezer/go/pkg/mod/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/errgroup/errgroup.go:57 +0x74
==================
2023/01/11 23:45:39 [INFO] 192.168.1.45:3320 is gone => olric.go:448
==================
WARNING: DATA RACE
Write at 0x00c000120470 by main goroutine:
main.main()
/Users/buraksezer/GolandProjects/redcon61/main.go:84 +0x92c
Previous write at 0x00c000120470 by goroutine 16:
main.main.func2()
/Users/buraksezer/GolandProjects/redcon61/main.go:39 +0x44
Goroutine 16 (finished) created at:
main.main()
/Users/buraksezer/GolandProjects/redcon61/main.go:37 +0x2c8
==================
Found 3 data race(s)
Thanks for detailed example. I pushed a fix moments ago.
Also, in your example code, you have a minor race condition at:
// Start the instance. It will form a single-node cluster.
go func() {
// Call Start at background. It's a blocker call.
err = db.Start()
if err != nil {
log.Fatalf("olric.Start returned an error: %v", err)
}
}()
The line err = db.Start()
may need to be err := db.Start()
Thank you @tidwall, I'll update the documentation.
My pleasure
Hello, there is a race condition in the redcon library used by olric v0.5.0. I was testing my code using
go test -race
and this warning appeared.Sample
Output