diff --git a/go/group/raft.go b/go/group/raft.go index c6416f03..7cc4cc93 100644 --- a/go/group/raft.go +++ b/go/group/raft.go @@ -61,9 +61,7 @@ func normalizeRaftNode(node string) string { // IsLeader tells if this node is the current raft leader func IsLeader() bool { - future := getRaft().VerifyLeader() - err := future.Error() - return err == nil + return GetState() == raft.Leader } // GetLeader returns identity of raft leader diff --git a/vendor/github.com/patrickmn/go-cache/README.md b/vendor/github.com/patrickmn/go-cache/README.md index 168ff7ba..c5789cc6 100644 --- a/vendor/github.com/patrickmn/go-cache/README.md +++ b/vendor/github.com/patrickmn/go-cache/README.md @@ -20,86 +20,62 @@ one) to recover from downtime quickly. (See the docs for `NewFrom()` for caveats ### Usage ```go - import ( - "fmt" - "github.com/patrickmn/go-cache" - "time" - ) - - func main() { - - // Create a cache with a default expiration time of 5 minutes, and which - // purges expired items every 30 seconds - c := cache.New(5*time.Minute, 30*time.Second) - - // Set the value of the key "foo" to "bar", with the default expiration time - c.Set("foo", "bar", cache.DefaultExpiration) - - // Set the value of the key "baz" to 42, with no expiration time - // (the item won't be removed until it is re-set, or removed using - // c.Delete("baz") - c.Set("baz", 42, cache.NoExpiration) - - // Get the string associated with the key "foo" from the cache - foo, found := c.Get("foo") - if found { - fmt.Println(foo) - } - - // Since Go is statically typed, and cache values can be anything, type - // assertion is needed when values are being passed to functions that don't - // take arbitrary types, (i.e. interface{}). The simplest way to do this for - // values which will only be used once--e.g. for passing to another - // function--is: - foo, found := c.Get("foo") - if found { - MyFunction(foo.(string)) - } - - // This gets tedious if the value is used several times in the same function. - // You might do either of the following instead: - if x, found := c.Get("foo"); found { - foo := x.(string) - // ... - } - // or - var foo string - if x, found := c.Get("foo"); found { - foo = x.(string) - } - // ... - // foo can then be passed around freely as a string +import ( + "fmt" + "github.com/patrickmn/go-cache" + "time" +) + +func main() { + // Create a cache with a default expiration time of 5 minutes, and which + // purges expired items every 10 minutes + c := cache.New(5*time.Minute, 10*time.Minute) + + // Set the value of the key "foo" to "bar", with the default expiration time + c.Set("foo", "bar", cache.DefaultExpiration) + + // Set the value of the key "baz" to 42, with no expiration time + // (the item won't be removed until it is re-set, or removed using + // c.Delete("baz") + c.Set("baz", 42, cache.NoExpiration) + + // Get the string associated with the key "foo" from the cache + foo, found := c.Get("foo") + if found { + fmt.Println(foo) + } - // Want performance? Store pointers! - c.Set("foo", &MyStruct, cache.DefaultExpiration) - if x, found := c.Get("foo"); found { - foo := x.(*MyStruct) - // ... - } - - // If you store a reference type like a pointer, slice, map or channel, you - // do not need to run Set if you modify the underlying data. The cached - // reference points to the same memory, so if you modify a struct whose - // pointer you've stored in the cache, retrieving that pointer with Get will - // point you to the same data: - foo := &MyStruct{Num: 1} - c.Set("foo", foo, cache.DefaultExpiration) - // ... - x, _ := c.Get("foo") - foo := x.(*MyStruct) - fmt.Println(foo.Num) - // ... - foo.Num++ - // ... - x, _ := c.Get("foo") - foo := x.(*MyStruct) - foo.Println(foo.Num) + // Since Go is statically typed, and cache values can be anything, type + // assertion is needed when values are being passed to functions that don't + // take arbitrary types, (i.e. interface{}). The simplest way to do this for + // values which will only be used once--e.g. for passing to another + // function--is: + foo, found := c.Get("foo") + if found { + MyFunction(foo.(string)) + } - // will print: - // 1 - // 2 + // This gets tedious if the value is used several times in the same function. + // You might do either of the following instead: + if x, found := c.Get("foo"); found { + foo := x.(string) + // ... + } + // or + var foo string + if x, found := c.Get("foo"); found { + foo = x.(string) + } + // ... + // foo can then be passed around freely as a string + // Want performance? Store pointers! + c.Set("foo", &MyStruct, cache.DefaultExpiration) + if x, found := c.Get("foo"); found { + foo := x.(*MyStruct) + // ... } +} ``` ### Reference diff --git a/vendor/github.com/patrickmn/go-cache/cache.go b/vendor/github.com/patrickmn/go-cache/cache.go index 35625430..db88d2f2 100644 --- a/vendor/github.com/patrickmn/go-cache/cache.go +++ b/vendor/github.com/patrickmn/go-cache/cache.go @@ -81,6 +81,12 @@ func (c *cache) set(k string, x interface{}, d time.Duration) { } } +// Add an item to the cache, replacing any existing item, using the default +// expiration. +func (c *cache) SetDefault(k string, x interface{}) { + c.Set(k, x, DefaultExpiration) +} + // Add an item to the cache only if an item doesn't already exist for the given // key, or if the existing item has expired. Returns an error otherwise. func (c *cache) Add(k string, x interface{}, d time.Duration) error { @@ -129,6 +135,36 @@ func (c *cache) Get(k string) (interface{}, bool) { return item.Object, true } +// GetWithExpiration returns an item and its expiration time from the cache. +// It returns the item or nil, the expiration time if one is set (if the item +// never expires a zero value for time.Time is returned), and a bool indicating +// whether the key was found. +func (c *cache) GetWithExpiration(k string) (interface{}, time.Time, bool) { + c.mu.RLock() + // "Inlining" of get and Expired + item, found := c.items[k] + if !found { + c.mu.RUnlock() + return nil, time.Time{}, false + } + + if item.Expiration > 0 { + if time.Now().UnixNano() > item.Expiration { + c.mu.RUnlock() + return nil, time.Time{}, false + } + + // Return the item and the expiration time + c.mu.RUnlock() + return item.Object, time.Unix(0, item.Expiration), true + } + + // If expiration <= 0 (i.e. no expiration time set) then return the item + // and a zeroed time.Time + c.mu.RUnlock() + return item.Object, time.Time{}, true +} + func (c *cache) get(k string) (interface{}, bool) { item, found := c.items[k] if !found { @@ -998,19 +1034,26 @@ func (c *cache) LoadFile(fname string) error { return fp.Close() } -// Returns the items in the cache. This may include items that have expired, -// but have not yet been cleaned up. If this is significant, the Expiration -// fields of the items should be checked. Note that explicit synchronization -// is needed to use a cache and its corresponding Items() return value at -// the same time, as the map is shared. +// Copies all unexpired items in the cache into a new map and returns it. func (c *cache) Items() map[string]Item { c.mu.RLock() defer c.mu.RUnlock() - return c.items + m := make(map[string]Item, len(c.items)) + now := time.Now().UnixNano() + for k, v := range c.items { + // "Inlining" of Expired + if v.Expiration > 0 { + if now > v.Expiration { + continue + } + } + m[k] = v + } + return m } // Returns the number of items in the cache. This may include items that have -// expired, but have not yet been cleaned up. Equivalent to len(c.Items()). +// expired, but have not yet been cleaned up. func (c *cache) ItemCount() int { c.mu.RLock() n := len(c.items) @@ -1031,7 +1074,6 @@ type janitor struct { } func (j *janitor) Run(c *cache) { - j.stop = make(chan bool) ticker := time.NewTicker(j.Interval) for { select { @@ -1051,6 +1093,7 @@ func stopJanitor(c *Cache) { func runJanitor(c *cache, ci time.Duration) { j := &janitor{ Interval: ci, + stop: make(chan bool), } c.janitor = j go j.Run(c) diff --git a/vendor/github.com/patrickmn/go-cache/cache_test.go b/vendor/github.com/patrickmn/go-cache/cache_test.go index 6e81693f..47a3d539 100644 --- a/vendor/github.com/patrickmn/go-cache/cache_test.go +++ b/vendor/github.com/patrickmn/go-cache/cache_test.go @@ -1459,7 +1459,7 @@ func BenchmarkRWMutexMapGet(b *testing.B) { func BenchmarkRWMutexInterfaceMapGetStruct(b *testing.B) { b.StopTimer() - s := struct{name string}{name: "foo"} + s := struct{ name string }{name: "foo"} m := map[interface{}]string{ s: "bar", } @@ -1676,3 +1676,96 @@ func BenchmarkDeleteExpiredLoop(b *testing.B) { tc.DeleteExpired() } } + +func TestGetWithExpiration(t *testing.T) { + tc := New(DefaultExpiration, 0) + + a, expiration, found := tc.GetWithExpiration("a") + if found || a != nil || !expiration.IsZero() { + t.Error("Getting A found value that shouldn't exist:", a) + } + + b, expiration, found := tc.GetWithExpiration("b") + if found || b != nil || !expiration.IsZero() { + t.Error("Getting B found value that shouldn't exist:", b) + } + + c, expiration, found := tc.GetWithExpiration("c") + if found || c != nil || !expiration.IsZero() { + t.Error("Getting C found value that shouldn't exist:", c) + } + + tc.Set("a", 1, DefaultExpiration) + tc.Set("b", "b", DefaultExpiration) + tc.Set("c", 3.5, DefaultExpiration) + tc.Set("d", 1, NoExpiration) + tc.Set("e", 1, 50*time.Millisecond) + + x, expiration, found := tc.GetWithExpiration("a") + if !found { + t.Error("a was not found while getting a2") + } + if x == nil { + t.Error("x for a is nil") + } else if a2 := x.(int); a2+2 != 3 { + t.Error("a2 (which should be 1) plus 2 does not equal 3; value:", a2) + } + if !expiration.IsZero() { + t.Error("expiration for a is not a zeroed time") + } + + x, expiration, found = tc.GetWithExpiration("b") + if !found { + t.Error("b was not found while getting b2") + } + if x == nil { + t.Error("x for b is nil") + } else if b2 := x.(string); b2+"B" != "bB" { + t.Error("b2 (which should be b) plus B does not equal bB; value:", b2) + } + if !expiration.IsZero() { + t.Error("expiration for b is not a zeroed time") + } + + x, expiration, found = tc.GetWithExpiration("c") + if !found { + t.Error("c was not found while getting c2") + } + if x == nil { + t.Error("x for c is nil") + } else if c2 := x.(float64); c2+1.2 != 4.7 { + t.Error("c2 (which should be 3.5) plus 1.2 does not equal 4.7; value:", c2) + } + if !expiration.IsZero() { + t.Error("expiration for c is not a zeroed time") + } + + x, expiration, found = tc.GetWithExpiration("d") + if !found { + t.Error("d was not found while getting d2") + } + if x == nil { + t.Error("x for d is nil") + } else if d2 := x.(int); d2+2 != 3 { + t.Error("d (which should be 1) plus 2 does not equal 3; value:", d2) + } + if !expiration.IsZero() { + t.Error("expiration for d is not a zeroed time") + } + + x, expiration, found = tc.GetWithExpiration("e") + if !found { + t.Error("e was not found while getting e2") + } + if x == nil { + t.Error("x for e is nil") + } else if e2 := x.(int); e2+2 != 3 { + t.Error("e (which should be 1) plus 2 does not equal 3; value:", e2) + } + if expiration.UnixNano() != tc.items["e"].Expiration { + t.Error("expiration for e is not the correct time") + } + if expiration.UnixNano() < time.Now().UnixNano() { + t.Error("expiration for e is in the past") + } +}