Deadlock in groupcache

Hi All,

I see a deadlock with below code,

Prog 1

package main

import (
        "context"
        "fmt"
        "log"
        "time"
        "net/http"
        "github.com/mailgun/groupcache/v2"
)

func main() {
                pool := groupcache.NewHTTPPoolOpts("http://localhost:8380", &groupcache.HTTPPoolOptions{})
                pool.Set("http://localhost:8280")
                server := http.Server{
                        Addr:    "localhost:8380",
                        Handler: pool,
                }
                go func() {
                        log.Printf("Serving....\n")
                        if err := server.ListenAndServe(); err != nil {
                                log.Fatal(err)
                        }
                }()
                defer server.Shutdown(context.Background())
        group := groupcache.NewGroup("users", 3000000, groupcache.GetterFunc(
                func(ctx context.Context, id string, dest groupcache.Sink) error {
                        user := User {
                                Id:             1234,
                                Name:           "Balaji ",
                                Age:            41,
                                IsSuper:        true,
                        }

                        if err := dest.SetProto(&user, time.Now().Add(time.Second*3600)); err != nil {
                                return err
                        }
                        return nil
                },
        ))

        ctx, cancel := context.WithCancel(context.Background())
        for {
            var user User

            defer cancel()

            if err := group.Get(ctx, "12345", groupcache.ProtoSink(&user)); err != nil {
                log.Fatal(err)
            }

            time.Sleep(time.Second*5)
            fmt.Printf("-- User --\n")
            fmt.Printf("Id: %d\n", user.Id)
            fmt.Printf("Name: %s\n", user.Name)
            fmt.Printf("Age: %d\n", user.Age)
            fmt.Printf("IsSuper: %t\n", user.IsSuper)
        }

}

Prog 2

package main

import (
        "context"
        "log"
        "fmt"
        "time"
        "net/http"
        "github.com/mailgun/groupcache/v2"
)

func main() {
                pool := groupcache.NewHTTPPoolOpts("http://localhost:8280", &groupcache.HTTPPoolOptions{})
                pool.Set("http://localhost:8380")
                server := http.Server{
                        Addr:    "localhost:8280",
                        Handler: pool,
                }
                go func() {
                        log.Printf("Serving....\n")
                        if err := server.ListenAndServe(); err != nil {
                                log.Fatal(err)
                        }
                }()
                defer server.Shutdown(context.Background())
        group := groupcache.NewGroup("users", 3000000, groupcache.GetterFunc(
                func(ctx context.Context, id string, dest groupcache.Sink) error {
                        user := User {
                                Id:             1234,
                                Name:           "Balaji ",
                                Age:            41,
                                IsSuper:        true,
                        }

                        if err := dest.SetProto(&user, time.Now().Add(time.Second*3600)); err != nil {
                                return err
                        }
                        return nil
                },
        ))

        fmt.Println(group)
        ctx, cancel := context.WithCancel(context.Background())
        fmt.Println(ctx)
        for {
            time.Sleep(5*time.Second)
            defer cancel()
/*
            if err := group.Get(ctx, "12345", groupcache.ProtoSink(&user)); err != nil {
                log.Fatal(err)
            }

            time.Sleep(time.Second*5)
            fmt.Printf("-- User --\n")
            fmt.Printf("Id: %d\n", user.Id)
            fmt.Printf("Name: %s\n", user.Name)
            fmt.Printf("Age: %d\n", user.Age)
            fmt.Printf("IsSuper: %t\n", user.IsSuper)
*/
        }

}

If you see above in prog2 I have the getter but in for{} I am not doing anything. When I start prog2 and then prog1 it hangs. Looks like if the cache is not hot in any it goes into a circular loop or deadlock so is it that when we specify peer we shouldn’t specify in that order ?. Have got stuck in this for a long, any help much appreciated.

Adding some debug into libraries… I see its circulating the request.

Prog1:
go run testcache.go user.pb.go
I am here atleast
Getting from library
Sending Peer Request
http://localhost:8280/_groupcache/users/12345
2020/12/31 23:00:55 Serving....
I am here atleast

Prog2:
go run testcache1.go user.pb.go
&{users 0x7e6800 {0 {0 0}} <nil> 3000000 {{{0 0} 0 0 0 0} 0 <nil> 0 0 0} {{{0 0} 0 0 0 0} 0 <nil> 0 0 0} 0xc000020f30 0xc000020f40 0 {0 0 0 0 0 0 0 0 0 0}}
context.Background.WithCancel
2020/12/31 23:00:33 Serving....
I am here atleast
Getting from library
Sending Peer Request
http://localhost:8380/_groupcache/users/12345
I am done

One another input is in prog2 when I remove the peer Set it works fine.

rgds
Balaji

1 Like

Try using sync package: https://teivah.medium.com/a-closer-look-at-go-sync-package-9f4e4a28c35a

There is a whole book on this subject: https://www.google.com/search?q=concurrency+in+go&oq=concurrency+in+go&aqs=chrome..69i57j46j0i67j0l5.4381j0j7&sourceid=chrome&ie=UTF-8

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.