mailgun / groupcache

Clone of golang/groupcache with TTL and Item Removal support
Apache License 2.0
484 stars 72 forks source link

add functionality to get or create a new group #23

Closed davidswu closed 3 years ago

davidswu commented 3 years ago

We're currently using this fork of groupcache, but are encountering an issue if multiple callers may possibly initialize the group. Added a function that allows the user to get a group if it exists, otherwise create it.

It effectively avoids the a pattern where we need to do the following:

g := groupcache.GetGroup("my_group")
if g == nil {
    // If two goroutines call once, one will return early. There is no guarantee that once runs before the early return
    mux.Lock()
    defer mux.Unlock()
    // Ensure we only initialize the group once
    once.Do(func() {
         // We have to call GetGroup again in case once does not execute for this goroutine
        _ = groupcache.NewGroup("my_group", 1024, getter)
    })
    return groupcache.GetGroup("my_group")
}
return g
thrawn01 commented 3 years ago

Thank you for making the PR and your interest in the project! It looks like you have a very specific use case that doesn't apply to the majority of users. The best thing todo in your case is to initialize the group before you spawn the go routines, perhaps even at the start of your application. If that is not possible then you will indeed have to write the code above. But this is no the common case. I fear most users would not benefit from this code.

A common pattern for initializing things that must only be initialized once (for instance registering prometheus metrics) is to put the initialization inside the init() function that is called by golang when the package is loaded into the runtime.

var groups sync.Map

// Package wide initialization only called once
func init() {
    groups["my-group"] = groupcache.NewGroup("my_group", 1024, getter)
}

func main() {
    go func(){
        groups["my-group"].Get(context.Background(), "my-key", &sink)
    }()
    go func(){
        groups["my-group"].Get(context.Background(), "my-key", &sink)
    }()
}