Решение на ExpireMap от Евгений Бояджиев

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

Към профила на Евгений Бояджиев

Резултати

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

Код

package main
import (
"fmt"
"strconv"
"strings"
"sync"
"time"
)
func main() {
return
}
type CacheValue struct {
value interface{}
expire time.Time
delete chan struct{}
}
func NewCacheValue(value interface{}, expire time.Duration) *CacheValue {
return &CacheValue{
value: value,
expire: time.Now().Add(expire),
delete: make(chan struct{}),
}
}
type ExpireMap struct {
container map[string]*CacheValue
expired chan string
shutdown chan struct{}
wg *sync.WaitGroup
}
func NewExpireMap() *ExpireMap {
return &ExpireMap{
container: make(map[string]*CacheValue),
expired: make(chan string),
shutdown: make(chan struct{}),
wg: &sync.WaitGroup{},
}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.container[key] = NewCacheValue(value, expire)
em.wg.Add(1)
go cacheValueLifetime(em, key, expire)
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
val, ok := em.getCacheValue(key)
if !ok {
return nil, false
}
return val.value, true
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
val, ok := em.Get(key)
if !ok {
return 0, false
}
result, ok := val.(int)
return result, ok
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
val, ok := em.Get(key)
if !ok {
return 0.0, false
}
result, ok := val.(float64)
return result, ok
}
func (em *ExpireMap) GetString(key string) (string, bool) {
val, ok := em.Get(key)
if !ok {
return "", false
}
result, ok := val.(string)
return result, ok
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
val, ok := em.Get(key)
if !ok {
return false, false
}
result, ok := val.(bool)
return result, ok
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
val, ok := em.getCacheValue(key)
if !ok {
return time.Time{}, false
}
return val.expire, true
}
func (em *ExpireMap) Delete(key string) {
close(em.container[key].delete)
delete(em.container, key)
}
func (em *ExpireMap) Contains(key string) bool {
_, ok := em.Get(key)
return ok
}
func (em *ExpireMap) Size() int {
return len(em.container)
}
func (em *ExpireMap) Increment(key string) error {
err := em.add(key, 1)
if err != nil {
return newCacheError("Cannot increment the value")
}
return nil
}
func (em *ExpireMap) Decrement(key string) error {
err := em.add(key, -1)
if err != nil {
return newCacheError("Cannot decrement the value")
}
return nil
}
func (em *ExpireMap) ToUpper(key string) error {
str, ok := em.GetString(key)
if !ok {
return newCacheError("Cannot update value. Key does not exist or value is not of string type")
}
return em.updateValue(key, strings.ToUpper(str))
}
func (em *ExpireMap) ToLower(key string) error {
str, ok := em.GetString(key)
if !ok {
return newCacheError("Cannot update value. Key does not exist or value is not of string type")
}
return em.updateValue(key, strings.ToLower(str))
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.expired
}
func (em *ExpireMap) Cleanup() {
for key, _ := range em.container {
em.Delete(key)
}
}
func (em *ExpireMap) Destroy() {
em.Cleanup()
close(em.shutdown)
}
/* Helper Methods */
func (em *ExpireMap) add(key string, integer int) error {
intVal, ok := em.GetInt(key)
if ok {
updatedValue := intVal + integer
em.updateValue(key, updatedValue)
return nil
}
stringVal, ok := em.GetString(key)
intVal, err := strconv.Atoi(stringVal)
if err == nil {
newValue := strconv.Itoa(intVal + integer)
em.updateValue(key, newValue)
return nil
}
return newCacheError("Cannot add the value. Incompatible type or non-existing key.")
}
func (em *ExpireMap) getCacheValue(key string) (*CacheValue, bool) {
value, ok := em.container[key]
return value, ok
}
func (em *ExpireMap) updateValue(key string, value interface{}) error {
_, ok := em.Get(key)
if !ok {
return newCacheError("Cannot update value. Key does not exist")
}
em.container[key].value = value
return nil
}
func cacheValueLifetime(em *ExpireMap, key string, expire time.Duration) {
defer em.wg.Done()
for {
select {
case <-time.After(expire):
em.Delete(key)
em.expired <- key
case <-em.container[key].delete:
case <-em.shutdown:
em.Delete(key)
}
}
}
/* Errors */
type ChacheError struct {
Message string
}
func (e *ChacheError) Error() string {
return fmt.Sprintf("ChacheError: %v", e.Message)
}
func newCacheError(message string) *ChacheError {
return &ChacheError{Message: message}
}

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

▸ Покажи лога

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

Евгений обнови решението на 18.11.2014 09:10 (преди над 3 години)

