Решение на ExpireMap от Цветелина Борисова

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

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

Резултати

  • 7 точки от тестове
  • 0 бонус точки
  • 7 точки общо
  • 18 успешни тест(а)
  • 7 неуспешни тест(а)

Код

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type ExpireMapError struct {
Message string
}
type Cache struct {
ExpireAt time.Time
Data interface{}
}
type ExpireMap struct {
wg sync.WaitGroup
ch chan string
Caches map[string]*Cache
}
func NewExpireMap() *ExpireMap {
caches := make(map[string]*Cache)
ch := make(chan string, 1)
em := &ExpireMap{Caches: caches, ch: ch}
return em
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.Caches[key] = &Cache{Data: value, ExpireAt: time.Now().UTC().Add(expire)}
em.wg.Add(1)
go func(em *ExpireMap, key string, expire time.Duration) {
<-time.After(expire)
em.ch <- key
em.Delete(key)
em.wg.Done()
}(em, key, expire)
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
value, exists := em.Caches[key]
elapsed_time := time.Now().UTC()
if exists && em.Caches[key].ExpireAt.After(elapsed_time) {
return value.Data, true
} else {
return nil, false
}
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
value, ok := em.Get(key)
if ok == false {
return 0, false
} else if int_val, ok_i := value.(int); ok_i {
return int_val, ok
} else {
return 0, false
}
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
value, ok := em.Get(key)
if ok == false {
return 0, false
} else if int_val, ok_i := value.(float64); ok_i {
return int_val, ok
} else {
return 0, false
}
}
func (em *ExpireMap) GetString(key string) (string, bool) {
value, ok := em.Get(key)
if ok == false {
return "", false
} else if int_val, ok_i := value.(string); ok_i {
return int_val, ok
} else {
return "", false
}
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
value, ok := em.Get(key)
if ok == false {
return false, false
} else if int_val, ok_i := value.(bool); ok_i {
return int_val, ok
} else {
return false, false
}
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
if _, ok := em.Get(key); ok {
return em.Caches[key].ExpireAt, true
} else {
return time.Now(), false
}
}
func (em *ExpireMap) Delete(key string) {
delete(em.Caches, key)
}
func (em *ExpireMap) Contains(key string) bool {
_, ok := em.Get(key)
return ok
}
func (em *ExpireMap) Size() int {
return len(em.Caches)
}
func (em *ExpireMap) Increment(key string) error {
value_int, ok_i := em.GetInt(key)
value_str, ok_s := em.GetString(key)
if ok_i {
em.Caches[key].Data = value_int + 1
return nil
} else if ok_s {
int_v, _ := strconv.Atoi(value_str)
int_v += 1
em.Caches[key].Data = strconv.Itoa(int_v)
return nil
} else {
return &ExpireMapError{Message: "wow suuch much"}
}
}
func (em *ExpireMap) Decrement(key string) error {
value_int, ok_i := em.GetInt(key)
value_str, ok_s := em.GetString(key)
if ok_i {
em.Caches[key].Data = value_int - 1
return nil
} else if ok_s {
int_v, _ := strconv.Atoi(value_str)
int_v -= 1
em.Caches[key].Data = strconv.Itoa(int_v)
return nil
} else {
return &ExpireMapError{Message: "wow suuch much"}
}
}
func (e *ExpireMapError) Error() string {
return e.Message
}
func (em *ExpireMap) ToUpper(key string) error {
value, ok := em.GetString(key)
if ok {
em.Caches[key].Data = strings.ToUpper(value)
return nil
} else {
return &ExpireMapError{Message: "wow such much"}
}
}
func (em *ExpireMap) ToLower(key string) error {
value, ok := em.GetString(key)
if ok {
em.Caches[key].Data = strings.ToLower(value)
return nil
} else {
return &ExpireMapError{Message: "wow such much"}
}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.ch
}
func (em *ExpireMap) Cleanup() {
for key, _ := range em.Caches {
delete(em.Caches, key)
}
}
func (em *ExpireMap) Destroy() {
go func() {
em.wg.Wait()
close(em.ch)
}()
}

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

PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.012s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	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(0x8147c74, 0x81c1ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8147c74, 0x81c1ba0, 0x19, 0x19, 0x81c4600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-sf0brw/_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-sf0brw.TestSizes(0x183611e0)
	/tmp/d20141204-6466-sf0brw/solution_test.go:111 +0x3a3
testing.tRunner(0x183611e0, 0x81c1bb8)
	/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 receive]:
