2015-08-29 22:35:28 +02:00
|
|
|
// Copyright (c) 2013-2015 The btcsuite developers
|
2014-01-01 17:16:15 +01:00
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2013-10-26 08:57:00 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/rand"
|
2015-08-29 22:35:28 +02:00
|
|
|
"fmt"
|
2013-10-26 08:57:00 +02:00
|
|
|
"testing"
|
2014-07-02 15:50:08 +02:00
|
|
|
|
2015-02-05 22:16:39 +01:00
|
|
|
"github.com/btcsuite/btcd/wire"
|
2013-10-26 08:57:00 +02:00
|
|
|
)
|
|
|
|
|
2015-08-29 22:35:28 +02:00
|
|
|
// TestMruInventoryMap ensures the MruInventoryMap behaves as expected including
|
|
|
|
// limiting, eviction of least-recently used entries, specific entry removal,
|
|
|
|
// and existence tests.
|
|
|
|
func TestMruInventoryMap(t *testing.T) {
|
|
|
|
// Create a bunch of fake inventory vectors to use in testing the mru
|
|
|
|
// inventory code.
|
|
|
|
numInvVects := 10
|
|
|
|
invVects := make([]*wire.InvVect, 0, numInvVects)
|
|
|
|
for i := 0; i < numInvVects; i++ {
|
|
|
|
hash := &wire.ShaHash{byte(i)}
|
|
|
|
iv := wire.NewInvVect(wire.InvTypeBlock, hash)
|
|
|
|
invVects = append(invVects, iv)
|
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
limit int
|
|
|
|
}{
|
|
|
|
{name: "limit 0", limit: 0},
|
|
|
|
{name: "limit 1", limit: 1},
|
|
|
|
{name: "limit 5", limit: 5},
|
|
|
|
{name: "limit 7", limit: 7},
|
|
|
|
{name: "limit one less than available", limit: numInvVects - 1},
|
|
|
|
{name: "limit all available", limit: numInvVects},
|
|
|
|
}
|
|
|
|
|
|
|
|
testLoop:
|
|
|
|
for i, test := range tests {
|
|
|
|
// Create a new mru inventory map limited by the specified test
|
|
|
|
// limit and add all of the test inventory vectors. This will
|
|
|
|
// cause evicition since there are more test inventory vectors
|
|
|
|
// than the limits.
|
|
|
|
mruInvMap := NewMruInventoryMap(uint(test.limit))
|
|
|
|
for j := 0; j < numInvVects; j++ {
|
|
|
|
mruInvMap.Add(invVects[j])
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the limited number of most recent entries in the
|
|
|
|
// inventory vector list exist.
|
|
|
|
for j := numInvVects - 1; j >= numInvVects-test.limit; j-- {
|
|
|
|
if !mruInvMap.Exists(invVects[j]) {
|
|
|
|
t.Errorf("Exists #%d (%s) entry %s does not "+
|
|
|
|
"exist", i, test.name, *invVects[j])
|
|
|
|
continue testLoop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the entries before the limited number of most recent
|
|
|
|
// entries in the inventory vector list do not exist.
|
|
|
|
for j := numInvVects - test.limit - 1; j >= 0; j-- {
|
|
|
|
if mruInvMap.Exists(invVects[j]) {
|
|
|
|
t.Errorf("Exists #%d (%s) entry %s exists", i,
|
|
|
|
test.name, *invVects[j])
|
|
|
|
continue testLoop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Readd the entry that should currently be the least-recently
|
|
|
|
// used entry so it becomes the most-recently used entry, then
|
|
|
|
// force an eviction by adding an entry that doesn't exist and
|
|
|
|
// ensure the evicted entry is the new least-recently used
|
|
|
|
// entry.
|
|
|
|
//
|
|
|
|
// This check needs at least 2 entries.
|
|
|
|
if test.limit > 1 {
|
|
|
|
origLruIndex := numInvVects - test.limit
|
|
|
|
mruInvMap.Add(invVects[origLruIndex])
|
|
|
|
|
|
|
|
iv := wire.NewInvVect(wire.InvTypeBlock,
|
|
|
|
&wire.ShaHash{0x00, 0x01})
|
|
|
|
mruInvMap.Add(iv)
|
|
|
|
|
|
|
|
// Ensure the original lru entry still exists since it
|
|
|
|
// was updated and should've have become the mru entry.
|
|
|
|
if !mruInvMap.Exists(invVects[origLruIndex]) {
|
|
|
|
t.Errorf("MRU #%d (%s) entry %s does not exist",
|
|
|
|
i, test.name, *invVects[origLruIndex])
|
|
|
|
continue testLoop
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the entry that should've become the new lru
|
|
|
|
// entry was evicted.
|
|
|
|
newLruIndex := origLruIndex + 1
|
|
|
|
if mruInvMap.Exists(invVects[newLruIndex]) {
|
|
|
|
t.Errorf("MRU #%d (%s) entry %s exists", i,
|
|
|
|
test.name, *invVects[newLruIndex])
|
|
|
|
continue testLoop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete all of the entries in the inventory vector list,
|
|
|
|
// including those that don't exist in the map, and ensure they
|
|
|
|
// no longer exist.
|
|
|
|
for j := 0; j < numInvVects; j++ {
|
|
|
|
mruInvMap.Delete(invVects[j])
|
|
|
|
if mruInvMap.Exists(invVects[j]) {
|
|
|
|
t.Errorf("Delete #%d (%s) entry %s exists", i,
|
|
|
|
test.name, *invVects[j])
|
|
|
|
continue testLoop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestMruInventoryMapStringer tests the stringized output for the
|
|
|
|
// MruInventoryMap type.
|
|
|
|
func TestMruInventoryMapStringer(t *testing.T) {
|
|
|
|
// Create a couple of fake inventory vectors to use in testing the mru
|
|
|
|
// inventory stringer code.
|
|
|
|
hash1 := &wire.ShaHash{0x01}
|
|
|
|
hash2 := &wire.ShaHash{0x02}
|
|
|
|
iv1 := wire.NewInvVect(wire.InvTypeBlock, hash1)
|
|
|
|
iv2 := wire.NewInvVect(wire.InvTypeBlock, hash2)
|
|
|
|
|
|
|
|
// Create new mru inventory map and add the inventory vectors.
|
|
|
|
mruInvMap := NewMruInventoryMap(uint(2))
|
|
|
|
mruInvMap.Add(iv1)
|
|
|
|
mruInvMap.Add(iv2)
|
|
|
|
|
|
|
|
// Ensure the stringer gives the expected result. Since map iteration
|
|
|
|
// is not ordered, either entry could be first, so account for both
|
|
|
|
// cases.
|
|
|
|
wantStr1 := fmt.Sprintf("<%d>[%s, %s]", 2, *iv1, *iv2)
|
|
|
|
wantStr2 := fmt.Sprintf("<%d>[%s, %s]", 2, *iv2, *iv1)
|
|
|
|
gotStr := mruInvMap.String()
|
|
|
|
if gotStr != wantStr1 && gotStr != wantStr2 {
|
|
|
|
t.Fatalf("unexpected string representation - got %q, want %q "+
|
|
|
|
"or %q", gotStr, wantStr1, wantStr2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-26 08:57:00 +02:00
|
|
|
// BenchmarkMruInventoryList performs basic benchmarks on the most recently
|
|
|
|
// used inventory handling.
|
|
|
|
func BenchmarkMruInventoryList(b *testing.B) {
|
|
|
|
// Create a bunch of fake inventory vectors to use in benchmarking
|
|
|
|
// the mru inventory code.
|
|
|
|
b.StopTimer()
|
|
|
|
numInvVects := 100000
|
2015-02-05 22:16:39 +01:00
|
|
|
invVects := make([]*wire.InvVect, 0, numInvVects)
|
2013-10-26 08:57:00 +02:00
|
|
|
for i := 0; i < numInvVects; i++ {
|
2015-02-05 22:16:39 +01:00
|
|
|
hashBytes := make([]byte, wire.HashSize)
|
2013-10-26 08:57:00 +02:00
|
|
|
rand.Read(hashBytes)
|
2015-02-05 22:16:39 +01:00
|
|
|
hash, _ := wire.NewShaHash(hashBytes)
|
|
|
|
iv := wire.NewInvVect(wire.InvTypeBlock, hash)
|
2013-10-26 08:57:00 +02:00
|
|
|
invVects = append(invVects, iv)
|
|
|
|
}
|
|
|
|
b.StartTimer()
|
|
|
|
|
|
|
|
// Benchmark the add plus evicition code.
|
|
|
|
limit := 20000
|
|
|
|
mruInvMap := NewMruInventoryMap(uint(limit))
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
mruInvMap.Add(invVects[i%numInvVects])
|
|
|
|
}
|
|
|
|
}
|