Example #1
0
File: lru.go Project: na--/nedomi
// 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
}
Example #2
0
File: lru.go Project: na--/nedomi
// 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
}
Example #3
0
File: lru.go Project: na--/nedomi
// 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
}