_/tmp/d20141204-6466-sf0brw.func·001(0x18331820, 0x18300308, 0x5, 0x3b9aca00, 0x0, ...)
	/tmp/d20141204-6466-sf0brw/solution.go:37 +0x45
created by _/tmp/d20141204-6466-sf0brw.(*ExpireMap).Set
	/tmp/d20141204-6466-sf0brw/solution.go:41 +0x14a

goroutine 6 [chan receive]:
_/tmp/d20141204-6466-sf0brw.func·001(0x18331820, 0x18300320, 0x5, 0x3b9aca00, 0x0, ...)
	/tmp/d20141204-6466-sf0brw/solution.go:37 +0x45
created by _/tmp/d20141204-6466-sf0brw.(*ExpireMap).Set
	/tmp/d20141204-6466-sf0brw/solution.go:41 +0x14a

goroutine 7 [chan receive]:
_/tmp/d20141204-6466-sf0brw.func·001(0x18331820, 0x18300338, 0x5, 0x3b9aca00, 0x0, ...)
	/tmp/d20141204-6466-sf0brw/solution.go:37 +0x45
created by _/tmp/d20141204-6466-sf0brw.(*ExpireMap).Set
	/tmp/d20141204-6466-sf0brw/solution.go:41 +0x14a

goroutine 8 [chan receive]:
_/tmp/d20141204-6466-sf0brw.func·001(0x18331820, 0x18300350, 0x5, 0x3b9aca00, 0x0, ...)
	/tmp/d20141204-6466-sf0brw/solution.go:37 +0x45
created by _/tmp/d20141204-6466-sf0brw.(*ExpireMap).Set
	/tmp/d20141204-6466-sf0brw/solution.go:41 +0x14a

goroutine 9 [chan receive]:
_/tmp/d20141204-6466-sf0brw.func·001(0x18331820, 0x18300368, 0x5, 0x3b9aca00, 0x0, ...)
	/tmp/d20141204-6466-sf0brw/solution.go:37 +0x45
created by _/tmp/d20141204-6466-sf0brw.(*ExpireMap).Set
	/tmp/d20141204-6466-sf0brw/solution.go:41 +0x14a

goroutine 10 [chan receive]:
_/tmp/d20141204-6466-sf0brw.func·001(0x18331820, 0x18300380, 0x5, 0x3b9aca00, 0x0, ...)
	/tmp/d20141204-6466-sf0brw/solution.go:37 +0x45
created by _/tmp/d20141204-6466-sf0brw.(*ExpireMap).Set
	/tmp/d20141204-6466-sf0brw/solution.go:41 +0x14a

goroutine 11 [chan receive]:
_/tmp/d20141204-6466-sf0brw.func·001(0x18331820, 0x18300398, 0x5, 0x3b9aca00, 0x0, ...)
	/tmp/d20141204-6466-sf0brw/solution.go:37 +0x45
created by _/tmp/d20141204-6466-sf0brw.(*ExpireMap).Set
	/tmp/d20141204-6466-sf0brw/solution.go:41 +0x14a

goroutine 12 [chan receive]:
_/tmp/d20141204-6466-sf0brw.func·001(0x18331820, 0x183003b0, 0x5, 0x3b9aca00, 0x0, ...)
	/tmp/d20141204-6466-sf0brw/solution.go:37 +0x45
created by _/tmp/d20141204-6466-sf0brw.(*ExpireMap).Set
	/tmp/d20141204-6466-sf0brw/solution.go:41 +0x14a

goroutine 13 [chan receive]:
_/tmp/d20141204-6466-sf0brw.func·001(0x18331820, 0x183003c8, 0x5, 0x3b9aca00, 0x0, ...)
	/tmp/d20141204-6466-sf0brw/solution.go:37 +0x45
created by _/tmp/d20141204-6466-sf0brw.(*ExpireMap).Set
	/tmp/d20141204-6466-sf0brw/solution.go:41 +0x14a

goroutine 14 [chan receive]:
_/tmp/d20141204-6466-sf0brw.func·001(0x18331820, 0x183003e0, 0x5, 0x3b9aca00, 0x0, ...)
	/tmp/d20141204-6466-sf0brw/solution.go:37 +0x45
