0x4a52466c696e74 il y a 2 ans
Parent
commit
2fe0fcfefd
7 fichiers modifiés avec 594 ajouts et 205 suppressions
  1. 13 0
      bufio/bits/bits.go
  2. 18 0
      bufio/bits/tools.go
  3. 10 0
      bufio/bits/z_test.go
  4. 167 127
      cache/cachemap.go
  5. 242 0
      cache/cachemap.go.tmp
  6. 41 78
      cache/z_test.go
  7. 103 0
      cache/z_test.go.tmp

+ 13 - 0
bufio/bits/bits.go

@@ -0,0 +1,13 @@
+package bits
+
+type Bits struct {
+	val int64
+}
+
+func (s *Bits) BitSet(val bool, offset int) {
+	//rVal := 0
+	//if !val {
+	//	rVal = 1
+	//}
+
+}

+ 18 - 0
bufio/bits/tools.go

@@ -0,0 +1,18 @@
+package bits
+
+import (
+	"fmt"
+)
+
+func SetBit(b byte, flag bool, offset byte) byte {
+	if flag {
+		b |= 1 << offset
+	} else {
+		b &= 0 << offset
+	}
+	return b
+}
+
+func StringBits(b byte) string {
+	return fmt.Sprintf("%b", b)
+}

+ 10 - 0
bufio/bits/z_test.go

@@ -0,0 +1,10 @@
+package bits
+
+import "testing"
+
+func TestBits(t *testing.T) {
+	var b byte
+	b = SetBit(b, true, 1)
+	b = SetBit(b, false, 1)
+	t.Log(StringBits(b))
+}

+ 167 - 127
cache/cachemap.go

@@ -1,240 +1,280 @@
 package cache
 
 import (
-	"runtime"
+	"context"
 	"sync"
 	"time"
 )
 
