// Copyright (c) 2013 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package main import ( "fmt" "github.com/conformal/btcwire" "time" ) // MruInventoryMap provides a map that is limited to a maximum number of items // with eviction for the oldest entry when the limit is exceeded. type MruInventoryMap struct { invMap map[btcwire.InvVect]int64 // Use int64 for time for less mem. limit uint } // String returns the map as a human-readable string. func (m MruInventoryMap) String() string { return fmt.Sprintf("<%d>%v", m.limit, m.invMap) } // Exists returns whether or not the passed inventory item is in the map. func (m *MruInventoryMap) Exists(iv *btcwire.InvVect) bool { if _, exists := m.invMap[*iv]; exists { return true } return false } // Add adds the passed inventory to the map and handles eviction of the oldest // item if adding the new item would exceed the max limit. func (m *MruInventoryMap) Add(iv *btcwire.InvVect) { // When the limit is zero, nothing can be added to the map, so just // return if m.limit == 0 { return } // When the entry already exists update its last seen time. if m.Exists(iv) { m.invMap[*iv] = time.Now().Unix() return } // Evict the oldest entry if the the new entry would exceed the size // limit for the map. if uint(len(m.invMap))+1 > m.limit { var oldestEntry btcwire.InvVect var oldestTime int64 for iv, lastUpdated := range m.invMap { if oldestTime == 0 || lastUpdated < oldestTime { oldestEntry = iv oldestTime = lastUpdated } } m.Delete(&oldestEntry) } m.invMap[*iv] = time.Now().Unix() return } // Delete deletes the passed inventory item from the map (if it exists). func (m *MruInventoryMap) Delete(iv *btcwire.InvVect) { delete(m.invMap, *iv) } // NewMruInventoryMap returns a new inventory map that is limited to the number // of entries specified by limit. When the number of entries exceeds the limit, // the oldest (least recently used) entry will be removed to make room for the // new entry.. func NewMruInventoryMap(limit uint) *MruInventoryMap { m := MruInventoryMap{ invMap: make(map[btcwire.InvVect]int64), limit: limit, } return &m }