| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 | 
							- /*
 
-  * Public Domain Software
 
-  *
 
-  * I (Matthias Ladkau) am the author of the source code in this file.
 
-  * I have placed the source code in this file in the public domain.
 
-  *
 
-  * For further information see: http://creativecommons.org/publicdomain/zero/1.0/
 
-  */
 
- package datautil
 
- import (
 
- 	"bytes"
 
- 	"fmt"
 
- 	"math"
 
- 	"sort"
 
- 	"sync"
 
- 	"time"
 
- )
 
- /*
 
- MapCache is a map based cache object storing string->interface{}. It is possible
 
- to specify a maximum size, which when reached causes the oldest entries to be
 
- removed. It is also possible to set an expiry time for values. Values which are
 
- old are purged on the next access to the object.
 
- */
 
- type MapCache struct {
 
- 	data    map[string]interface{} // Data for the cache
 
- 	ts      map[string]int64       // Timestamps for values
 
- 	size    uint64                 // Size of the cache
 
- 	maxsize uint64                 // Max size of the cache
 
- 	maxage  int64                  // Max age of the cache
 
- 	mutex   *sync.RWMutex          // Mutex to protect atomic map operations
 
- }
 
- /*
 
- NewMapCache creates a new MapCache object. The calling function can specify
 
- the maximum size and the maximum age in seconds for entries. A value of 0
 
- means no size constraint and no age constraint.
 
- */
 
- func NewMapCache(maxsize uint64, maxage int64) *MapCache {
 
- 	return &MapCache{make(map[string]interface{}), make(map[string]int64),
 
- 		0, maxsize, maxage, &sync.RWMutex{}}
 
- }
 
- /*
 
- Clear removes all entries.
 
- */
 
- func (mc *MapCache) Clear() {
 
- 	// Take writer lock
 
- 	mc.mutex.Lock()
 
- 	defer mc.mutex.Unlock()
 
- 	mc.data = make(map[string]interface{})
 
- 	mc.ts = make(map[string]int64)
 
- 	mc.size = 0
 
- }
 
- /*
 
- Size returns the current size of the MapCache.
 
- */
 
- func (mc *MapCache) Size() uint64 {
 
- 	return mc.size
 
- }
 
- /*
 
- Put stores an item in the MapCache.
 
- */
 
- func (mc *MapCache) Put(k string, v interface{}) {
 
- 	// Do cache maintenance
 
- 	oldest := mc.maintainCache()
 
- 	// Take writer lock
 
- 	mc.mutex.Lock()
 
- 	defer mc.mutex.Unlock()
 
- 	// Check if the entry is a new entry
 
- 	if _, exists := mc.data[k]; !exists {
 
- 		// If the list is full remove the oldest item otherwise increase the size
 
- 		if mc.maxsize != 0 && mc.size == mc.maxsize {
 
- 			delete(mc.data, oldest)
 
- 			delete(mc.ts, oldest)
 
- 		} else {
 
- 			mc.size++
 
- 		}
 
- 	}
 
- 	// Do the actual map operation
 
- 	mc.data[k] = v
 
- 	mc.ts[k] = time.Now().Unix()
 
- }
 
- /*
 
- Remove removes an item in the MapCache.
 
- */
 
- func (mc *MapCache) Remove(k string) bool {
 
- 	// Do cache maintenance
 
- 	mc.maintainCache()
 
- 	// Take writer lock
 
- 	mc.mutex.Lock()
 
- 	defer mc.mutex.Unlock()
 
- 	// Check if the entry exists
 
- 	_, exists := mc.data[k]
 
- 	if exists {
 
- 		// Do the actual map operation
 
- 		delete(mc.data, k)
 
- 		delete(mc.ts, k)
 
- 		mc.size--
 
- 	}
 
- 	return exists
 
- }
 
- /*
 
- Get retrieves an item from the MapCache.
 
- */
 
- func (mc *MapCache) Get(k string) (interface{}, bool) {
 
- 	// Do cache maintenance
 
- 	mc.maintainCache()
 
- 	// Take reader lock
 
- 	mc.mutex.RLock()
 
- 	defer mc.mutex.RUnlock()
 
- 	// Do the actual map operation
 
- 	v, ok := mc.data[k]
 
- 	return v, ok
 
- }
 
- /*
 
- GetAll retrieves all items from the MapCache.
 
- */
 
- func (mc *MapCache) GetAll() map[string]interface{} {
 
- 	// Do cache maintenance
 
- 	mc.maintainCache()
 
- 	// Take reader lock
 
- 	mc.mutex.RLock()
 
- 	defer mc.mutex.RUnlock()
 
- 	// Create return map
 
- 	cp := make(map[string]interface{})
 
- 	for k, v := range mc.data {
 
- 		cp[k] = v
 
- 	}
 
- 	return cp
 
- }
 
- /*
 
- String returns a string representation of this MapCache.
 
- */
 
- func (mc *MapCache) String() string {
 
- 	mc.mutex.RLock()
 
- 	defer mc.mutex.RUnlock()
 
- 	// Sort keys before printing the map
 
- 	var keys []string
 
- 	for k := range mc.data {
 
- 		keys = append(keys, k)
 
- 	}
 
- 	sort.Sort(sort.StringSlice(keys))
 
- 	buf := &bytes.Buffer{}
 
- 	for _, k := range keys {
 
- 		buf.WriteString(fmt.Sprint(k, ":", mc.data[k], "\n"))
 
- 	}
 
- 	return buf.String()
 
- }
 
- /*
 
- maintainCache removes expired items and returns the oldest entry.
 
- */
 
- func (mc *MapCache) maintainCache() string {
 
- 	mc.mutex.RLock()
 
- 	oldestTS := int64(math.MaxInt64)
 
- 	oldestK := ""
 
- 	now := time.Now().Unix()
 
- 	for k, v := range mc.ts {
 
- 		// Check if the entry has expired
 
- 		if mc.maxage != 0 && now-v > mc.maxage {
 
- 			// Remove entry if it has expired
 
- 			mc.mutex.RUnlock()
 
- 			mc.mutex.Lock()
 
- 			delete(mc.data, k)
 
- 			delete(mc.ts, k)
 
- 			mc.size--
 
- 			mc.mutex.Unlock()
 
- 			mc.mutex.RLock()
 
- 		}
 
- 		// Gather oldest entry
 
- 		if v < oldestTS {
 
- 			oldestTS = v
 
- 			oldestK = k
 
- 		}
 
- 	}
 
- 	mc.mutex.RUnlock()
 
- 	return oldestK
 
- }
 
 
  |