github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/storage/common_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  //</624342680603725824>
    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  	"crypto/rand"
    34  	"flag"
    35  	"fmt"
    36  	"io"
    37  	"sync"
    38  	"testing"
    39  	"time"
    40  
    41  	"github.com/ethereum/go-ethereum/log"
    42  	colorable "github.com/mattn/go-colorable"
    43  )
    44  
    45  var (
    46  	loglevel = flag.Int("loglevel", 3, "verbosity of logs")
    47  )
    48  
    49  func init() {
    50  	flag.Parse()
    51  	log.PrintOrigins(true)
    52  	log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))))
    53  }
    54  
    55  type brokenLimitedReader struct {
    56  	lr    io.Reader
    57  	errAt int
    58  	off   int
    59  	size  int
    60  }
    61  
    62  func brokenLimitReader(data io.Reader, size int, errAt int) *brokenLimitedReader {
    63  	return &brokenLimitedReader{
    64  		lr:    data,
    65  		errAt: errAt,
    66  		size:  size,
    67  	}
    68  }
    69  
    70  func mputRandomChunks(store ChunkStore, processors int, n int, chunksize int64) (hs []Address) {
    71  	return mput(store, processors, n, GenerateRandomChunk)
    72  }
    73  
    74  func mput(store ChunkStore, processors int, n int, f func(i int64) *Chunk) (hs []Address) {
    75  	wg := sync.WaitGroup{}
    76  	wg.Add(processors)
    77  	c := make(chan *Chunk)
    78  	for i := 0; i < processors; i++ {
    79  		go func() {
    80  			defer wg.Done()
    81  			for chunk := range c {
    82  				wg.Add(1)
    83  				chunk := chunk
    84  				store.Put(context.TODO(), chunk)
    85  				go func() {
    86  					defer wg.Done()
    87  					<-chunk.dbStoredC
    88  				}()
    89  			}
    90  		}()
    91  	}
    92  	fa := f
    93  	if _, ok := store.(*MemStore); ok {
    94  		fa = func(i int64) *Chunk {
    95  			chunk := f(i)
    96  			chunk.markAsStored()
    97  			return chunk
    98  		}
    99  	}
   100  	for i := 0; i < n; i++ {
   101  		chunk := fa(int64(i))
   102  		hs = append(hs, chunk.Addr)
   103  		c <- chunk
   104  	}
   105  	close(c)
   106  	wg.Wait()
   107  	return hs
   108  }
   109  
   110  func mget(store ChunkStore, hs []Address, f func(h Address, chunk *Chunk) error) error {
   111  	wg := sync.WaitGroup{}
   112  	wg.Add(len(hs))
   113  	errc := make(chan error)
   114  
   115  	for _, k := range hs {
   116  		go func(h Address) {
   117  			defer wg.Done()
   118  			chunk, err := store.Get(context.TODO(), h)
   119  			if err != nil {
   120  				errc <- err
   121  				return
   122  			}
   123  			if f != nil {
   124  				err = f(h, chunk)
   125  				if err != nil {
   126  					errc <- err
   127  					return
   128  				}
   129  			}
   130  		}(k)
   131  	}
   132  	go func() {
   133  		wg.Wait()
   134  		close(errc)
   135  	}()
   136  	var err error
   137  	select {
   138  	case err = <-errc:
   139  	case <-time.NewTimer(5 * time.Second).C:
   140  		err = fmt.Errorf("timed out after 5 seconds")
   141  	}
   142  	return err
   143  }
   144  
   145  func testDataReader(l int) (r io.Reader) {
   146  	return io.LimitReader(rand.Reader, int64(l))
   147  }
   148  
   149  func (r *brokenLimitedReader) Read(buf []byte) (int, error) {
   150  	if r.off+len(buf) > r.errAt {
   151  		return 0, fmt.Errorf("Broken reader")
   152  	}
   153  	r.off += len(buf)
   154  	return r.lr.Read(buf)
   155  }
   156  
   157  func generateRandomData(l int) (r io.Reader, slice []byte) {
   158  	slice = make([]byte, l)
   159  	if _, err := rand.Read(slice); err != nil {
   160  		panic("rand error")
   161  	}
   162  	r = io.LimitReader(bytes.NewReader(slice), int64(l))
   163  	return
   164  }
   165  
   166  func testStoreRandom(m ChunkStore, processors int, n int, chunksize int64, t *testing.T) {
   167  	hs := mputRandomChunks(m, processors, n, chunksize)
   168  	err := mget(m, hs, nil)
   169  	if err != nil {
   170  		t.Fatalf("testStore failed: %v", err)
   171  	}
   172  }
   173  
   174  func testStoreCorrect(m ChunkStore, processors int, n int, chunksize int64, t *testing.T) {
   175  	hs := mputRandomChunks(m, processors, n, chunksize)
   176  	f := func(h Address, chunk *Chunk) error {
   177  		if !bytes.Equal(h, chunk.Addr) {
   178  			return fmt.Errorf("key does not match retrieved chunk Key")
   179  		}
   180  		hasher := MakeHashFunc(DefaultHash)()
   181  		hasher.ResetWithLength(chunk.SData[:8])
   182  		hasher.Write(chunk.SData[8:])
   183  		exp := hasher.Sum(nil)
   184  		if !bytes.Equal(h, exp) {
   185  			return fmt.Errorf("key is not hash of chunk data")
   186  		}
   187  		return nil
   188  	}
   189  	err := mget(m, hs, f)
   190  	if err != nil {
   191  		t.Fatalf("testStore failed: %v", err)
   192  	}
   193  }
   194  
   195  func benchmarkStorePut(store ChunkStore, processors int, n int, chunksize int64, b *testing.B) {
   196  	chunks := make([]*Chunk, n)
   197  	i := 0
   198  	f := func(dataSize int64) *Chunk {
   199  		chunk := GenerateRandomChunk(dataSize)
   200  		chunks[i] = chunk
   201  		i++
   202  		return chunk
   203  	}
   204  
   205  	mput(store, processors, n, f)
   206  
   207  	f = func(dataSize int64) *Chunk {
   208  		chunk := chunks[i]
   209  		i++
   210  		return chunk
   211  	}
   212  
   213  	b.ReportAllocs()
   214  	b.ResetTimer()
   215  
   216  	for j := 0; j < b.N; j++ {
   217  		i = 0
   218  		mput(store, processors, n, f)
   219  	}
   220  }
   221  
   222  func benchmarkStoreGet(store ChunkStore, processors int, n int, chunksize int64, b *testing.B) {
   223  	hs := mputRandomChunks(store, processors, n, chunksize)
   224  	b.ReportAllocs()
   225  	b.ResetTimer()
   226  	for i := 0; i < b.N; i++ {
   227  		err := mget(store, hs, nil)
   228  		if err != nil {
   229  			b.Fatalf("mget failed: %v", err)
   230  		}
   231  	}
   232  }
   233