created by _/tmp/d20141204-6466-sf0brw.(*ExpireMap).Set
	/tmp/d20141204-6466-sf0brw/solution.go:41 +0x14a
exit status 2
FAIL	_/tmp/d20141204-6466-sf0brw	1.012s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.122s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.175s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.015s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.013s
--- FAIL: TestSimpleIncrementAndDecrementCalls-2 (0.00 seconds)
	solution_test.go:276: Incrementing non-number value did not return error
	solution_test.go:288: Decrementing non-number value did not return error
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-sf0brw	0.031s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.014s
--- FAIL: TestIncAndDecInManyRoutines-2 (0.01 seconds)
	solution_test.go:388: Expected 666 but found 599
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-sf0brw	0.022s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.012s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.012s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.012s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.012s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.112s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.062s
--- FAIL: TestExpiredChanWhenNoOneIsReading-2 (0.06 seconds)
	solution_test.go:554: Wrong key expired
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-sf0brw	0.072s
--- FAIL: TestExpiredChanDoesNotReturnDeletedKeys-2 (0.05 seconds)
	solution_test.go:590: Expires chan returned deleted key
	solution_test.go:594: Expire chan did not return the expected key: long-key
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-sf0brw	0.062s
--- FAIL: TestExpiredChanDoesNotReturnCleanedupKeys-2 (0.05 seconds)
	solution_test.go:612: Expire chan returned key key after it was cleaned up
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-sf0brw	0.062s
--- FAIL: TestConcurrentOperations-2 (0.08 seconds)
	solution_test.go:716: Expected something bigger than 1.5e6 but found 14449
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-sf0brw	0.096s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.012s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.012s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.012s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.272s
PASS
ok  	_/tmp/d20141204-6466-sf0brw	0.012s

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

Цветелина обнови решението на 15.11.2014 16:48 (преди над 3 години)

+package main
+
+import (
+ "strings"
+ "time"
+ // "sync"
+ "strconv"
+)
+
+type ExpireMapError struct {
+ Message string
+}
+
+type ExpireMap struct {
+ // wg sync.WaitGroup
+ mini_map_dns map[string]interface{}
+ mini_map_active_to map[string]time.Time
+ ch chan string
+}
+
+func NewExpireMap() *ExpireMap {
+ mini_map_dns := make(map[string]interface{})
+ mini_map := make(map[string]time.Time)
+ ch := make(chan string, 1)
+ em := &ExpireMap{mini_map_dns: mini_map_dns, mini_map_active_to: mini_map, ch: ch}
+
+ return em
+}
+
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+ em.mini_map_active_to[key] = time.Now().UTC().Add(expire)
+ em.mini_map_dns[key] = value
+ // em.wg.Add(1)
+ go func(em *ExpireMap, key string) {
+ for {
+ if !em.mini_map_active_to[key].After(time.Now().UTC()) {
+ em.ch <- key
+ em.Delete(key)
+ }
+ }
+ }(em, key)
+}
+
+func (em *ExpireMap) Get(key string) (interface{}, bool) {
+ value, exists := em.mini_map_dns[key]
+ elapsed_time := time.Now().UTC()
+ if exists && em.mini_map_active_to[key].After(elapsed_time) {
+ return value, true
+ } else {
+ return nil, false
+ }
+}
+
+func (em *ExpireMap) GetInt(key string) (int, bool) {
+ value, ok := em.Get(key)
+ if ok == false {
+ return 0, false
+ } else if int_val, ok_i := value.(int); ok_i {
+ return int_val, ok
+ } else {
+ return 0, false
+ }
+}
+
+func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
+ value, ok := em.Get(key)
+ if ok == false {
+ return 0, false
+ } else if int_val, ok_i := value.(float64); ok_i {
+ return int_val, ok
+ } else {
+ return 0, false
+ }
+}
+
+func (em *ExpireMap) GetString(key string) (string, bool) {
+ value, ok := em.Get(key)
+ if ok == false {
+ return "", false
+ } else if int_val, ok_i := value.(string); ok_i {
+ return int_val, ok
+ } else {
+ return "", false
+ }
+}
+
+func (em *ExpireMap) GetBool(key string) (bool, bool) {
+ value, ok := em.Get(key)
+
+ if ok == false {
+ return false, false
+ } else if int_val, ok_i := value.(bool); ok_i {
+ return int_val, ok
+ } else {
+ return false, false
+ }
+}
+
+func (em *ExpireMap) Expires(key string) (time.Time, bool) {
+ if _, ok := em.Get(key); ok {
+ return em.mini_map_active_to[key], true
+ } else {
+ return time.Now(), false
+ }
+}
+
+func (em *ExpireMap) Delete(key string) {
+ delete(em.mini_map_dns, key)
+ delete(em.mini_map_active_to, key)
+}
+
+func (em *ExpireMap) Contains(key string) bool {
+ _, ok := em.Get(key)
+
+ return ok
+}
+
+func (em *ExpireMap) Size() int {
+ return len(em.mini_map_dns)
+}
+
+func (em *ExpireMap) Increment(key string) error {
+ // value, ok := em.Get(key)
+ value_int, ok_i := em.GetInt(key)
+ value_str, ok_s := em.GetString(key)
+
+ if ok_i {
+ em.mini_map_dns[key] = value_int + 1
+ return nil
+ } else if ok_s {
+ int_v, _ := strconv.Atoi(value_str)
+ int_v += 1
+ em.mini_map_dns[key] = strconv.Itoa(int_v)
+ return nil
+ } else {
+ return &ExpireMapError{Message: "wow suuch much"}
+ }
+}
+
+func (em *ExpireMap) Decrement(key string) error {
+ value_int, ok_i := em.GetInt(key)
+ value_str, ok_s := em.GetString(key)
+
+ if ok_i {
+ em.mini_map_dns[key] = value_int - 1
+ return nil
+ } else if ok_s {
+ int_v, _ := strconv.Atoi(value_str)
+ int_v -= 1
+ em.mini_map_dns[key] = strconv.Itoa(int_v)
+ return nil
+ } else {
+ return &ExpireMapError{Message: "wow suuch much"}
+ }
+}
+
+func (e *ExpireMapError) Error() string {
+ return e.Message
+}
+
+func (em *ExpireMap) ToUpper(key string) error {
+ value, ok := em.GetString(key)
+
+ if ok {
+ em.mini_map_dns[key] = strings.ToUpper(value)
+ return nil
+ } else {
+ return &ExpireMapError{Message: "wow such much"}
+ }
+}
+
+func (em *ExpireMap) ToLower(key string) error {
+ value, ok := em.GetString(key)
+
+ if ok {
+ em.mini_map_dns[key] = strings.ToLower(value)
+ return nil
+ } else {
+ return &ExpireMapError{Message: "wow such much"}
+ }
+}
+
+func (em *ExpireMap) ExpiredChan() <-chan string {
+ return em.ch
+}
+
+func (em *ExpireMap) Cleanup() {
+ for key, _ := range em.mini_map_dns {
+ delete(em.mini_map_dns, key)
+ delete(em.mini_map_active_to, key)
+ }
+}
+
+func (em *ExpireMap) Destroy() {
+ // close(em.ch)
+ // em.wg.Done()
+}

Цветелина обнови решението на 16.11.2014 10:57 (преди над 3 години)

package main
import (
+ "strconv"
"strings"
+ "sync"
"time"
- // "sync"
- "strconv"
)
type ExpireMapError struct {
Message string
}
type ExpireMap struct {
- // wg sync.WaitGroup
+ wg sync.WaitGroup
mini_map_dns map[string]interface{}
mini_map_active_to map[string]time.Time
ch chan string
}
func NewExpireMap() *ExpireMap {
mini_map_dns := make(map[string]interface{})
mini_map := make(map[string]time.Time)
ch := make(chan string, 1)
em := &ExpireMap{mini_map_dns: mini_map_dns, mini_map_active_to: mini_map, ch: ch}
return em
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.mini_map_active_to[key] = time.Now().UTC().Add(expire)
em.mini_map_dns[key] = value
- // em.wg.Add(1)
+ em.wg.Add(em.Size())
+
go func(em *ExpireMap, key string) {
for {
if !em.mini_map_active_to[key].After(time.Now().UTC()) {
em.ch <- key
em.Delete(key)
+ em.wg.Done()
}
}
}(em, key)
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
value, exists := em.mini_map_dns[key]
elapsed_time := time.Now().UTC()
if exists && em.mini_map_active_to[key].After(elapsed_time) {
return value, true
} else {
return nil, false
}
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
value, ok := em.Get(key)
if ok == false {
return 0, false
} else if int_val, ok_i := value.(int); ok_i {
return int_val, ok
} else {
return 0, false
}
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
value, ok := em.Get(key)
if ok == false {
return 0, false
} else if int_val, ok_i := value.(float64); ok_i {
return int_val, ok
} else {
return 0, false
}
}
func (em *ExpireMap) GetString(key string) (string, bool) {
value, ok := em.Get(key)
if ok == false {
return "", false
} else if int_val, ok_i := value.(string); ok_i {
return int_val, ok
} else {
return "", false
}
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
value, ok := em.Get(key)
if ok == false {
return false, false
} else if int_val, ok_i := value.(bool); ok_i {
return int_val, ok
} else {
return false, false
}
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
if _, ok := em.Get(key); ok {
return em.mini_map_active_to[key], true
} else {
return time.Now(), false
}
}
func (em *ExpireMap) Delete(key string) {
delete(em.mini_map_dns, key)
delete(em.mini_map_active_to, key)
}
func (em *ExpireMap) Contains(key string) bool {
_, ok := em.Get(key)
return ok
}
func (em *ExpireMap) Size() int {
return len(em.mini_map_dns)
}
func (em *ExpireMap) Increment(key string) error {
- // value, ok := em.Get(key)
value_int, ok_i := em.GetInt(key)
value_str, ok_s := em.GetString(key)
if ok_i {
em.mini_map_dns[key] = value_int + 1
return nil
} else if ok_s {
int_v, _ := strconv.Atoi(value_str)
int_v += 1
em.mini_map_dns[key] = strconv.Itoa(int_v)
return nil
} else {
return &ExpireMapError{Message: "wow suuch much"}
}
}
func (em *ExpireMap) Decrement(key string) error {
value_int, ok_i := em.GetInt(key)
value_str, ok_s := em.GetString(key)
if ok_i {
em.mini_map_dns[key] = value_int - 1
return nil
} else if ok_s {
int_v, _ := strconv.Atoi(value_str)
int_v -= 1
em.mini_map_dns[key] = strconv.Itoa(int_v)
return nil
} else {
return &ExpireMapError{Message: "wow suuch much"}
}
}
func (e *ExpireMapError) Error() string {
return e.Message
}
func (em *ExpireMap) ToUpper(key string) error {
value, ok := em.GetString(key)
if ok {
em.mini_map_dns[key] = strings.ToUpper(value)
return nil
} else {
return &ExpireMapError{Message: "wow such much"}
}
}
func (em *ExpireMap) ToLower(key string) error {
value, ok := em.GetString(key)
if ok {
em.mini_map_dns[key] = strings.ToLower(value)
return nil
} else {
return &ExpireMapError{Message: "wow such much"}
}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.ch
}
func (em *ExpireMap) Cleanup() {
for key, _ := range em.mini_map_dns {
delete(em.mini_map_dns, key)
delete(em.mini_map_active_to, key)
}
}
func (em *ExpireMap) Destroy() {
- // close(em.ch)
- // em.wg.Done()
+ go func() {
+ em.wg.Wait()
+ close(em.ch)
+ }()
}

Ми при мен се панира, навярно покрай безкрайния цикъл на ред 36 - който не знам защо трябва да е безкраен и да е цикъл ... ползвай select и виж примера в документацията на time.After.

Навярно има и други проблеми, но след тези не виждам смисъл да продължавам да гледам за сега

Цветелина обнови решението на 17.11.2014 16:49 (преди над 3 години)

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type ExpireMapError struct {
Message string
}
type ExpireMap struct {
wg sync.WaitGroup
mini_map_dns map[string]interface{}
mini_map_active_to map[string]time.Time
ch chan string
}
func NewExpireMap() *ExpireMap {
mini_map_dns := make(map[string]interface{})
mini_map := make(map[string]time.Time)
ch := make(chan string, 1)
em := &ExpireMap{mini_map_dns: mini_map_dns, mini_map_active_to: mini_map, ch: ch}
return em
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.mini_map_active_to[key] = time.Now().UTC().Add(expire)
em.mini_map_dns[key] = value
em.wg.Add(em.Size())
-
- go func(em *ExpireMap, key string) {
- for {
- if !em.mini_map_active_to[key].After(time.Now().UTC()) {
- em.ch <- key
- em.Delete(key)
- em.wg.Done()
- }
- }
- }(em, key)
+ go func(em *ExpireMap, key string, expire time.Duration) {
+ <-time.After(expire)
+ em.ch <- key
+ em.Delete(key)
+ em.wg.Done()
+ }(em, key, expire)
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
value, exists := em.mini_map_dns[key]
elapsed_time := time.Now().UTC()
if exists && em.mini_map_active_to[key].After(elapsed_time) {
return value, true
} else {
return nil, false
}
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
value, ok := em.Get(key)
if ok == false {
return 0, false
} else if int_val, ok_i := value.(int); ok_i {
return int_val, ok
} else {
return 0, false
}
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
value, ok := em.Get(key)
if ok == false {
return 0, false
} else if int_val, ok_i := value.(float64); ok_i {
return int_val, ok
} else {
return 0, false
}
}
func (em *ExpireMap) GetString(key string) (string, bool) {
value, ok := em.Get(key)
if ok == false {
return "", false
} else if int_val, ok_i := value.(string); ok_i {
return int_val, ok
} else {
return "", false
}
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
value, ok := em.Get(key)
if ok == false {
return false, false
} else if int_val, ok_i := value.(bool); ok_i {
return int_val, ok
} else {
return false, false
}
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
if _, ok := em.Get(key); ok {
return em.mini_map_active_to[key], true
} else {
return time.Now(), false
}
}
func (em *ExpireMap) Delete(key string) {
delete(em.mini_map_dns, key)
delete(em.mini_map_active_to, key)
}
func (em *ExpireMap) Contains(key string) bool {
_, ok := em.Get(key)
return ok
}
func (em *ExpireMap) Size() int {
return len(em.mini_map_dns)
}
func (em *ExpireMap) Increment(key string) error {
value_int, ok_i := em.GetInt(key)
value_str, ok_s := em.GetString(key)
if ok_i {
em.mini_map_dns[key] = value_int + 1
return nil
} else if ok_s {
int_v, _ := strconv.Atoi(value_str)
int_v += 1
em.mini_map_dns[key] = strconv.Itoa(int_v)
return nil
} else {
return &ExpireMapError{Message: "wow suuch much"}
}
}
func (em *ExpireMap) Decrement(key string) error {
value_int, ok_i := em.GetInt(key)
value_str, ok_s := em.GetString(key)
if ok_i {
em.mini_map_dns[key] = value_int - 1
return nil
} else if ok_s {
int_v, _ := strconv.Atoi(value_str)
int_v -= 1
em.mini_map_dns[key] = strconv.Itoa(int_v)
return nil
} else {
return &ExpireMapError{Message: "wow suuch much"}
}
}
func (e *ExpireMapError) Error() string {
return e.Message
}
func (em *ExpireMap) ToUpper(key string) error {
value, ok := em.GetString(key)
if ok {
em.mini_map_dns[key] = strings.ToUpper(value)
return nil
} else {
return &ExpireMapError{Message: "wow such much"}
}
}
func (em *ExpireMap) ToLower(key string) error {
value, ok := em.GetString(key)
if ok {
em.mini_map_dns[key] = strings.ToLower(value)
return nil
} else {
return &ExpireMapError{Message: "wow such much"}
}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.ch
}
func (em *ExpireMap) Cleanup() {
for key, _ := range em.mini_map_dns {
delete(em.mini_map_dns, key)
delete(em.mini_map_active_to, key)
}
}
func (em *ExpireMap) Destroy() {
go func() {
em.wg.Wait()
close(em.ch)
}()
}

