Mercurial > gemma
view pkg/octree/cache.go @ 955:920fba3f593f
chore: upgrading packages to latest
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Tue, 16 Oct 2018 11:13:06 +0200 |
parents | 41c8dc61f38f |
children | a244b18cb916 |
line wrap: on
line source
package octree import ( "context" "database/sql" "sync" "time" ) type ( cacheKey struct { date time.Time bottleneck string } cacheEntry struct { checksum string tree *Tree access time.Time } OctreeCache struct { sync.Mutex entries map[cacheKey]*cacheEntry } ) const ( cleanupCacheSleep = 6 * time.Minute maxCacheAge = 5 * time.Minute maxCacheEntries = 4 ) const ( fetchOctreeSQL = ` SELECT checksum, octree_index FROM waterway.octrees ot JOIN waterway.sounding_results sr ON ot.sounding_result_id = sr.id WHERE sr.bottleneck_id = $1 AND sr.date_info = $2::date ` checkOctreeSQL = ` SELECT CASE WHEN checksum = $3 THEN NULL ELSE ot.octree_index END FROM waterway.octrees ot JOIN waterway.sounding_results sr ON ot.sounding_result_id = sr.id WHERE sr.bottleneck_id = $1 AND sr.date_info = $2::date ` ) var Cache = OctreeCache{ entries: map[cacheKey]*cacheEntry{}, } func init() { go Cache.background() } func (oc *OctreeCache) background() { for { time.Sleep(cleanupCacheSleep) oc.cleanup() } } func (oc *OctreeCache) cleanup() { oc.Lock() defer oc.Unlock() good := time.Now().Add(-maxCacheAge) for k, v := range oc.entries { if v.access.Before(good) { delete(oc.entries, k) } } } func (oc *OctreeCache) Get( bottleneck string, date time.Time, conn *sql.Conn, ctx context.Context, ) (*Tree, error) { oc.Lock() defer oc.Unlock() key := cacheKey{date, bottleneck} entry := oc.entries[key] var data []byte var checksum string if entry == nil { // fetch from database err := conn.QueryRowContext( ctx, fetchOctreeSQL, bottleneck, date).Scan(&checksum, &data) switch { case err == sql.ErrNoRows: return nil, nil case err != nil: return nil, err } } else { // check if we are not outdated. err := conn.QueryRowContext( ctx, checkOctreeSQL, bottleneck, date, entry.checksum).Scan(&data) switch { case err == sql.ErrNoRows: return nil, nil case err != nil: return nil, err } if data == nil { // we are still current entry.access = time.Now() return entry.tree, nil } } tree, err := Deserialize(data) if err != nil { return nil, err } now := time.Now() if entry != nil { entry.tree = tree entry.access = now return tree, nil } for len(oc.entries) >= maxCacheEntries { // Evict the entry that is accessed the longest time ago. var oldestKey cacheKey oldest := now for k, v := range oc.entries { if v.access.Before(oldest) { oldest = v.access oldestKey = k } } delete(oc.entries, oldestKey) } oc.entries[key] = &cacheEntry{ checksum: checksum, tree: tree, access: now, } return tree, nil }