github.com/xxRanger/go-ethereum@v1.8.23/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/shed" 21 "github.com/ethereum/go-ethereum/swarm/storage" 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 storage.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 unlock, err := db.lockAddr(item.Address) 68 if err != nil { 69 return err 70 } 71 defer unlock() 72 73 batch := new(leveldb.Batch) 74 75 // variables that provide information for operations 76 // to be done after write batch function successfully executes 77 var gcSizeChange int64 // number to add or subtract from gcSize 78 var triggerPullFeed bool // signal pull feed subscriptions to iterate 79 var triggerPushFeed bool // signal push feed subscriptions to iterate 80 81 switch mode { 82 case ModePutRequest: 83 // put to indexes: retrieve, gc; it does not enter the syncpool 84 85 // check if the chunk already is in the database 86 // as gc index is updated 87 i, err := db.retrievalAccessIndex.Get(item) 88 switch err { 89 case nil: 90 item.AccessTimestamp = i.AccessTimestamp 91 case leveldb.ErrNotFound: 92 // no chunk accesses 93 default: 94 return err 95 } 96 i, err = db.retrievalDataIndex.Get(item) 97 switch err { 98 case nil: 99 item.StoreTimestamp = i.StoreTimestamp 100 case leveldb.ErrNotFound: 101 // no chunk accesses 102 default: 103 return err 104 } 105 if item.AccessTimestamp != 0 { 106 // delete current entry from the gc index 107 db.gcIndex.DeleteInBatch(batch, item) 108 gcSizeChange-- 109 } 110 if item.StoreTimestamp == 0 { 111 item.StoreTimestamp = now() 112 } 113 // update access timestamp 114 item.AccessTimestamp = now() 115 // update retrieve access index 116 db.retrievalAccessIndex.PutInBatch(batch, item) 117 // add new entry to gc index 118 db.gcIndex.PutInBatch(batch, item) 119 db.gcUncountedHashesIndex.PutInBatch(batch, item) 120 gcSizeChange++ 121 122 db.retrievalDataIndex.PutInBatch(batch, item) 123 124 case ModePutUpload: 125 // put to indexes: retrieve, push, pull 126 127 item.StoreTimestamp = now() 128 db.retrievalDataIndex.PutInBatch(batch, item) 129 db.pullIndex.PutInBatch(batch, item) 130 triggerPullFeed = true 131 db.pushIndex.PutInBatch(batch, item) 132 triggerPushFeed = true 133 134 case ModePutSync: 135 // put to indexes: retrieve, pull 136 137 item.StoreTimestamp = now() 138 db.retrievalDataIndex.PutInBatch(batch, item) 139 db.pullIndex.PutInBatch(batch, item) 140 triggerPullFeed = true 141 142 default: 143 return ErrInvalidMode 144 } 145 146 err = db.shed.WriteBatch(batch) 147 if err != nil { 148 return err 149 } 150 if gcSizeChange != 0 { 151 db.incGCSize(gcSizeChange) 152 } 153 if triggerPullFeed { 154 db.triggerPullSubscriptions(db.po(item.Address)) 155 } 156 if triggerPushFeed { 157 db.triggerPushSubscriptions() 158 } 159 return nil 160 }