github.com/alanchchen/go-ethereum@v1.6.6-0.20170601190819-6171d01b1195/swarm/storage/netstore.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package storage
    18  
    19  import (
    20  	"fmt"
    21  	"path/filepath"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/log"
    26  )
    27  
    28  /*
    29  NetStore is a cloud storage access abstaction layer for swarm
    30  it contains the shared logic of network served chunk store/retrieval requests
    31  both local (coming from DPA api) and remote (coming from peers via bzz protocol)
    32  it implements the ChunkStore interface and embeds LocalStore
    33  
    34  It is called by the bzz protocol instances via Depo (the store/retrieve request handler)
    35  a protocol instance is running on each peer, so this is heavily parallelised.
    36  NetStore falls back to a backend (CloudStorage interface)
    37  implemented by bzz/network/forwarder. forwarder or IPFS or IPΞS
    38  */
    39  type NetStore struct {
    40  	hashfunc   Hasher
    41  	localStore *LocalStore
    42  	cloud      CloudStore
    43  	lock       sync.Mutex
    44  }
    45  
    46  // backend engine for cloud store
    47  // It can be aggregate dispatching to several parallel implementations:
    48  // bzz/network/forwarder. forwarder or IPFS or IPΞS
    49  type CloudStore interface {
    50  	Store(*Chunk)
    51  	Deliver(*Chunk)
    52  	Retrieve(*Chunk)
    53  }
    54  
    55  type StoreParams struct {
    56  	ChunkDbPath   string
    57  	DbCapacity    uint64
    58  	CacheCapacity uint
    59  	Radius        int
    60  }
    61  
    62  func NewStoreParams(path string) (self *StoreParams) {
    63  	return &StoreParams{
    64  		ChunkDbPath:   filepath.Join(path, "chunks"),
    65  		DbCapacity:    defaultDbCapacity,
    66  		CacheCapacity: defaultCacheCapacity,
    67  		Radius:        defaultRadius,
    68  	}
    69  }
    70  
    71  // netstore contructor, takes path argument that is used to initialise dbStore,
    72  // the persistent (disk) storage component of LocalStore
    73  // the second argument is the hive, the connection/logistics manager for the node
    74  func NewNetStore(hash Hasher, lstore *LocalStore, cloud CloudStore, params *StoreParams) *NetStore {
    75  	return &NetStore{
    76  		hashfunc:   hash,
    77  		localStore: lstore,
    78  		cloud:      cloud,
    79  	}
    80  }
    81  
    82  const (
    83  	// maximum number of peers that a retrieved message is delivered to
    84  	requesterCount = 3
    85  )
    86  
    87  var (
    88  	// timeout interval before retrieval is timed out
    89  	searchTimeout = 3 * time.Second
    90  )
    91  
    92  // store logic common to local and network chunk store requests
    93  // ~ unsafe put in localdb no check if exists no extra copy no hash validation
    94  // the chunk is forced to propagate (Cloud.Store) even if locally found!
    95  // caller needs to make sure if that is wanted
    96  func (self *NetStore) Put(entry *Chunk) {
    97  	self.localStore.Put(entry)
    98  
    99  	// handle deliveries
   100  	if entry.Req != nil {
   101  		log.Trace(fmt.Sprintf("NetStore.Put: localStore.Put %v hit existing request...delivering", entry.Key.Log()))
   102  		// closing C signals to other routines (local requests)
   103  		// that the chunk is has been retrieved
   104  		close(entry.Req.C)
   105  		// deliver the chunk to requesters upstream
   106  		go self.cloud.Deliver(entry)
   107  	} else {
   108  		log.Trace(fmt.Sprintf("NetStore.Put: localStore.Put %v stored locally", entry.Key.Log()))
   109  		// handle propagating store requests
   110  		// go self.cloud.Store(entry)
   111  		go self.cloud.Store(entry)
   112  	}
   113  }
   114  
   115  // retrieve logic common for local and network chunk retrieval requests
   116  func (self *NetStore) Get(key Key) (*Chunk, error) {
   117  	var err error
   118  	chunk, err := self.localStore.Get(key)
   119  	if err == nil {
   120  		if chunk.Req == nil {
   121  			log.Trace(fmt.Sprintf("NetStore.Get: %v found locally", key))
   122  		} else {
   123  			log.Trace(fmt.Sprintf("NetStore.Get: %v hit on an existing request", key))
   124  			// no need to launch again
   125  		}
   126  		return chunk, err
   127  	}
   128  	// no data and no request status
   129  	log.Trace(fmt.Sprintf("NetStore.Get: %v not found locally. open new request", key))
   130  	chunk = NewChunk(key, newRequestStatus(key))
   131  	self.localStore.memStore.Put(chunk)
   132  	go self.cloud.Retrieve(chunk)
   133  	return chunk, nil
   134  }
   135  
   136  // Close netstore
   137  func (self *NetStore) Close() {
   138  	return
   139  }