▸ Покажи разликите
+package main
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+func main() {
+ return
+}
+
+type CacheValue struct {
+ value interface{}
+ expire time.Time
+ delete chan struct{}
+}
+
+func NewCacheValue(value interface{}, expire time.Duration) *CacheValue {
+ return &CacheValue{
+ value: value,
+ expire: time.Now().Add(expire),
+ delete: make(chan struct{}),
+ }
+}
+
+type ExpireMap struct {
+ container map[string]*CacheValue
+ expired chan string
+ shutdown chan struct{}
+ wg *sync.WaitGroup
+}
+
+func NewExpireMap() *ExpireMap {
+ return &ExpireMap{
+ container: make(map[string]*CacheValue),
+ expired: make(chan string),
+ shutdown: make(chan struct{}),
+ wg: &sync.WaitGroup{},
+ }
+}
+
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+ em.container[key] = NewCacheValue(value, expire)
+ em.wg.Add(1)
+ go cacheValueLifetime(em, key, expire)
+}
+
+func (em *ExpireMap) Get(key string) (interface{}, bool) {
+ val, ok := em.getCacheValue(key)
+ if !ok {
+ return nil, false
+ }
+ return val.value, true
+}
+
+func (em *ExpireMap) GetInt(key string) (int, bool) {
+ val, ok := em.Get(key)
+ if !ok {
+ return 0, false
+ }
+ result, ok := val.(int)
+ return result, ok
+}
+
+func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
+ val, ok := em.Get(key)
+ if !ok {
+ return 0.0, false
+ }
+ result, ok := val.(float64)
+ return result, ok
+}
+
+func (em *ExpireMap) GetString(key string) (string, bool) {
+ val, ok := em.Get(key)
+ if !ok {
+ return "", false
+ }
+ result, ok := val.(string)
+ return result, ok
+}
+
+func (em *ExpireMap) GetBool(key string) (bool, bool) {
+ val, ok := em.Get(key)
+ if !ok {
+ return false, false
+ }
+ result, ok := val.(bool)
+ return result, ok
+}
+
+func (em *ExpireMap) Expires(key string) (time.Time, bool) {
+ val, ok := em.getCacheValue(key)
+ if !ok {
+ return time.Time{}, false
+ }
+ return val.expire, true
+}
+
+func (em *ExpireMap) Delete(key string) {
+ close(em.container[key].delete)
+ delete(em.container, key)
+}
+
+func (em *ExpireMap) Contains(key string) bool {
+ _, ok := em.Get(key)
+ return ok
+}
+
+func (em *ExpireMap) Size() int {
+ return len(em.container)
+}
+
+func (em *ExpireMap) Increment(key string) error {
+ err := em.add(key, 1)
+ if err != nil {
+ return newCacheError("Cannot increment the value")
+ }
+ return nil
+}
+
+func (em *ExpireMap) Decrement(key string) error {
+ err := em.add(key, -1)
+ if err != nil {
+ return newCacheError("Cannot decrement the value")
+ }
+ return nil
+}
+
+func (em *ExpireMap) ToUpper(key string) error {
+ str, ok := em.GetString(key)
+ if !ok {
+ return newCacheError("Cannot update value. Key does not exist or value is not of string type")
+ }
+ return em.updateValue(key, strings.ToUpper(str))
+}
+
+func (em *ExpireMap) ToLower(key string) error {
+ str, ok := em.GetString(key)
+ if !ok {
+ return newCacheError("Cannot update value. Key does not exist or value is not of string type")
+ }
+ return em.updateValue(key, strings.ToLower(str))
+}
+
+func (em *ExpireMap) ExpiredChan() <-chan string {
+ return em.expired
+}
+
+func (em *ExpireMap) Cleanup() {
+ for key, _ := range em.container {
+ em.Delete(key)
+ }
+}
+
+func (em *ExpireMap) Destroy() {
+ em.Cleanup()
+ close(em.shutdown)
+}
+
+/* Helper Methods */
+func (em *ExpireMap) add(key string, integer int) error {
+ intVal, ok := em.GetInt(key)
+ if ok {
+ updatedValue := intVal + integer
+ em.updateValue(key, updatedValue)
+ return nil
+ }
+ stringVal, ok := em.GetString(key)
+ intVal, err := strconv.Atoi(stringVal)
+ if err == nil {
+ newValue := strconv.Itoa(intVal + integer)
+ em.updateValue(key, newValue)
+ return nil
+ }
+
+ return newCacheError("Cannot add the value. Incompatible type or non-existing key.")
+}
+
+func (em *ExpireMap) getCacheValue(key string) (*CacheValue, bool) {
+ value, ok := em.container[key]
+ return value, ok
+}
+
+func (em *ExpireMap) updateValue(key string, value interface{}) error {
+ _, ok := em.Get(key)
+ if !ok {
+ return newCacheError("Cannot update value. Key does not exist")
+ }
+ em.container[key].value = value
+ return nil
+}
+
+func cacheValueLifetime(em *ExpireMap, key string, expire time.Duration) {
+ defer em.wg.Done()
+ for {
+ select {
+ case <-time.After(expire):
+ em.Delete(key)
+ em.expired <- key
+ case <-em.container[key].delete:
+ case <-em.shutdown:
+ em.Delete(key)
+ }
+ }
+}
+
+/* Errors */
+type ChacheError struct {
+ Message string
+}
+
+func (e *ChacheError) Error() string {
+ return fmt.Sprintf("ChacheError: %v", e.Message)
+}
+
+func newCacheError(message string) *ChacheError {
+ return &ChacheError{Message: message}
+}