Александър обнови решението на 17.11.2014 11:39 (преди над 3 години)
+package main
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+const DEFAULT_TIME = 10 * time.Millisecond
+
+var (
+ errIncr = fmt.Errorf("Incrementing did not succeed")
+ errDecr = fmt.Errorf("Decrementing did not succeed")
+ errToUpper = fmt.Errorf("ToUpper did not succeed")
+ errToLower = fmt.Errorf("ToLower did not succeed")
+)
+
+type Item struct {
+ Value interface{}
+ Expiration time.Time
+}
+
+func (i *Item) Expired() bool {
+ return i.Expiration.Before(time.Now())
+}
+
+func NewItem(v interface{}, t time.Time, em *ExpireMap) *Item {
+ i := new(Item)
+ i.Value = v
+ i.Expiration = t
+ go func(it *Item, expm *ExpireMap) {
+ for {
+ if it.Expiration.Before(time.Now()) {
+ expm.Lock()
+ expm.Unlock()
+ expm.ExpiredChan()
+ expm.DeleteExpired()
+ return
+ }
+ }
+ }(i, em)
+ return i
+}
+
+type ExpireMap struct {
+ sync.Mutex
+ items map[string]*Item
+ expires chan string
+}
+
+func NewExpireMap() *ExpireMap {
+ em := new(ExpireMap)
+ em.items = make(map[string]*Item)
+ em.expires = make(chan string, 20)
+ return em
+}
+
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+ em.Lock()
+ defer em.Unlock()
+ if expire == 0 {
+ expire = DEFAULT_TIME
+ }
+ var e time.Time
+ if expire > 0 {
+ e = time.Now().Add(expire)
+ }
+ i := NewItem(value, e, em)
+ em.items[key] = i
+}
+
+func (em *ExpireMap) Get(key string) (interface{}, bool) {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ if !found {
+ return nil, false
+ }
+ if item.Expired() {
+ return nil, false
+ }
+ return item.Value, true
+}
+
+func (em *ExpireMap) GetInt(key string) (int, bool) {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ var v int
+ if !found || item.Expired() {
+ return 0, false
+ }
+ v, ok := item.Value.(int)
+ return v, ok
+}
+
+func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ var v float64
+ if !found || item.Expired() {
+ return v, false
+ }
+ v, ok := item.Value.(float64)
+ return v, ok
+}
+
+func (em *ExpireMap) GetString(key string) (string, bool) {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ var v string
+ if !found || item.Expired() {
+ return v, false
+ }
+ v, ok := item.Value.(string)
+ return v, ok
+}
+
+func (em *ExpireMap) GetBool(key string) (bool, bool) {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ var v bool
+ if !found || item.Expired() {
+ return v, false
+ }
+ v, ok := item.Value.(bool)
+ return v, ok
+}
+
+// return time when key expires
+func (em *ExpireMap) Expires(key string) (time.Time, bool) {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ var t time.Time
+ if !found || item.Expired() {
+ return t, false
+ }
+ t = item.Expiration
+ return t, true
+}
+
+func (em *ExpireMap) Delete(key string) {
+ em.Lock()
+ defer em.Unlock()
+ delete(em.items, key)
+ return
+}
+
+func (em *ExpireMap) DeleteExpired() {
+ em.Lock()
+ defer em.Unlock()
+ for k, v := range em.items {
+ if v.Expired() {
+ delete(em.items, k)
+ }
+ }
+}
+
+func (em *ExpireMap) Contains(key string) bool {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ if !found || item.Expired() {
+ return false
+ }
+ return true
+}
+
+func (em *ExpireMap) Size() int {
+ em.Lock()
+ defer em.Unlock()
+ var size int
+ for _, item := range em.items {
+ if !item.Expired() {
+ size++
+ }
+ }
+ return size
+}
+
+func (em *ExpireMap) Increment(key string) error {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ if !found || item.Expired() {
+ return errIncr
+ }
+ if v, ok := item.Value.(int); ok {
+ v++
+ item.Value = v
+ return nil
+ }
+ if str, ok := item.Value.(string); ok {
+ if v, err := strconv.Atoi(str); err == nil {
+ v++
+ item.Value = strconv.Itoa(v)
+ return nil
+ } else {
+ return errIncr
+ }
+ }
+ return errIncr
+}
+
+func (em *ExpireMap) Decrement(key string) error {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ if !found || item.Expired() {
+ return errDecr
+ }
+ if v, ok := item.Value.(int); ok {
+ v--
+ item.Value = v
+ return nil
+ }
+ if str, ok := item.Value.(string); ok {
+ if v, err := strconv.Atoi(str); err == nil {
+ v--
+ item.Value = strconv.Itoa(v)
+ return nil
+ } else {
+ return errDecr
+ }
+ }
+ return errDecr
+}
+
+func (em *ExpireMap) ToUpper(key string) error {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ if !found || item.Expired() {
+ return errToUpper
+ }
+ if str, ok := item.Value.(string); ok {
+ item.Value = strings.ToUpper(str)
+ return nil
+ }
+ return errToUpper
+}
+
+func (em *ExpireMap) ToLower(key string) error {
+ em.Lock()
+ defer em.Unlock()
+ item, found := em.items[key]
+ if !found || item.Expired() {
+ return errToLower
+ }
+ if str, ok := item.Value.(string); ok {
+ item.Value = strings.ToLower(str)
+ return nil
+ }
+ return errToLower
+}
+
+func (em *ExpireMap) ExpiredChan() <-chan string {
+ for k, v := range em.items {
+ if v.Expired() {
+ em.expires <- k
+ }
+ }
+ return em.expires
+}
+
+func (em *ExpireMap) Cleanup() {
+ em.Lock()
+ defer em.Unlock()
+ for key, _ := range em.items {
+ delete(em.items, key)
+ }
+}
+
+func (em *ExpireMap) Destroy() {
+ em.Lock()
+ defer em.Unlock()
+ close(em.expires)
+ for key, _ := range em.items {
+ delete(em.items, key)
+ }
+ em = nil
+}
На пръв поглед две неща:
- на ред 34 имаш цикъл който ще се върти постоянно до изтичането на времето, помисли как да го направиш да чака нещо ... чакайки ;)
- погледни си ExpiredChan-а