github.com/xxRanger/go-ethereum@v1.8.23/swarm/storage/localstore/mode_set.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/storage" 21 "github.com/syndtr/goleveldb/leveldb" 22 ) 23 24 // ModeSet enumerates different Setter modes. 25 type ModeSet int 26 27 // Setter modes. 28 const ( 29 // ModeSetAccess: when an update request is received for a chunk or chunk is retrieved for delivery 30 ModeSetAccess ModeSet = iota 31 // ModeSetSync: when push sync receipt is received 32 ModeSetSync 33 // modeSetRemove: when GC-d 34 // unexported as no external packages should remove chunks from database 35 modeSetRemove 36 ) 37 38 // Setter sets the state of a particular 39 // Chunk in database by changing indexes. 40 type Setter struct { 41 db *DB 42 mode ModeSet 43 } 44 45 // NewSetter returns a new Setter on database 46 // with a specific Mode. 47 func (db *DB) NewSetter(mode ModeSet) *Setter { 48 return &Setter{ 49 mode: mode, 50 db: db, 51 } 52 } 53 54 // Set updates database indexes for a specific 55 // chunk represented by the address. 56 func (s *Setter) Set(addr storage.Address) (err error) { 57 return s.db.set(s.mode, addr) 58 } 59 60 // set updates database indexes for a specific 61 // chunk represented by the address. 62 // It acquires lockAddr to protect two calls 63 // of this function for the same address in parallel. 64 func (db *DB) set(mode ModeSet, addr storage.Address) (err error) { 65 // protect parallel updates 66 unlock, err := db.lockAddr(addr) 67 if err != nil { 68 return err 69 } 70 defer unlock() 71 72 batch := new(leveldb.Batch) 73 74 // variables that provide information for operations 75 // to be done after write batch function successfully executes 76 var gcSizeChange int64 // number to add or subtract from gcSize 77 var triggerPullFeed bool // signal pull feed subscriptions to iterate 78 79 item := addressToItem(addr) 80 81 switch mode { 82 case ModeSetAccess: 83 // add to pull, insert to gc 84 85 // need to get access timestamp here as it is not 86 // provided by the access function, and it is not 87 // a property of a chunk provided to Accessor.Put. 88 89 i, err := db.retrievalDataIndex.Get(item) 90 switch err { 91 case nil: 92 item.StoreTimestamp = i.StoreTimestamp 93 case leveldb.ErrNotFound: 94 db.pushIndex.DeleteInBatch(batch, item) 95 item.StoreTimestamp = now() 96 default: 97 return err 98 } 99 100 i, err = db.retrievalAccessIndex.Get(item) 101 switch err { 102 case nil: 103 item.AccessTimestamp = i.AccessTimestamp 104 db.gcIndex.DeleteInBatch(batch, item) 105 gcSizeChange-- 106 case leveldb.ErrNotFound: 107 // the chunk is not accessed before 108 default: 109 return err 110 } 111 item.AccessTimestamp = now() 112 db.retrievalAccessIndex.PutInBatch(batch, item) 113 db.pullIndex.PutInBatch(batch, item) 114 triggerPullFeed = true 115 db.gcIndex.PutInBatch(batch, item) 116 db.gcUncountedHashesIndex.PutInBatch(batch, item) 117 gcSizeChange++ 118 119 case ModeSetSync: 120 // delete from push, insert to gc 121 122 // need to get access timestamp here as it is not 123 // provided by the access function, and it is not 124 // a property of a chunk provided to Accessor.Put. 125 i, err := db.retrievalDataIndex.Get(item) 126 if err != nil { 127 if err == leveldb.ErrNotFound { 128 // chunk is not found, 129 // no need to update gc index 130 // just delete from the push index 131 // if it is there 132 db.pushIndex.DeleteInBatch(batch, item) 133 return nil 134 } 135 return err 136 } 137 item.StoreTimestamp = i.StoreTimestamp 138 139 i, err = db.retrievalAccessIndex.Get(item) 140 switch err { 141 case nil: 142 item.AccessTimestamp = i.AccessTimestamp 143 db.gcIndex.DeleteInBatch(batch, item) 144 gcSizeChange-- 145 case leveldb.ErrNotFound: 146 // the chunk is not accessed before 147 default: 148 return err 149 } 150 item.AccessTimestamp = now() 151 db.retrievalAccessIndex.PutInBatch(batch, item) 152 db.pushIndex.DeleteInBatch(batch, item) 153 db.gcIndex.PutInBatch(batch, item) 154 db.gcUncountedHashesIndex.PutInBatch(batch, item) 155 gcSizeChange++ 156 157 case modeSetRemove: 158 // delete from retrieve, pull, gc 159 160 // need to get access timestamp here as it is not 161 // provided by the access function, and it is not 162 // a property of a chunk provided to Accessor.Put. 163 164 i, err := db.retrievalAccessIndex.Get(item) 165 switch err { 166 case nil: 167 item.AccessTimestamp = i.AccessTimestamp 168 case leveldb.ErrNotFound: 169 default: 170 return err 171 } 172 i, err = db.retrievalDataIndex.Get(item) 173 if err != nil { 174 return err 175 } 176 item.StoreTimestamp = i.StoreTimestamp 177 178 db.retrievalDataIndex.DeleteInBatch(batch, item) 179 db.retrievalAccessIndex.DeleteInBatch(batch, item) 180 db.pullIndex.DeleteInBatch(batch, item) 181 db.gcIndex.DeleteInBatch(batch, item) 182 db.gcUncountedHashesIndex.DeleteInBatch(batch, item) 183 // a check is needed for decrementing gcSize 184 // as delete is not reporting if the key/value pair 185 // is deleted or not 186 if _, err := db.gcIndex.Get(item); err == nil { 187 gcSizeChange = -1 188 } 189 190 default: 191 return ErrInvalidMode 192 } 193 194 err = db.shed.WriteBatch(batch) 195 if err != nil { 196 return err 197 } 198 if gcSizeChange != 0 { 199 db.incGCSize(gcSizeChange) 200 } 201 if triggerPullFeed { 202 db.triggerPullSubscriptions(db.po(item.Address)) 203 } 204 return nil 205 }