func (fm *lruFileMap) LoadForRead(name string, f func(string, FileEntry)) bool {
	e, ok := fm.syncGet(name)
	if !ok {
		return false
	}
	e.RLock()
	defer e.RUnlock()
	if ne, ok := fm.syncGetAndTouch(name); !ok {
		return false
	} else if ne != e {
		return false
	}
	f(name, e.fe)
	return true
}
LoadForRead looks up the value of key k and executes f under the protection
of RLock.
While f executes, it is guaranteed that k will not be deleted from the map.
Returns false if k was not found.
It updates last access time.
package base
import (
	"container/list"
	"os"
	"sync"
	"time"
	"github.com/uber/makisu/lib/log"
	"github.com/uber/makisu/lib/storage/metadata"
	"github.com/andres-erbsen/clock"
)
type FileMap interface {
	Contains(name string) bool
	TryStore(name string, entry FileEntry, f func(string, FileEntry) bool) bool
	LoadForWrite(name string, f func(string, FileEntry)) bool
	LoadForRead(name string, f func(string, FileEntry)) bool
	LoadForPeek(name string, f func(string, FileEntry)) bool
	Delete(name string, f func(string, FileEntry) bool) bool
}
var _ FileMap = (*lruFileMap)(nil)
type fileEntryWithAccessTime struct {
	sync.RWMutex
	fe FileEntry
	lastAccessTime time.Time
}
type lruFileMap struct {
	sync.Mutex
	size int
	clk clock.Clock
	timeResolution time.Duration
	queue          *list.List
	elements       map[string]*list.Element
}
func NewLRUFileMap(size int, clk clock.Clock) FileMap {
	m := &lruFileMap{
		size:           size,
		clk:            clk,
		timeResolution: time.Minute * 5,
		queue:          list.New(),
		elements:       make(map[string]*list.Element),
	}
	return m
}
func NewLATFileMap(clk clock.Clock) FileMap {
	m := &lruFileMap{
		size:           0,  
		clk:            clk,
		timeResolution: time.Minute * 5,
		queue:          list.New(),
		elements:       make(map[string]*list.Element),
	}
	return m
}
func (fm *lruFileMap) get(name string) (*fileEntryWithAccessTime, bool) {
	if element, ok := fm.elements[name]; ok {
		fm.queue.MoveToFront(element)
		return element.Value.(*fileEntryWithAccessTime), ok
	}
	return nil, false
}
func (fm *lruFileMap) syncGet(name string) (*fileEntryWithAccessTime, bool) {
	fm.Lock()
	defer fm.Unlock()
	return fm.get(name)
}
func (fm *lruFileMap) syncGetAndTouch(name string) (*fileEntryWithAccessTime, bool) {
	fm.Lock()
	defer fm.Unlock()
	e, ok := fm.get(name)
	if !ok {
		return nil, false
	}
	t := fm.clk.Now()
	if t.Sub(e.lastAccessTime) >= fm.timeResolution {
		e.lastAccessTime = t
		e.fe.SetMetadata(metadata.NewLastAccessTime(t))
	}
	return e, true
}
func (fm *lruFileMap) add(name string, e *fileEntryWithAccessTime) bool {
	if _, ok := fm.elements[name]; !ok {
		element := fm.queue.PushFront(e)
		fm.elements[name] = element
		return true
	}
	return false
}
func (fm *lruFileMap) getOldest() (*fileEntryWithAccessTime, bool) {
	if e := fm.queue.Back(); e != nil {
		return e.Value.(*fileEntryWithAccessTime), true
	}
	return nil, false
}
func (fm *lruFileMap) remove(name string) (*fileEntryWithAccessTime, bool) {
	if e, ok := fm.elements[name]; ok {
		delete(fm.elements, name)
		fm.queue.Remove(e)
		return e.Value.(*fileEntryWithAccessTime), ok
	}
	return nil, false
}
func (fm *lruFileMap) syncRemove(name string) (*fileEntryWithAccessTime, bool) {
	fm.Lock()
	defer fm.Unlock()
	return fm.remove(name)
}
func (fm *lruFileMap) syncRemoveOldestIfNeeded() (e *fileEntryWithAccessTime, ok bool) {
	fm.Lock()
	if fm.size <= 0 || fm.queue.Len() <= fm.size {
		defer fm.Unlock()
		return nil, false
	}
	e, ok = fm.getOldest()
	if !ok {
		defer fm.Unlock()
		return nil, false
	}
	fm.Unlock()
	e.Lock()
	defer e.Unlock()
	name := e.fe.GetName()
	if ne, ok := fm.syncGet(name); !ok {
		return nil, false
	} else if ne != e {
		return nil, false
	}
	if err := e.fe.Delete(); err != nil {
		log.With("name", e.fe.GetName()).Errorf("Error deleting evicted entry: %s", err)
	}
	fm.syncRemove(name)
	return e, true
}
func (fm *lruFileMap) Contains(name string) bool {
	fm.Lock()
	defer fm.Unlock()
	_, ok := fm.elements[name]
	return ok
}
func (fm *lruFileMap) TryStore(name string, entry FileEntry, f func(string, FileEntry) bool) bool {
	e := &fileEntryWithAccessTime{
		fe: entry,
	}
	defer fm.syncRemoveOldestIfNeeded()
	e.Lock()
	defer e.Unlock()
	fm.Lock()
	if _, ok := fm.get(name); ok {
		defer fm.Unlock()
		t := fm.clk.Now()
		if t.Sub(e.lastAccessTime) >= fm.timeResolution {
			e.lastAccessTime = t
			e.fe.SetMetadata(metadata.NewLastAccessTime(t))
		}
		return false
	}
	fm.add(name, e)
	lat := metadata.NewLastAccessTime(fm.clk.Now())
	if err := e.fe.GetMetadata(lat); err != nil {
		if !os.IsNotExist(err) {
			log.With("name", e.fe.GetName()).Errorf("Error reading LAT: %s", err)
		}
		if _, err := e.fe.SetMetadata(lat); err != nil {
			log.With("name", e.fe.GetName()).Errorf("Error setting LAT: %s", err)
		}
	}
	e.lastAccessTime = lat.Time
	fm.Unlock()
	if !f(name, e.fe) {
		fm.syncRemove(name)
		return false
	}
	return true
}
func (fm *lruFileMap) LoadForWrite(name string, f func(string, FileEntry)) bool {
	e, ok := fm.syncGet(name)
	if !ok {
		return false
	}
	e.Lock()
	defer e.Unlock()
	if ne, ok := fm.syncGetAndTouch(name); !ok {
		return false
	} else if ne != e {
		return false
	}
	f(name, e.fe)
	return true
}