From 62a061f1f4012540098c4e5a86d0d731fdf8434d Mon Sep 17 00:00:00 2001 From: Patrick Mylund Nielsen Date: Wed, 4 Jan 2012 09:09:39 +0100 Subject: [PATCH] Add/Replace atomicity for r60.3 --- cache.go | 41 +++++++++++++++++++++-------------------- cache_test.go | 21 +++++++++++++++------ 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/cache.go b/cache.go index 161b694..90473d0 100644 --- a/cache.go +++ b/cache.go @@ -2,6 +2,7 @@ package cache import ( "fmt" + "os" "reflect" "runtime" "sync" @@ -91,7 +92,7 @@ type Cache struct { } type cache struct { - DefaultExpiration time.Duration + DefaultExpiration int64 Items map[string]*Item mu *sync.Mutex janitor *janitor @@ -99,30 +100,30 @@ type cache struct { type Item struct { Object interface{} - Expiration *time.Time + Expiration *int64 } type janitor struct { - Interval time.Duration + Interval int64 stop chan bool } // Adds an item to the cache, replacing any existing item. If the duration is 0, the // cache's default expiration time is used. If it is -1, the item never expires. -func (c *cache) Set(k string, x interface{}, d time.Duration) { +func (c *cache) Set(k string, x interface{}, d int64) { c.mu.Lock() defer c.mu.Unlock() c.set(k, x, d) } -func (c *cache) set(k string, x interface{}, d time.Duration) { - var e *time.Time +func (c *cache) set(k string, x interface{}, d int64) { + var e *int64 if d == 0 { d = c.DefaultExpiration } if d > 0 { - t := time.Now().Add(d) + t := time.Nanoseconds() + d e = &t } c.Items[k] = &Item{ @@ -132,8 +133,8 @@ func (c *cache) set(k string, x interface{}, d time.Duration) { } // Adds 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 if not. -func (c *cache) Add(k string, x interface{}, d time.Duration) error { +// or if the existing item has expired. Returns an os.Error if not. +func (c *cache) Add(k string, x interface{}, d int64) os.Error { c.mu.Lock() defer c.mu.Unlock() @@ -145,9 +146,9 @@ func (c *cache) Add(k string, x interface{}, d time.Duration) error { return nil } -// Sets a new value for the cache item only if it already exists. Returns an error if +// Sets a new value for the cache item only if it already exists. Returns an os.Error if // it does not. -func (c *cache) Replace(k string, x interface{}, d time.Duration) error { +func (c *cache) Replace(k string, x interface{}, d int64) os.Error { c.mu.Lock() defer c.mu.Unlock() @@ -181,10 +182,10 @@ func (c *cache) get(k string) (interface{}, bool) { } // Increment an item of type int, int8, int16, int32, int64, uintptr, uint, uint8, -// uint32, uint64, float32 or float64 by n. Returns an error if the item's value is +// uint32, uint64, float32 or float64 by n. Returns an os.Error if the item's value is // not an integer, if it was not found, or if it is not possible to increment it by // n. Passing a negative number will cause the item to be decremented. -func (c *cache) IncrementFloat(k string, n float64) error { +func (c *cache) IncrementFloat(k string, n float64) os.Error { c.mu.Lock() defer c.mu.Unlock() @@ -228,18 +229,18 @@ func (c *cache) IncrementFloat(k string, n float64) error { } // Increment an item of type int, int8, int16, int32, int64, uintptr, uint, uint8, -// uint32, or uint64, float32 or float64 by n. Returns an error if the item's value +// uint32, or uint64, float32 or float64 by n. Returns an os.Error if the item's value // is not an integer, if it was not found, or if it is not possible to increment it // by n. Passing a negative number will cause the item to be decremented. -func (c *cache) Increment(k string, n int64) error { +func (c *cache) Increment(k string, n int64) os.Error { return c.IncrementFloat(k, float64(n)) } // Decrement an item of type int, int8, int16, int32, int64, uintptr, uint, uint8, -// uint32, or uint64, float32 or float64 by n. Returns an error if the item's value +// uint32, or uint64, float32 or float64 by n. Returns an os.Error if the item's value // is not an integer, if it was not found, or if it is not possible to decrement it // by n. -func (c *cache) Decrement(k string, n int64) error { +func (c *cache) Decrement(k string, n int64) os.Error { return c.Increment(k, n*-1) } @@ -252,7 +253,7 @@ func (c *cache) Delete(k string) { } func (c *cache) delete(k string) { - delete(c.Items, k) + c.Items[k] = nil, false } // Deletes all expired items from the cache. @@ -280,7 +281,7 @@ func (i *Item) Expired() bool { if i.Expiration == nil { return false } - return i.Expiration.Before(time.Now()) + return *i.Expiration < time.Nanoseconds() } func (j *janitor) Run(c *cache) { @@ -309,7 +310,7 @@ func stopJanitor(c *Cache) { // expire and must be deleted manually. If the cleanup interval is less than one, // expired items are not deleted from the cache before their next lookup or before // calling DeleteExpired. -func New(de, ci time.Duration) *Cache { +func New(de, ci int64) *Cache { if de == 0 { de = -1 } diff --git a/cache_test.go b/cache_test.go index bc9b6a4..38b2b00 100644 --- a/cache_test.go +++ b/cache_test.go @@ -5,6 +5,15 @@ import ( "time" ) +const ( + Nanosecond = 1 + Microsecond = 1000 * Nanosecond + Millisecond = 1000 * Microsecond + Second = 1000 * Millisecond + Minute = 60 * Second + Hour = 60 * Minute +) + func TestCache(t *testing.T) { tc := New(0, 0) @@ -61,19 +70,19 @@ func TestCache(t *testing.T) { func TestCacheTimes(t *testing.T) { var found bool - tc := New(50*time.Millisecond, 1*time.Millisecond) + tc := New(50*Millisecond, 1*Millisecond) tc.Set("a", 1, 0) tc.Set("b", 2, -1) - tc.Set("c", 3, 20*time.Millisecond) - tc.Set("d", 4, 70*time.Millisecond) + tc.Set("c", 3, 20*Millisecond) + tc.Set("d", 4, 70*Millisecond) - <-time.After(25 * time.Millisecond) + <-time.After(25 * Millisecond) _, found = tc.Get("c") if found { t.Error("Found c when it should have been automatically deleted") } - <-time.After(30 * time.Millisecond) + <-time.After(30 * Millisecond) _, found = tc.Get("a") if found { t.Error("Found a when it should have been automatically deleted") @@ -89,7 +98,7 @@ func TestCacheTimes(t *testing.T) { t.Error("Did not find d even though it was set to expire later than the default") } - <-time.After(20 * time.Millisecond) + <-time.After(20 * Millisecond) _, found = tc.Get("d") if found { t.Error("Found d when it should have been automatically deleted (later than the default)")