Решение на ExpireMap от Диян Димитров

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

Към профила на Диян Димитров

Резултати

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

Код

package main
import (
"reflect"
"strconv"
"strings"
"sync"
"time"
)
type ExpireMap struct {
Map map[string]interface{}
Expire map[string]time.Time
Expired chan string
sync.Mutex
}
//Връща указател към нов обект от тип ExpireMap, готов за използване.
func NewExpireMap() *ExpireMap {
result := new(ExpireMap)
result.Map = make(map[string]interface{})
result.Expire = make(map[string]time.Time)
result.Expired = make(chan string)
return result
}
type MapError struct {
mapError string
}
func (err MapError) Error() string {
return err.mapError
}
//Добавя в хранилището нов ключ key със стойност value за expire време.
//Duration е дефиниран в пакета time.
//expire време след добавянето на ключа
//той вече трябва да спре да бъде в хранилището.
//Стойността може да е от всякакъв тип, докато ключа е от тип string.
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
if _, ok := em.Map[key]; !ok {
em.Map[key] = value
em.Expire[key] = time.Now().Add(expire) //Момента, когато ще изтече
go func() {
for {
if time.Now().After(em.Expire[key]) {
em.Delete(key)
em.Expired <- key
return
}
}
}()
} else {
em.Lock()
defer em.Unlock()
em.Map[key] = value
em.Expire[key] = time.Now().Add(expire)
}
}
//Връща стойността на ключ и true, когато ключа е намерен.
// Когато ключа липсва или е изтекъл връща nil и false.
func (em *ExpireMap) Get(key string) (interface{}, bool) {
if _, ok := em.Map[key]; ok {
return em.Map[key], true
} else {
return nil, false
}
}
//Връща стойността, отговаряща на този
//ключ и true, когато ключа е намерен и стойността му е от тип int.
//Когато ключа липсва, изтекъл е или
//стойността му не е от този тип метода трябва да върне нула и false.
func (em *ExpireMap) GetInt(key string) (int, bool) {
if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.Int {
return reflect.ValueOf(value).Interface().(int), ok
}
return 0, false
}
//Връща стойността на този ключ и true,
//когато ключа е намерен и стойността му е от тип float64.
// Когато ключа липсва, изтекъл е или
//стойността му не е от този тип метода трябва да върне нула и false.
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.Float64 {
return reflect.ValueOf(value).Interface().(float64), ok
}
return 0, false
}
//Връща стойността на ключ и true,
// когато ключа е намерен и стойността му е от тип string.
// Когато ключа липсва, изтекъл е или
//стойността не е от тип string метода трябва да върне празен стринг и false.
func (em *ExpireMap) GetString(key string) (string, bool) {
if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.String {
return reflect.ValueOf(value).Interface().(string), ok
}
return "", false
}
//Връща стойността на ключ и true, когато ключа е намерен и стойността му е от тип bool.
// Когато ключа липсва, изтекъл е или
//стойността не е от тип bool метода трябва да върне false и false.
func (em *ExpireMap) GetBool(key string) (bool, bool) {
if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.Bool {
return reflect.ValueOf(value).Interface().(bool), ok
}
return false, false
}
//За определен ключ тази функция трябва да върне времето, когато той ще изтече.
//Втората върната стойност е true когато ключа е намерен в хранилището.
//Когато не е намерен функцията трябва да върне нулевото време и false.
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
if result, ok := em.Expire[key]; ok {
return result, ok
}
var zeroTime time.Time //default time.Time е нулево време.
return zeroTime, false
}
//Премахва ключа от хранилището. Когато няма такъв ключ метода не трябав да гърми.
func (em *ExpireMap) Delete(key string) {
if _, ok := em.Get(key); ok {
em.Lock()
delete(em.Map, key)
em.Unlock()
//<-em.Done //излизам от горутината дето цикли за тоя ключ
}
}
//Казва дали ключ е в хранилището или не. Отново,
//ключове са в хранилището само ако техния expire не е вече изтекъл.
func (em *ExpireMap) Contains(key string) bool {
_, ok := em.Map[key]
return ok
}
//Връща големината на хранилището. Големина е бройката неизтекли ключове, които са в него.
func (em *ExpireMap) Size() int {
return len(em.Map)
}
//За ключ увеличава стойността му числово с 1 когато тази стойност
// е от тип int или стринг, представящ цяло число.
//Когато стойността е от тип, различен от тези неща функцията трябва
// да върне грешка, различна от nil. float32 и float64 не са целочислен типове.
// Времето на изтичане на ключа не трябва да се променя.
func (em *ExpireMap) Increment(key string) error {
if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.Int {
newValue := value.(int)
newValue++
em.Map[key] = newValue
}
if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.String {
if newValue, errNotConvertable := strconv.Atoi(em.Map[key].(string)); errNotConvertable == nil {
newValue++
em.Map[key] = strconv.Itoa(newValue)
return nil
} else {
return &MapError{"Cannot increment"}
}
}
return &MapError{"Cannot increment"}
}
//Същото като Increment, но намалява стойността с 1 вместо да я увеличава.
func (em *ExpireMap) Decrement(key string) error {
if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.Int {
newValue := value.(int)
newValue--
em.Map[key] = newValue
}
if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.String {
if newValue, errNotConvertable := strconv.Atoi(em.Map[key].(string)); errNotConvertable == nil {
newValue--
em.Map[key] = strconv.Itoa(newValue)
return nil
} else {
return &MapError{"Cannot decrement"}
}
}
return &MapError{"Cannot decrement"}
}
//Ако стойността за ключа key е от тип string, то всички
//букви в този string трябва да станат главни.
// При успех метода трябва да върне nil, а при невъзможност
//да изпълни задачата - грешка. Пример за употреба:
func (em *ExpireMap) ToUpper(key string) error {
if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.String {
newValue := value.(string)
em.Map[key] = strings.ToUpper(newValue)
return nil
} else {
return &MapError{"Cannot convert to upper case"}
}
}
//Същото като ToUpper, но всички букви трябва станат малки.
func (em *ExpireMap) ToLower(key string) error {
if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.String {
newValue := value.(string)
em.Map[key] = strings.ToLower(newValue)
return nil
} else {
return &MapError{"Cannot convert to lower case"}
}
}
//Тази функция трябва да върне канал, по който да идват ключовете, които са изтекли.
// Те трябва да се пускат по канала в момента на изтичането си.
// Ключове, които са изтрити с Delete или Cleanup не трябва да се връщат по този канал.
// Единствено тези, които са достигнали до времето си на изтичане.
// Не е задължително през цялото време някой да чете от върнатия канал.
// Ключове добавени в инстанцията след извикването на ExpireChan също
//трябва да се пратят по канала, когато тяхното време дойде.
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.Expired
}
//Изчиства хранилището. След извикване на функцията в
//ExpireMap-a не трябва да се съдържа нито един ключ.
func (em *ExpireMap) Cleanup() {
for key, _ := range em.Map {
em.Delete(key)
}
}
// Трябва да освободи всички ресурси, които е използвал този ExpireMap.
// Това означава изчистване на всички структури, затваряне на
// всички канали и спиране на всички горутини, свързани с нормалната му работа.
// След извикване на Destroy тази инстанция на ExpireMap няма да бъде повече използвана.
func (em *ExpireMap) Destroy() {
em.Cleanup()
}

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

