Решение на ExpireMap от Йосиф Цветков

Обратно към всички решения

Към профила на Йосиф Цветков

Резултати

  • 9 точки от тестове
  • 0 бонус точки
  • 9 точки общо
  • 23 успешни тест(а)
  • 2 неуспешни тест(а)

Код

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type SomeError struct {
Message string
}
func (se *SomeError) Error() string {
return se.Message
}
type cacheRecord struct {
timeOfDeath time.Time
value interface{}
deathChannel chan struct{}
}
type ExpireMap struct {
lockCache *sync.Mutex
returnKeys *chan string
cache map[string]*cacheRecord
}
func NewExpireMap() *ExpireMap {
channel := make(chan string, 1000)
return &ExpireMap{
lockCache: &sync.Mutex{},
returnKeys: &channel,
cache: make(map[string]*cacheRecord),
}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.lockCache.Lock()
if record, isPresent := em.cache[key]; isPresent == true {
record.deathChannel <- struct{}{}
record.value = value
record.timeOfDeath = time.Now().Add(expire)
em.lockCache.Unlock()
em.startGoRoutine(key, expire)
} else {
newRecord := new(cacheRecord)
newRecord.value = value
newRecord.timeOfDeath = time.Now().Add(expire)
newRecord.deathChannel = make(chan struct{})
em.cache[key] = newRecord
em.lockCache.Unlock()
em.startGoRoutine(key, expire)
}
}
func (em *ExpireMap) startGoRoutine(key string, expire time.Duration) {
go func(key string, expire time.Duration) {
select {
case <-time.After(expire):
em.lockCache.Lock()
*em.returnKeys <- key
delete(em.cache, key)
em.lockCache.Unlock()
case <-em.cache[key].deathChannel:
}
}(key, expire)
}
func (em *ExpireMap) Contains(key string) bool {
_, isPresent := em.cache[key]
return isPresent
}
func (em *ExpireMap) Get(key string) (value interface{}, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
return record.value, isPresent
}
return
}
func (em *ExpireMap) GetInt(key string) (value int, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(int); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetFloat64(key string) (value float64, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(float64); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetString(key string) (value string, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(string); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetBool(key string) (value bool, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(bool); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) Expires(key string) (value time.Time, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
return record.timeOfDeath, isPresent
}
return
}
func (em *ExpireMap) Delete(key string) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
em.cache[key].deathChannel <- struct{}{}
delete(em.cache, key)
}
func (em *ExpireMap) Size() (size int) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
for _ = range em.cache {
size++
}
return
}
func (em *ExpireMap) Increment(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
switch value := record.value.(type) {
case int:
record.value = value + 1
return nil
case string:
if number, ok := strconv.Atoi(value); ok == nil {
record.value = strconv.Itoa(number + 1)
return nil
} else {
return &SomeError{Message: "This value cannot be incremented !"}
}
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) Decrement(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
switch value := record.value.(type) {
case int:
record.value = value - 1
return nil
case string:
if number, ok := strconv.Atoi(value); ok == nil {
record.value = strconv.Itoa(number - 1)
return nil
} else {
return &SomeError{Message: "This value cannot be incremented !"}
}
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToUpper(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, ok := em.cache[key]; ok == true {
switch value := record.value.(type) {
case string:
record.value = strings.ToUpper(value)
return nil
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToLower(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, ok := em.cache[key]; ok == true {
switch value := record.value.(type) {
case string:
record.value = strings.ToLower(value)
return nil
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return *em.returnKeys
}
func (em *ExpireMap) Cleanup() {
em.lockCache.Lock()
defer em.lockCache.Unlock()
for _, value := range em.cache {
value.deathChannel <- struct{}{}
}
em.cache = make(map[string]*cacheRecord)
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
close(*em.returnKeys)
}

Лог от изпълнението

PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.016s
panic: test timed out

goroutine 15 [running]:
testing.alarm()
	/usr/local/lib/go/src/pkg/testing/testing.go:533 +0x44
created by time.goFunc
	/usr/local/lib/go/src/pkg/time/sleep.go:122 +0x45

goroutine 1 [chan receive]:
testing.RunTests(0x8148a70, 0x81c3ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148a70, 0x81c3ba0, 0x19, 0x19, 0x81c6600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-1hc7ipf/_test/_testmain.go:91 +0x81

goroutine 4 [sleep]:
time.Sleep(0x3c336080, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-1hc7ipf.TestSizes(0x183611e0)
	/tmp/d20141204-6466-1hc7ipf/solution_test.go:111 +0x3ce
testing.tRunner(0x183611e0, 0x81c3bb8)
	/usr/local/lib/go/src/pkg/testing/testing.go:353 +0x87
created by testing.RunTests
	/usr/local/lib/go/src/pkg/testing/testing.go:433 +0x684

goroutine 5 [select]:
_/tmp/d20141204-6466-1hc7ipf.func·001(0x18300318, 0x5, 0x3b9aca00, 0x0)
	/tmp/d20141204-6466-1hc7ipf/solution.go:61 +0x148
created by _/tmp/d20141204-6466-1hc7ipf.(*ExpireMap).startGoRoutine
	/tmp/d20141204-6466-1hc7ipf/solution.go:69 +0x7d

goroutine 6 [select]:
_/tmp/d20141204-6466-1hc7ipf.func·001(0x18300340, 0x5, 0x3b9aca00, 0x0)
	/tmp/d20141204-6466-1hc7ipf/solution.go:61 +0x148
created by _/tmp/d20141204-6466-1hc7ipf.(*ExpireMap).startGoRoutine
	/tmp/d20141204-6466-1hc7ipf/solution.go:69 +0x7d

goroutine 7 [select]:
_/tmp/d20141204-6466-1hc7ipf.func·001(0x18300368, 0x5, 0x3b9aca00, 0x0)
	/tmp/d20141204-6466-1hc7ipf/solution.go:61 +0x148
created by _/tmp/d20141204-6466-1hc7ipf.(*ExpireMap).startGoRoutine
	/tmp/d20141204-6466-1hc7ipf/solution.go:69 +0x7d

goroutine 8 [select]:
_/tmp/d20141204-6466-1hc7ipf.func·001(0x18300390, 0x5, 0x3b9aca00, 0x0)
	/tmp/d20141204-6466-1hc7ipf/solution.go:61 +0x148
created by _/tmp/d20141204-6466-1hc7ipf.(*ExpireMap).startGoRoutine
	/tmp/d20141204-6466-1hc7ipf/solution.go:69 +0x7d

goroutine 9 [select]:
_/tmp/d20141204-6466-1hc7ipf.func·001(0x183003b8, 0x5, 0x3b9aca00, 0x0)
	/tmp/d20141204-6466-1hc7ipf/solution.go:61 +0x148
created by _/tmp/d20141204-6466-1hc7ipf.(*ExpireMap).startGoRoutine
	/tmp/d20141204-6466-1hc7ipf/solution.go:69 +0x7d

goroutine 10 [select]:
_/tmp/d20141204-6466-1hc7ipf.func·001(0x183003e0, 0x5, 0x3b9aca00, 0x0)
	/tmp/d20141204-6466-1hc7ipf/solution.go:61 +0x148
created by _/tmp/d20141204-6466-1hc7ipf.(*ExpireMap).startGoRoutine
	/tmp/d20141204-6466-1hc7ipf/solution.go:69 +0x7d

goroutine 11 [select]:
_/tmp/d20141204-6466-1hc7ipf.func·001(0x18300408, 0x5, 0x3b9aca00, 0x0)
	/tmp/d20141204-6466-1hc7ipf/solution.go:61 +0x148
created by _/tmp/d20141204-6466-1hc7ipf.(*ExpireMap).startGoRoutine
	/tmp/d20141204-6466-1hc7ipf/solution.go:69 +0x7d

goroutine 12 [select]:
_/tmp/d20141204-6466-1hc7ipf.func·001(0x18300430, 0x5, 0x3b9aca00, 0x0)
	/tmp/d20141204-6466-1hc7ipf/solution.go:61 +0x148
created by _/tmp/d20141204-6466-1hc7ipf.(*ExpireMap).startGoRoutine
	/tmp/d20141204-6466-1hc7ipf/solution.go:69 +0x7d

goroutine 13 [select]:
_/tmp/d20141204-6466-1hc7ipf.func·001(0x18300458, 0x5, 0x3b9aca00, 0x0)
	/tmp/d20141204-6466-1hc7ipf/solution.go:61 +0x148
created by _/tmp/d20141204-6466-1hc7ipf.(*ExpireMap).startGoRoutine
	/tmp/d20141204-6466-1hc7ipf/solution.go:69 +0x7d

goroutine 14 [select]:
_/tmp/d20141204-6466-1hc7ipf.func·001(0x18300480, 0x5, 0x3b9aca00, 0x0)
	/tmp/d20141204-6466-1hc7ipf/solution.go:61 +0x148
created by _/tmp/d20141204-6466-1hc7ipf.(*ExpireMap).startGoRoutine
	/tmp/d20141204-6466-1hc7ipf/solution.go:69 +0x7d
exit status 2
FAIL	_/tmp/d20141204-6466-1hc7ipf	1.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.122s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.172s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.014s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.040s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.013s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.112s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.062s
--- FAIL: TestExpiredChanWhenNoOneIsReading-2 (0.06 seconds)
	solution_test.go:554: Wrong key expired
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-1hc7ipf	0.072s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.114s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.132s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.145s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.272s
PASS
ok  	_/tmp/d20141204-6466-1hc7ipf	0.012s

История (9 версии и 3 коментара)

Йосиф обнови решението на 13.11.2014 21:34 (преди над 3 години)

+package main
+
+import "time"
+import "sync"
+import "strconv"
+import "strings"
+
+type SomeError struct {
+ Message string
+}
+
+func (se *SomeError) Error() string {
+ return se.Message
+}
+
+type ExpireMap struct {
+ Cache map[string]interface{}
+ Times map[string]time.Duration
+ Communication chan string
+ Lock *sync.Mutex
+}
+
+func NewExpireMap() *ExpireMap {
+ return &ExpireMap{
+ Cache: make(map[string]interface{}),
+ Times: make(map[string]time.Duration),
+ Communication: make(chan string, 1000),
+ Lock: &sync.Mutex{}}
+}
+
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+ em.Cache[key] = value
+ em.Times[key] = expire
+ go func() {
+ time.Sleep(expire)
+ em.Lock.Lock()
+ defer em.Lock.Unlock()
+
+ if _, isPresent := em.Cache[key]; isPresent == true {
+ delete(em.Cache, key)
+ delete(em.Times, key)
+ em.Communication <- key
+ }
+ }()
+}
+
+func (em *ExpireMap) Get(key string) (interface{}, bool) {
+ value, isPresent := em.Cache[key]
+ return value, isPresent
+}
+
+func (em *ExpireMap) GetInt(key string) (int, bool) {
+ value, isPresent := em.Cache[key].(int)
+ if isPresent {
+ return value, isPresent
+ } else {
+ return 0, false
+ }
+}
+
+func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
+ value, isPresent := em.Cache[key].(float64)
+ if isPresent {
+ return value, isPresent
+ } else {
+ return 0, false
+ }
+}
+
+func (em *ExpireMap) GetString(key string) (string, bool) {
+ value, isPresent := em.Cache[key].(string)
+ if isPresent {
+ return value, isPresent
+ } else {
+ return "", false
+ }
+}
+
+func (em *ExpireMap) GetBool(key string) (bool, bool) {
+ value, isPresent := em.Cache[key].(bool)
+ if isPresent {
+ return value, isPresent
+ } else {
+ return false, false
+ }
+}
+
+func (em *ExpireMap) Expires(key string) (time.Time, bool) {
+ timeToLive, isPresent := em.Times[key]
+ if !isPresent {
+ return time.Time{}, false
+ } else {
+ return time.Now().Add(timeToLive), true
+ }
+}
+
+func (em *ExpireMap) Delete(key string) {
+ em.Lock.Lock()
+ defer em.Lock.Unlock()
+
+ delete(em.Cache, key)
+ delete(em.Times, key)
+}
+
+func (em *ExpireMap) Contains(key string) bool {
+ _, isPresent := em.Cache[key]
+ return isPresent
+}
+
+func (em *ExpireMap) Size() int {
+ size := 0
+ for _ = range em.Cache {
+ size++
+ }
+ return size
+}
+
+func (em *ExpireMap) Increment(key string) error {
+ em.Lock.Lock()
+ defer em.Lock.Unlock()
+
+ if value, isPresent := em.Cache[key]; isPresent == true {
+ switch value_type := value.(type) {
+ case int:
+ em.Cache[key] = value_type + 1
+ return nil
+ case string:
+ if number, err := strconv.Atoi(value_type); err == nil {
+ em.Cache[key] = strconv.Itoa(number + 1)
+ return nil
+ } else {
+ return err
+ }
+ default:
+ return &SomeError{Message: "Unsupported type for this function !"}
+ }
+ }
+ return &SomeError{Message: "No such key"}
+}
+
+func (em *ExpireMap) Decrement(key string) error {
+ em.Lock.Lock()
+ defer em.Lock.Unlock()
+
+ if value_type, isPresent := em.Cache[key]; isPresent == true {
+ switch value := value_type.(type) {
+ case int:
+ em.Cache[key] = value - 1
+ return nil
+ case string:
+ if number, err := strconv.Atoi(value); err == nil {
+ em.Cache[key] = strconv.Itoa(number - 1)
+ return nil
+ } else {
+ return err
+ }
+ default:
+ return &SomeError{Message: "Unsupported type for this function !"}
+ }
+ }
+ return &SomeError{Message: "No such key"}
+}
+
+func (em *ExpireMap) ToUpper(key string) error {
+ em.Lock.Lock()
+ defer em.Lock.Unlock()
+
+ if value_type, isPresent := em.Cache[key]; isPresent == true {
+ switch value := value_type.(type) {
+ case string:
+ em.Cache[key] = strings.ToUpper(value)
+ return nil
+ default:
+ return &SomeError{Message: "Unsupported value for this function !"}
+ }
+ }
+ return &SomeError{Message: "No such keykey !"}
+}
+
+func (em *ExpireMap) ToLower(key string) error {
+ em.Lock.Lock()
+ defer em.Lock.Unlock()
+
+ if value, isPresent := em.Cache[key]; isPresent == true {
+ switch value_type := value.(type) {
+ case string:
+ em.Cache[key] = strings.ToLower(value_type)
+ return nil
+ default:
+ return &SomeError{Message: "Unsupported type for this function !"}
+ }
+ }
+ return &SomeError{Message: "No such keykey !"}
+}
+
+func (em *ExpireMap) ExpiredChan() <-chan string {
+ channel := make(chan string, 1000)
+ go func() {
+ for {
+ value := <-em.Communication
+ channel <- value
+ }
+ }()
+ return channel
+}
+
+func (em *ExpireMap) Cleanup() {
+ em.Cache = nil
+ em.Times = nil
+ em.Lock = nil
+}
+
+func (em *ExpireMap) Destroy() {
+ em.Cache = nil
+ em.Times = nil
+ em.Lock = nil
+ em = nil
+}

Йосиф обнови решението на 15.11.2014 16:34 (преди над 3 години)

package main
-import "time"
-import "sync"
-import "strconv"
-import "strings"
+import (
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
type SomeError struct {
Message string
}
func (se *SomeError) Error() string {
return se.Message
}
type ExpireMap struct {
- Cache map[string]interface{}
- Times map[string]time.Duration
- Communication chan string
- Lock *sync.Mutex
+ numberOfRunningRoutines int
+ lockCache *sync.Mutex
+ lockNumberOfRunningRoutines *sync.Mutex
+ returnKeys chan string
+ signalForDeathOfRoutine chan struct{}
+ signalFromLastRunningRoutine chan struct{}
+ timesOfDeath map[string]time.Time
+ cache map[string]interface{}
}
func NewExpireMap() *ExpireMap {
return &ExpireMap{
- Cache: make(map[string]interface{}),
- Times: make(map[string]time.Duration),
- Communication: make(chan string, 1000),
- Lock: &sync.Mutex{}}
+ numberOfRunningRoutines: 0,
+ lockCache: &sync.Mutex{},
+ lockNumberOfRunningRoutines: &sync.Mutex{},
+ signalForDeathOfRoutine: make(chan struct{}),
+ signalFromLastRunningRoutine: make(chan struct{}),
+ returnKeys: make(chan string, 1000),
+ timesOfDeath: make(map[string]time.Time),
+ cache: make(map[string]interface{}),
+ }
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
- em.Cache[key] = value
- em.Times[key] = expire
+ em.cache[key] = value
+ em.timesOfDeath[key] = time.Now().Add(expire)
+
+ em.lockNumberOfRunningRoutines.Lock()
+ em.numberOfRunningRoutines += 1
+ em.lockNumberOfRunningRoutines.Unlock()
+
go func() {
- time.Sleep(expire)
- em.Lock.Lock()
- defer em.Lock.Unlock()
+ select {
+ case <-time.After(expire):
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
- if _, isPresent := em.Cache[key]; isPresent == true {
- delete(em.Cache, key)
- delete(em.Times, key)
- em.Communication <- key
+ if _, isPresent := em.cache[key]; isPresent == true {
+ delete(em.cache, key)
+ delete(em.timesOfDeath, key)
+ em.returnKeys <- key
+
+ em.lockNumberOfRunningRoutines.Lock()
+ em.numberOfRunningRoutines -= 1
+ em.lockNumberOfRunningRoutines.Unlock()
+ }
+ case <-em.signalForDeathOfRoutine:
+ em.lockNumberOfRunningRoutines.Lock()
+ em.numberOfRunningRoutines -= 1
+ temp := em.numberOfRunningRoutines
+ em.lockNumberOfRunningRoutines.Unlock()
+
+ if temp > 0 {
+ em.signalForDeathOfRoutine <- struct{}{}
+ } else {
+ em.signalFromLastRunningRoutine <- struct{}{}
+ }
+
}
}()
}
+func (em *ExpireMap) Contains(key string) bool {
+ _, isPresent := em.cache[key]
+ return isPresent
+}
+
func (em *ExpireMap) Get(key string) (interface{}, bool) {
- value, isPresent := em.Cache[key]
+ value, isPresent := em.cache[key]
return value, isPresent
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
- value, isPresent := em.Cache[key].(int)
- if isPresent {
- return value, isPresent
- } else {
- return 0, false
- }
+ value, isPresent := em.cache[key].(int)
+ return value, isPresent
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
- value, isPresent := em.Cache[key].(float64)
- if isPresent {
- return value, isPresent
- } else {
- return 0, false
- }
+ value, isPresent := em.cache[key].(float64)
+ return value, isPresent
}
func (em *ExpireMap) GetString(key string) (string, bool) {
- value, isPresent := em.Cache[key].(string)
- if isPresent {
- return value, isPresent
- } else {
- return "", false
- }
+ value, isPresent := em.cache[key].(string)
+ return value, isPresent
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
- value, isPresent := em.Cache[key].(bool)
- if isPresent {
- return value, isPresent
- } else {
- return false, false
- }
+ value, isPresent := em.cache[key].(bool)
+ return value, isPresent
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
- timeToLive, isPresent := em.Times[key]
- if !isPresent {
- return time.Time{}, false
- } else {
- return time.Now().Add(timeToLive), true
- }
+ timeOfDeath, isPresent := em.timesOfDeath[key]
+ return timeOfDeath, isPresent
}
func (em *ExpireMap) Delete(key string) {
- em.Lock.Lock()
- defer em.Lock.Unlock()
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
- delete(em.Cache, key)
- delete(em.Times, key)
+ delete(em.cache, key)
+ delete(em.timesOfDeath, key)
}
-func (em *ExpireMap) Contains(key string) bool {
- _, isPresent := em.Cache[key]
- return isPresent
-}
-
func (em *ExpireMap) Size() int {
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
+
size := 0
- for _ = range em.Cache {
+ for _ = range em.cache {
size++
}
return size
}
func (em *ExpireMap) Increment(key string) error {
- em.Lock.Lock()
- defer em.Lock.Unlock()
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
- if value, isPresent := em.Cache[key]; isPresent == true {
+ if value, isPresent := em.cache[key]; isPresent == true {
switch value_type := value.(type) {
case int:
- em.Cache[key] = value_type + 1
+ em.cache[key] = value_type + 1
return nil
case string:
if number, err := strconv.Atoi(value_type); err == nil {
- em.Cache[key] = strconv.Itoa(number + 1)
+ em.cache[key] = strconv.Itoa(number + 1)
return nil
} else {
return err
}
default:
return &SomeError{Message: "Unsupported type for this function !"}
}
}
return &SomeError{Message: "No such key"}
}
func (em *ExpireMap) Decrement(key string) error {
- em.Lock.Lock()
- defer em.Lock.Unlock()
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
- if value_type, isPresent := em.Cache[key]; isPresent == true {
+ if value_type, isPresent := em.cache[key]; isPresent == true {
switch value := value_type.(type) {
case int:
- em.Cache[key] = value - 1
+ em.cache[key] = value - 1
return nil
case string:
if number, err := strconv.Atoi(value); err == nil {
- em.Cache[key] = strconv.Itoa(number - 1)
+ em.cache[key] = strconv.Itoa(number - 1)
return nil
} else {
return err
}
default:
return &SomeError{Message: "Unsupported type for this function !"}
}
}
return &SomeError{Message: "No such key"}
}
func (em *ExpireMap) ToUpper(key string) error {
- em.Lock.Lock()
- defer em.Lock.Unlock()
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
- if value_type, isPresent := em.Cache[key]; isPresent == true {
+ if value_type, isPresent := em.cache[key]; isPresent == true {
switch value := value_type.(type) {
case string:
- em.Cache[key] = strings.ToUpper(value)
+ em.cache[key] = strings.ToUpper(value)
return nil
default:
return &SomeError{Message: "Unsupported value for this function !"}
}
}
- return &SomeError{Message: "No such keykey !"}
+ return &SomeError{Message: "No such key !"}
}
func (em *ExpireMap) ToLower(key string) error {
- em.Lock.Lock()
- defer em.Lock.Unlock()
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
- if value, isPresent := em.Cache[key]; isPresent == true {
+ if value, isPresent := em.cache[key]; isPresent == true {
switch value_type := value.(type) {
case string:
- em.Cache[key] = strings.ToLower(value_type)
+ em.cache[key] = strings.ToLower(value_type)
return nil
default:
return &SomeError{Message: "Unsupported type for this function !"}
}
}
- return &SomeError{Message: "No such keykey !"}
+ return &SomeError{Message: "No such key !"}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
- channel := make(chan string, 1000)
- go func() {
- for {
- value := <-em.Communication
- channel <- value
- }
- }()
- return channel
+ return em.returnKeys
}
func (em *ExpireMap) Cleanup() {
- em.Cache = nil
- em.Times = nil
- em.Lock = nil
+ if em.numberOfRunningRoutines != 0 {
+ em.signalForDeathOfRoutine <- struct{}{}
+ x := <-em.signalFromLastRunningRoutine
+ x = x
+ }
+
+ em.lockCache = &sync.Mutex{}
+ em.numberOfRunningRoutines = 0
+ em.cache = make(map[string]interface{})
+ em.returnKeys = make(chan string, 1000)
+ em.timesOfDeath = make(map[string]time.Time)
+ em.lockNumberOfRunningRoutines = &sync.Mutex{}
+ em.signalForDeathOfRoutine = make(chan struct{})
+ em.signalFromLastRunningRoutine = make(chan struct{})
}
func (em *ExpireMap) Destroy() {
- em.Cache = nil
- em.Times = nil
- em.Lock = nil
+ if em.numberOfRunningRoutines != 0 {
+ em.signalForDeathOfRoutine <- struct{}{}
+ _ = <-em.signalFromLastRunningRoutine
+ }
+
+ em.cache = nil
+ em.timesOfDeath = nil
+ em.lockCache = nil
+ em.lockNumberOfRunningRoutines = nil
+ em.numberOfRunningRoutines = 0
+ em.signalForDeathOfRoutine = nil
+ em.signalFromLastRunningRoutine = nil
+ em.returnKeys = nil
em = nil
}

Йосиф обнови решението на 15.11.2014 17:36 (преди над 3 години)

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type SomeError struct {
Message string
}
func (se *SomeError) Error() string {
return se.Message
}
type ExpireMap struct {
numberOfRunningRoutines int
lockCache *sync.Mutex
lockNumberOfRunningRoutines *sync.Mutex
returnKeys chan string
signalForDeathOfRoutine chan struct{}
signalFromLastRunningRoutine chan struct{}
timesOfDeath map[string]time.Time
cache map[string]interface{}
}
func NewExpireMap() *ExpireMap {
return &ExpireMap{
numberOfRunningRoutines: 0,
lockCache: &sync.Mutex{},
lockNumberOfRunningRoutines: &sync.Mutex{},
signalForDeathOfRoutine: make(chan struct{}),
signalFromLastRunningRoutine: make(chan struct{}),
returnKeys: make(chan string, 1000),
timesOfDeath: make(map[string]time.Time),
cache: make(map[string]interface{}),
}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.cache[key] = value
em.timesOfDeath[key] = time.Now().Add(expire)
em.lockNumberOfRunningRoutines.Lock()
em.numberOfRunningRoutines += 1
em.lockNumberOfRunningRoutines.Unlock()
go func() {
select {
case <-time.After(expire):
em.lockCache.Lock()
defer em.lockCache.Unlock()
if _, isPresent := em.cache[key]; isPresent == true {
delete(em.cache, key)
delete(em.timesOfDeath, key)
em.returnKeys <- key
em.lockNumberOfRunningRoutines.Lock()
em.numberOfRunningRoutines -= 1
em.lockNumberOfRunningRoutines.Unlock()
}
case <-em.signalForDeathOfRoutine:
em.lockNumberOfRunningRoutines.Lock()
em.numberOfRunningRoutines -= 1
temp := em.numberOfRunningRoutines
em.lockNumberOfRunningRoutines.Unlock()
if temp > 0 {
em.signalForDeathOfRoutine <- struct{}{}
} else {
em.signalFromLastRunningRoutine <- struct{}{}
}
}
}()
}
func (em *ExpireMap) Contains(key string) bool {
_, isPresent := em.cache[key]
return isPresent
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
value, isPresent := em.cache[key]
return value, isPresent
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
value, isPresent := em.cache[key].(int)
return value, isPresent
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
value, isPresent := em.cache[key].(float64)
return value, isPresent
}
func (em *ExpireMap) GetString(key string) (string, bool) {
value, isPresent := em.cache[key].(string)
return value, isPresent
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
value, isPresent := em.cache[key].(bool)
return value, isPresent
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
timeOfDeath, isPresent := em.timesOfDeath[key]
return timeOfDeath, isPresent
}
func (em *ExpireMap) Delete(key string) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
delete(em.cache, key)
delete(em.timesOfDeath, key)
}
func (em *ExpireMap) Size() int {
em.lockCache.Lock()
defer em.lockCache.Unlock()
size := 0
for _ = range em.cache {
size++
}
return size
}
func (em *ExpireMap) Increment(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
- if value, isPresent := em.cache[key]; isPresent == true {
- switch value_type := value.(type) {
- case int:
- em.cache[key] = value_type + 1
- return nil
- case string:
- if number, err := strconv.Atoi(value_type); err == nil {
- em.cache[key] = strconv.Itoa(number + 1)
- return nil
- } else {
- return err
- }
- default:
- return &SomeError{Message: "Unsupported type for this function !"}
- }
+ if value, ok := em.cache[key].(int); ok == true {
+ em.cache[key] = value + 1
+ return nil
+ } else if value, ok := strconv.Atoi(em.cache[key].(string)); ok == nil {
+ em.cache[key] = strconv.Itoa(value + 1)
+ return nil
}
- return &SomeError{Message: "No such key"}
+ return &SomeError{Message: "Operation cannot be executed !"}
}
func (em *ExpireMap) Decrement(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
- if value_type, isPresent := em.cache[key]; isPresent == true {
- switch value := value_type.(type) {
- case int:
- em.cache[key] = value - 1
- return nil
- case string:
- if number, err := strconv.Atoi(value); err == nil {
- em.cache[key] = strconv.Itoa(number - 1)
- return nil
- } else {
- return err
- }
- default:
- return &SomeError{Message: "Unsupported type for this function !"}
- }
+ if value, ok := em.cache[key].(int); ok == true {
+ em.cache[key] = value - 1
+ return nil
+ } else if value, ok := strconv.Atoi(em.cache[key].(string)); ok == nil {
+ em.cache[key] = strconv.Itoa(value - 1)
+ return nil
}
- return &SomeError{Message: "No such key"}
+ return &SomeError{Message: "Operation cannot be executed !"}
}
func (em *ExpireMap) ToUpper(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
- if value_type, isPresent := em.cache[key]; isPresent == true {
- switch value := value_type.(type) {
- case string:
- em.cache[key] = strings.ToUpper(value)
- return nil
- default:
- return &SomeError{Message: "Unsupported value for this function !"}
- }
+ if value, ok := em.cache[key].(string); ok == true {
+ em.cache[key] = strings.ToUpper(value)
+ return nil
}
- return &SomeError{Message: "No such key !"}
+ return &SomeError{Message: "Operation cannot be executed !"}
}
func (em *ExpireMap) ToLower(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
- if value, isPresent := em.cache[key]; isPresent == true {
- switch value_type := value.(type) {
- case string:
- em.cache[key] = strings.ToLower(value_type)
- return nil
- default:
- return &SomeError{Message: "Unsupported type for this function !"}
- }
+ if value, ok := em.cache[key].(string); ok == true {
+ em.cache[key] = strings.ToLower(value)
+ return nil
}
- return &SomeError{Message: "No such key !"}
+ return &SomeError{Message: "Operation cannot be executed !"}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.returnKeys
}
func (em *ExpireMap) Cleanup() {
if em.numberOfRunningRoutines != 0 {
em.signalForDeathOfRoutine <- struct{}{}
- x := <-em.signalFromLastRunningRoutine
- x = x
+ _ = <-em.signalFromLastRunningRoutine
}
-
- em.lockCache = &sync.Mutex{}
- em.numberOfRunningRoutines = 0
em.cache = make(map[string]interface{})
- em.returnKeys = make(chan string, 1000)
- em.timesOfDeath = make(map[string]time.Time)
- em.lockNumberOfRunningRoutines = &sync.Mutex{}
- em.signalForDeathOfRoutine = make(chan struct{})
- em.signalFromLastRunningRoutine = make(chan struct{})
}
func (em *ExpireMap) Destroy() {
- if em.numberOfRunningRoutines != 0 {
- em.signalForDeathOfRoutine <- struct{}{}
- _ = <-em.signalFromLastRunningRoutine
- }
-
- em.cache = nil
- em.timesOfDeath = nil
- em.lockCache = nil
- em.lockNumberOfRunningRoutines = nil
- em.numberOfRunningRoutines = 0
- em.signalForDeathOfRoutine = nil
- em.signalFromLastRunningRoutine = nil
- em.returnKeys = nil
- em = nil
+ em.Cleanup()
+ *em = *(NewExpireMap())
}

Йосиф обнови решението на 16.11.2014 22:30 (преди над 3 години)

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type SomeError struct {
Message string
}
func (se *SomeError) Error() string {
return se.Message
}
type ExpireMap struct {
- numberOfRunningRoutines int
- lockCache *sync.Mutex
- lockNumberOfRunningRoutines *sync.Mutex
- returnKeys chan string
- signalForDeathOfRoutine chan struct{}
- signalFromLastRunningRoutine chan struct{}
- timesOfDeath map[string]time.Time
- cache map[string]interface{}
+ lockCache *sync.Mutex
+ lockNumberOfRunningRoutines *sync.Mutex
+ returnKeys chan string
+ die []chan struct{}
+ dieIndex map[string]int
+ timesOfDeath map[string]time.Time
+ cache map[string]interface{}
}
func NewExpireMap() *ExpireMap {
return &ExpireMap{
- numberOfRunningRoutines: 0,
- lockCache: &sync.Mutex{},
- lockNumberOfRunningRoutines: &sync.Mutex{},
- signalForDeathOfRoutine: make(chan struct{}),
- signalFromLastRunningRoutine: make(chan struct{}),
- returnKeys: make(chan string, 1000),
- timesOfDeath: make(map[string]time.Time),
- cache: make(map[string]interface{}),
+ lockCache: &sync.Mutex{},
+ lockNumberOfRunningRoutines: &sync.Mutex{},
+ dieIndex: make(map[string]int),
+ returnKeys: make(chan string, 1000),
+ timesOfDeath: make(map[string]time.Time),
+ cache: make(map[string]interface{}),
+ die: make([]chan struct{}, 0, 1000),
}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+ if _, isPresent := em.cache[key]; isPresent == true {
+ em.die[em.dieIndex[key]] <- struct{}{}
+ } else {
+ em.lockNumberOfRunningRoutines.Lock()
+ index := len(em.die)
+ em.dieIndex[key] = index
+ ch := make(chan struct{})
+ em.die = append(em.die, ch)
+ em.lockNumberOfRunningRoutines.Unlock()
+ }
+
+ em.lockCache.Lock()
em.cache[key] = value
em.timesOfDeath[key] = time.Now().Add(expire)
+ em.lockCache.Unlock()
- em.lockNumberOfRunningRoutines.Lock()
- em.numberOfRunningRoutines += 1
- em.lockNumberOfRunningRoutines.Unlock()
-
go func() {
select {
case <-time.After(expire):
em.lockCache.Lock()
- defer em.lockCache.Unlock()
+ delete(em.cache, key)
+ delete(em.timesOfDeath, key)
+ em.lockCache.Unlock()
- if _, isPresent := em.cache[key]; isPresent == true {
- delete(em.cache, key)
- delete(em.timesOfDeath, key)
- em.returnKeys <- key
-
- em.lockNumberOfRunningRoutines.Lock()
- em.numberOfRunningRoutines -= 1
- em.lockNumberOfRunningRoutines.Unlock()
- }
- case <-em.signalForDeathOfRoutine:
em.lockNumberOfRunningRoutines.Lock()
- em.numberOfRunningRoutines -= 1
- temp := em.numberOfRunningRoutines
+ delete(em.dieIndex, key)
em.lockNumberOfRunningRoutines.Unlock()
- if temp > 0 {
- em.signalForDeathOfRoutine <- struct{}{}
- } else {
- em.signalFromLastRunningRoutine <- struct{}{}
- }
-
+ em.returnKeys <- key
+ case <-em.die[em.dieIndex[key]]:
}
}()
+
}
func (em *ExpireMap) Contains(key string) bool {
_, isPresent := em.cache[key]
return isPresent
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
value, isPresent := em.cache[key]
return value, isPresent
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
value, isPresent := em.cache[key].(int)
return value, isPresent
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
value, isPresent := em.cache[key].(float64)
return value, isPresent
}
func (em *ExpireMap) GetString(key string) (string, bool) {
value, isPresent := em.cache[key].(string)
return value, isPresent
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
value, isPresent := em.cache[key].(bool)
return value, isPresent
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
timeOfDeath, isPresent := em.timesOfDeath[key]
return timeOfDeath, isPresent
}
func (em *ExpireMap) Delete(key string) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
delete(em.cache, key)
delete(em.timesOfDeath, key)
}
func (em *ExpireMap) Size() int {
em.lockCache.Lock()
defer em.lockCache.Unlock()
size := 0
for _ = range em.cache {
size++
}
return size
}
func (em *ExpireMap) Increment(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if value, ok := em.cache[key].(int); ok == true {
em.cache[key] = value + 1
return nil
} else if value, ok := strconv.Atoi(em.cache[key].(string)); ok == nil {
em.cache[key] = strconv.Itoa(value + 1)
return nil
}
return &SomeError{Message: "Operation cannot be executed !"}
}
func (em *ExpireMap) Decrement(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if value, ok := em.cache[key].(int); ok == true {
em.cache[key] = value - 1
return nil
} else if value, ok := strconv.Atoi(em.cache[key].(string)); ok == nil {
em.cache[key] = strconv.Itoa(value - 1)
return nil
}
return &SomeError{Message: "Operation cannot be executed !"}
}
func (em *ExpireMap) ToUpper(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if value, ok := em.cache[key].(string); ok == true {
em.cache[key] = strings.ToUpper(value)
return nil
}
return &SomeError{Message: "Operation cannot be executed !"}
}
func (em *ExpireMap) ToLower(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if value, ok := em.cache[key].(string); ok == true {
em.cache[key] = strings.ToLower(value)
return nil
}
return &SomeError{Message: "Operation cannot be executed !"}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.returnKeys
}
func (em *ExpireMap) Cleanup() {
- if em.numberOfRunningRoutines != 0 {
- em.signalForDeathOfRoutine <- struct{}{}
- _ = <-em.signalFromLastRunningRoutine
+ for _, value := range em.dieIndex {
+ em.die[value] <- struct{}{}
}
em.cache = make(map[string]interface{})
+ em.dieIndex = make(map[string]int)
+ em.timesOfDeath = make(map[string]time.Time)
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
- *em = *(NewExpireMap())
+ close(em.returnKeys)
+ for _, i := range em.die {
+ close(i)
+ }
}

Йосиф обнови решението на 17.11.2014 20:59 (преди над 3 години)

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type SomeError struct {
Message string
}
func (se *SomeError) Error() string {
return se.Message
}
+type cacheRecord struct {
+ timeOfDeath time.Time
+ value interface{}
+ deathChannel chan struct{}
+}
+
type ExpireMap struct {
- lockCache *sync.Mutex
- lockNumberOfRunningRoutines *sync.Mutex
- returnKeys chan string
- die []chan struct{}
- dieIndex map[string]int
- timesOfDeath map[string]time.Time
- cache map[string]interface{}
+ lockCache *sync.Mutex
+ returnKeys chan string
+ cache map[string]*cacheRecord
}
func NewExpireMap() *ExpireMap {
return &ExpireMap{
- lockCache: &sync.Mutex{},
- lockNumberOfRunningRoutines: &sync.Mutex{},
- dieIndex: make(map[string]int),
- returnKeys: make(chan string, 1000),
- timesOfDeath: make(map[string]time.Time),
- cache: make(map[string]interface{}),
- die: make([]chan struct{}, 0, 1000),
+ lockCache: &sync.Mutex{},
+ returnKeys: make(chan string, 1000),
+ cache: make(map[string]*cacheRecord),
}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
- if _, isPresent := em.cache[key]; isPresent == true {
- em.die[em.dieIndex[key]] <- struct{}{}
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
+ if record, isPresent := em.cache[key]; isPresent == true {
+ record.deathChannel <- struct{}{}
+ record.value = value
+ record.timeOfDeath = time.Now().Add(expire)
+ em.startGoRoutine(key, expire)
} else {
- em.lockNumberOfRunningRoutines.Lock()
- index := len(em.die)
- em.dieIndex[key] = index
- ch := make(chan struct{})
- em.die = append(em.die, ch)
- em.lockNumberOfRunningRoutines.Unlock()
+ newRecord := new(cacheRecord)
+ newRecord.value = value
+ newRecord.timeOfDeath = time.Now().Add(expire)
+ newRecord.deathChannel = make(chan struct{})
+ em.cache[key] = newRecord
+ em.startGoRoutine(key, expire)
}
+}
- em.lockCache.Lock()
- em.cache[key] = value
- em.timesOfDeath[key] = time.Now().Add(expire)
- em.lockCache.Unlock()
-
+func (em *ExpireMap) startGoRoutine(key string, expire time.Duration) {
go func() {
select {
case <-time.After(expire):
em.lockCache.Lock()
delete(em.cache, key)
- delete(em.timesOfDeath, key)
em.lockCache.Unlock()
-
- em.lockNumberOfRunningRoutines.Lock()
- delete(em.dieIndex, key)
- em.lockNumberOfRunningRoutines.Unlock()
-
em.returnKeys <- key
- case <-em.die[em.dieIndex[key]]:
+ case <-em.cache[key].deathChannel:
}
}()
-
}
func (em *ExpireMap) Contains(key string) bool {
_, isPresent := em.cache[key]
return isPresent
}
-func (em *ExpireMap) Get(key string) (interface{}, bool) {
- value, isPresent := em.cache[key]
- return value, isPresent
+func (em *ExpireMap) Get(key string) (value interface{}, isPresent bool) {
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
+ if record, isPresent := em.cache[key]; isPresent {
+ return record.value, isPresent
+ }
+ return
}
-func (em *ExpireMap) GetInt(key string) (int, bool) {
- value, isPresent := em.cache[key].(int)
- return value, isPresent
+func (em *ExpireMap) GetInt(key string) (value int, isPresent bool) {
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
+ if record, isPresent := em.cache[key]; isPresent {
+ if value, ok := record.value.(int); ok == true {
+ return value, ok
+ }
+ }
+ return
}
-func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
- value, isPresent := em.cache[key].(float64)
- return value, isPresent
+func (em *ExpireMap) GetFloat64(key string) (value float64, isPresent bool) {
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
+ if record, isPresent := em.cache[key]; isPresent {
+ if value, ok := record.value.(float64); ok == true {
+ return value, ok
+ }
+ }
+ return
}
-func (em *ExpireMap) GetString(key string) (string, bool) {
- value, isPresent := em.cache[key].(string)
- return value, isPresent
+func (em *ExpireMap) GetString(key string) (value string, isPresent bool) {
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
+ if record, isPresent := em.cache[key]; isPresent {
+ if value, ok := record.value.(string); ok == true {
+ return value, ok
+ }
+ }
+ return
}
-func (em *ExpireMap) GetBool(key string) (bool, bool) {
- value, isPresent := em.cache[key].(bool)
- return value, isPresent
+func (em *ExpireMap) GetBool(key string) (value bool, isPresent bool) {
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
+ if record, isPresent := em.cache[key]; isPresent {
+ if value, ok := record.value.(bool); ok == true {
+ return value, ok
+ }
+ }
+ return
}
-func (em *ExpireMap) Expires(key string) (time.Time, bool) {
- timeOfDeath, isPresent := em.timesOfDeath[key]
- return timeOfDeath, isPresent
+func (em *ExpireMap) Expires(key string) (value time.Time, isPresent bool) {
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
+ if record, isPresent := em.cache[key]; isPresent {
+ return record.timeOfDeath, isPresent
+ }
+ return
}
func (em *ExpireMap) Delete(key string) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
-
delete(em.cache, key)
- delete(em.timesOfDeath, key)
}
-func (em *ExpireMap) Size() int {
+func (em *ExpireMap) Size() (size int) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
- size := 0
for _ = range em.cache {
size++
}
- return size
+ return
}
func (em *ExpireMap) Increment(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
- if value, ok := em.cache[key].(int); ok == true {
- em.cache[key] = value + 1
- return nil
- } else if value, ok := strconv.Atoi(em.cache[key].(string)); ok == nil {
- em.cache[key] = strconv.Itoa(value + 1)
- return nil
+ if record, isPresent := em.cache[key]; isPresent == true {
+ switch value := record.value.(type) {
+ case int:
+ record.value = value + 1
+ return nil
+ case string:
+ if number, ok := strconv.Atoi(value); ok == nil {
+ record.value = strconv.Itoa(number + 1)
+ return nil
+ }
+ default:
+ return &SomeError{Message: "Wrong types !"}
+ }
}
- return &SomeError{Message: "Operation cannot be executed !"}
+ return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) Decrement(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
- if value, ok := em.cache[key].(int); ok == true {
- em.cache[key] = value - 1
- return nil
- } else if value, ok := strconv.Atoi(em.cache[key].(string)); ok == nil {
- em.cache[key] = strconv.Itoa(value - 1)
- return nil
+ if record, isPresent := em.cache[key]; isPresent == true {
+ switch value := record.value.(type) {
+ case int:
+ record.value = value - 1
+ return nil
+ case string:
+ if number, ok := strconv.Atoi(value); ok == nil {
+ record.value = strconv.Itoa(number - 1)
+ return nil
+ }
+ default:
+ return &SomeError{Message: "Wrong types !"}
+ }
}
- return &SomeError{Message: "Operation cannot be executed !"}
+ return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToUpper(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
- if value, ok := em.cache[key].(string); ok == true {
- em.cache[key] = strings.ToUpper(value)
- return nil
+ if record, ok := em.cache[key]; ok == true {
+ switch value := record.value.(type) {
+ case string:
+ record.value = strings.ToUpper(value)
+ return nil
+ default:
+ return &SomeError{Message: "Wrong types !"}
+ }
}
- return &SomeError{Message: "Operation cannot be executed !"}
+ return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToLower(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
- if value, ok := em.cache[key].(string); ok == true {
- em.cache[key] = strings.ToLower(value)
- return nil
+ if record, ok := em.cache[key]; ok == true {
+ switch value := record.value.(type) {
+ case string:
+ record.value = strings.ToLower(value)
+ return nil
+ default:
+ return &SomeError{Message: "Wrong types !"}
+ }
}
- return &SomeError{Message: "Operation cannot be executed !"}
+ return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.returnKeys
}
func (em *ExpireMap) Cleanup() {
- for _, value := range em.dieIndex {
- em.die[value] <- struct{}{}
+ for _, value := range em.cache {
+ value.deathChannel <- struct{}{}
}
- em.cache = make(map[string]interface{})
- em.dieIndex = make(map[string]int)
- em.timesOfDeath = make(map[string]time.Time)
+ em.cache = make(map[string]*cacheRecord)
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
close(em.returnKeys)
- for _, i := range em.die {
- close(i)
- }
}

Йосиф обнови решението на 17.11.2014 23:21 (преди над 3 години)

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type SomeError struct {
Message string
}
func (se *SomeError) Error() string {
return se.Message
}
type cacheRecord struct {
timeOfDeath time.Time
value interface{}
deathChannel chan struct{}
}
type ExpireMap struct {
lockCache *sync.Mutex
returnKeys chan string
cache map[string]*cacheRecord
}
func NewExpireMap() *ExpireMap {
return &ExpireMap{
lockCache: &sync.Mutex{},
returnKeys: make(chan string, 1000),
cache: make(map[string]*cacheRecord),
}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
+
if record, isPresent := em.cache[key]; isPresent == true {
record.deathChannel <- struct{}{}
record.value = value
record.timeOfDeath = time.Now().Add(expire)
em.startGoRoutine(key, expire)
} else {
newRecord := new(cacheRecord)
newRecord.value = value
newRecord.timeOfDeath = time.Now().Add(expire)
newRecord.deathChannel = make(chan struct{})
em.cache[key] = newRecord
em.startGoRoutine(key, expire)
}
}
func (em *ExpireMap) startGoRoutine(key string, expire time.Duration) {
go func() {
select {
case <-time.After(expire):
em.lockCache.Lock()
delete(em.cache, key)
em.lockCache.Unlock()
em.returnKeys <- key
case <-em.cache[key].deathChannel:
}
}()
}
func (em *ExpireMap) Contains(key string) bool {
_, isPresent := em.cache[key]
return isPresent
}
func (em *ExpireMap) Get(key string) (value interface{}, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
return record.value, isPresent
}
return
}
func (em *ExpireMap) GetInt(key string) (value int, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(int); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetFloat64(key string) (value float64, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(float64); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetString(key string) (value string, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(string); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetBool(key string) (value bool, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(bool); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) Expires(key string) (value time.Time, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
return record.timeOfDeath, isPresent
}
return
}
func (em *ExpireMap) Delete(key string) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
delete(em.cache, key)
}
func (em *ExpireMap) Size() (size int) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
for _ = range em.cache {
size++
}
return
}
func (em *ExpireMap) Increment(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
switch value := record.value.(type) {
case int:
record.value = value + 1
return nil
case string:
if number, ok := strconv.Atoi(value); ok == nil {
record.value = strconv.Itoa(number + 1)
return nil
+ } else {
+ return &SomeError{Message: "This value cannot be incremented !"}
}
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) Decrement(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
switch value := record.value.(type) {
case int:
record.value = value - 1
return nil
case string:
if number, ok := strconv.Atoi(value); ok == nil {
record.value = strconv.Itoa(number - 1)
return nil
+ } else {
+ return &SomeError{Message: "This value cannot be incremented !"}
}
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToUpper(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, ok := em.cache[key]; ok == true {
switch value := record.value.(type) {
case string:
record.value = strings.ToUpper(value)
return nil
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToLower(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, ok := em.cache[key]; ok == true {
switch value := record.value.(type) {
case string:
record.value = strings.ToLower(value)
return nil
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.returnKeys
}
func (em *ExpireMap) Cleanup() {
for _, value := range em.cache {
value.deathChannel <- struct{}{}
}
em.cache = make(map[string]*cacheRecord)
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
close(em.returnKeys)
}

Йосиф обнови решението на 18.11.2014 16:00 (преди над 3 години)

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type SomeError struct {
Message string
}
func (se *SomeError) Error() string {
return se.Message
}
type cacheRecord struct {
timeOfDeath time.Time
value interface{}
deathChannel chan struct{}
}
type ExpireMap struct {
lockCache *sync.Mutex
returnKeys chan string
cache map[string]*cacheRecord
}
func NewExpireMap() *ExpireMap {
return &ExpireMap{
lockCache: &sync.Mutex{},
returnKeys: make(chan string, 1000),
cache: make(map[string]*cacheRecord),
}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
record.deathChannel <- struct{}{}
record.value = value
record.timeOfDeath = time.Now().Add(expire)
em.startGoRoutine(key, expire)
} else {
newRecord := new(cacheRecord)
newRecord.value = value
newRecord.timeOfDeath = time.Now().Add(expire)
newRecord.deathChannel = make(chan struct{})
em.cache[key] = newRecord
em.startGoRoutine(key, expire)
}
}
func (em *ExpireMap) startGoRoutine(key string, expire time.Duration) {
go func() {
select {
case <-time.After(expire):
em.lockCache.Lock()
delete(em.cache, key)
em.lockCache.Unlock()
em.returnKeys <- key
case <-em.cache[key].deathChannel:
}
}()
}
func (em *ExpireMap) Contains(key string) bool {
_, isPresent := em.cache[key]
return isPresent
}
func (em *ExpireMap) Get(key string) (value interface{}, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
return record.value, isPresent
}
return
}
func (em *ExpireMap) GetInt(key string) (value int, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(int); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetFloat64(key string) (value float64, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(float64); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetString(key string) (value string, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(string); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetBool(key string) (value bool, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(bool); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) Expires(key string) (value time.Time, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
return record.timeOfDeath, isPresent
}
return
}
func (em *ExpireMap) Delete(key string) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
+
+ em.cache[key].deathChannel <- struct{}{}
delete(em.cache, key)
}
func (em *ExpireMap) Size() (size int) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
for _ = range em.cache {
size++
}
return
}
func (em *ExpireMap) Increment(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
switch value := record.value.(type) {
case int:
record.value = value + 1
return nil
case string:
if number, ok := strconv.Atoi(value); ok == nil {
record.value = strconv.Itoa(number + 1)
return nil
} else {
return &SomeError{Message: "This value cannot be incremented !"}
}
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) Decrement(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
switch value := record.value.(type) {
case int:
record.value = value - 1
return nil
case string:
if number, ok := strconv.Atoi(value); ok == nil {
record.value = strconv.Itoa(number - 1)
return nil
} else {
return &SomeError{Message: "This value cannot be incremented !"}
}
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToUpper(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, ok := em.cache[key]; ok == true {
switch value := record.value.(type) {
case string:
record.value = strings.ToUpper(value)
return nil
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToLower(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, ok := em.cache[key]; ok == true {
switch value := record.value.(type) {
case string:
record.value = strings.ToLower(value)
return nil
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.returnKeys
}
func (em *ExpireMap) Cleanup() {
+ em.lockCache.Lock()
+ defer em.lockCache.Unlock()
for _, value := range em.cache {
value.deathChannel <- struct{}{}
}
em.cache = make(map[string]*cacheRecord)
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
close(em.returnKeys)
}

Йосиф обнови решението на 18.11.2014 16:07 (преди над 3 години)

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type SomeError struct {
Message string
}
func (se *SomeError) Error() string {
return se.Message
}
type cacheRecord struct {
timeOfDeath time.Time
value interface{}
deathChannel chan struct{}
}
type ExpireMap struct {
lockCache *sync.Mutex
returnKeys chan string
cache map[string]*cacheRecord
}
func NewExpireMap() *ExpireMap {
return &ExpireMap{
lockCache: &sync.Mutex{},
returnKeys: make(chan string, 1000),
cache: make(map[string]*cacheRecord),
}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
record.deathChannel <- struct{}{}
record.value = value
record.timeOfDeath = time.Now().Add(expire)
em.startGoRoutine(key, expire)
} else {
newRecord := new(cacheRecord)
newRecord.value = value
newRecord.timeOfDeath = time.Now().Add(expire)
newRecord.deathChannel = make(chan struct{})
em.cache[key] = newRecord
em.startGoRoutine(key, expire)
}
}
func (em *ExpireMap) startGoRoutine(key string, expire time.Duration) {
go func() {
select {
case <-time.After(expire):
em.lockCache.Lock()
delete(em.cache, key)
em.lockCache.Unlock()
em.returnKeys <- key
case <-em.cache[key].deathChannel:
}
}()
}
func (em *ExpireMap) Contains(key string) bool {
_, isPresent := em.cache[key]
return isPresent
}
func (em *ExpireMap) Get(key string) (value interface{}, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
+
if record, isPresent := em.cache[key]; isPresent {
return record.value, isPresent
}
return
}
func (em *ExpireMap) GetInt(key string) (value int, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
+
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(int); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetFloat64(key string) (value float64, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
+
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(float64); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetString(key string) (value string, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
+
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(string); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetBool(key string) (value bool, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
+
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(bool); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) Expires(key string) (value time.Time, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
+
if record, isPresent := em.cache[key]; isPresent {
return record.timeOfDeath, isPresent
}
return
}
func (em *ExpireMap) Delete(key string) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
em.cache[key].deathChannel <- struct{}{}
delete(em.cache, key)
}
func (em *ExpireMap) Size() (size int) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
for _ = range em.cache {
size++
}
return
}
func (em *ExpireMap) Increment(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
switch value := record.value.(type) {
case int:
record.value = value + 1
return nil
case string:
if number, ok := strconv.Atoi(value); ok == nil {
record.value = strconv.Itoa(number + 1)
return nil
} else {
return &SomeError{Message: "This value cannot be incremented !"}
}
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) Decrement(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
switch value := record.value.(type) {
case int:
record.value = value - 1
return nil
case string:
if number, ok := strconv.Atoi(value); ok == nil {
record.value = strconv.Itoa(number - 1)
return nil
} else {
return &SomeError{Message: "This value cannot be incremented !"}
}
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToUpper(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, ok := em.cache[key]; ok == true {
switch value := record.value.(type) {
case string:
record.value = strings.ToUpper(value)
return nil
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToLower(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, ok := em.cache[key]; ok == true {
switch value := record.value.(type) {
case string:
record.value = strings.ToLower(value)
return nil
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.returnKeys
}
func (em *ExpireMap) Cleanup() {
em.lockCache.Lock()
defer em.lockCache.Unlock()
+
for _, value := range em.cache {
value.deathChannel <- struct{}{}
}
em.cache = make(map[string]*cacheRecord)
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
close(em.returnKeys)
}

Йосиф обнови решението на 18.11.2014 16:51 (преди над 3 години)

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type SomeError struct {
Message string
}
func (se *SomeError) Error() string {
return se.Message
}
type cacheRecord struct {
timeOfDeath time.Time
value interface{}
deathChannel chan struct{}
}
type ExpireMap struct {
lockCache *sync.Mutex
- returnKeys chan string
+ returnKeys *chan string
cache map[string]*cacheRecord
}
func NewExpireMap() *ExpireMap {
+ channel := make(chan string, 1000)
return &ExpireMap{
lockCache: &sync.Mutex{},
- returnKeys: make(chan string, 1000),
+ returnKeys: &channel,
cache: make(map[string]*cacheRecord),
}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.lockCache.Lock()
- defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
record.deathChannel <- struct{}{}
record.value = value
record.timeOfDeath = time.Now().Add(expire)
+ em.lockCache.Unlock()
em.startGoRoutine(key, expire)
} else {
newRecord := new(cacheRecord)
newRecord.value = value
newRecord.timeOfDeath = time.Now().Add(expire)
newRecord.deathChannel = make(chan struct{})
em.cache[key] = newRecord
+ em.lockCache.Unlock()
em.startGoRoutine(key, expire)
}
}
func (em *ExpireMap) startGoRoutine(key string, expire time.Duration) {
- go func() {
+ go func(key string, expire time.Duration) {
select {
case <-time.After(expire):
em.lockCache.Lock()
+ *em.returnKeys <- key
delete(em.cache, key)
em.lockCache.Unlock()
- em.returnKeys <- key
case <-em.cache[key].deathChannel:
}
- }()
+ }(key, expire)
}
func (em *ExpireMap) Contains(key string) bool {
_, isPresent := em.cache[key]
return isPresent
}
func (em *ExpireMap) Get(key string) (value interface{}, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
return record.value, isPresent
}
return
}
func (em *ExpireMap) GetInt(key string) (value int, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(int); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetFloat64(key string) (value float64, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(float64); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetString(key string) (value string, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(string); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) GetBool(key string) (value bool, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
if value, ok := record.value.(bool); ok == true {
return value, ok
}
}
return
}
func (em *ExpireMap) Expires(key string) (value time.Time, isPresent bool) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent {
return record.timeOfDeath, isPresent
}
return
}
func (em *ExpireMap) Delete(key string) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
em.cache[key].deathChannel <- struct{}{}
delete(em.cache, key)
}
func (em *ExpireMap) Size() (size int) {
em.lockCache.Lock()
defer em.lockCache.Unlock()
for _ = range em.cache {
size++
}
return
}
func (em *ExpireMap) Increment(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
switch value := record.value.(type) {
case int:
record.value = value + 1
return nil
case string:
if number, ok := strconv.Atoi(value); ok == nil {
record.value = strconv.Itoa(number + 1)
return nil
} else {
return &SomeError{Message: "This value cannot be incremented !"}
}
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) Decrement(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, isPresent := em.cache[key]; isPresent == true {
switch value := record.value.(type) {
case int:
record.value = value - 1
return nil
case string:
if number, ok := strconv.Atoi(value); ok == nil {
record.value = strconv.Itoa(number - 1)
return nil
} else {
return &SomeError{Message: "This value cannot be incremented !"}
}
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToUpper(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, ok := em.cache[key]; ok == true {
switch value := record.value.(type) {
case string:
record.value = strings.ToUpper(value)
return nil
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ToLower(key string) error {
em.lockCache.Lock()
defer em.lockCache.Unlock()
if record, ok := em.cache[key]; ok == true {
switch value := record.value.(type) {
case string:
record.value = strings.ToLower(value)
return nil
default:
return &SomeError{Message: "Wrong types !"}
}
}
return &SomeError{Message: "Key not found !"}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
- return em.returnKeys
+ return *em.returnKeys
}
func (em *ExpireMap) Cleanup() {
em.lockCache.Lock()
defer em.lockCache.Unlock()
for _, value := range em.cache {
value.deathChannel <- struct{}{}
}
em.cache = make(map[string]*cacheRecord)
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
- close(em.returnKeys)
+ close(*em.returnKeys)
}

Решението ти е много близо до вярното. Основния ти проблем е в канала за изтекли ключове. В описанието на метода има едно изречение:

Не е задължително през цялото време някой да чете от върнатия канал.

Т.к. в повечето случаи тестовете не четат от този канал и ти остават висящи рутини на 64ти ред. Тези рутини никога няма да стигнат до четене от deathChan, който се вика за тях. От това ти остава да виси и Cleanup метода.

Малко като домино е :)