Commit 24e8dccd authored by Dustin L. Howett's avatar Dustin L. Howett

Fix concurrency in Map, allow it to be zero-initialized.

parent bffcfba1
package gotimeout
import (
"sync"
"time"
)
......@@ -12,6 +13,9 @@ type MapValue interface{}
type Map struct {
expirator *Expirator
values map[string]MapValue
mu sync.RWMutex
once sync.Once
}
type expirationProxy ExpirableID
......@@ -30,25 +34,63 @@ func NewMap() *Map {
return v
}
func (e *Map) init() {
e.once.Do(func() {
e.mu.Lock()
if e.values == nil {
e.values = make(map[string]MapValue)
}
if e.expirator == nil {
e.expirator = NewExpirator("", e)
}
e.mu.Unlock()
})
}
// Put places the given object into the key-value store and queues its expiration.
func (e *Map) Put(k string, v MapValue, lifespan time.Duration) {
e.init()
e.mu.Lock()
defer e.mu.Unlock()
e.values[k] = v
e.expirator.ExpireObject(expirationProxy(k), lifespan)
}
// Get returns the object referred to by the given key.
func (e *Map) Get(k string) (v MapValue, ok bool) {
e.mu.RLock()
defer e.mu.RUnlock()
if e.values == nil {
return nil, false
}
v, ok = e.values[k]
return
}
// Delete removes the object referred to by the given key from the key-value store and stays its execution.
func (e *Map) Delete(k string) {
e.mu.Lock()
defer e.mu.Unlock()
if e.values == nil {
return
}
e.expirator.CancelObjectExpiration(expirationProxy(k))
delete(e.values, k)
}
func (e *Map) GetExpirable(id ExpirableID) Expirable {
e.mu.RLock()
defer e.mu.RUnlock()
_, ok := e.values[string(id)]
if !ok {
return nil
......@@ -57,5 +99,8 @@ func (e *Map) GetExpirable(id ExpirableID) Expirable {
}
func (e *Map) DestroyExpirable(ex Expirable) {
e.mu.Lock()
defer e.mu.Unlock()
delete(e.values, string(ex.ExpirationID()))
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment