Решение на ExpireMap от Иван Главчев

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

Към профила на Иван Главчев

Резултати

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

Код

package main
import (
"sync"
"time"
//"fmt"
"errors"
"strconv"
"strings"
)
type MapItem struct {
data interface{}
expirationTime time.Time
wg sync.WaitGroup
rwm sync.RWMutex
del chan struct{}
}
type ExpireMap struct {
keys map[string]*MapItem
expired chan string
m sync.RWMutex
delWG sync.WaitGroup
expWG sync.WaitGroup
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
item := MapItem{data: value, expirationTime: time.Now().Add(expire), del: make(chan struct{})}
_, ok := em.keys[key]
if ok {
em.Delete(key)
}
em.keys[key] = &item
destroy := func() {
delete(em.keys, key)
close(item.del)
// waiting for completion of all operations that are taking place when the timer is running out. Thats ok because timer was still on when they started
item.wg.Wait()
}
go func() {
timer := time.NewTimer(expire)
select {
case <-timer.C:
em.expWG.Add(1)
defer em.expWG.Done()
em.expired <- key
destroy()
return
case <-item.del:
em.delWG.Add(1)
defer em.delWG.Done()
timer.Stop()
destroy()
return
}
return
}()
}
func (em *ExpireMap) Get(key string) (d interface{}, k bool) {
em.m.RLock()
defer em.m.RUnlock()
data, ok := em.keys[key]
if ok {
data.wg.Add(1)
defer data.wg.Done()
data.rwm.RLock()
defer data.rwm.RUnlock()
d = data.data
}
k = ok
return
}
func (em *ExpireMap) GetInt(key string) (d int, k bool) {
data, ok := em.Get(key)
if ok {
d, k = data.(int)
}
return
}
func (em *ExpireMap) GetFloat64(key string) (d float64, k bool) {
data, ok := em.Get(key)
if ok {
d, k = data.(float64)
}
return
}
func (em *ExpireMap) GetString(key string) (d string, k bool) {
data, ok := em.Get(key)
if ok {
d, k = data.(string)
}
return
}
func (em *ExpireMap) GetBool(key string) (d bool, k bool) {
data, ok := em.Get(key)
if ok {
d, k = data.(bool)
}
return
}
func (em *ExpireMap) Expires(key string) (t time.Time, k bool) {
em.m.RLock()
defer em.m.RUnlock()
data, ok := em.keys[key]
if ok {
data.wg.Add(1)
defer data.wg.Done()
data.rwm.RLock()
defer data.rwm.RUnlock()
t = data.expirationTime
}
return
}
func (em *ExpireMap) Delete(key string) {
em.m.Lock()
defer em.m.Unlock()
data, ok := em.keys[key]
if ok {
data.wg.Add(1)
defer data.wg.Done()
data.del <- struct{}{}
}
}
func (em *ExpireMap) Contains(key string) bool {
em.m.RLock()
defer em.m.RUnlock()
_, ok := em.keys[key]
return ok
}
func (em *ExpireMap) Size() int {
em.m.RLock()
defer em.m.RUnlock()
return len(em.keys)
}
func (em *ExpireMap) plusMinus(key string, sign bool) error { // sign is true for +
num, ok := em.GetInt(key)
if !ok {
str, ok := em.GetString(key)
if !ok {
return errors.New("random error")
}
strint, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return err
}
d := em.keys[key]
d.wg.Add(1)
defer d.wg.Done()
d.rwm.Lock()
defer d.rwm.Unlock()
// ZA6TO NA MAIKA MU V PUTKATA NQMA TERNAREN OPERATOR V GO?? TOQ EZIK SUXVA QKO!!!
// d.data = strconv.FormatInt( sign ? strint + 1 : strint - 1, 10)
if sign {
d.data = strconv.FormatInt(strint+1, 10)
} else {
d.data = strconv.FormatInt(strint-1, 10)
}
} else {
d := em.keys[key]
d.wg.Add(1)
defer d.wg.Done()
d.rwm.Lock()
defer d.rwm.Unlock()
// d.data = sign ? d.data.(int) + 1 : d.data.(int) - 1
if sign {
d.data = num + 1
} else {
d.data = num - 1
}
}
return nil
}
func (em *ExpireMap) Increment(key string) error {
em.m.RLock()
defer em.m.RUnlock()
return em.plusMinus(key, true)
}
func (em *ExpireMap) Decrement(key string) error {
em.m.RLock()
defer em.m.RUnlock()
return em.plusMinus(key, false)
}
func (em *ExpireMap) stringUpDown(key string, up bool) error {
_, ok := em.GetString(key)
if !ok {
return errors.New("random error")
}
data := em.keys[key]
data.wg.Add(1)
defer data.wg.Done()
data.rwm.Lock()
defer data.rwm.Unlock()
if up {
data.data = strings.ToUpper(data.data.(string))
} else {
data.data = strings.ToLower(data.data.(string))
}
return nil
}
func (em *ExpireMap) ToUpper(key string) error {
em.m.RLock()
defer em.m.RUnlock()
return em.stringUpDown(key, true)
}
func (em *ExpireMap) ToLower(key string) error {
em.m.RLock()
defer em.m.RUnlock()
return em.stringUpDown(key, false)
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.expired
}
func (em *ExpireMap) Cleanup() {
for item := range em.keys {
em.Delete(item)
}
em.delWG.Wait()
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
em.expWG.Wait()
close(em.expired)
}
func NewExpireMap() *ExpireMap {
em := ExpireMap{}
em.keys = make(map[string]*MapItem)
em.expired = make(chan string, 1000)
return &em
}

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