-type CallCreate func(key interface{}) (value interface{}, created bool)
-type CallCreateNew func(key interface{}) (rKey, value interface{}, created bool)
-type CallCheck func(key, value interface{}, exists bool) (rKey, rValue interface{}, created bool)
-
-func NewMap(liveDuration time.Duration, maxSize int) *CacheMap {
-	res := &CacheMap{&cacheMap{
-		locker:          new(sync.RWMutex),
-		items:           make(map[interface{}]*cacheMapItem),
-		liveDuration:    liveDuration,
-		maxSize:         maxSize,
-		stopCleanerChan: make(chan byte),
-	}}
-	runtime.SetFinalizer(res, destroyCacheMap)
+const (
+	LiveInfinite = time.Duration(-1)
+)
+
+type CallCreate func(key any) (value any, created bool)
+type CallCreateNew func(key any) (rKey, value any, created bool)
+type CallCheck func(key, value any, exists bool) (rKey, rValue any, created bool)
+
+type item struct {
+	value  any
+	expire int64
+}
+
+func NewCacheMap(ctx context.Context, maxSize int, live time.Duration) *CacheMap {
+	cctx, cancel := context.WithCancel(ctx)
+	res := &CacheMap{
+		ctx:     cctx,
+		cancel:  cancel,
+		items:   make(map[any]*item),
+		mi:      new(sync.RWMutex),
+		live:    live,
+		maxSize: maxSize,
+		mc:      new(sync.RWMutex),
+	}
+	// todo - clean worker
 	return res
 }
 
 type CacheMap struct {
-	*cacheMap
+	finished   bool
+	ctx        context.Context
+	cancel     context.CancelFunc
+	items      map[any]*item
+	mi         *sync.RWMutex
+	live       time.Duration
+	maxSize    int
+	cleanChans []chan map[any]any
+	mc         *sync.RWMutex
 }
 
-type cacheMapItem struct {
-	value  interface{}
-	expire int64
+func (s *CacheMap) IsFinished() bool {
+	return s.finished
 }
 
-type cacheMap struct {
-	locker           *sync.RWMutex
-	items            map[interface{}]*cacheMapItem
-	liveDuration     time.Duration
-	maxSize          int
-	cleanerWork      bool
-	stopCleanerChan  chan byte
-	cleanedEventChan chan map[interface{}]interface{}
+func (s *CacheMap) close() {
+	s.finished = true
+	s.mc.Lock()
+	for _, ch := range s.cleanChans {
+		close(ch)
+	}
+	s.cleanChans = nil
+	s.mc.Unlock()
+
 }
 
-func (s *cacheMap) CleanEvent() (eventChan <-chan map[interface{}]interface{}) {
-	s.locker.Lock()
-	if s.cleanedEventChan == nil {
-		s.cleanedEventChan = make(chan map[interface{}]interface{})
+func (s *CacheMap) eventClean(m map[any]any) {
+	s.mc.RLock()
+	for _, ch := range s.cleanChans {
+		select {
+		case ch <- m:
+		default:
+		}
 	}
-	eventChan = s.cleanedEventChan
-	s.locker.Unlock()
-	return
+	s.mc.RUnlock()
+}
+
+func (s *CacheMap) EventCleaner() <-chan map[any]any {
+	s.mc.Lock()
+	ech := make(chan map[any]any, 1)
+	s.cleanChans = append(s.cleanChans, ech)
+	s.mc.Unlock()
+	return ech
 }
 
-func (s *cacheMap) runCleaner() {
-	ticker := time.NewTicker(s.liveDuration / 2)
+func (s *CacheMap) cleanWorker() {
+	t := time.NewTicker(s.live)
+loop:
 	for {
 		select {
-		case <-ticker.C:
-			{
-				now := time.Now().UnixNano()
-				s.locker.Lock()
-				cleaned := make(map[interface{}]interface{})
-				for key, val := range s.items {
-					if now > val.expire {
-						cleaned[key] = val.value
-						delete(s.items, key)
-					}
-				}
-				if len(cleaned) > 0 {
-					select {
-					case s.cleanedEventChan <- cleaned:
-					default:
-					}
+		case <-t.C:
+			// clean items
+			nowTS := time.Now().Unix()
+			m := make(map[any]any)
+			s.mi.Lock()
+			for key, item := range s.items {
+				if item.expire < nowTS {
+					delete(s.items, key)
+					m[key] = item.value
 				}
-				if len(s.items) == 0 {
-					s.cleanerWork = false
-					ticker.Stop()
-					s.locker.Unlock()
-					return
-				}
-				s.locker.Unlock()
 			}
-		case <-s.stopCleanerChan:
-			{
-				s.cleanerWork = false
-				ticker.Stop()
-				return
+			s.mi.Unlock()
+			if len(m) > 0 {
+				s.eventClean(m)
 			}
+		case <-s.ctx.Done():
+			break loop
 		}
 	}
 }
 
-func (s *cacheMap) delete(key interface{}) {
+func (s *CacheMap) delete(key any) {
 	delete(s.items, key)
-	if len(s.items) == 0 && s.cleanerWork {
-		s.stopCleanerChan <- 0
-	}
 }
 
 // Delete removes cached object
-func (s *cacheMap) Delete(key interface{}) {
-	s.locker.Lock()
+func (s *CacheMap) Delete(key any) {
+	s.mi.Lock()
 	s.delete(key)
-	s.locker.Unlock()
+	s.mi.Unlock()
 }
 
-func (s *cacheMap) set(key, value interface{}) {
-	s.items[key] = &cacheMapItem{
+func (s *CacheMap) set(key, value any) {
+	s.items[key] = &item{
 		value:  value,
-		expire: time.Now().Add(s.liveDuration).UnixNano(),
+		expire: time.Now().Add(s.live).UnixNano(),
+	}
+}
+
+func (s *CacheMap) keysOlder(count int) []any {
+	if count > len(s.items) {
+		count = len(s.items)
 	}
-	if !s.cleanerWork {
-		s.cleanerWork = true
-		go s.runCleaner()
+	last, llast := time.Now().Unix(), int64(-1)
+	res := make([]any, 0, count)
+	for len(res) < count {
+		var rKey any
+		ltmp := last
+		for key, val := range s.items {
+			if val.expire < ltmp && val.expire > llast {
+				rKey = key
+				ltmp = val.expire
+			}
+		}
+		res = append(res, rKey)
+		llast = ltmp
 	}
+	return res
 }
 
-func (s *cacheMap) Set(key, value interface{}) {
-	s.locker.Lock()
+func (s *CacheMap) Set(key, value any) {
+	s.mi.Lock()
+	if s.maxSize > 0 && len(s.items) == s.maxSize {
+		// remove first
+		for key, val := range s.items {
+			delete(s.items, key)
+			s.eventClean(map[any]any{
+				key: val.value,
+			})
+			break
+		}
+	}
 	s.set(key, value)
-	s.locker.Unlock()
+	s.mi.Unlock()
 }
 
-func (s *cacheMap) SetMulti(m map[interface{}]interface{}) {
-	s.locker.Lock()
+func (s *CacheMap) SetMulti(m map[any]any) {
+	s.mi.Lock()
+	/*
+		if s.maxSize > 0 && len(s.items)+len(m) > s.maxSize {
+			// remove first
+			for key, val := range s.items {
+				delete(s.items, key)
+				s.eventClean(map[any]any{
+					key: val.value,
+				})
+				break
+			}
+		}
+	*/
 	for key, val := range m {
 		s.set(key, val)
 	}
-	s.locker.Unlock()
+	s.mi.Unlock()
 }
 
-func (s *CacheMap) DeleteMulti(keys []interface{}) {
-	s.locker.Lock()
+func (s *CacheMap) DeleteMulti(keys []any) {
+	s.mi.Lock()
 	for _, key := range keys {
 		delete(s.items, key)
 	}
-	s.locker.Unlock()
+	s.mi.Unlock()
 }
 
-func (s *cacheMap) get(key interface{}) (res interface{}, check bool) {
-	var item *cacheMapItem
-	if item, check = s.items[key]; check {
-		res = item.value
+func (s *CacheMap) get(key any) (res any, check bool) {
+	var it *item
+	if it, check = s.items[key]; check {
+		res = it.value
 	}
 	return
 }
 
-func (s *cacheMap) Get(key interface{}) (res interface{}, check bool) {
-	s.locker.RLock()
+func (s *CacheMap) Get(key any) (res any, check bool) {
+	s.mi.RLock()
 	res, check = s.get(key)
-	s.locker.RUnlock()
+	s.mi.RUnlock()
 	return
 }
 
-func (s *cacheMap) GetCreate(key interface{}, mCreate CallCreate) (val interface{}, check bool) {
+func (s *CacheMap) GetCreate(key any, mCreate CallCreate) (val any, check bool) {
 	if val, check = s.Get(key); !check {
-		s.locker.Lock()
+		s.mi.Lock()
+		defer s.mi.Unlock()
 		if val, check = s.get(key); check {
-			s.locker.Unlock()
 			return
 		}
 
 		if val, check = mCreate(key); check {
 			s.set(key, val)
 		}
-		s.locker.Unlock()
 	}
 	return
 }
 
-func (s *cacheMap) GetCreateNew(key interface{}, mCreateNew CallCreateNew) (rKey, val interface{}, check bool) {
+func (s *CacheMap) GetCreateNew(key any, mCreateNew CallCreateNew) (rKey, val any, check bool) {
 	rKey = key
 	if val, check = s.Get(key); !check {
-		s.locker.Lock()
+		s.mi.Lock()
+		defer s.mi.Unlock()
 		if val, check = s.get(key); check {
-			s.locker.Unlock()
 			return
 		}
-
 		if rKey, val, check = mCreateNew(key); check {
 			s.set(rKey, val)
 		}
-		s.locker.Unlock()
 	}
 	return
 }
 
-func (s *cacheMap) GetCheck(key interface{}, mCheck CallCheck) (res interface{}, check bool) {
-	s.locker.Lock()
+func (s *CacheMap) GetCheck(key any, mCheck CallCheck) (res any, check bool) {
+	s.mi.Lock()
 	res, check = s.get(key)
 	if rKey, rVal, rCheck := mCheck(key, res, check); rCheck {
 		s.set(rKey, rVal)
 		key, res, check = rKey, rVal, true
 	}
-	s.locker.Unlock()
+	s.mi.Unlock()
 	return
 }
 
 // Each implements a map bypass for each key using the callback function. If the callback function returns false, then the cycle stops
-func (s *cacheMap) Each(callback func(interface{}, interface{}) bool) {
-	s.locker.RLock()
+func (s *CacheMap) Each(callback func(any, any) bool) {
+	s.mi.RLock()
+	defer s.mi.RUnlock()
 	for key, val := range s.items {
 		if !callback(key, val.value) {
-			s.locker.RUnlock()
 			return
 		}
 	}
-	s.locker.RUnlock()
 }
 
-func (s *cacheMap) Len() (res int) {
-	s.locker.RLock()
+func (s CacheMap) Len() (res int) {
+	s.mi.RLock()
 	res = len(s.items)
-	s.locker.RUnlock()
+	s.mi.RUnlock()
 	return
 }
 
-func (s *cacheMap) Keys() (res []interface{}) {
-	s.locker.RLock()
-	res = make([]interface{}, 0, len(s.items))
+func (s *CacheMap) Keys() (res []any) {
+	s.mi.RLock()
+	res = make([]any, 0, len(s.items))
 	for key := range s.items {
 		res = append(res, key)
 	}
-	s.locker.RUnlock()
+	s.mi.RUnlock()
 	return
 }
 
-func (s *cacheMap) Clear() {
-	s.locker.Lock()
-	s.items = make(map[interface{}]*cacheMapItem)
-	s.locker.Unlock()
-}
-
-// for garbage collector
-func destroyCacheMap(m *CacheMap) {
-	close(m.stopCleanerChan)
-	if m.cleanedEventChan != nil {
-		close(m.cleanedEventChan)
-	}
+func (s *CacheMap) Clear() {
+	s.mi.Lock()
+	s.items = make(map[any]*item)
+	s.mi.Unlock()
 }

+ 242 - 0
cache/cachemap.go.tmp

@@ -0,0 +1,242 @@
+package cache
+
+import (
+	"log"
+	"runtime"
+	"sync"
+	"time"
+)
+
+type CallCreate func(key interface{}) (value interface{}, created bool)
+type CallCreateNew func(key interface{}) (rKey, value interface{}, created bool)
+type CallCheck func(key, value interface{}, exists bool) (rKey, rValue interface{}, created bool)
+
+func NewMap(liveDuration time.Duration, maxSize int) *CacheMap {
+	res := &CacheMap{&cacheMap{
+		locker:          new(sync.RWMutex),
+		items:           make(map[interface{}]*cacheMapItem),
+		liveDuration:    liveDuration,
+		maxSize:         maxSize,
+		stopCleanerChan: make(chan byte),
+	}}
+	runtime.SetFinalizer(res, destroyCacheMap)
+	return res
+}
+
+type CacheMap struct {
+	*cacheMap
+}
+
+type cacheMapItem struct {
+	value  interface{}
+	expire int64
+}
+
+type cacheMap struct {
+	locker           *sync.RWMutex
+	items            map[interface{}]*cacheMapItem
+	liveDuration     time.Duration
+	maxSize          int
+	cleanerWork      bool
+	stopCleanerChan  chan byte
+	cleanedEventChan chan map[interface{}]interface{}
+}
+
+func (s *cacheMap) CleanEvent() (eventChan <-chan map[interface{}]interface{}) {
+	s.locker.Lock()
+	if s.cleanedEventChan == nil {
+		s.cleanedEventChan = make(chan map[interface{}]interface{})
+	}
+	eventChan = s.cleanedEventChan
+	s.locker.Unlock()
+	return
+}
+
+func (s *cacheMap) runCleaner() {
+	ticker := time.NewTicker(s.liveDuration / 2)
+	for {
+		log.Println("CLEANER")
+		select {
+		case <-ticker.C:
+			{
+				now := time.Now().UnixNano()
+				s.locker.Lock()
+				cleaned := make(map[interface{}]interface{})
+				for key, val := range s.items {
+					if now > val.expire {
+						cleaned[key] = val.value
+						delete(s.items, key)
+					}
+				}
+				if len(cleaned) > 0 {
+					select {
+					case s.cleanedEventChan <- cleaned:
+					default:
+					}
+				}
+				if len(s.items) == 0 {
+					s.cleanerWork = false
+					ticker.Stop()
+					s.locker.Unlock()
+					return
+				}
+				s.locker.Unlock()
+			}
+		case <-s.stopCleanerChan:
+			{
+				s.cleanerWork = false
+				ticker.Stop()
+				return
+			}
+		}
+	}
+}
+
+func (s *cacheMap) delete(key interface{}) {
+	delete(s.items, key)
+	if len(s.items) == 0 && s.cleanerWork {
+		s.stopCleanerChan <- 0
+	}
+}
+
+// Delete removes cached object
+func (s *cacheMap) Delete(key interface{}) {
+	s.locker.Lock()
+	s.delete(key)
+	s.locker.Unlock()
+}
+
+func (s *cacheMap) set(key, value interface{}) {
+	s.items[key] = &cacheMapItem{
+		value:  value,
+		expire: time.Now().Add(s.liveDuration).UnixNano(),
+	}
+	if !s.cleanerWork {
+		s.cleanerWork = true
+		go s.runCleaner()
+	}
+}
+
+func (s *cacheMap) Set(key, value interface{}) {
+	s.locker.Lock()
+	s.set(key, value)
+	s.locker.Unlock()
+}
+
+func (s *cacheMap) SetMulti(m map[interface{}]interface{}) {
+	s.locker.Lock()
+	for key, val := range m {
+		s.set(key, val)
+	}
+	s.locker.Unlock()
+}
+
+func (s *CacheMap) DeleteMulti(keys []interface{}) {
+	s.locker.Lock()
+	for _, key := range keys {
+		delete(s.items, key)
+	}
+	s.locker.Unlock()
+}
+
+func (s *cacheMap) get(key interface{}) (res interface{}, check bool) {
+	var item *cacheMapItem
+	if item, check = s.items[key]; check {
+		res = item.value
+	}
+	return
+}
+
+func (s *cacheMap) Get(key interface{}) (res interface{}, check bool) {
+	s.locker.RLock()
+	res, check = s.get(key)
+	s.locker.RUnlock()
+	return
+}
+
+func (s *cacheMap) GetCreate(key interface{}, mCreate CallCreate) (val interface{}, check bool) {
+	if val, check = s.Get(key); !check {
+		s.locker.Lock()
+		if val, check = s.get(key); check {
+			s.locker.Unlock()
+			return
+		}
+
+		if val, check = mCreate(key); check {
+			s.set(key, val)
+		}
+		s.locker.Unlock()
+	}
+	return
+}
+
+func (s *cacheMap) GetCreateNew(key interface{}, mCreateNew CallCreateNew) (rKey, val interface{}, check bool) {
+	rKey = key
+	if val, check = s.Get(key); !check {
+		s.locker.Lock()
+		if val, check = s.get(key); check {
+			s.locker.Unlock()
+			return
+		}
+
+		if rKey, val, check = mCreateNew(key); check {
+			s.set(rKey, val)
+		}
+		s.locker.Unlock()
+	}
+	return
+}
+
+func (s *cacheMap) GetCheck(key interface{}, mCheck CallCheck) (res interface{}, check bool) {
+	s.locker.Lock()
+	res, check = s.get(key)
+	if rKey, rVal, rCheck := mCheck(key, res, check); rCheck {
+		s.set(rKey, rVal)
+		key, res, check = rKey, rVal, true
+	}
+	s.locker.Unlock()
+	return
+}
+
+// Each implements a map bypass for each key using the callback function. If the callback function returns false, then the cycle stops
+func (s *cacheMap) Each(callback func(interface{}, interface{}) bool) {
+	s.locker.RLock()
+	for key, val := range s.items {
+		if !callback(key, val.value) {
+			s.locker.RUnlock()
+			return
+		}
+	}
+	s.locker.RUnlock()
+}
+
+func (s *cacheMap) Len() (res int) {
+	s.locker.RLock()
+	res = len(s.items)
+	s.locker.RUnlock()
+	return
+}
+
+func (s *cacheMap) Keys() (res []interface{}) {
+	s.locker.RLock()
+	res = make([]interface{}, 0, len(s.items))
+	for key := range s.items {
+		res = append(res, key)
+	}
+	s.locker.RUnlock()
+	return
+}
+
+func (s *cacheMap) Clear() {
+	s.locker.Lock()
+	s.items = make(map[interface{}]*cacheMapItem)
+	s.locker.Unlock()
+}
+
+// for garbage collector
+func destroyCacheMap(m *CacheMap) {
+	close(m.stopCleanerChan)
+	if m.cleanedEventChan != nil {
+		close(m.cleanedEventChan)
+	}
+}

+ 41 - 78
cache/z_test.go

@@ -1,95 +1,58 @@
 package cache
 
 import (
+	"context"
 	"log"
+	"sync"
 	"testing"
 	"time"
 )
 
-func TestMap(t *testing.T) {
-	m := NewMap(time.Second*5, 10)
-
-	m.Set("key", 10)
-
-	log.Println(m.Get("key"))
-	m.Delete("key")
-	log.Println(m.Get("key"))
-	log.Println(m.Get("key1"))
-
-	go func() {
-		for e := range m.CleanEvent() {
-			log.Println("CLEANED", e)
-		}
-	}()
+func TestChan(t *testing.T) {
+	t.Log("!!!")
+	ch := make(chan int, 1)
 
 	for i := 0; i < 5; i++ {
-		time.Sleep(time.Second * 10)
-		m.Set("key", "oneee")
-
+		go func(im int) {
+			for val := range ch {
+				t.Log(im, val)
+			}
+		}(i)
 	}
-}
-
-func TestMapCheck(t *testing.T) {
-	m := NewMap(time.Second*20, 0)
-
-	m.Set("key", 10)
 
-	log.Println(m.GetCheck("key", func(key, value interface{}, exists bool) (rKey, rVal interface{}, needUpdate bool) {
-		log.Println("MCHECK", key, value, exists)
-		rVal = "Cool!!!"
-		rKey, needUpdate = "key1", true
-		return
-	}))
-
-	log.Println("===================")
-	log.Println(m.Get("key"))
-	log.Println(m.Get("key1"))
-
-	log.Println(m.GetCreateNew("key", func(key interface{}) (rKey, val interface{}, created bool) {
-		return "oooone", 1000, true
-	}))
-
-	/*
-		// test cleaner
-			for {
-				log.Println("enter")
-				m.GetCheck("key", func(key, value interface{}, exists bool) (rKey, rVal interface{}, needUpdate bool) {
-					log.Println("Program", key, value, exists)
-					if exists {
-						needUpdate = false
-					}
-					rKey = key
-					rVal = 100
-					needUpdate = true
-					return
-				})
-				time.Sleep(time.Second * 10)
-			}
-	*/
+	for i := 0; i < 10; i++ {
+		ch <- i
+		time.Sleep(time.Second * 2)
+	}
 }
 
-func TestMapEach(t *testing.T) {
-	m := NewMap(time.Second*5, 10)
-	m.SetMulti(map[interface{}]interface{}{
-		1: "one",
-		2: "two",
-		3: "three",
-	})
-
-	m.Each(func(key, val interface{}) bool {
-		log.Println(key, val)
-		return false
-	})
+func TestContext(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func() {
+		log.Println("OK")
+		<-ctx.Done()
+		log.Println("Context done")
+		//wg.Add(1)
+		go func() {
+			log.Println("ST")
+			<-ctx.Done()
+			log.Println("Context done 2")
+		}()
+	}()
+	time.Sleep(time.Second * 2)
+	cancel()
+	wg.Wait()
 }
 
-func TestKeys(t *testing.T) {
-	m := NewMap(time.Second*5, 20)
-	m.SetMulti(map[interface{}]interface{}{
-		"one": 1,
-		"two": 2,
-	})
-	log.Println(m.Keys())
-	m.Clear()
-	log.Println(m.Keys())
-
+func TestCacheMap(t *testing.T) {
+	cm := NewCacheMap(context.Background(), 10, LiveInfinite)
+	for i := 0; i < 10; i++ {
+		cm.Set(i, i)
+		t.Log(cm)
+		time.Sleep(time.Second)
+	}
+	ko := cm.keysOlder(3)
+	t.Log(ko)
 }

+ 103 - 0
cache/z_test.go.tmp

@@ -0,0 +1,103 @@
+package cache
+
+import (
+	"log"
+	"testing"
+	"time"
+)
+
+func TestMap(t *testing.T) {
+	m := NewMap(time.Second*5, 10)
+
+	m.Set("key", 10)
+
+	log.Println(m.Get("key"))
+	m.Delete("key")
+	log.Println(m.Get("key"))
+	log.Println(m.Get("key1"))
+
+	go func() {
+		for e := range m.CleanEvent() {
+			log.Println("CLEANED", e)
+		}
+	}()
+
+	for i := 0; i < 5; i++ {
+		time.Sleep(time.Second * 10)
+		m.Set("key", "oneee")
+
+	}
+}
+
+func TestMapCheck(t *testing.T) {
+	m := NewMap(time.Second*20, 0)
+
+	m.Set("key", 10)
+
+	log.Println(m.GetCheck("key", func(key, value interface{}, exists bool) (rKey, rVal interface{}, needUpdate bool) {
+		log.Println("MCHECK", key, value, exists)
+		rVal = "Cool!!!"
+		rKey, needUpdate = "key1", true
+		return
+	}))
+
+	log.Println("===================")
+	log.Println(m.Get("key"))
+	log.Println(m.Get("key1"))
+
+	log.Println(m.GetCreateNew("key", func(key interface{}) (rKey, val interface{}, created bool) {
+		return "oooone", 1000, true
+	}))
+
+	/*
+		// test cleaner
+			for {
+				log.Println("enter")
+				m.GetCheck("key", func(key, value interface{}, exists bool) (rKey, rVal interface{}, needUpdate bool) {
+					log.Println("Program", key, value, exists)
+					if exists {
+						needUpdate = false
+					}
+					rKey = key
+					rVal = 100
+					needUpdate = true
+					return
+				})
+				time.Sleep(time.Second * 10)
+			}
+	*/
+}
+
+func TestMapEach(t *testing.T) {
+	m := NewMap(time.Second*5, 10)
+	m.SetMulti(map[interface{}]interface{}{
+		1: "one",
+		2: "two",
+		3: "three",
+	})
+
+	m.Each(func(key, val interface{}) bool {
+		log.Println(key, val)
+		return false
+	})
+}
+
+func TestKeys(t *testing.T) {
+	m := NewMap(time.Second*5, 20)
+	m.SetMulti(map[interface{}]interface{}{
+		"one": 1,
+		"two": 2,
+	})
+	log.Println(m.Keys())
+	m.Clear()
+	log.Println(m.Keys())
+}
+
+func TestCleaner(t *testing.T) {
+	m := NewMap(time.Second*5, 20)
+	m.SetMulti(map[interface{}]interface{}{
+		"one": 1,
+		"two": 2,
+	})
+	time.Sleep(time.Second * 60)
+}