peer: rename noncemap to noncecache

It's a cache, but it is implemented with a map.
This commit is contained in:
Andrew Chiw 2018-01-20 19:22:21 +01:00 committed by Dave Collins
parent 70dd37e644
commit b9225dcb66
3 changed files with 57 additions and 57 deletions

View File

@ -12,27 +12,27 @@ import (
"sync"
)
// lruNonceMap provides a concurrency safe map that is limited to a maximum
// lruNonceCache provides a concurrency safe cache that is limited to a maximum
// number of items with eviction for the oldest entry when the limit is
// exceeded.
type lruNonceMap struct {
mtx sync.Mutex
nonceMap map[uint64]*list.Element // nearly O(1) lookups
nonceList *list.List // O(1) insert, update, delete
limit uint
type lruNonceCache struct {
mtx sync.Mutex
nonceCache map[uint64]*list.Element // nearly O(1) lookups
nonceList *list.List // O(1) insert, update, delete
limit uint
}
// String returns the map as a human-readable string.
// String returns the cache as a human-readable string.
//
// This function is safe for concurrent access.
func (m *lruNonceMap) String() string {
func (m *lruNonceCache) String() string {
m.mtx.Lock()
defer m.mtx.Unlock()
lastEntryNum := len(m.nonceMap) - 1
lastEntryNum := len(m.nonceCache) - 1
curEntry := 0
buf := bytes.NewBufferString("[")
for nonce := range m.nonceMap {
for nonce := range m.nonceCache {
buf.WriteString(fmt.Sprintf("%d", nonce))
if curEntry < lastEntryNum {
buf.WriteString(", ")
@ -44,27 +44,27 @@ func (m *lruNonceMap) String() string {
return fmt.Sprintf("<%d>%s", m.limit, buf.String())
}
// Exists returns whether or not the passed nonce is in the map.
// Exists returns whether or not the passed nonce is in the cache.
//
// This function is safe for concurrent access.
func (m *lruNonceMap) Exists(nonce uint64) bool {
func (m *lruNonceCache) Exists(nonce uint64) bool {
m.mtx.Lock()
_, exists := m.nonceMap[nonce]
_, exists := m.nonceCache[nonce]
m.mtx.Unlock()
return exists
}
// Add adds the passed nonce to the map and handles eviction of the oldest item
// Add adds the passed nonce to the cache and handles eviction of the oldest item
// if adding the new item would exceed the max limit. Adding an existing item
// makes it the most recently used item.
//
// This function is safe for concurrent access.
func (m *lruNonceMap) Add(nonce uint64) {
func (m *lruNonceCache) Add(nonce uint64) {
m.mtx.Lock()
defer m.mtx.Unlock()
// When the limit is zero, nothing can be added to the map, so just
// When the limit is zero, nothing can be added to the cache, so just
// return.
if m.limit == 0 {
return
@ -72,55 +72,55 @@ func (m *lruNonceMap) Add(nonce uint64) {
// When the entry already exists move it to the front of the list
// thereby marking it most recently used.
if node, exists := m.nonceMap[nonce]; exists {
if node, exists := m.nonceCache[nonce]; exists {
m.nonceList.MoveToFront(node)
return
}
// Evict the least recently used entry (back of the list) if the the new
// entry would exceed the size limit for the map. Also reuse the list
// entry would exceed the size limit for the cache. Also reuse the list
// node so a new one doesn't have to be allocated.
if uint(len(m.nonceMap))+1 > m.limit {
if uint(len(m.nonceCache))+1 > m.limit {
node := m.nonceList.Back()
lru := node.Value.(uint64)
// Evict least recently used item.
delete(m.nonceMap, lru)
delete(m.nonceCache, lru)
// Reuse the list node of the item that was just evicted for the
// new item.
node.Value = nonce
m.nonceList.MoveToFront(node)
m.nonceMap[nonce] = node
m.nonceCache[nonce] = node
return
}
// The limit hasn't been reached yet, so just add the new item.
node := m.nonceList.PushFront(nonce)
m.nonceMap[nonce] = node
m.nonceCache[nonce] = node
}
// Delete deletes the passed nonce from the map (if it exists).
// Delete deletes the passed nonce from the cache (if it exists).
//
// This function is safe for concurrent access.
func (m *lruNonceMap) Delete(nonce uint64) {
func (m *lruNonceCache) Delete(nonce uint64) {
m.mtx.Lock()
if node, exists := m.nonceMap[nonce]; exists {
if node, exists := m.nonceCache[nonce]; exists {
m.nonceList.Remove(node)
delete(m.nonceMap, nonce)
delete(m.nonceCache, nonce)
}
m.mtx.Unlock()
}
// newLruNonceMap returns a new nonce map that is limited to the number of
// newLruNonceCache returns a new nonce cache 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 newLruNonceMap(limit uint) *lruNonceMap {
m := lruNonceMap{
nonceMap: make(map[uint64]*list.Element),
nonceList: list.New(),
limit: limit,
func newLruNonceCache(limit uint) *lruNonceCache {
m := lruNonceCache{
nonceCache: make(map[uint64]*list.Element),
nonceList: list.New(),
limit: limit,
}
return &m
}

View File

@ -10,10 +10,10 @@ import (
"testing"
)
// TestLruNonceMap ensures the lruNonceMap behaves as expected including
// TestLruNonceCache ensures the lruNonceCache behaves as expected including
// limiting, eviction of least-recently used entries, specific entry removal,
// and existence tests.
func TestLruNonceMap(t *testing.T) {
func TestLruNonceCache(t *testing.T) {
// Create a bunch of fake nonces to use in testing the lru nonce code.
numNonces := 10
nonces := make([]uint64, 0, numNonces)
@ -35,18 +35,18 @@ func TestLruNonceMap(t *testing.T) {
testLoop:
for i, test := range tests {
// Create a new lru nonce map limited by the specified test
// Create a new lru nonce cache limited by the specified test
// limit and add all of the test nonces. This will cause
// evicition since there are more test nonces than the limits.
lruNonceMap := newLruNonceMap(uint(test.limit))
lruNonceCache := newLruNonceCache(uint(test.limit))
for j := 0; j < numNonces; j++ {
lruNonceMap.Add(nonces[j])
lruNonceCache.Add(nonces[j])
}
// Ensure the limited number of most recent entries in the list
// exist.
for j := numNonces - test.limit; j < numNonces; j++ {
if !lruNonceMap.Exists(nonces[j]) {
if !lruNonceCache.Exists(nonces[j]) {
t.Errorf("Exists #%d (%s) entry %d does not "+
"exist", i, test.name, nonces[j])
continue testLoop
@ -56,7 +56,7 @@ testLoop:
// Ensure the entries before the limited number of most recent
// entries in the list do not exist.
for j := 0; j < numNonces-test.limit; j++ {
if lruNonceMap.Exists(nonces[j]) {
if lruNonceCache.Exists(nonces[j]) {
t.Errorf("Exists #%d (%s) entry %d exists", i,
test.name, nonces[j])
continue testLoop
@ -72,13 +72,13 @@ testLoop:
// This check needs at least 2 entries.
if test.limit > 1 {
origLruIndex := numNonces - test.limit
lruNonceMap.Add(nonces[origLruIndex])
lruNonceCache.Add(nonces[origLruIndex])
lruNonceMap.Add(uint64(numNonces) + 1)
lruNonceCache.Add(uint64(numNonces) + 1)
// Ensure the original lru entry still exists since it
// was updated and should've have become the lru entry.
if !lruNonceMap.Exists(nonces[origLruIndex]) {
if !lruNonceCache.Exists(nonces[origLruIndex]) {
t.Errorf("LRU #%d (%s) entry %d does not exist",
i, test.name, nonces[origLruIndex])
continue testLoop
@ -87,7 +87,7 @@ testLoop:
// Ensure the entry that should've become the new lru
// entry was evicted.
newLruIndex := origLruIndex + 1
if lruNonceMap.Exists(nonces[newLruIndex]) {
if lruNonceCache.Exists(nonces[newLruIndex]) {
t.Errorf("LRU #%d (%s) entry %d exists", i,
test.name, nonces[newLruIndex])
continue testLoop
@ -95,10 +95,10 @@ testLoop:
}
// Delete all of the entries in the list, including those that
// don't exist in the map, and ensure they no longer exist.
// don't exist in the cache, and ensure they no longer exist.
for j := 0; j < numNonces; j++ {
lruNonceMap.Delete(nonces[j])
if lruNonceMap.Exists(nonces[j]) {
lruNonceCache.Delete(nonces[j])
if lruNonceCache.Exists(nonces[j]) {
t.Errorf("Delete #%d (%s) entry %d exists", i,
test.name, nonces[j])
continue testLoop
@ -107,24 +107,24 @@ testLoop:
}
}
// TestLruNonceMapStringer tests the stringized output for the lruNonceMap type.
func TestLruNonceMapStringer(t *testing.T) {
// TestLruNonceCacheStringer tests the stringized output for the lruNonceCache type.
func TestLruNonceCacheStringer(t *testing.T) {
// Create a couple of fake nonces to use in testing the lru nonce
// stringer code.
nonce1 := uint64(10)
nonce2 := uint64(20)
// Create new lru nonce map and add the nonces.
lruNonceMap := newLruNonceMap(uint(2))
lruNonceMap.Add(nonce1)
lruNonceMap.Add(nonce2)
// Create new lru nonce cache and add the nonces.
lruNonceCache := newLruNonceCache(uint(2))
lruNonceCache.Add(nonce1)
lruNonceCache.Add(nonce2)
// Ensure the stringer gives the expected result. Since map iteration
// Ensure the stringer gives the expected result. Since cache iteration
// is not ordered, either entry could be first, so account for both
// cases.
wantStr1 := fmt.Sprintf("<%d>[%d, %d]", 2, nonce1, nonce2)
wantStr2 := fmt.Sprintf("<%d>[%d, %d]", 2, nonce2, nonce1)
gotStr := lruNonceMap.String()
gotStr := lruNonceCache.String()
if gotStr != wantStr1 && gotStr != wantStr2 {
t.Fatalf("unexpected string representation - got %q, want %q "+
"or %q", gotStr, wantStr1, wantStr2)
@ -146,8 +146,8 @@ func BenchmarkLruNonceList(b *testing.B) {
// Benchmark the add plus evicition code.
limit := 20000
lruNonceMap := newLruNonceMap(uint(limit))
lruNonceCache := newLruNonceCache(uint(limit))
for i := 0; i < b.N; i++ {
lruNonceMap.Add(nonces[i%numNonces])
lruNonceCache.Add(nonces[i%numNonces])
}
}

View File

@ -78,7 +78,7 @@ var (
// sentNonces houses the unique nonces that are generated when pushing
// version messages that are used to detect self connections.
sentNonces = newLruNonceMap(50)
sentNonces = newLruNonceCache(50)
// allowSelfConns is only used to allow the tests to bypass the self
// connection detecting and disconnect logic since they intentionally