PASS
ok  	_/tmp/d20141204-6466-1heycda	0.012s
PASS
ok  	_/tmp/d20141204-6466-1heycda	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(0x8148890, 0x81c3ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148890, 0x81c3ba0, 0x19, 0x19, 0x81c6600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-1heycda/_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-1heycda.TestSizes(0x1837a1e0)
	/tmp/d20141204-6466-1heycda/solution_test.go:111 +0x409
testing.tRunner(0x1837a1e0, 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
exit status 2
FAIL	_/tmp/d20141204-6466-1heycda	1.013s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.122s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.172s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.012s
--- FAIL: TestDeleteMethod-2 (0.00 seconds)
	solution_test.go:211: Key foo did not get deleted
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-1heycda	0.012s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.012s
--- FAIL: TestCleaningUpTheMap-2 (0.00 seconds)
	solution_test.go:341: Cleaning up ExpireMap did not work
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-1heycda	0.012s
--- FAIL: TestIncAndDecInManyRoutines-2 (0.04 seconds)
	solution_test.go:388: Expected 666 but found 672
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-1heycda	0.047s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.012s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.012s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.016s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.012s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.113s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.062s
--- FAIL: TestExpiredChanWhenNoOneIsReading-2 (0.06 seconds)
	solution_test.go:554: Wrong key expired
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-1heycda	0.072s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.112s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.132s
--- FAIL: TestConcurrentOperations-2 (0.07 seconds)
	solution_test.go:710: Expected integer key to be in the map but it was not
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-1heycda	0.079s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.012s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.012s
--- FAIL: TestExpiresMethod-2 (0.00 seconds)
	solution_test.go:843: Did not find expires for key key1
	solution_test.go:843: Did not find expires for key key2
	solution_test.go:843: Did not find expires for key key3
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-1heycda	0.012s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.272s
PASS
ok  	_/tmp/d20141204-6466-1heycda	0.012s

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

Иван обнови решението на 18.11.2014 16:36 (преди над 3 години)

+package main
+
+import (
+ "sync"
+ "time"
+ //"fmt"
+ "errors"
+ "strconv"
+ "strings"
+)
+
+type MapItem struct {
+ data interface{}
+ expirationTime time.Time
+ wg sync.WaitGroup
+ rwm sync.RWMutex
+ del chan struct{}
+}
+
+type ExpireMap struct {
+ keys map[string]*MapItem
+ expired chan string
+ m sync.RWMutex
+ delWG sync.WaitGroup
+ expWG sync.WaitGroup
+}
+
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+ item := MapItem{data: value, expirationTime: time.Now().Add(expire), del: make(chan struct{})}
+ _, ok := em.keys[key]
+
+ if ok {
+ em.Delete(key)
+ }
+
+ em.keys[key] = &item
+ destroy := func() {
+ delete(em.keys, key)
+ close(item.del)
+ // waiting for completion of all operations that are taking place when the timer is running out. Thats ok because timer was still on when they started
+ item.wg.Wait()
+ }
+
+ go func() {
+ timer := time.NewTimer(expire)
+
+ select {
+ case <-timer.C:
+ em.expWG.Add(1)
+ defer em.expWG.Done()
+ em.expired <- key
+ destroy()
+ return
+ case <-item.del:
+ em.delWG.Add(1)
+ defer em.delWG.Done()
+ timer.Stop()
+ destroy()
+ return
+ }
+ return
+ }()
+}
+
+func (em *ExpireMap) Get(key string) (d interface{}, k bool) {
+ em.m.RLock()
+ defer em.m.RUnlock()
+ data, ok := em.keys[key]
+ if ok {
+ data.wg.Add(1)
+ defer data.wg.Done()
+ d = data.data
+ }
+ k = ok
+ return
+}
+
+func (em *ExpireMap) GetInt(key string) (d int, k bool) {
+ data, ok := em.Get(key)
+ if ok {
+ d, k = data.(int)
+ }
+ return
+}
+
+func (em *ExpireMap) GetFloat64(key string) (d float64, k bool) {
+ data, ok := em.Get(key)
+ if ok {
+ d, k = data.(float64)
+ }
+ return
+}
+
+func (em *ExpireMap) GetString(key string) (d string, k bool) {
+ data, ok := em.Get(key)
+ if ok {
+ d, k = data.(string)
+ }
+ return
+}
+
+func (em *ExpireMap) GetBool(key string) (d bool, k bool) {
+ data, ok := em.Get(key)
+ if ok {
+ d, k = data.(bool)
+ }
+ return
+}
+
+func (em *ExpireMap) Expires(key string) (t time.Time, k bool) {
+ em.m.RLock()
+ defer em.m.RUnlock()
+ data, ok := em.keys[key]
+ if ok {
+ t = data.expirationTime
+ }
+ return
+}
+
+func (em *ExpireMap) Delete(key string) {
+ em.m.Lock()
+ defer em.m.Unlock()
+ data, ok := em.keys[key]
+ if ok {
+ data.wg.Add(1)
+ defer data.wg.Done()
+ data.del <- struct{}{}
+ }
+}
+
+func (em *ExpireMap) Contains(key string) bool {
+ em.m.RLock()
+ defer em.m.RUnlock()
+ _, ok := em.keys[key]
+ return ok
+}
+
+func (em *ExpireMap) Size() int {
+ em.m.RLock()
+ defer em.m.RUnlock()
+ return len(em.keys)
+}
+
+func (em *ExpireMap) plusMinus(key string, sign bool) error { // sign is true for +
+ num, ok := em.GetInt(key)
+ if !ok {
+ str, ok := em.GetString(key)
+ if !ok {
+ return errors.New("random error")
+ }
+ strint, err := strconv.ParseInt(str, 10, 64)
+ if err != nil {
+ return err
+ }
+ d := em.keys[key]
+ // ZA6TO NA MAIKA MU V PUTKATA NQMA TERNAREN OPERATOR V GO?? TOQ EZIK SUXVA QKO!!!
+ // d.data = strconv.FormatInt( sign ? strint + 1 : strint - 1, 10)
+ if sign {
+ d.data = strconv.FormatInt(strint+1, 10)
+ } else {
+ d.data = strconv.FormatInt(strint-1, 10)
+ }
+ } else {
+ d := em.keys[key]
+ // d.data = sign ? d.data.(int) + 1 : d.data.(int) - 1
+ if sign {
+ d.data = num + 1
+ } else {
+ d.data = num - 1
+ }
+ }
+ return nil
+}
+
+func (em *ExpireMap) Increment(key string) error {
+ em.m.RLock()
+ defer em.m.RUnlock()
+ return em.plusMinus(key, true)
+}
+
+func (em *ExpireMap) Decrement(key string) error {
+ em.m.RLock()
+ defer em.m.RUnlock()
+ return em.plusMinus(key, false)
+}
+
+func (em *ExpireMap) stringUpDown(key string, up bool) error {
+ _, ok := em.GetString(key)
+ if !ok {
+ return errors.New("random error")
+ }
+ data := em.keys[key]
+ if up {
+ data.data = strings.ToUpper(data.data.(string))
+ } else {
+ data.data = strings.ToLower(data.data.(string))
+ }
+ return nil
+}
+
+func (em *ExpireMap) ToUpper(key string) error {
+ em.m.RLock()
+ defer em.m.RUnlock()
+ return em.stringUpDown(key, true)
+}
+
+func (em *ExpireMap) ToLower(key string) error {
+ em.m.RLock()
+ defer em.m.RUnlock()
+ _, ok := em.GetString(key)
+ if !ok {
+ return errors.New("random error")
+ }
+ data := em.keys[key]
+ data.data = strings.ToLower(data.data.(string))
+ return nil
+}
+
+func (em *ExpireMap) ExpiredChan() <-chan string {
+ return em.expired
+}
+
+func (em *ExpireMap) Cleanup() {
+
+ for item := range em.keys {
+ em.Delete(item)
+ }
+ em.delWG.Wait()
+}
+
+func (em *ExpireMap) Destroy() {
+ em.Cleanup()
+ em.expWG.Wait()
+ close(em.expired)
+}
+
+func NewExpireMap() *ExpireMap {
+ em := ExpireMap{}
+ em.keys = make(map[string]*MapItem)
+ em.expired = make(chan string, 1000)
+ return &em
+}

Иван обнови решението на 18.11.2014 16:45 (преди над 3 години)

package main
import (
"sync"
"time"
//"fmt"
"errors"
"strconv"
"strings"
)
type MapItem struct {
data interface{}
expirationTime time.Time
wg sync.WaitGroup
rwm sync.RWMutex
del chan struct{}
}
type ExpireMap struct {
keys map[string]*MapItem
expired chan string
m sync.RWMutex
delWG sync.WaitGroup
expWG sync.WaitGroup
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
item := MapItem{data: value, expirationTime: time.Now().Add(expire), del: make(chan struct{})}
_, ok := em.keys[key]
if ok {
em.Delete(key)
}
em.keys[key] = &item
destroy := func() {
delete(em.keys, key)
close(item.del)
// waiting for completion of all operations that are taking place when the timer is running out. Thats ok because timer was still on when they started
item.wg.Wait()
}
go func() {
timer := time.NewTimer(expire)
select {
case <-timer.C:
em.expWG.Add(1)
defer em.expWG.Done()
em.expired <- key
destroy()
return
case <-item.del:
em.delWG.Add(1)
defer em.delWG.Done()
timer.Stop()
destroy()
return
}
return
}()
}
func (em *ExpireMap) Get(key string) (d interface{}, k bool) {
em.m.RLock()
defer em.m.RUnlock()
data, ok := em.keys[key]
if ok {
data.wg.Add(1)
defer data.wg.Done()
+ data.rwm.RLock()
+ defer data.rwm.RUnlock()
d = data.data
}
k = ok
return
}
func (em *ExpireMap) GetInt(key string) (d int, k bool) {
data, ok := em.Get(key)
if ok {
d, k = data.(int)
}
return
}
func (em *ExpireMap) GetFloat64(key string) (d float64, k bool) {
data, ok := em.Get(key)
if ok {
d, k = data.(float64)
}
return
}
func (em *ExpireMap) GetString(key string) (d string, k bool) {
data, ok := em.Get(key)
if ok {
d, k = data.(string)
}
return
}
func (em *ExpireMap) GetBool(key string) (d bool, k bool) {
data, ok := em.Get(key)
if ok {
d, k = data.(bool)
}
return
}
func (em *ExpireMap) Expires(key string) (t time.Time, k bool) {
em.m.RLock()
defer em.m.RUnlock()
data, ok := em.keys[key]
if ok {
+ data.wg.Add(1)
+ defer data.wg.Done()
+ data.rwm.RLock()
+ defer data.rwm.RUnlock()
t = data.expirationTime
}
return
}
func (em *ExpireMap) Delete(key string) {
em.m.Lock()
defer em.m.Unlock()
data, ok := em.keys[key]
if ok {
data.wg.Add(1)
defer data.wg.Done()
data.del <- struct{}{}
}
}
func (em *ExpireMap) Contains(key string) bool {
em.m.RLock()
defer em.m.RUnlock()
_, ok := em.keys[key]
return ok
}
func (em *ExpireMap) Size() int {
em.m.RLock()
defer em.m.RUnlock()
return len(em.keys)
}
func (em *ExpireMap) plusMinus(key string, sign bool) error { // sign is true for +
num, ok := em.GetInt(key)
if !ok {
str, ok := em.GetString(key)
if !ok {
return errors.New("random error")
}
strint, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return err
}
d := em.keys[key]
+ d.wg.Add(1)
+ defer d.wg.Done()
+ d.rwm.Lock()
+ defer d.rwm.Unlock()
// ZA6TO NA MAIKA MU V PUTKATA NQMA TERNAREN OPERATOR V GO?? TOQ EZIK SUXVA QKO!!!
// d.data = strconv.FormatInt( sign ? strint + 1 : strint - 1, 10)
if sign {
d.data = strconv.FormatInt(strint+1, 10)
} else {
d.data = strconv.FormatInt(strint-1, 10)
}
} else {
d := em.keys[key]
+ d.wg.Add(1)
+ defer d.wg.Done()
+ d.rwm.Lock()
+ defer d.rwm.Unlock()
// d.data = sign ? d.data.(int) + 1 : d.data.(int) - 1
if sign {
d.data = num + 1
} else {
d.data = num - 1
}
}
return nil
}
func (em *ExpireMap) Increment(key string) error {
em.m.RLock()
defer em.m.RUnlock()
return em.plusMinus(key, true)
}
func (em *ExpireMap) Decrement(key string) error {
em.m.RLock()
defer em.m.RUnlock()
return em.plusMinus(key, false)
}
func (em *ExpireMap) stringUpDown(key string, up bool) error {
_, ok := em.GetString(key)
if !ok {
return errors.New("random error")
}
data := em.keys[key]
+ data.wg.Add(1)
+ defer data.wg.Done()
+ data.rwm.Lock()
+ defer data.rwm.Unlock()
+
if up {
data.data = strings.ToUpper(data.data.(string))
} else {
data.data = strings.ToLower(data.data.(string))
}
return nil
}
func (em *ExpireMap) ToUpper(key string) error {
em.m.RLock()
defer em.m.RUnlock()
return em.stringUpDown(key, true)
}
func (em *ExpireMap) ToLower(key string) error {
em.m.RLock()
defer em.m.RUnlock()
- _, ok := em.GetString(key)
- if !ok {
- return errors.New("random error")
- }
- data := em.keys[key]
- data.data = strings.ToLower(data.data.(string))
- return nil
+ return em.stringUpDown(key, false)
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.expired
}
func (em *ExpireMap) Cleanup() {
for item := range em.keys {
em.Delete(item)
}
em.delWG.Wait()
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
em.expWG.Wait()
close(em.expired)
}
func NewExpireMap() *ExpireMap {
em := ExpireMap{}
em.keys = make(map[string]*MapItem)
em.expired = make(chan string, 1000)
return &em
}