github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/swarm/storage/localstore/mode_get.go (about)

     1  // Copyright 2018 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 localstore
    18  
    19  import (
    20  	"github.com/ethereum/go-ethereum/log"
    21  	"github.com/ethereum/go-ethereum/swarm/chunk"
    22  	"github.com/ethereum/go-ethereum/swarm/shed"
    23  	"github.com/syndtr/goleveldb/leveldb"
    24  )
    25  
    26  // ModeGet enumerates different Getter modes.
    27  type ModeGet int
    28  
    29  // Getter modes.
    30  const (
    31  	// ModeGetRequest: when accessed for retrieval
    32  	ModeGetRequest ModeGet = iota
    33  	// ModeGetSync: when accessed for syncing or proof of custody request
    34  	ModeGetSync
    35  )
    36  
    37  // Getter provides Get method to retrieve Chunks
    38  // from database.
    39  type Getter struct {
    40  	db   *DB
    41  	mode ModeGet
    42  }
    43  
    44  // NewGetter returns a new Getter on database
    45  // with a specific Mode.
    46  func (db *DB) NewGetter(mode ModeGet) *Getter {
    47  	return &Getter{
    48  		mode: mode,
    49  		db:   db,
    50  	}
    51  }
    52  
    53  // Get returns a chunk from the database. If the chunk is
    54  // not found chunk.ErrChunkNotFound will be returned.
    55  // All required indexes will be updated required by the
    56  // Getter Mode.
    57  func (g *Getter) Get(addr chunk.Address) (ch chunk.Chunk, err error) {
    58  	out, err := g.db.get(g.mode, addr)
    59  	if err != nil {
    60  		if err == leveldb.ErrNotFound {
    61  			return nil, chunk.ErrChunkNotFound
    62  		}
    63  		return nil, err
    64  	}
    65  	return chunk.NewChunk(out.Address, out.Data), nil
    66  }
    67  
    68  // get returns Item from the retrieval index
    69  // and updates other indexes.
    70  func (db *DB) get(mode ModeGet, addr chunk.Address) (out shed.Item, err error) {
    71  	item := addressToItem(addr)
    72  
    73  	out, err = db.retrievalDataIndex.Get(item)
    74  	if err != nil {
    75  		return out, err
    76  	}
    77  	switch mode {
    78  	// update the access timestamp and gc index
    79  	case ModeGetRequest:
    80  		if db.updateGCSem != nil {
    81  			// wait before creating new goroutines
    82  			// if updateGCSem buffer id full
    83  			db.updateGCSem <- struct{}{}
    84  		}
    85  		db.updateGCWG.Add(1)
    86  		go func() {
    87  			defer db.updateGCWG.Done()
    88  			if db.updateGCSem != nil {
    89  				// free a spot in updateGCSem buffer
    90  				// for a new goroutine
    91  				defer func() { <-db.updateGCSem }()
    92  			}
    93  			err := db.updateGC(out)
    94  			if err != nil {
    95  				log.Error("localstore update gc", "err", err)
    96  			}
    97  			// if gc update hook is defined, call it
    98  			if testHookUpdateGC != nil {
    99  				testHookUpdateGC()
   100  			}
   101  		}()
   102  
   103  	// no updates to indexes
   104  	case ModeGetSync:
   105  	default:
   106  		return out, ErrInvalidMode
   107  	}
   108  	return out, nil
   109  }
   110  
   111  // updateGC updates garbage collection index for
   112  // a single item. Provided item is expected to have
   113  // only Address and Data fields with non zero values,
   114  // which is ensured by the get function.
   115  func (db *DB) updateGC(item shed.Item) (err error) {
   116  	db.batchMu.Lock()
   117  	defer db.batchMu.Unlock()
   118  
   119  	batch := new(leveldb.Batch)
   120  
   121  	// update accessTimeStamp in retrieve, gc
   122  
   123  	i, err := db.retrievalAccessIndex.Get(item)
   124  	switch err {
   125  	case nil:
   126  		item.AccessTimestamp = i.AccessTimestamp
   127  	case leveldb.ErrNotFound:
   128  		// no chunk accesses
   129  	default:
   130  		return err
   131  	}
   132  	if item.AccessTimestamp == 0 {
   133  		// chunk is not yet synced
   134  		// do not add it to the gc index
   135  		return nil
   136  	}
   137  	// delete current entry from the gc index
   138  	db.gcIndex.DeleteInBatch(batch, item)
   139  	// update access timestamp
   140  	item.AccessTimestamp = now()
   141  	// update retrieve access index
   142  	db.retrievalAccessIndex.PutInBatch(batch, item)
   143  	// add new entry to gc index
   144  	db.gcIndex.PutInBatch(batch, item)
   145  
   146  	return db.shed.WriteBatch(batch)
   147  }
   148  
   149  // testHookUpdateGC is a hook that can provide
   150  // information when a garbage collection index is updated.
   151  var testHookUpdateGC func()