Цветелина обнови решението на 17.11.2014 17:13 (преди над 3 години)

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type ExpireMapError struct {
Message string
}
+type Cache struct {
+ ExpireAt time.Time
+ Data interface{}
+}
+
type ExpireMap struct {
- wg sync.WaitGroup
- mini_map_dns map[string]interface{}
- mini_map_active_to map[string]time.Time
- ch chan string
+ wg sync.WaitGroup
+ ch chan string
+ Caches map[string]*Cache
}
func NewExpireMap() *ExpireMap {
- mini_map_dns := make(map[string]interface{})
- mini_map := make(map[string]time.Time)
+ caches := make(map[string]*Cache)
ch := make(chan string, 1)
- em := &ExpireMap{mini_map_dns: mini_map_dns, mini_map_active_to: mini_map, ch: ch}
+ em := &ExpireMap{Caches: caches, ch: ch}
return em
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
- em.mini_map_active_to[key] = time.Now().UTC().Add(expire)
- em.mini_map_dns[key] = value
- em.wg.Add(em.Size())
+ em.Caches[key] = &Cache{Data: value, ExpireAt: time.Now().UTC().Add(expire)}
+ em.wg.Add(len(em.Caches))
go func(em *ExpireMap, key string, expire time.Duration) {
<-time.After(expire)
em.ch <- key
em.Delete(key)
em.wg.Done()
}(em, key, expire)
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
- value, exists := em.mini_map_dns[key]
+ value, exists := em.Caches[key]
elapsed_time := time.Now().UTC()
- if exists && em.mini_map_active_to[key].After(elapsed_time) {
- return value, true
+ if exists && em.Caches[key].ExpireAt.After(elapsed_time) {
+ return value.Data, true
} else {
return nil, false
}
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
value, ok := em.Get(key)
if ok == false {
return 0, false
} else if int_val, ok_i := value.(int); ok_i {
return int_val, ok
} else {
return 0, false
}
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
value, ok := em.Get(key)
if ok == false {
return 0, false
} else if int_val, ok_i := value.(float64); ok_i {
return int_val, ok
} else {
return 0, false
}
}
func (em *ExpireMap) GetString(key string) (string, bool) {
value, ok := em.Get(key)
if ok == false {
return "", false
} else if int_val, ok_i := value.(string); ok_i {
return int_val, ok
} else {
return "", false
}
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
value, ok := em.Get(key)
if ok == false {
return false, false
} else if int_val, ok_i := value.(bool); ok_i {
return int_val, ok
} else {
return false, false
}
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
if _, ok := em.Get(key); ok {
- return em.mini_map_active_to[key], true
+ return em.Caches[key].ExpireAt, true
} else {
return time.Now(), false
}
}
func (em *ExpireMap) Delete(key string) {
- delete(em.mini_map_dns, key)
- delete(em.mini_map_active_to, key)
+ delete(em.Caches, key)
}
func (em *ExpireMap) Contains(key string) bool {
_, ok := em.Get(key)
return ok
}
func (em *ExpireMap) Size() int {
- return len(em.mini_map_dns)
+ return len(em.Caches)
}
func (em *ExpireMap) Increment(key string) error {
value_int, ok_i := em.GetInt(key)
value_str, ok_s := em.GetString(key)
if ok_i {
- em.mini_map_dns[key] = value_int + 1
+ em.Caches[key].Data = value_int + 1
return nil
} else if ok_s {
int_v, _ := strconv.Atoi(value_str)
int_v += 1
- em.mini_map_dns[key] = strconv.Itoa(int_v)
+ em.Caches[key].Data = strconv.Itoa(int_v)
return nil
} else {
return &ExpireMapError{Message: "wow suuch much"}
}
}
func (em *ExpireMap) Decrement(key string) error {
value_int, ok_i := em.GetInt(key)
value_str, ok_s := em.GetString(key)
if ok_i {
- em.mini_map_dns[key] = value_int - 1
+ em.Caches[key].Data = value_int - 1
return nil
} else if ok_s {
int_v, _ := strconv.Atoi(value_str)
int_v -= 1
- em.mini_map_dns[key] = strconv.Itoa(int_v)
+ em.Caches[key].Data = strconv.Itoa(int_v)
return nil
} else {
return &ExpireMapError{Message: "wow suuch much"}
}
}
func (e *ExpireMapError) Error() string {
return e.Message
}
func (em *ExpireMap) ToUpper(key string) error {
value, ok := em.GetString(key)
if ok {
- em.mini_map_dns[key] = strings.ToUpper(value)
+ em.Caches[key].Data = strings.ToUpper(value)
return nil
} else {
return &ExpireMapError{Message: "wow such much"}
}
}
func (em *ExpireMap) ToLower(key string) error {
value, ok := em.GetString(key)
if ok {
- em.mini_map_dns[key] = strings.ToLower(value)
+ em.Caches[key].Data = strings.ToLower(value)
return nil
} else {
return &ExpireMapError{Message: "wow such much"}
}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.ch
}
func (em *ExpireMap) Cleanup() {
- for key, _ := range em.mini_map_dns {
- delete(em.mini_map_dns, key)
- delete(em.mini_map_active_to, key)
+ for key, _ := range em.Caches {
+ delete(em.Caches, key)
}
}
func (em *ExpireMap) Destroy() {
go func() {
em.wg.Wait()
close(em.ch)
}()
}

Цветелина обнови решението на 18.11.2014 14:57 (преди над 3 години)

package main
import (
"strconv"
"strings"
"sync"
"time"
)
type ExpireMapError struct {
Message string
}
type Cache struct {
ExpireAt time.Time
Data interface{}
}
type ExpireMap struct {
wg sync.WaitGroup
ch chan string
Caches map[string]*Cache
}
func NewExpireMap() *ExpireMap {
caches := make(map[string]*Cache)
ch := make(chan string, 1)
em := &ExpireMap{Caches: caches, ch: ch}
return em
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.Caches[key] = &Cache{Data: value, ExpireAt: time.Now().UTC().Add(expire)}
- em.wg.Add(len(em.Caches))
+ em.wg.Add(1)
go func(em *ExpireMap, key string, expire time.Duration) {
<-time.After(expire)
em.ch <- key
em.Delete(key)
em.wg.Done()
}(em, key, expire)
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
value, exists := em.Caches[key]
elapsed_time := time.Now().UTC()
if exists && em.Caches[key].ExpireAt.After(elapsed_time) {
return value.Data, true
} else {
return nil, false
}
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
value, ok := em.Get(key)
if ok == false {
return 0, false
} else if int_val, ok_i := value.(int); ok_i {
return int_val, ok
} else {
return 0, false
}
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
value, ok := em.Get(key)
if ok == false {
return 0, false
} else if int_val, ok_i := value.(float64); ok_i {
return int_val, ok
} else {
return 0, false
}
}
func (em *ExpireMap) GetString(key string) (string, bool) {
value, ok := em.Get(key)
if ok == false {
return "", false
} else if int_val, ok_i := value.(string); ok_i {
return int_val, ok
} else {
return "", false
}
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
value, ok := em.Get(key)
if ok == false {
return false, false
} else if int_val, ok_i := value.(bool); ok_i {
return int_val, ok
} else {
return false, false
}
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
if _, ok := em.Get(key); ok {
return em.Caches[key].ExpireAt, true
} else {
return time.Now(), false
}
}
func (em *ExpireMap) Delete(key string) {
delete(em.Caches, key)
}
func (em *ExpireMap) Contains(key string) bool {
_, ok := em.Get(key)
return ok
}
func (em *ExpireMap) Size() int {
return len(em.Caches)
}
func (em *ExpireMap) Increment(key string) error {
value_int, ok_i := em.GetInt(key)
value_str, ok_s := em.GetString(key)
if ok_i {
em.Caches[key].Data = value_int + 1
return nil
} else if ok_s {
int_v, _ := strconv.Atoi(value_str)
int_v += 1
em.Caches[key].Data = strconv.Itoa(int_v)
return nil
} else {
return &ExpireMapError{Message: "wow suuch much"}
}
}
func (em *ExpireMap) Decrement(key string) error {
value_int, ok_i := em.GetInt(key)
value_str, ok_s := em.GetString(key)
if ok_i {
em.Caches[key].Data = value_int - 1
return nil
} else if ok_s {
int_v, _ := strconv.Atoi(value_str)
int_v -= 1
em.Caches[key].Data = strconv.Itoa(int_v)
return nil
} else {
return &ExpireMapError{Message: "wow suuch much"}
}
}
func (e *ExpireMapError) Error() string {
return e.Message
}
func (em *ExpireMap) ToUpper(key string) error {
value, ok := em.GetString(key)
if ok {
em.Caches[key].Data = strings.ToUpper(value)
return nil
} else {
return &ExpireMapError{Message: "wow such much"}
}
}
func (em *ExpireMap) ToLower(key string) error {
value, ok := em.GetString(key)
if ok {
em.Caches[key].Data = strings.ToLower(value)
return nil
} else {
return &ExpireMapError{Message: "wow such much"}
}
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.ch
}
func (em *ExpireMap) Cleanup() {
for key, _ := range em.Caches {
delete(em.Caches, key)
}
}
func (em *ExpireMap) Destroy() {
go func() {
em.wg.Wait()
close(em.ch)
}()
}

Основния проблем в решенето ти е, че обект от този ExpireMap не би могъл да се ползва от различни go-рутини безопасно. Друг малък проблем е, че очакваш винаги някой да чете от канала за изтекли ключове. В условието изрично е казано обратното - не е задължително някой да чете от него. Заради това ти остават висящи рутини.