PASS
ok  	_/tmp/d20141204-6466-6qptom	0.012s
panic: test timed out

goroutine 8PASS
 [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 [panicwait]:

goroutine 5 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 6 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 7 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186
exit status 2
FAIL	_/tmp/d20141204-6466-6qptom	7.013s
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(0x8148c30, 0x81c3ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148c30, 0x81c3ba0, 0x19, 0x19, 0x81c6600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-6qptom/_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-6qptom.TestSizes(0x1837a1e0)
	/tmp/d20141204-6466-6qptom/solution_test.go:111 +0x3c3
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

goroutine 5 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 6 [running]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 7 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 8 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 9 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 10 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 11 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 12 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 13 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 14 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186
exit status 2
FAIL	_/tmp/d20141204-6466-6qptom	1.012s
PASS
ok  	_/tmp/d20141204-6466-6qptom	0.122s
PASS
ok  	_/tmp/d20141204-6466-6qptom	0.172s
panic: PASS
test timed out

goroutine 7 [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 [panicwait]:

goroutine 5 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 6 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186
exit status 2
FAIL	_/tmp/d20141204-6466-6qptom	3.012s
panic: test timed out

--- FAIL: TestDeleteMethod-2 (0.00 seconds)
	solution_test.go:215: Key foo expires did not get deleted
goroutine 7 [FAIL
runningexit status 1
FAIL	_/tmp/d20141204-6466-6qptom	15.012s
panic: test timed out
PASS

goroutine 10 [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 [panicwait]:

goroutine 5 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 6 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 7 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 8 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 9 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186
exit status 2
FAIL	_/tmp/d20141204-6466-6qptom	15.013s
panic: test timed outPASS


goroutine 7 [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 [panicwait]:

goroutine 5 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 6 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186
exit status 2
FAIL	_/tmp/d20141204-6466-6qptom	15.012s
panic: test timed out

goroutine 14 [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(0x8148c30, 0x81c3ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148c30, 0x81c3ba0, 0x19, 0x19, 0x81c6600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-6qptom/_test/_testmain.go:91 +0x81

goroutine 4 [semacquire]:
sync.runtime_Semacquire(0x18300328)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*WaitGroup).Wait(0x18331860)
	/usr/local/lib/go/src/pkg/sync/waitgroup.go:109 +0xda
_/tmp/d20141204-6466-6qptom.TestIncAndDecInManyRoutines(0x18371120)
	/tmp/d20141204-6466-6qptom/solution_test.go:379 +0x275
testing.tRunner(0x18371120, 0x81c3c0c)
	/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-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186
--- FAIL: TestIncAndDecInManyRoutines-2 (40.01 seconds)
	solution_test.go:388: Expected 666 but found 2360
exit status 2
FAIL	_/tmp/d20141204-6466-6qptom	40.022s
PASS
ok  	_/tmp/d20141204-6466-6qptom	0.014s
PASS
ok  	_/tmp/d20141204-6466-6qptom	0.038s
PASS
panic: test timed out

goroutine 8 [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 [syscall]:
syscall.Syscall()
	/usr/local/lib/go/src/pkg/syscall/asm_linux_386.s:14 +0x5
syscall.write(0x1, 0x18348180, 0x5, 0x2c, 0x80f9400, ...)
	/usr/local/lib/go/src/pkg/syscall/zerrors_linux_386.go:2716 +0x5b
syscall.Write(0x1, 0x18348180, 0x5, 0x2c, 0xb7b10000, ...)
	/usr/local/lib/go/src/pkg/syscall/syscall_unix.go:143 +0x51
os.(*File).write(0x183000a0, 0x18348180, 0x5, 0x2c, 0x0, ...)
	/usr/local/lib/go/src/pkg/os/file_unix.go:188 +0x66
os.(*File).Write(0x183000a0, 0x18348180, 0x5, 0x2c, 0x8050101, ...)
	/usr/local/lib/go/src/pkg/os/file.go:139 +0x77
fmt.Fprintln(0x18331760, 0x183000a0, 0xb7b1ff8c, 0x1, 0x1, ...)
	/usr/local/lib/go/src/pkg/fmt/print.go:281 +0x82
fmt.Println(0xb7b1ff8c, 0x1, 0x1, 0x80f9400, 0x0, ...)
	/usr/local/lib/go/src/pkg/fmt/print.go:290 +0x63
testing.Main(0x8148c30, 0x81c3ba0, 0x19, 0x19, 0x81c6600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:371 +0x119
main.main()
	_/tmp/d20141204-6466-6qptom/_test/_testmain.go:91 +0x81

goroutine 5 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 6 [running]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 7 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186
exit status 2
FAIL	_/tmp/d20141204-6466-6qptom	15.027s
PASS
ok  	_/tmp/d20141204-6466-6qptom	0.051s
PASS
ok  	_/tmp/d20141204-6466-6qptom	0.112s
PASS
ok  	_/tmp/d20141204-6466-6qptom	0.076s
--- FAIL: TestExpiredChanWhenNoOneIsReading-2 (0.06 seconds)
	solution_test.go:554: Wrong key expired
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-6qptom	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-6qptom	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-6qptom	0.062s
panic: test timed out

goroutine 49 [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(0x8148c30, 0x81c3ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148c30, 0x81c3ba0, 0x19, 0x19, 0x81c6600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-6qptom/_test/_testmain.go:91 +0x81

goroutine 4 [semacquire]:
sync.runtime_Semacquire(0x183004d0)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*WaitGroup).Wait(0x18331860)
	/usr/local/lib/go/src/pkg/sync/waitgroup.go:109 +0xda
_/tmp/d20141204-6466-6qptom.TestConcurrentOperations(0x1837b120)
	/tmp/d20141204-6466-6qptom/solution_test.go:705 +0x559
testing.tRunner(0x1837b120, 0x81c3c84)
	/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-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 6 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 7 [sleep]:
time.Sleep(0x5, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-6qptom.func·008()
	/tmp/d20141204-6466-6qptom/solution_test.go:635 +0x6c
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:637 +0x24b

goroutine 8 [sleep]:
time.Sleep(0x7, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-6qptom.func·009()
	/tmp/d20141204-6466-6qptom/solution_test.go:643 +0x6c
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:645 +0x29e

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

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

goroutine 11 [running]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 12 [runnable]:
_/tmp/d20141204-6466-6qptom.func·012(0x18300340, 0x5, 0x18300348, 0x7)
	/tmp/d20141204-6466-6qptom/solution_test.go:688
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:701 +0x528

goroutine 13 [runnable]:
_/tmp/d20141204-6466-6qptom.func·010()
	/tmp/d20141204-6466-6qptom/solution_test.go:653
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:663 +0x300

goroutine 14 [runnable]:
_/tmp/d20141204-6466-6qptom.func·011()
	/tmp/d20141204-6466-6qptom/solution_test.go:668
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:678 +0x353

goroutine 15 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 16 [runnable]:
_/tmp/d20141204-6466-6qptom.func·012(0x18300368, 0x5, 0x18300370, 0x7)
	/tmp/d20141204-6466-6qptom/solution_test.go:688
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:701 +0x528

goroutine 17 [runnable]:
_/tmp/d20141204-6466-6qptom.func·010()
	/tmp/d20141204-6466-6qptom/solution_test.go:653
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:663 +0x300

goroutine 18 [runnable]:
_/tmp/d20141204-6466-6qptom.func·011()
	/tmp/d20141204-6466-6qptom/solution_test.go:668
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:678 +0x353

goroutine 19 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 20 [runnable]:
_/tmp/d20141204-6466-6qptom.func·012(0x18300390, 0x5, 0x18300398, 0x7)
	/tmp/d20141204-6466-6qptom/solution_test.go:688
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:701 +0x528

goroutine 21 [runnable]:
_/tmp/d20141204-6466-6qptom.func·010()
	/tmp/d20141204-6466-6qptom/solution_test.go:653
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:663 +0x300

goroutine 22 [runnable]:
_/tmp/d20141204-6466-6qptom.func·011()
	/tmp/d20141204-6466-6qptom/solution_test.go:668
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:678 +0x353

goroutine 23 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 24 [runnable]:
_/tmp/d20141204-6466-6qptom.func·012(0x183003b8, 0x5, 0x183003c0, 0x7)
	/tmp/d20141204-6466-6qptom/solution_test.go:688
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:701 +0x528

goroutine 25 [runnable]:
_/tmp/d20141204-6466-6qptom.func·010()
	/tmp/d20141204-6466-6qptom/solution_test.go:653
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:663 +0x300

goroutine 26 [runnable]:
_/tmp/d20141204-6466-6qptom.func·011()
	/tmp/d20141204-6466-6qptom/solution_test.go:668
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:678 +0x353

goroutine 27 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 28 [runnable]:
_/tmp/d20141204-6466-6qptom.func·012(0x183003e0, 0x5, 0x183003e8, 0x7)
	/tmp/d20141204-6466-6qptom/solution_test.go:688
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:701 +0x528

goroutine 29 [runnable]:
_/tmp/d20141204-6466-6qptom.func·010()
	/tmp/d20141204-6466-6qptom/solution_test.go:653
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:663 +0x300

goroutine 30 [runnable]:
_/tmp/d20141204-6466-6qptom.func·011()
	/tmp/d20141204-6466-6qptom/solution_test.go:668
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:678 +0x353

goroutine 31 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 32 [runnable]:
_/tmp/d20141204-6466-6qptom.func·012(0x18300408, 0x5, 0x18300410, 0x7)
	/tmp/d20141204-6466-6qptom/solution_test.go:688
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:701 +0x528

goroutine 33 [runnable]:
_/tmp/d20141204-6466-6qptom.func·010()
	/tmp/d20141204-6466-6qptom/solution_test.go:653
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:663 +0x300

goroutine 34 [runnable]:
_/tmp/d20141204-6466-6qptom.func·011()
	/tmp/d20141204-6466-6qptom/solution_test.go:668
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:678 +0x353

goroutine 35 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 36 [runnable]:
_/tmp/d20141204-6466-6qptom.func·012(0x18300430, 0x5, 0x18300438, 0x7)
	/tmp/d20141204-6466-6qptom/solution_test.go:688
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:701 +0x528

goroutine 37 [runnable]:
_/tmp/d20141204-6466-6qptom.func·010()
	/tmp/d20141204-6466-6qptom/solution_test.go:653
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:663 +0x300

goroutine 38 [runnable]:
_/tmp/d20141204-6466-6qptom.func·011()
	/tmp/d20141204-6466-6qptom/solution_test.go:668
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:678 +0x353

goroutine 39 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 40 [runnable]:
_/tmp/d20141204-6466-6qptom.func·012(0x18300458, 0x5, 0x18300460, 0x7)
	/tmp/d20141204-6466-6qptom/solution_test.go:688
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:701 +0x528

goroutine 41 [runnable]:
_/tmp/d20141204-6466-6qptom.func·010()
	/tmp/d20141204-6466-6qptom/solution_test.go:653
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:663 +0x300

goroutine 42 [runnable]:
_/tmp/d20141204-6466-6qptom.func·011()
	/tmp/d20141204-6466-6qptom/solution_test.go:668
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:678 +0x353

goroutine 43 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 44 [runnable]:
_/tmp/d20141204-6466-6qptom.func·012(0x18300480, 0x5, 0x18300488, 0x7)
	/tmp/d20141204-6466-6qptom/solution_test.go:688
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:701 +0x528

goroutine 45 [runnable]:
_/tmp/d20141204-6466-6qptom.func·010()
	/tmp/d20141204-6466-6qptom/solution_test.go:653
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:663 +0x300

goroutine 46 [runnable]:
_/tmp/d20141204-6466-6qptom.func·011()
	/tmp/d20141204-6466-6qptom/solution_test.go:668
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:678 +0x353

goroutine 47 [runnable]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 48 [runnable]:
_/tmp/d20141204-6466-6qptom.func·012(0x183004a8, 0x5, 0x183004b0, 0x7)
	/tmp/d20141204-6466-6qptom/solution_test.go:688
created by _/tmp/d20141204-6466-6qptom.TestConcurrentOperations
	/tmp/d20141204-6466-6qptom/solution_test.go:701 +0x528
exit status 2
FAIL	_/tmp/d20141204-6466-6qptom	15.021s
panic: PASS
test timed out

goroutine 12 [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 [panicwait]:

goroutine 5 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 6 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 7 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 8 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 9 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 10 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 11 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186
exit status 2
FAIL	_/tmp/d20141204-6466-6qptom	15.013s
--- 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-6qptom	0.062s
PASS
ok  	_/tmp/d20141204-6466-6qptom	10.012s
--- FAIL: TestMultipleKeysWithTheSameExpireTime-2 (0.26 seconds)
	solution_test.go:900: Key same-time-key-0 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-1 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-2 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-3 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-4 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-5 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-6 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-7 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-8 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-9 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-10 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-11 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-12 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-13 had expire time even though it has expired
	solution_test.go:900: Key same-time-key-14 had expire time even though it has expired
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-6qptom	0.272s
panic: test timed out

goroutine 7 [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 [runnable]:
testing.RunTests(0x8148c30, 0x81c3ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148c30, 0x81c3ba0, 0x19, 0x19, 0x81c6600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-6qptom/_test/_testmain.go:91 +0x81

goroutine 5 [running]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:45
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186

goroutine 6 [chan send]:
_/tmp/d20141204-6466-6qptom.func·001()
	/tmp/d20141204-6466-6qptom/solution.go:50 +0x10b
created by _/tmp/d20141204-6466-6qptom.(*ExpireMap).Set
	/tmp/d20141204-6466-6qptom/solution.go:55 +0x186
exit status 2
FAIL	_/tmp/d20141204-6466-6qptom	5.089s

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

Диян обнови решението на 18.11.2014 11:49 (преди над 3 години)

+package main
+
+import (
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+type ExpireMap struct {
+ Map map[string]interface{}
+ Expire map[string]time.Time
+ Expired chan string
+ sync.Mutex
+}
+
+//Връща указател към нов обект от тип ExpireMap, готов за използване.
+func NewExpireMap() *ExpireMap {
+ result := new(ExpireMap)
+ result.Map = make(map[string]interface{})
+ result.Expire = make(map[string]time.Time)
+ result.Expired = make(chan string)
+ return result
+}
+
+type MapError struct {
+ mapError string
+}
+
+func (err MapError) Error() string {
+ return err.mapError
+}
+
+//Добавя в хранилището нов ключ key със стойност value за expire време.
+//Duration е дефиниран в пакета time.
+//expire време след добавянето на ключа
+//той вече трябва да спре да бъде в хранилището.
+//Стойността може да е от всякакъв тип, докато ключа е от тип string.
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+
+ if _, ok := em.Map[key]; !ok {
+ em.Map[key] = value
+ em.Expire[key] = time.Now().Add(expire) //Момента, когато ще изтече
+ go func() {
+ for {
+ if time.Now().After(em.Expire[key]) {
+
+ em.Delete(key)
+ em.Expired <- key
+ return
+ }
+ }
+
+ }()
+ } else {
+ em.Lock()
+ defer em.Unlock()
+ em.Map[key] = value
+ em.Expire[key] = time.Now().Add(expire)
+ }
+}
+
+//Връща стойността на ключ и true, когато ключа е намерен.
+// Когато ключа липсва или е изтекъл връща nil и false.
+func (em *ExpireMap) Get(key string) (interface{}, bool) {
+ if _, ok := em.Map[key]; ok {
+ return em.Map[key], true
+ } else {
+ return nil, false
+ }
+
+}
+
+//Връща стойността, отговаряща на този
+//ключ и true, когато ключа е намерен и стойността му е от тип int.
+//Когато ключа липсва, изтекъл е или
+//стойността му не е от този тип метода трябва да върне нула и false.
+
+func (em *ExpireMap) GetInt(key string) (int, bool) {
+ if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.Int {
+ return reflect.ValueOf(value).Interface().(int), ok
+ }
+
+ return 0, false
+}
+
+//Връща стойността на този ключ и true,
+//когато ключа е намерен и стойността му е от тип float64.
+// Когато ключа липсва, изтекъл е или
+//стойността му не е от този тип метода трябва да върне нула и false.
+func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
+ if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.Float64 {
+ return reflect.ValueOf(value).Interface().(float64), ok
+ }
+ return 0, false
+}
+
+//Връща стойността на ключ и true,
+// когато ключа е намерен и стойността му е от тип string.
+// Когато ключа липсва, изтекъл е или
+//стойността не е от тип string метода трябва да върне празен стринг и false.
+func (em *ExpireMap) GetString(key string) (string, bool) {
+ if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.String {
+ return reflect.ValueOf(value).Interface().(string), ok
+ }
+ return "", false
+}
+
+//Връща стойността на ключ и true, когато ключа е намерен и стойността му е от тип bool.
+// Когато ключа липсва, изтекъл е или
+//стойността не е от тип bool метода трябва да върне false и false.
+func (em *ExpireMap) GetBool(key string) (bool, bool) {
+ if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.Bool {
+ return reflect.ValueOf(value).Interface().(bool), ok
+ }
+ return false, false
+}
+
+//За определен ключ тази функция трябва да върне времето, когато той ще изтече.
+//Втората върната стойност е true когато ключа е намерен в хранилището.
+//Когато не е намерен функцията трябва да върне нулевото време и false.
+func (em *ExpireMap) Expires(key string) (time.Time, bool) {
+ if result, ok := em.Expire[key]; ok {
+ return result, ok
+ }
+
+ var zeroTime time.Time //default time.Time е нулево време.
+ return zeroTime, false
+}
+
+//Премахва ключа от хранилището. Когато няма такъв ключ метода не трябав да гърми.
+func (em *ExpireMap) Delete(key string) {
+ if _, ok := em.Get(key); ok {
+ em.Lock()
+ delete(em.Map, key)
+ em.Unlock()
+ //<-em.Done //излизам от горутината дето цикли за тоя ключ
+ }
+}
+
+//Казва дали ключ е в хранилището или не. Отново,
+//ключове са в хранилището само ако техния expire не е вече изтекъл.
+func (em *ExpireMap) Contains(key string) bool {
+ _, ok := em.Map[key]
+ return ok
+}
+
+//Връща големината на хранилището. Големина е бройката неизтекли ключове, които са в него.
+func (em *ExpireMap) Size() int {
+ return len(em.Map)
+}
+
+//За ключ увеличава стойността му числово с 1 когато тази стойност
+// е от тип int или стринг, представящ цяло число.
+//Когато стойността е от тип, различен от тези неща функцията трябва
+// да върне грешка, различна от nil. float32 и float64 не са целочислен типове.
+// Времето на изтичане на ключа не трябва да се променя.
+
+func (em *ExpireMap) Increment(key string) error {
+ if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.Int {
+ newValue := value.(int)
+ newValue++
+ em.Map[key] = newValue
+ }
+ if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.String {
+ if newValue, errNotConvertable := strconv.Atoi(em.Map[key].(string)); errNotConvertable == nil {
+ newValue++
+ em.Map[key] = strconv.Itoa(newValue)
+ return nil
+ } else {
+
+ return &MapError{"Cannot increment"}
+
+ }
+ }
+
+ return &MapError{"Cannot increment"}
+}
+
+//Същото като Increment, но намалява стойността с 1 вместо да я увеличава.
+func (em *ExpireMap) Decrement(key string) error {
+ if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.Int {
+ newValue := value.(int)
+ newValue--
+ em.Map[key] = newValue
+ }
+ if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.String {
+ if newValue, errNotConvertable := strconv.Atoi(em.Map[key].(string)); errNotConvertable == nil {
+ newValue--
+ em.Map[key] = strconv.Itoa(newValue)
+ return nil
+ } else {
+
+ return &MapError{"Cannot decrement"}
+
+ }
+ }
+
+ return &MapError{"Cannot decrement"}
+}
+
+//Ако стойността за ключа key е от тип string, то всички
+//букви в този string трябва да станат главни.
+// При успех метода трябва да върне nil, а при невъзможност
+//да изпълни задачата - грешка. Пример за употреба:
+func (em *ExpireMap) ToUpper(key string) error {
+ if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.String {
+ newValue := value.(string)
+ em.Map[key] = strings.ToUpper(newValue)
+ return nil
+ } else {
+ return &MapError{"Cannot convert to upper case"}
+ }
+}
+
+//Същото като ToUpper, но всички букви трябва станат малки.
+func (em *ExpireMap) ToLower(key string) error {
+ if value, ok := em.Map[key]; ok && reflect.TypeOf(value).Kind() == reflect.String {
+ newValue := value.(string)
+ em.Map[key] = strings.ToLower(newValue)
+ return nil
+ } else {
+ return &MapError{"Cannot convert to lower case"}
+ }
+
+}
+
+//Тази функция трябва да върне канал, по който да идват ключовете, които са изтекли.
+// Те трябва да се пускат по канала в момента на изтичането си.
+// Ключове, които са изтрити с Delete или Cleanup не трябва да се връщат по този канал.
+// Единствено тези, които са достигнали до времето си на изтичане.
+// Не е задължително през цялото време някой да чете от върнатия канал.
+// Ключове добавени в инстанцията след извикването на ExpireChan също
+//трябва да се пратят по канала, когато тяхното време дойде.
+func (em *ExpireMap) ExpiredChan() <-chan string {
+ return em.Expired
+}
+
+//Изчиства хранилището. След извикване на функцията в
+//ExpireMap-a не трябва да се съдържа нито един ключ.
+func (em *ExpireMap) Cleanup() {
+
+ for key, _ := range em.Map {
+ em.Delete(key)
+
+ }
+
+}
+
+// Трябва да освободи всички ресурси, които е използвал този ExpireMap.
+// Това означава изчистване на всички структури, затваряне на
+// всички канали и спиране на всички горутини, свързани с нормалната му работа.
+// След извикване на Destroy тази инстанция на ExpireMap няма да бъде повече използвана.
+func (em *ExpireMap) Destroy() {
+ em.Cleanup()
+}