// Lookup implements part of types.CacheAlgorithm interface func (tc *TieredLRUCache) Lookup(oi *types.ObjectIndex) bool { tc.mutex.Lock() defer tc.mutex.Unlock() tc.requests++ _, ok := tc.lookup[oi.Hash()] if ok { tc.hits++ } return ok }
// AddObject implements part of types.CacheAlgorithm interface func (tc *TieredLRUCache) AddObject(oi *types.ObjectIndex) error { tc.mutex.Lock() defer tc.mutex.Unlock() if _, ok := tc.lookup[oi.Hash()]; ok { return types.ErrAlreadyInCache } lastList := tc.tiers[cacheTiers-1] if lastList.Len() >= tc.tierListSize { tc.freeSpaceInLastList() } le := &Element{ ListTier: cacheTiers - 1, ListElem: lastList.PushFront(*oi), } tc.logger.Logf("Storing %s in cache", oi) tc.lookup[oi.Hash()] = le return nil }
// PromoteObject implements part of types.CacheAlgorithm interface. // It will reorder the linked lists so that this object index will be promoted in // rank. func (tc *TieredLRUCache) PromoteObject(oi *types.ObjectIndex) { tc.mutex.Lock() defer tc.mutex.Unlock() if debug { tc.checkTiers() defer tc.checkTiers() } lruEl, ok := tc.lookup[oi.Hash()] if !ok { // Unlocking the mutex in order to prevent a deadlock while calling // AddObject which tries to lock it too. tc.mutex.Unlock() // This object is not in the cache yet. So we add it. if err := tc.AddObject(oi); err != nil { tc.logger.Errorf("Adding object in cache failed. Object: %v\n%s", oi, err) } // The mutex must be locked because of the deferred Unlock tc.mutex.Lock() return } currentTier := tc.tiers[lruEl.ListTier] if lruEl.ListTier == 0 { // This object is in the uppermost tier. It has nowhere to be promoted to // but the front of the tier. if currentTier.Front() == lruEl.ListElem { return } currentTier.MoveToFront(lruEl.ListElem) return } upperTier := tc.tiers[lruEl.ListTier-1] defer func() { currentTier.Remove(lruEl.ListElem) lruEl.ListElem = upperTier.PushFront(*oi) lruEl.ListTier-- }() if upperTier.Len() < tc.tierListSize { // The upper tier is not yet full. So we can push our object at the end // of it without needing to remove anything from it. return } // The upper tier is full. An element from it will be swapped with the one // currently promted. upperListLastOi := upperTier.Remove(upperTier.Back()).(types.ObjectIndex) upperListLastLruEl, ok := tc.lookup[upperListLastOi.Hash()] if !ok { tc.logger.Error("ERROR! Cache incosistency. Element from the linked list " + "was not found in the lookup table") } upperListLastLruEl.ListElem = currentTier.PushFront(upperListLastOi) upperListLastLruEl.ListTier = lruEl.ListTier }