Решение на ExpireMap от Любомир Коев

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

Към профила на Любомир Коев

Резултати

  • 8 точки от тестове
  • 0 бонус точки
  • 8 точки общо
  • 21 успешни тест(а)
  • 4 неуспешни тест(а)

Код

package main
import "sync"
import "time"
import "strings"
import "errors"
import "strconv"
import "fmt"
type mapItem struct {
value interface{}
expires time.Time
deleted chan struct{}
}
type ExpireMap struct {
write sync.Mutex
data map[string]mapItem
expired chan string
}
func NewExpireMap() *ExpireMap {
return &ExpireMap{
data: make(map[string]mapItem),
expired: make(chan string),
}
}
func (em *ExpireMap) watchKey(key string, expire time.Duration) {
go func() {
select {
case <-time.After(expire):
em.write.Lock()
if _, ok := em.data[key]; ok {
delete(em.data, key)
em.write.Unlock()
em.expired <- key
return
}
em.write.Unlock()
case <-em.data[key].deleted:
return
}
}()
}
func (em *ExpireMap) unwatchKey(key string) {
em.data[key].deleted <- struct{}{}
}
func (em *ExpireMap) removeValue(key string) {
if _, ok := em.data[key]; ok {
em.unwatchKey(key)
delete(em.data, key)
}
}
func (em *ExpireMap) addValue(key string, value interface{}, expire time.Duration) {
em.data[key] = mapItem{
value: value,
expires: time.Now().Add(expire),
deleted: make(chan struct{}),
}
em.watchKey(key, expire)
}
func (em *ExpireMap) updateValue(key string, value interface{}) {
em.unwatchKey(key)
em.data[key] = mapItem{
value: value,
expires: em.data[key].expires,
deleted: make(chan struct{}),
}
em.watchKey(key, em.data[key].expires.Sub(time.Now()))
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.write.Lock()
defer em.write.Unlock()
if item, ok := em.data[key]; ok {
item.deleted <- struct{}{}
}
em.addValue(key, value, expire)
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
em.write.Lock()
defer em.write.Unlock()
item, ok := em.data[key]
return item.value, ok
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
value, ok := em.Get(key)
int_value, ok2 := value.(int)
return int_value, ok && ok2
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
value, ok := em.Get(key)
float_value, ok2 := value.(float64)
return float_value, ok && ok2
}
func (em *ExpireMap) GetString(key string) (string, bool) {
value, ok := em.Get(key)
string_value, ok2 := value.(string)
return string_value, ok && ok2
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
value, ok := em.Get(key)
bool_value, ok2 := value.(bool)
return bool_value, ok && ok2
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
em.write.Lock()
defer em.write.Unlock()
item, ok := em.data[key]
return item.expires, ok
}
func (em *ExpireMap) Delete(key string) {
em.write.Lock()
defer em.write.Unlock()
em.removeValue(key)
}
func (em *ExpireMap) Contains(key string) (ok bool) {
_, ok = em.data[key]
return
}
func (em *ExpireMap) Size() int {
em.write.Lock()
defer em.write.Unlock()
return len(em.data)
}
func (em *ExpireMap) Increment(key string) error {
em.write.Lock()
defer em.write.Unlock()
if item, ok := em.data[key]; ok {
if value, ok := item.value.(int); ok {
em.updateValue(key, value+1)
return nil
} else if value, ok := item.value.(string); ok {
if int_val, err := strconv.Atoi(value); err == nil {
em.updateValue(key, fmt.Sprintf("%d", int_val+1))
return nil
} else {
return err
}
}
return errors.New("Item not string nor int")
}
return errors.New("No such key")
}
func (em *ExpireMap) Decrement(key string) error {
em.write.Lock()
defer em.write.Unlock()
if item, ok := em.data[key]; ok {
if value, ok := item.value.(int); ok {
em.updateValue(key, value-1)
return nil
} else if value, ok := item.value.(string); ok {
if int_val, err := strconv.Atoi(value); err == nil {
em.updateValue(key, fmt.Sprintf("%d", int_val-1))
return nil
} else {
return err
}
}
return errors.New("Item not string nor int")
}
return errors.New("No such key")
}
func (em *ExpireMap) ToUpper(key string) error {
em.write.Lock()
defer em.write.Unlock()
if item, ok := em.data[key]; ok {
if value, ok := item.value.(string); ok {
em.updateValue(key, strings.ToUpper(value))
return nil
}
return errors.New("Not a string")
}
return errors.New("No such key")
}
func (em *ExpireMap) ToLower(key string) error {
em.write.Lock()
defer em.write.Unlock()
if item, ok := em.data[key]; ok {
if value, ok := item.value.(string); ok {
em.updateValue(key, strings.ToLower(value))
return nil
}
return errors.New("Not a string")
}
return errors.New("No such key")
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.expired
}
func (em *ExpireMap) Cleanup() {
em.write.Lock()
defer em.write.Unlock()
for _, item := range em.data {
item.deleted <- struct{}{}
}
em.data = make(map[string]mapItem)
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
}

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

PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s
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(0x8148730, 0x81c2ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148730, 0x81c2ba0, 0x19, 0x19, 0x81c5600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-1kvewez/_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-1kvewez.TestSizes(0x1837a1e0)
	/tmp/d20141204-6466-1kvewez/solution_test.go:111 +0x38b
testing.tRunner(0x1837a1e0, 0x81c2bb8)
	/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 [chan send]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:37 +0x124
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 6 [chan send]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:37 +0x124
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 7 [chan send]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:37 +0x124
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 8 [chan send]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:37 +0x124
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 9 [chan send]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:37 +0x124
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 10 [chan send]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:37 +0x124
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 11 [chan send]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:37 +0x124
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 12 [chan send]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:37 +0x124
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 13 [chan send]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:37 +0x124
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 14 [chan send]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:37 +0x124
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac
exit status 2
FAIL	_/tmp/d20141204-6466-1kvewez	1.014s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.122s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.172s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.014s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.263s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.112s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.062s
--- FAIL: TestExpiredChanWhenNoOneIsReading-2 (0.06 seconds)
	solution_test.go:554: Wrong key expired
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-1kvewez	0.072s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.112s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.132s
panic: test timed out

goroutine 129022 [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(0x8148730, 0x81c2ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148730, 0x81c2ba0, 0x19, 0x19, 0x81c5600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-1kvewez/_test/_testmain.go:91 +0x81

goroutine 4 [semacquire]:
sync.runtime_Semacquire(0x194eba80)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*WaitGroup).Wait(0x18331720)
	/usr/local/lib/go/src/pkg/sync/waitgroup.go:109 +0xda
_/tmp/d20141204-6466-1kvewez.TestConcurrentOperations(0x18371120)
	/tmp/d20141204-6466-1kvewez/solution_test.go:705 +0x51e
testing.tRunner(0x18371120, 0x81c2c84)
	/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 120154 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Get(0x18351040, 0x194eb8d0, 0x5, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:87 +0x3e
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).GetString(0x18351040, 0x194eb8d0, 0x5, 0x1, 0x804c0ed, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:106 +0x39
_/tmp/d20141204-6466-1kvewez.func·012(0x194eb8d0, 0x5, 0x194eb8d8, 0x7)
	/tmp/d20141204-6466-1kvewez/solution_test.go:692 +0x9a
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:701 +0x4ed

goroutine 120151 [runnable]:
time.Sleep(0x5, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-1kvewez.func·010()
	/tmp/d20141204-6466-1kvewez/solution_test.go:659 +0xa8
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:663 +0x2e6

goroutine 120181 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 120180 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).ToUpper(0x18351040, 0x8125f98, 0x6, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:184 +0x39
_/tmp/d20141204-6466-1kvewez.func·011()
	/tmp/d20141204-6466-1kvewez/solution_test.go:672 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:678 +0x336

goroutine 120182 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Get(0x18351040, 0x194eba20, 0x5, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:87 +0x3e
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).GetString(0x18351040, 0x194eba20, 0x5, 0x1, 0x804c0ed, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:106 +0x39
_/tmp/d20141204-6466-1kvewez.func·012(0x194eba20, 0x5, 0x194eba28, 0x7)
	/tmp/d20141204-6466-1kvewez/solution_test.go:692 +0x9a
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:701 +0x4ed

goroutine 120179 [runnable]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Increment(0x18351040, 0x8125498, 0x7, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:142 +0x39
_/tmp/d20141204-6466-1kvewez.func·010()
	/tmp/d20141204-6466-1kvewez/solution_test.go:657 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:663 +0x2e6

goroutine 120147 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Increment(0x18351040, 0x8125498, 0x7, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:142 +0x39
_/tmp/d20141204-6466-1kvewez.func·010()
	/tmp/d20141204-6466-1kvewez/solution_test.go:661 +0xd0
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:663 +0x2e6

goroutine 120165 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 120145 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Set(0x18351040, 0x8125498, 0x7, 0x80f8b60, 0x16e360, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:78 +0x29
_/tmp/d20141204-6466-1kvewez.func·008()
	/tmp/d20141204-6466-1kvewez/solution_test.go:636 +0xa9
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:637 +0x237

goroutine 120178 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Get(0x18351040, 0x194eb9f0, 0x5, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:87 +0x3e
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).GetString(0x18351040, 0x194eb9f0, 0x5, 0x1, 0x804c0ed, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:106 +0x39
_/tmp/d20141204-6466-1kvewez.func·012(0x194eb9f0, 0x5, 0x194eb9f8, 0x7)
	/tmp/d20141204-6466-1kvewez/solution_test.go:692 +0x9a
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:701 +0x4ed

goroutine 120177 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 120152 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).ToUpper(0x18351040, 0x8125f98, 0x6, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:184 +0x39
_/tmp/d20141204-6466-1kvewez.func·011()
	/tmp/d20141204-6466-1kvewez/solution_test.go:672 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:678 +0x336

goroutine 120148 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).ToUpper(0x18351040, 0x8125f98, 0x6, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:184 +0x39
_/tmp/d20141204-6466-1kvewez.func·011()
	/tmp/d20141204-6466-1kvewez/solution_test.go:676 +0xd0
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:678 +0x336

goroutine 120176 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).ToUpper(0x18351040, 0x8125f98, 0x6, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:184 +0x39
_/tmp/d20141204-6466-1kvewez.func·011()
	/tmp/d20141204-6466-1kvewez/solution_test.go:672 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:678 +0x336

goroutine 120146 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Set(0x18351040, 0x8125f98, 0x6, 0x80f8de0, 0x1931da58, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:78 +0x29
_/tmp/d20141204-6466-1kvewez.func·009()
	/tmp/d20141204-6466-1kvewez/solution_test.go:644 +0xbd
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:645 +0x287

goroutine 120175 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Increment(0x18351040, 0x8125498, 0x7, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:142 +0x39
_/tmp/d20141204-6466-1kvewez.func·010()
	/tmp/d20141204-6466-1kvewez/solution_test.go:657 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:663 +0x2e6

goroutine 120155 [runnable]:
time.Sleep(0x5, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-1kvewez.func·010()
	/tmp/d20141204-6466-1kvewez/solution_test.go:659 +0xa8
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:663 +0x2e6

goroutine 120171 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Increment(0x18351040, 0x8125498, 0x7, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:142 +0x39
_/tmp/d20141204-6466-1kvewez.func·010()
	/tmp/d20141204-6466-1kvewez/solution_test.go:657 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:663 +0x2e6

goroutine 120174 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Get(0x18351040, 0x194eb9c0, 0x5, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:87 +0x3e
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).GetString(0x18351040, 0x194eb9c0, 0x5, 0x1, 0x804c0ed, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:106 +0x39
_/tmp/d20141204-6466-1kvewez.func·012(0x194eb9c0, 0x5, 0x194eb9c8, 0x7)
	/tmp/d20141204-6466-1kvewez/solution_test.go:692 +0x9a
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:701 +0x4ed

goroutine 120173 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 120161 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 120170 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Get(0x18351040, 0x194eb990, 0x5, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:87 +0x3e
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).GetString(0x18351040, 0x194eb990, 0x5, 0x1, 0x804c0ed, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:106 +0x39
_/tmp/d20141204-6466-1kvewez.func·012(0x194eb990, 0x5, 0x194eb998, 0x7)
	/tmp/d20141204-6466-1kvewez/solution_test.go:692 +0x9a
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:701 +0x4ed

goroutine 120168 [runnable]:
time.Sleep(0x7, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-1kvewez.func·011()
	/tmp/d20141204-6466-1kvewez/solution_test.go:674 +0xa8
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:678 +0x336

goroutine 120172 [runnable]:
time.Sleep(0x7, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-1kvewez.func·011()
	/tmp/d20141204-6466-1kvewez/solution_test.go:674 +0xa8
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:678 +0x336

goroutine 120156 [sleep]:
time.Sleep(0x7, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-1kvewez.func·011()
	/tmp/d20141204-6466-1kvewez/solution_test.go:674 +0xa8
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:678 +0x336

goroutine 120167 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Increment(0x18351040, 0x8125498, 0x7, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:142 +0x39
_/tmp/d20141204-6466-1kvewez.func·010()
	/tmp/d20141204-6466-1kvewez/solution_test.go:661 +0xd0
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:663 +0x2e6

goroutine 127186 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 120158 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Get(0x18351040, 0x194eb900, 0x5, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:87 +0x3e
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).GetString(0x18351040, 0x194eb900, 0x5, 0x1, 0x804c0ed, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:106 +0x39
_/tmp/d20141204-6466-1kvewez.func·012(0x194eb900, 0x5, 0x194eb908, 0x7)
	/tmp/d20141204-6466-1kvewez/solution_test.go:692 +0x9a
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:701 +0x4ed

goroutine 120160 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).ToUpper(0x18351040, 0x8125f98, 0x6, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:184 +0x39
_/tmp/d20141204-6466-1kvewez.func·011()
	/tmp/d20141204-6466-1kvewez/solution_test.go:672 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:678 +0x336

goroutine 120164 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).ToUpper(0x18351040, 0x8125f98, 0x6, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:184 +0x39
_/tmp/d20141204-6466-1kvewez.func·011()
	/tmp/d20141204-6466-1kvewez/solution_test.go:672 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:678 +0x336

goroutine 120162 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Get(0x18351040, 0x194eb930, 0x5, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:87 +0x3e
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).GetString(0x18351040, 0x194eb930, 0x5, 0x1, 0x804c0ed, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:106 +0x39
_/tmp/d20141204-6466-1kvewez.func·012(0x194eb930, 0x5, 0x194eb938, 0x7)
	/tmp/d20141204-6466-1kvewez/solution_test.go:692 +0x9a
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:701 +0x4ed

goroutine 120163 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Increment(0x18351040, 0x8125498, 0x7, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:142 +0x39
_/tmp/d20141204-6466-1kvewez.func·010()
	/tmp/d20141204-6466-1kvewez/solution_test.go:657 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:663 +0x2e6

goroutine 120169 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 120159 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Increment(0x18351040, 0x8125498, 0x7, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:142 +0x39
_/tmp/d20141204-6466-1kvewez.func·010()
	/tmp/d20141204-6466-1kvewez/solution_test.go:657 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:663 +0x2e6

goroutine 120149 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 120157 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 120153 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac

goroutine 120183 [semacquire]:
sync.runtime_Semacquire(0x18351044)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x18351040)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
_/tmp/d20141204-6466-1kvewez.(*ExpireMap).Increment(0x18351040, 0x8125498, 0x7, 0x0, 0x0, ...)
	/tmp/d20141204-6466-1kvewez/solution.go:142 +0x39
_/tmp/d20141204-6466-1kvewez.func·010()
	/tmp/d20141204-6466-1kvewez/solution_test.go:657 +0x84
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:663 +0x2e6

goroutine 120184 [runnable]:
time.Sleep(0x7, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-1kvewez.func·011()
	/tmp/d20141204-6466-1kvewez/solution_test.go:674 +0xa8
created by _/tmp/d20141204-6466-1kvewez.TestConcurrentOperations
	/tmp/d20141204-6466-1kvewez/solution_test.go:678 +0x336

goroutine 120185 [select]:
_/tmp/d20141204-6466-1kvewez.func·001()
	/tmp/d20141204-6466-1kvewez/solution.go:31 +0x18f
created by _/tmp/d20141204-6466-1kvewez.(*ExpireMap).watchKey
	/tmp/d20141204-6466-1kvewez/solution.go:44 +0xac
exit status 2
FAIL	_/tmp/d20141204-6466-1kvewez	1.067s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.026s
--- FAIL: TestDestroyMethodClosesExpireChannel-2 (0.05 seconds)
	solution_test.go:818: Expire channel was not closed in time
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-1kvewez	0.062s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.272s
PASS
ok  	_/tmp/d20141204-6466-1kvewez	0.012s

История (1 версия и 0 коментара)

Любомир обнови решението на 18.11.2014 02:26 (преди над 3 години)

+package main
+
+import "sync"
+import "time"
+import "strings"
+import "errors"
+import "strconv"
+import "fmt"
+
+type mapItem struct {
+ value interface{}
+ expires time.Time
+ deleted chan struct{}
+}
+
+type ExpireMap struct {
+ write sync.Mutex
+ data map[string]mapItem
+ expired chan string
+}
+
+func NewExpireMap() *ExpireMap {
+ return &ExpireMap{
+ data: make(map[string]mapItem),
+ expired: make(chan string),
+ }
+}
+
+func (em *ExpireMap) watchKey(key string, expire time.Duration) {
+ go func() {
+ select {
+ case <-time.After(expire):
+ em.write.Lock()
+ if _, ok := em.data[key]; ok {
+ delete(em.data, key)
+ em.write.Unlock()
+ em.expired <- key
+ return
+ }
+ em.write.Unlock()
+ case <-em.data[key].deleted:
+ return
+ }
+ }()
+}
+
+func (em *ExpireMap) unwatchKey(key string) {
+ em.data[key].deleted <- struct{}{}
+}
+
+func (em *ExpireMap) removeValue(key string) {
+ if _, ok := em.data[key]; ok {
+ em.unwatchKey(key)
+ delete(em.data, key)
+ }
+}
+
+func (em *ExpireMap) addValue(key string, value interface{}, expire time.Duration) {
+ em.data[key] = mapItem{
+ value: value,
+ expires: time.Now().Add(expire),
+ deleted: make(chan struct{}),
+ }
+ em.watchKey(key, expire)
+}
+
+func (em *ExpireMap) updateValue(key string, value interface{}) {
+ em.unwatchKey(key)
+ em.data[key] = mapItem{
+ value: value,
+ expires: em.data[key].expires,
+ deleted: make(chan struct{}),
+ }
+ em.watchKey(key, em.data[key].expires.Sub(time.Now()))
+}
+
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+ em.write.Lock()
+ defer em.write.Unlock()
+ if item, ok := em.data[key]; ok {
+ item.deleted <- struct{}{}
+ }
+ em.addValue(key, value, expire)
+}
+
+func (em *ExpireMap) Get(key string) (interface{}, bool) {
+ em.write.Lock()
+ defer em.write.Unlock()
+ item, ok := em.data[key]
+ return item.value, ok
+}
+
+func (em *ExpireMap) GetInt(key string) (int, bool) {
+ value, ok := em.Get(key)
+ int_value, ok2 := value.(int)
+ return int_value, ok && ok2
+}
+
+func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
+ value, ok := em.Get(key)
+ float_value, ok2 := value.(float64)
+ return float_value, ok && ok2
+}
+
+func (em *ExpireMap) GetString(key string) (string, bool) {
+ value, ok := em.Get(key)
+ string_value, ok2 := value.(string)
+ return string_value, ok && ok2
+}
+
+func (em *ExpireMap) GetBool(key string) (bool, bool) {
+ value, ok := em.Get(key)
+ bool_value, ok2 := value.(bool)
+ return bool_value, ok && ok2
+}
+
+func (em *ExpireMap) Expires(key string) (time.Time, bool) {
+ em.write.Lock()
+ defer em.write.Unlock()
+ item, ok := em.data[key]
+ return item.expires, ok
+}
+
+func (em *ExpireMap) Delete(key string) {
+ em.write.Lock()
+ defer em.write.Unlock()
+ em.removeValue(key)
+}
+
+func (em *ExpireMap) Contains(key string) (ok bool) {
+ _, ok = em.data[key]
+ return
+}
+
+func (em *ExpireMap) Size() int {
+ em.write.Lock()
+ defer em.write.Unlock()
+ return len(em.data)
+}
+
+func (em *ExpireMap) Increment(key string) error {
+ em.write.Lock()
+ defer em.write.Unlock()
+
+ if item, ok := em.data[key]; ok {
+ if value, ok := item.value.(int); ok {
+ em.updateValue(key, value+1)
+ return nil
+ } else if value, ok := item.value.(string); ok {
+ if int_val, err := strconv.Atoi(value); err == nil {
+ em.updateValue(key, fmt.Sprintf("%d", int_val+1))
+ return nil
+ } else {
+ return err
+ }
+ }
+ return errors.New("Item not string nor int")
+ }
+ return errors.New("No such key")
+}
+
+func (em *ExpireMap) Decrement(key string) error {
+ em.write.Lock()
+ defer em.write.Unlock()
+
+ if item, ok := em.data[key]; ok {
+ if value, ok := item.value.(int); ok {
+ em.updateValue(key, value-1)
+ return nil
+ } else if value, ok := item.value.(string); ok {
+ if int_val, err := strconv.Atoi(value); err == nil {
+ em.updateValue(key, fmt.Sprintf("%d", int_val-1))
+ return nil
+ } else {
+ return err
+ }
+ }
+ return errors.New("Item not string nor int")
+ }
+ return errors.New("No such key")
+}
+
+func (em *ExpireMap) ToUpper(key string) error {
+ em.write.Lock()
+ defer em.write.Unlock()
+
+ if item, ok := em.data[key]; ok {
+ if value, ok := item.value.(string); ok {
+ em.updateValue(key, strings.ToUpper(value))
+ return nil
+ }
+ return errors.New("Not a string")
+ }
+ return errors.New("No such key")
+}
+
+func (em *ExpireMap) ToLower(key string) error {
+ em.write.Lock()
+ defer em.write.Unlock()
+
+ if item, ok := em.data[key]; ok {
+ if value, ok := item.value.(string); ok {
+ em.updateValue(key, strings.ToLower(value))
+ return nil
+ }
+ return errors.New("Not a string")
+ }
+ return errors.New("No such key")
+}
+
+func (em *ExpireMap) ExpiredChan() <-chan string {
+ return em.expired
+}
+
+func (em *ExpireMap) Cleanup() {
+ em.write.Lock()
+ defer em.write.Unlock()
+ for _, item := range em.data {
+ item.deleted <- struct{}{}
+ }
+ em.data = make(map[string]mapItem)
+}
+
+func (em *ExpireMap) Destroy() {
+ em.Cleanup()
+}