btcd/mruinvmap.go
Dave Collins 121f7a47d4 Add block inventory relay.
This commit adds support for relaying blocks between peers.  It keeps
track of inventory that has either already been advertised to remote peers
or advertised by remote peers using a size-limited most recently used
cache.  This helps avoid relaying inventory the peer already knows as
much as possible while not allowing rogue peers to eat up arbitrary
amounts of memory with bogus inventory.
2013-09-11 20:14:13 -05:00

83 lines
2.2 KiB
Go

// 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
}