github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/storage/ldbstore_test.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:49</date>
    10  //</624342681455169536>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package storage
    29  
    30  import (
    31  	"bytes"
    32  	"context"
    33  	"fmt"
    34  	"io/ioutil"
    35  	"os"
    36  	"sync"
    37  	"testing"
    38  	"time"
    39  
    40  	"github.com/ethereum/go-ethereum/common"
    41  	"github.com/ethereum/go-ethereum/swarm/chunk"
    42  	"github.com/ethereum/go-ethereum/swarm/log"
    43  	"github.com/ethereum/go-ethereum/swarm/storage/mock/mem"
    44  
    45  	ldberrors "github.com/syndtr/goleveldb/leveldb/errors"
    46  )
    47  
    48  type testDbStore struct {
    49  	*LDBStore
    50  	dir string
    51  }
    52  
    53  func newTestDbStore(mock bool, trusted bool) (*testDbStore, func(), error) {
    54  	dir, err := ioutil.TempDir("", "bzz-storage-test")
    55  	if err != nil {
    56  		return nil, func() {}, err
    57  	}
    58  
    59  	var db *LDBStore
    60  	storeparams := NewDefaultStoreParams()
    61  	params := NewLDBStoreParams(storeparams, dir)
    62  	params.Po = testPoFunc
    63  
    64  	if mock {
    65  		globalStore := mem.NewGlobalStore()
    66  		addr := common.HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")
    67  		mockStore := globalStore.NewNodeStore(addr)
    68  
    69  		db, err = NewMockDbStore(params, mockStore)
    70  	} else {
    71  		db, err = NewLDBStore(params)
    72  	}
    73  
    74  	cleanup := func() {
    75  		if db != nil {
    76  			db.Close()
    77  		}
    78  		err = os.RemoveAll(dir)
    79  		if err != nil {
    80  			panic(fmt.Sprintf("db cleanup failed: %v", err))
    81  		}
    82  	}
    83  
    84  	return &testDbStore{db, dir}, cleanup, err
    85  }
    86  
    87  func testPoFunc(k Address) (ret uint8) {
    88  	basekey := make([]byte, 32)
    89  	return uint8(Proximity(basekey[:], k[:]))
    90  }
    91  
    92  func (db *testDbStore) close() {
    93  	db.Close()
    94  	err := os.RemoveAll(db.dir)
    95  	if err != nil {
    96  		panic(err)
    97  	}
    98  }
    99  
   100  func testDbStoreRandom(n int, processors int, chunksize int64, mock bool, t *testing.T) {
   101  	db, cleanup, err := newTestDbStore(mock, true)
   102  	defer cleanup()
   103  	if err != nil {
   104  		t.Fatalf("init dbStore failed: %v", err)
   105  	}
   106  	testStoreRandom(db, processors, n, chunksize, t)
   107  }
   108  
   109  func testDbStoreCorrect(n int, processors int, chunksize int64, mock bool, t *testing.T) {
   110  	db, cleanup, err := newTestDbStore(mock, false)
   111  	defer cleanup()
   112  	if err != nil {
   113  		t.Fatalf("init dbStore failed: %v", err)
   114  	}
   115  	testStoreCorrect(db, processors, n, chunksize, t)
   116  }
   117  
   118  func TestDbStoreRandom_1(t *testing.T) {
   119  	testDbStoreRandom(1, 1, 0, false, t)
   120  }
   121  
   122  func TestDbStoreCorrect_1(t *testing.T) {
   123  	testDbStoreCorrect(1, 1, 4096, false, t)
   124  }
   125  
   126  func TestDbStoreRandom_1_5k(t *testing.T) {
   127  	testDbStoreRandom(8, 5000, 0, false, t)
   128  }
   129  
   130  func TestDbStoreRandom_8_5k(t *testing.T) {
   131  	testDbStoreRandom(8, 5000, 0, false, t)
   132  }
   133  
   134  func TestDbStoreCorrect_1_5k(t *testing.T) {
   135  	testDbStoreCorrect(1, 5000, 4096, false, t)
   136  }
   137  
   138  func TestDbStoreCorrect_8_5k(t *testing.T) {
   139  	testDbStoreCorrect(8, 5000, 4096, false, t)
   140  }
   141  
   142  func TestMockDbStoreRandom_1(t *testing.T) {
   143  	testDbStoreRandom(1, 1, 0, true, t)
   144  }
   145  
   146  func TestMockDbStoreCorrect_1(t *testing.T) {
   147  	testDbStoreCorrect(1, 1, 4096, true, t)
   148  }
   149  
   150  func TestMockDbStoreRandom_1_5k(t *testing.T) {
   151  	testDbStoreRandom(8, 5000, 0, true, t)
   152  }
   153  
   154  func TestMockDbStoreRandom_8_5k(t *testing.T) {
   155  	testDbStoreRandom(8, 5000, 0, true, t)
   156  }
   157  
   158  func TestMockDbStoreCorrect_1_5k(t *testing.T) {
   159  	testDbStoreCorrect(1, 5000, 4096, true, t)
   160  }
   161  
   162  func TestMockDbStoreCorrect_8_5k(t *testing.T) {
   163  	testDbStoreCorrect(8, 5000, 4096, true, t)
   164  }
   165  
   166  func testDbStoreNotFound(t *testing.T, mock bool) {
   167  	db, cleanup, err := newTestDbStore(mock, false)
   168  	defer cleanup()
   169  	if err != nil {
   170  		t.Fatalf("init dbStore failed: %v", err)
   171  	}
   172  
   173  	_, err = db.Get(context.TODO(), ZeroAddr)
   174  	if err != ErrChunkNotFound {
   175  		t.Errorf("Expected ErrChunkNotFound, got %v", err)
   176  	}
   177  }
   178  
   179  func TestDbStoreNotFound(t *testing.T) {
   180  	testDbStoreNotFound(t, false)
   181  }
   182  func TestMockDbStoreNotFound(t *testing.T) {
   183  	testDbStoreNotFound(t, true)
   184  }
   185  
   186  func testIterator(t *testing.T, mock bool) {
   187  	var chunkcount int = 32
   188  	var i int
   189  	var poc uint
   190  	chunkkeys := NewAddressCollection(chunkcount)
   191  	chunkkeys_results := NewAddressCollection(chunkcount)
   192  
   193  	db, cleanup, err := newTestDbStore(mock, false)
   194  	defer cleanup()
   195  	if err != nil {
   196  		t.Fatalf("init dbStore failed: %v", err)
   197  	}
   198  
   199  	chunks := GenerateRandomChunks(chunk.DefaultSize, chunkcount)
   200  
   201  	wg := &sync.WaitGroup{}
   202  	wg.Add(len(chunks))
   203  	for i = 0; i < len(chunks); i++ {
   204  		db.Put(context.TODO(), chunks[i])
   205  		chunkkeys[i] = chunks[i].Addr
   206  		j := i
   207  		go func() {
   208  			defer wg.Done()
   209  			<-chunks[j].dbStoredC
   210  		}()
   211  	}
   212  
   213  //
   214  
   215  	for i = 0; i < len(chunkkeys); i++ {
   216  		log.Trace(fmt.Sprintf("Chunk array pos %d/%d: '%v'", i, chunkcount, chunkkeys[i]))
   217  	}
   218  	wg.Wait()
   219  	i = 0
   220  	for poc = 0; poc <= 255; poc++ {
   221  		err := db.SyncIterator(0, uint64(chunkkeys.Len()), uint8(poc), func(k Address, n uint64) bool {
   222  			log.Trace(fmt.Sprintf("Got key %v number %d poc %d", k, n, uint8(poc)))
   223  			chunkkeys_results[n-1] = k
   224  			i++
   225  			return true
   226  		})
   227  		if err != nil {
   228  			t.Fatalf("Iterator call failed: %v", err)
   229  		}
   230  	}
   231  
   232  	for i = 0; i < chunkcount; i++ {
   233  		if !bytes.Equal(chunkkeys[i], chunkkeys_results[i]) {
   234  			t.Fatalf("Chunk put #%d key '%v' does not match iterator's key '%v'", i, chunkkeys[i], chunkkeys_results[i])
   235  		}
   236  	}
   237  
   238  }
   239  
   240  func TestIterator(t *testing.T) {
   241  	testIterator(t, false)
   242  }
   243  func TestMockIterator(t *testing.T) {
   244  	testIterator(t, true)
   245  }
   246  
   247  func benchmarkDbStorePut(n int, processors int, chunksize int64, mock bool, b *testing.B) {
   248  	db, cleanup, err := newTestDbStore(mock, true)
   249  	defer cleanup()
   250  	if err != nil {
   251  		b.Fatalf("init dbStore failed: %v", err)
   252  	}
   253  	benchmarkStorePut(db, processors, n, chunksize, b)
   254  }
   255  
   256  func benchmarkDbStoreGet(n int, processors int, chunksize int64, mock bool, b *testing.B) {
   257  	db, cleanup, err := newTestDbStore(mock, true)
   258  	defer cleanup()
   259  	if err != nil {
   260  		b.Fatalf("init dbStore failed: %v", err)
   261  	}
   262  	benchmarkStoreGet(db, processors, n, chunksize, b)
   263  }
   264  
   265  func BenchmarkDbStorePut_1_500(b *testing.B) {
   266  	benchmarkDbStorePut(500, 1, 4096, false, b)
   267  }
   268  
   269  func BenchmarkDbStorePut_8_500(b *testing.B) {
   270  	benchmarkDbStorePut(500, 8, 4096, false, b)
   271  }
   272  
   273  func BenchmarkDbStoreGet_1_500(b *testing.B) {
   274  	benchmarkDbStoreGet(500, 1, 4096, false, b)
   275  }
   276  
   277  func BenchmarkDbStoreGet_8_500(b *testing.B) {
   278  	benchmarkDbStoreGet(500, 8, 4096, false, b)
   279  }
   280  
   281  func BenchmarkMockDbStorePut_1_500(b *testing.B) {
   282  	benchmarkDbStorePut(500, 1, 4096, true, b)
   283  }
   284  
   285  func BenchmarkMockDbStorePut_8_500(b *testing.B) {
   286  	benchmarkDbStorePut(500, 8, 4096, true, b)
   287  }
   288  
   289  func BenchmarkMockDbStoreGet_1_500(b *testing.B) {
   290  	benchmarkDbStoreGet(500, 1, 4096, true, b)
   291  }
   292  
   293  func BenchmarkMockDbStoreGet_8_500(b *testing.B) {
   294  	benchmarkDbStoreGet(500, 8, 4096, true, b)
   295  }
   296  
   297  //
   298  //
   299  func TestLDBStoreWithoutCollectGarbage(t *testing.T) {
   300  	capacity := 50
   301  	n := 10
   302  
   303  	ldb, cleanup := newLDBStore(t)
   304  	ldb.setCapacity(uint64(capacity))
   305  	defer cleanup()
   306  
   307  	chunks := []*Chunk{}
   308  	for i := 0; i < n; i++ {
   309  		c := GenerateRandomChunk(chunk.DefaultSize)
   310  		chunks = append(chunks, c)
   311  		log.Trace("generate random chunk", "idx", i, "chunk", c)
   312  	}
   313  
   314  	for i := 0; i < n; i++ {
   315  		go ldb.Put(context.TODO(), chunks[i])
   316  	}
   317  
   318  //
   319  	for i := 0; i < n; i++ {
   320  		<-chunks[i].dbStoredC
   321  	}
   322  
   323  	log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt)
   324  
   325  	for i := 0; i < n; i++ {
   326  		ret, err := ldb.Get(context.TODO(), chunks[i].Addr)
   327  		if err != nil {
   328  			t.Fatal(err)
   329  		}
   330  
   331  		if !bytes.Equal(ret.SData, chunks[i].SData) {
   332  			t.Fatal("expected to get the same data back, but got smth else")
   333  		}
   334  
   335  		log.Info("got back chunk", "chunk", ret)
   336  	}
   337  
   338  	if ldb.entryCnt != uint64(n+1) {
   339  		t.Fatalf("expected entryCnt to be equal to %v, but got %v", n+1, ldb.entryCnt)
   340  	}
   341  
   342  	if ldb.accessCnt != uint64(2*n+1) {
   343  		t.Fatalf("expected accessCnt to be equal to %v, but got %v", n+1, ldb.accessCnt)
   344  	}
   345  }
   346  
   347  //
   348  //
   349  func TestLDBStoreCollectGarbage(t *testing.T) {
   350  	capacity := 500
   351  	n := 2000
   352  
   353  	ldb, cleanup := newLDBStore(t)
   354  	ldb.setCapacity(uint64(capacity))
   355  	defer cleanup()
   356  
   357  	chunks := []*Chunk{}
   358  	for i := 0; i < n; i++ {
   359  		c := GenerateRandomChunk(chunk.DefaultSize)
   360  		chunks = append(chunks, c)
   361  		log.Trace("generate random chunk", "idx", i, "chunk", c)
   362  	}
   363  
   364  	for i := 0; i < n; i++ {
   365  		ldb.Put(context.TODO(), chunks[i])
   366  	}
   367  
   368  //
   369  	for i := 0; i < n; i++ {
   370  		<-chunks[i].dbStoredC
   371  	}
   372  
   373  	log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt)
   374  
   375  //
   376  	time.Sleep(5 * time.Second)
   377  
   378  	var missing int
   379  	for i := 0; i < n; i++ {
   380  		ret, err := ldb.Get(context.TODO(), chunks[i].Addr)
   381  		if err == ErrChunkNotFound || err == ldberrors.ErrNotFound {
   382  			missing++
   383  			continue
   384  		}
   385  		if err != nil {
   386  			t.Fatal(err)
   387  		}
   388  
   389  		if !bytes.Equal(ret.SData, chunks[i].SData) {
   390  			t.Fatal("expected to get the same data back, but got smth else")
   391  		}
   392  
   393  		log.Trace("got back chunk", "chunk", ret)
   394  	}
   395  
   396  	if missing < n-capacity {
   397  		t.Fatalf("gc failure: expected to miss %v chunks, but only %v are actually missing", n-capacity, missing)
   398  	}
   399  
   400  	log.Info("ldbstore", "total", n, "missing", missing, "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt)
   401  }
   402  
   403  //
   404  func TestLDBStoreAddRemove(t *testing.T) {
   405  	ldb, cleanup := newLDBStore(t)
   406  	ldb.setCapacity(200)
   407  	defer cleanup()
   408  
   409  	n := 100
   410  
   411  	chunks := []*Chunk{}
   412  	for i := 0; i < n; i++ {
   413  		c := GenerateRandomChunk(chunk.DefaultSize)
   414  		chunks = append(chunks, c)
   415  		log.Trace("generate random chunk", "idx", i, "chunk", c)
   416  	}
   417  
   418  	for i := 0; i < n; i++ {
   419  		go ldb.Put(context.TODO(), chunks[i])
   420  	}
   421  
   422  //
   423  	for i := 0; i < n; i++ {
   424  		<-chunks[i].dbStoredC
   425  	}
   426  
   427  	for i := 0; i < n; i++ {
   428  //
   429  		if i%2 == 0 {
   430  
   431  			key := chunks[i].Addr
   432  			ikey := getIndexKey(key)
   433  
   434  			var indx dpaDBIndex
   435  			ldb.tryAccessIdx(ikey, &indx)
   436  
   437  			ldb.delete(indx.Idx, ikey, ldb.po(key))
   438  		}
   439  	}
   440  
   441  	log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt)
   442  
   443  	for i := 0; i < n; i++ {
   444  		ret, err := ldb.Get(context.TODO(), chunks[i].Addr)
   445  
   446  		if i%2 == 0 {
   447  //
   448  			if err == nil || ret != nil {
   449  				t.Fatal("expected chunk to be missing, but got no error")
   450  			}
   451  		} else {
   452  //
   453  			if err != nil {
   454  				t.Fatalf("expected no error, but got %s", err)
   455  			}
   456  
   457  			if !bytes.Equal(ret.SData, chunks[i].SData) {
   458  				t.Fatal("expected to get the same data back, but got smth else")
   459  			}
   460  		}
   461  	}
   462  }
   463  
   464  //
   465  func TestLDBStoreRemoveThenCollectGarbage(t *testing.T) {
   466  	capacity := 10
   467  
   468  	ldb, cleanup := newLDBStore(t)
   469  	ldb.setCapacity(uint64(capacity))
   470  
   471  	n := 7
   472  
   473  	chunks := []*Chunk{}
   474  	for i := 0; i < capacity; i++ {
   475  		c := GenerateRandomChunk(chunk.DefaultSize)
   476  		chunks = append(chunks, c)
   477  		log.Trace("generate random chunk", "idx", i, "chunk", c)
   478  	}
   479  
   480  	for i := 0; i < n; i++ {
   481  		ldb.Put(context.TODO(), chunks[i])
   482  	}
   483  
   484  //
   485  	for i := 0; i < n; i++ {
   486  		<-chunks[i].dbStoredC
   487  	}
   488  
   489  //
   490  	for i := 0; i < n; i++ {
   491  		key := chunks[i].Addr
   492  		ikey := getIndexKey(key)
   493  
   494  		var indx dpaDBIndex
   495  		ldb.tryAccessIdx(ikey, &indx)
   496  
   497  		ldb.delete(indx.Idx, ikey, ldb.po(key))
   498  	}
   499  
   500  	log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt)
   501  
   502  	cleanup()
   503  
   504  	ldb, cleanup = newLDBStore(t)
   505  	ldb.setCapacity(uint64(capacity))
   506  
   507  	n = 10
   508  
   509  	for i := 0; i < n; i++ {
   510  		ldb.Put(context.TODO(), chunks[i])
   511  	}
   512  
   513  //
   514  	for i := 0; i < n; i++ {
   515  		<-chunks[i].dbStoredC
   516  	}
   517  
   518  //
   519  	idx := 0
   520  	ret, err := ldb.Get(context.TODO(), chunks[idx].Addr)
   521  	if err == nil || ret != nil {
   522  		t.Fatal("expected first chunk to be missing, but got no error")
   523  	}
   524  
   525  //
   526  	idx = 9
   527  	ret, err = ldb.Get(context.TODO(), chunks[idx].Addr)
   528  	if err != nil {
   529  		t.Fatalf("expected no error, but got %s", err)
   530  	}
   531  
   532  	if !bytes.Equal(ret.SData, chunks[idx].SData) {
   533  		t.Fatal("expected to get the same data back, but got smth else")
   534  	}
   535  }
   536