github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/storage/localstore.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  //</624342681564221440>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package storage
    29  
    30  import (
    31  	"context"
    32  	"encoding/binary"
    33  	"fmt"
    34  	"path/filepath"
    35  	"sync"
    36  
    37  	"github.com/ethereum/go-ethereum/metrics"
    38  	"github.com/ethereum/go-ethereum/swarm/log"
    39  	"github.com/ethereum/go-ethereum/swarm/storage/mock"
    40  )
    41  
    42  type LocalStoreParams struct {
    43  	*StoreParams
    44  	ChunkDbPath string
    45  	Validators  []ChunkValidator `toml:"-"`
    46  }
    47  
    48  func NewDefaultLocalStoreParams() *LocalStoreParams {
    49  	return &LocalStoreParams{
    50  		StoreParams: NewDefaultStoreParams(),
    51  	}
    52  }
    53  
    54  //
    55  //
    56  func (p *LocalStoreParams) Init(path string) {
    57  	if p.ChunkDbPath == "" {
    58  		p.ChunkDbPath = filepath.Join(path, "chunks")
    59  	}
    60  }
    61  
    62  //
    63  //
    64  type LocalStore struct {
    65  	Validators []ChunkValidator
    66  	memStore   *MemStore
    67  	DbStore    *LDBStore
    68  	mu         sync.Mutex
    69  }
    70  
    71  //
    72  func NewLocalStore(params *LocalStoreParams, mockStore *mock.NodeStore) (*LocalStore, error) {
    73  	ldbparams := NewLDBStoreParams(params.StoreParams, params.ChunkDbPath)
    74  	dbStore, err := NewMockDbStore(ldbparams, mockStore)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	return &LocalStore{
    79  		memStore:   NewMemStore(params.StoreParams, dbStore),
    80  		DbStore:    dbStore,
    81  		Validators: params.Validators,
    82  	}, nil
    83  }
    84  
    85  func NewTestLocalStoreForAddr(params *LocalStoreParams) (*LocalStore, error) {
    86  	ldbparams := NewLDBStoreParams(params.StoreParams, params.ChunkDbPath)
    87  	dbStore, err := NewLDBStore(ldbparams)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	localStore := &LocalStore{
    92  		memStore:   NewMemStore(params.StoreParams, dbStore),
    93  		DbStore:    dbStore,
    94  		Validators: params.Validators,
    95  	}
    96  	return localStore, nil
    97  }
    98  
    99  //
   100  //
   101  //
   102  //
   103  //
   104  //
   105  //
   106  //
   107  //
   108  //
   109  //
   110  //
   111  func (ls *LocalStore) Put(ctx context.Context, chunk *Chunk) {
   112  	valid := true
   113  //
   114  //
   115  	for _, v := range ls.Validators {
   116  		if valid = v.Validate(chunk.Addr, chunk.SData); valid {
   117  			break
   118  		}
   119  	}
   120  	if !valid {
   121  		log.Trace("invalid chunk", "addr", chunk.Addr, "len", len(chunk.SData))
   122  		chunk.SetErrored(ErrChunkInvalid)
   123  		chunk.markAsStored()
   124  		return
   125  	}
   126  
   127  	log.Trace("localstore.put", "addr", chunk.Addr)
   128  
   129  	ls.mu.Lock()
   130  	defer ls.mu.Unlock()
   131  
   132  	chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8]))
   133  
   134  	memChunk, err := ls.memStore.Get(ctx, chunk.Addr)
   135  	switch err {
   136  	case nil:
   137  		if memChunk.ReqC == nil {
   138  			chunk.markAsStored()
   139  			return
   140  		}
   141  	case ErrChunkNotFound:
   142  	default:
   143  		chunk.SetErrored(err)
   144  		return
   145  	}
   146  
   147  	ls.DbStore.Put(ctx, chunk)
   148  
   149  //
   150  	newc := NewChunk(chunk.Addr, nil)
   151  	newc.SData = chunk.SData
   152  	newc.Size = chunk.Size
   153  	newc.dbStoredC = chunk.dbStoredC
   154  
   155  	ls.memStore.Put(ctx, newc)
   156  
   157  	if memChunk != nil && memChunk.ReqC != nil {
   158  		close(memChunk.ReqC)
   159  	}
   160  }
   161  
   162  //
   163  //
   164  //
   165  //
   166  func (ls *LocalStore) Get(ctx context.Context, addr Address) (chunk *Chunk, err error) {
   167  	ls.mu.Lock()
   168  	defer ls.mu.Unlock()
   169  
   170  	return ls.get(ctx, addr)
   171  }
   172  
   173  func (ls *LocalStore) get(ctx context.Context, addr Address) (chunk *Chunk, err error) {
   174  	chunk, err = ls.memStore.Get(ctx, addr)
   175  	if err == nil {
   176  		if chunk.ReqC != nil {
   177  			select {
   178  			case <-chunk.ReqC:
   179  			default:
   180  				metrics.GetOrRegisterCounter("localstore.get.errfetching", nil).Inc(1)
   181  				return chunk, ErrFetching
   182  			}
   183  		}
   184  		metrics.GetOrRegisterCounter("localstore.get.cachehit", nil).Inc(1)
   185  		return
   186  	}
   187  	metrics.GetOrRegisterCounter("localstore.get.cachemiss", nil).Inc(1)
   188  	chunk, err = ls.DbStore.Get(ctx, addr)
   189  	if err != nil {
   190  		metrics.GetOrRegisterCounter("localstore.get.error", nil).Inc(1)
   191  		return
   192  	}
   193  	chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8]))
   194  	ls.memStore.Put(ctx, chunk)
   195  	return
   196  }
   197  
   198  //
   199  func (ls *LocalStore) GetOrCreateRequest(ctx context.Context, addr Address) (chunk *Chunk, created bool) {
   200  	metrics.GetOrRegisterCounter("localstore.getorcreaterequest", nil).Inc(1)
   201  
   202  	ls.mu.Lock()
   203  	defer ls.mu.Unlock()
   204  
   205  	var err error
   206  	chunk, err = ls.get(ctx, addr)
   207  	if err == nil && chunk.GetErrored() == nil {
   208  		metrics.GetOrRegisterCounter("localstore.getorcreaterequest.hit", nil).Inc(1)
   209  		log.Trace(fmt.Sprintf("LocalStore.GetOrRetrieve: %v found locally", addr))
   210  		return chunk, false
   211  	}
   212  	if err == ErrFetching && chunk.GetErrored() == nil {
   213  		metrics.GetOrRegisterCounter("localstore.getorcreaterequest.errfetching", nil).Inc(1)
   214  		log.Trace(fmt.Sprintf("LocalStore.GetOrRetrieve: %v hit on an existing request %v", addr, chunk.ReqC))
   215  		return chunk, false
   216  	}
   217  //
   218  	metrics.GetOrRegisterCounter("localstore.getorcreaterequest.miss", nil).Inc(1)
   219  	log.Trace(fmt.Sprintf("LocalStore.GetOrRetrieve: %v not found locally. open new request", addr))
   220  	chunk = NewChunk(addr, make(chan bool))
   221  	ls.memStore.Put(ctx, chunk)
   222  	return chunk, true
   223  }
   224  
   225  //
   226  func (ls *LocalStore) RequestsCacheLen() int {
   227  	return ls.memStore.requests.Len()
   228  }
   229  
   230  //
   231  func (ls *LocalStore) Close() {
   232  	ls.DbStore.Close()
   233  }
   234