swarm/storage: Add ordered garbage collection test for ldb

This commit is contained in:
lash 2018-09-28 22:18:55 +02:00
parent dcaabfe7f6
commit 5c8bd94513

View file

@ -19,6 +19,7 @@ package storage
import (
"bytes"
"context"
"encoding/binary"
"fmt"
"io/ioutil"
"os"
@ -340,6 +341,111 @@ func TestLDBStoreCollectGarbage(t *testing.T) {
log.Info("ldbstore", "total", n, "missing", missing, "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt)
}
// TestLDBStoreCollectGarbageOrdered checks if the most recently added chunks according to capacity are left after garbage collection
func TestLDBStoreCollectGarbageOrdered(t *testing.T) {
capacity := 10000
chunkCount := 20000
hasher := MakeHashFunc(DefaultHash)()
// four byte value incremented sequentially as chunk data (one chunk has 1024 values)
var byteValue uint32 = 0
// lru buffer
cursor := 0
buf := make([][ch.DefaultSize]byte, capacity)
// record keeping
madeChunks := make([]Chunk, capacity)
madeAddrs := make([]Address, capacity)
matchAddrs := make([]Address, capacity)
// needed for hashing (all chunks are full chunks here)
meta := make([]byte, 8)
binary.LittleEndian.PutUint64(meta, uint64(ch.DefaultSize))
// the store
store, cleanup := newLDBStore(t)
store.setCapacity(uint64(capacity))
defer cleanup()
for i := 0; i < chunkCount; i++ {
hasher.ResetWithLength(meta)
// write (same) sequential data to buffer and hasher
for j := 0; j < ch.DefaultSize; j += 4 { // uint32 intervals
byteValueByte := [4]byte{}
binary.LittleEndian.PutUint32(byteValueByte[:], byteValue)
copy(buf[cursor][j:], byteValueByte[:])
hasher.Write(byteValueByte[:])
byteValue++
}
// create chunk, add to record keeping and put chunk in store
madeChunks[cursor] = NewChunk(hasher.Sum(nil), buf[cursor][:])
madeAddrs[cursor] = madeChunks[cursor].Address()
matchAddrs[cursor] = madeChunks[cursor].Address()
savedChunk, err := mput(store, 1, func(n int64) Chunk { return madeChunks[cursor] })
if err != nil {
t.Fatalf("store put fail: %v", err)
} else if !bytes.Equal(savedChunk[0].Address(), madeAddrs[cursor]) { // probably redundant but let's be careful for now
t.Fatalf("saved addr mismatch %x/%x: %v", savedChunk[0].Address(), madeAddrs[cursor], err)
}
log.Debug("putting", "address", matchAddrs[cursor])
// wrap cursor on capacity.
cursor++
cursor %= capacity
}
log.Info("chunks put, sir", "cursor", cursor, "lastvalue", byteValue, "count", len(madeAddrs))
// madeAddrs should now contain only the last added chunks.
var matches uint64
var seq uint64
err := mget(store, madeAddrs, func(h Address, retrievedChunk Chunk) error {
oldMatch := matches
seq++
// matchedAddr originally equal to madeAddr
// when an element is found, remove it
for i, matchedAddr := range matchAddrs {
if bytes.Equal(matchedAddr, h) {
matchAddrs[i] = matchAddrs[len(matchAddrs)-1]
// last one needs special treatment
if len(matchAddrs) == 1 {
matchAddrs = []Address{}
} else {
matchAddrs = matchAddrs[:len(matchAddrs)-1]
}
matches++
log.Debug("found match", "addr", h, "match", matches, "seq", seq, "left", len(matchAddrs))
break
}
}
// we don't seem to reach this, which suggests retrieve fails are handled further up...?
if oldMatch == matches {
log.Warn("no match", "addr", h, "left", len(matchAddrs))
return fmt.Errorf("not found (%d): %x", matches, h)
}
return nil
})
// check the retrieve errors
if err != nil {
t.Fatalf("matches %d/%d, retrieve fail: %v", matches, capacity, err)
}
// if all elements are found the array should be empty
if len(matchAddrs) > 0 {
t.Fatalf("expected 0 chunks in match array, have %d", len(matchAddrs))
}
}
// TestLDBStoreAddRemove tests that we can put and then delete a given chunk
func TestLDBStoreAddRemove(t *testing.T) {
ldb, cleanup := newLDBStore(t)