package mapblockaccessor import ( "mapserver/eventbus" "mapserver/types" "sync" "github.com/minetest-go/mapparser" cache "github.com/patrickmn/go-cache" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" ) var lock = &sync.RWMutex{} func (a *MapBlockAccessor) GetMapBlock(pos *types.MapBlockCoords) (*mapparser.MapBlock, error) { cache_enabled := a.maxcount > 0 key := getKey(pos) if cache_enabled { //maintenance cacheBlocks.Set(float64(a.blockcache.ItemCount())) if a.blockcache.ItemCount() > a.maxcount { //flush cache fields := logrus.Fields{ "cached items": a.blockcache.ItemCount(), "maxcount": a.maxcount, } logrus.WithFields(fields).Debug("Flushing cache") a.blockcache.Flush() } //read section lock.RLock() cachedblock, found := a.blockcache.Get(key) if found { defer lock.RUnlock() getCacheHitCount.Inc() if cachedblock == nil { return nil, nil } else { return cachedblock.(*mapparser.MapBlock), nil } } //end read lock.RUnlock() timer := prometheus.NewTimer(dbGetDuration) defer timer.ObserveDuration() //write section lock.Lock() defer lock.Unlock() //try read cachedblock, found = a.blockcache.Get(key) if found { getCacheHitCount.Inc() if cachedblock == nil { return nil, nil } else { return cachedblock.(*mapparser.MapBlock), nil } } } block, err := a.accessor.GetBlock(pos) if err != nil { return nil, err } if block == nil { //no mapblock here if cache_enabled { cacheBlockCount.Inc() a.blockcache.Set(key, nil, cache.DefaultExpiration) } return nil, nil } if cache_enabled { getCacheMissCount.Inc() } mapblock, err := mapparser.Parse(block.Data) if err != nil { return nil, err } a.Eventbus.Emit(eventbus.MAPBLOCK_RENDERED, types.NewParsedMapblock(mapblock, pos)) if cache_enabled { cacheBlockCount.Inc() a.blockcache.Set(key, mapblock, cache.DefaultExpiration) } return mapblock, nil }