github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/swarm/storage/localstore/mode_put.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/swarm/chunk"
    21  	"github.com/ethereum/go-ethereum/swarm/shed"
    22  	"github.com/syndtr/goleveldb/leveldb"
    23  )
    24  
    25  // ModePut enumerates different Putter modes.
    26  type ModePut int
    27  
    28  // Putter modes.
    29  const (
    30  	// ModePutRequest: when a chunk is received as a result of retrieve request and delivery
    31  	ModePutRequest ModePut = iota
    32  	// ModePutSync: when a chunk is received via syncing
    33  	ModePutSync
    34  	// ModePutUpload: when a chunk is created by local upload
    35  	ModePutUpload
    36  )
    37  
    38  // Putter provides Put method to store Chunks
    39  // to database.
    40  type Putter struct {
    41  	db   *DB
    42  	mode ModePut
    43  }
    44  
    45  // NewPutter returns a new Putter on database
    46  // with a specific Mode.
    47  func (db *DB) NewPutter(mode ModePut) *Putter {
    48  	return &Putter{
    49  		mode: mode,
    50  		db:   db,
    51  	}
    52  }
    53  
    54  // Put stores the Chunk to database and depending
    55  // on the Putter mode, it updates required indexes.
    56  func (p *Putter) Put(ch chunk.Chunk) (err error) {
    57  	return p.db.put(p.mode, chunkToItem(ch))
    58  }
    59  
    60  // put stores Item to database and updates other
    61  // indexes. It acquires lockAddr to protect two calls
    62  // of this function for the same address in parallel.
    63  // Item fields Address and Data must not be
    64  // with their nil values.
    65  func (db *DB) put(mode ModePut, item shed.Item) (err error) {
    66  	// protect parallel updates
    67  	db.batchMu.Lock()
    68  	defer db.batchMu.Unlock()
    69  
    70  	batch := new(leveldb.Batch)
    71  
    72  	// variables that provide information for operations
    73  	// to be done after write batch function successfully executes
    74  	var gcSizeChange int64   // number to add or subtract from gcSize
    75  	var triggerPullFeed bool // signal pull feed subscriptions to iterate
    76  	var triggerPushFeed bool // signal push feed subscriptions to iterate
    77  
    78  	switch mode {
    79  	case ModePutRequest:
    80  		// put to indexes: retrieve, gc; it does not enter the syncpool
    81  
    82  		// check if the chunk already is in the database
    83  		// as gc index is updated
    84  		i, err := db.retrievalAccessIndex.Get(item)
    85  		switch err {
    86  		case nil:
    87  			item.AccessTimestamp = i.AccessTimestamp
    88  		case leveldb.ErrNotFound:
    89  			// no chunk accesses
    90  		default:
    91  			return err
    92  		}
    93  		i, err = db.retrievalDataIndex.Get(item)
    94  		switch err {
    95  		case nil:
    96  			item.StoreTimestamp = i.StoreTimestamp
    97  		case leveldb.ErrNotFound:
    98  			// no chunk accesses
    99  		default:
   100  			return err
   101  		}
   102  		if item.AccessTimestamp != 0 {
   103  			// delete current entry from the gc index
   104  			db.gcIndex.DeleteInBatch(batch, item)
   105  			gcSizeChange--
   106  		}
   107  		if item.StoreTimestamp == 0 {
   108  			item.StoreTimestamp = now()
   109  		}
   110  		// update access timestamp
   111  		item.AccessTimestamp = now()
   112  		// update retrieve access index
   113  		db.retrievalAccessIndex.PutInBatch(batch, item)
   114  		// add new entry to gc index
   115  		db.gcIndex.PutInBatch(batch, item)
   116  		gcSizeChange++
   117  
   118  		db.retrievalDataIndex.PutInBatch(batch, item)
   119  
   120  	case ModePutUpload:
   121  		// put to indexes: retrieve, push, pull
   122  
   123  		item.StoreTimestamp = now()
   124  		db.retrievalDataIndex.PutInBatch(batch, item)
   125  		db.pullIndex.PutInBatch(batch, item)
   126  		triggerPullFeed = true
   127  		db.pushIndex.PutInBatch(batch, item)
   128  		triggerPushFeed = true
   129  
   130  	case ModePutSync:
   131  		// put to indexes: retrieve, pull
   132  
   133  		item.StoreTimestamp = now()
   134  		db.retrievalDataIndex.PutInBatch(batch, item)
   135  		db.pullIndex.PutInBatch(batch, item)
   136  		triggerPullFeed = true
   137  
   138  	default:
   139  		return ErrInvalidMode
   140  	}
   141  
   142  	err = db.incGCSizeInBatch(batch, gcSizeChange)
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	err = db.shed.WriteBatch(batch)
   148  	if err != nil {
   149  		return err
   150  	}
   151  	if triggerPullFeed {
   152  		db.triggerPullSubscriptions(db.po(item.Address))
   153  	}
   154  	if triggerPushFeed {
   155  		db.triggerPushSubscriptions()
   156  	}
   157  	return nil
   158  }