github.com/daeglee/go-ethereum@v0.0.0-20190504220456-cad3e8d18e9b/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/chunk" 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 chunk.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 chunk.Address) (err error) { 65 // protect parallel updates 66 db.batchMu.Lock() 67 defer db.batchMu.Unlock() 68 69 batch := new(leveldb.Batch) 70 71 // variables that provide information for operations 72 // to be done after write batch function successfully executes 73 var gcSizeChange int64 // number to add or subtract from gcSize 74 var triggerPullFeed bool // signal pull feed subscriptions to iterate 75 76 item := addressToItem(addr) 77 78 switch mode { 79 case ModeSetAccess: 80 // add to pull, insert to gc 81 82 // need to get access timestamp here as it is not 83 // provided by the access function, and it is not 84 // a property of a chunk provided to Accessor.Put. 85 86 i, err := db.retrievalDataIndex.Get(item) 87 switch err { 88 case nil: 89 item.StoreTimestamp = i.StoreTimestamp 90 case leveldb.ErrNotFound: 91 db.pushIndex.DeleteInBatch(batch, item) 92 item.StoreTimestamp = now() 93 default: 94 return err 95 } 96 97 i, err = db.retrievalAccessIndex.Get(item) 98 switch err { 99 case nil: 100 item.AccessTimestamp = i.AccessTimestamp 101 db.gcIndex.DeleteInBatch(batch, item) 102 gcSizeChange-- 103 case leveldb.ErrNotFound: 104 // the chunk is not accessed before 105 default: 106 return err 107 } 108 item.AccessTimestamp = now() 109 db.retrievalAccessIndex.PutInBatch(batch, item) 110 db.pullIndex.PutInBatch(batch, item) 111 triggerPullFeed = true 112 db.gcIndex.PutInBatch(batch, item) 113 gcSizeChange++ 114 115 case ModeSetSync: 116 // delete from push, insert to gc 117 118 // need to get access timestamp here as it is not 119 // provided by the access function, and it is not 120 // a property of a chunk provided to Accessor.Put. 121 i, err := db.retrievalDataIndex.Get(item) 122 if err != nil { 123 if err == leveldb.ErrNotFound { 124 // chunk is not found, 125 // no need to update gc index 126 // just delete from the push index 127 // if it is there 128 db.pushIndex.DeleteInBatch(batch, item) 129 return nil 130 } 131 return err 132 } 133 item.StoreTimestamp = i.StoreTimestamp 134 135 i, err = db.retrievalAccessIndex.Get(item) 136 switch err { 137 case nil: 138 item.AccessTimestamp = i.AccessTimestamp 139 db.gcIndex.DeleteInBatch(batch, item) 140 gcSizeChange-- 141 case leveldb.ErrNotFound: 142 // the chunk is not accessed before 143 default: 144 return err 145 } 146 item.AccessTimestamp = now() 147 db.retrievalAccessIndex.PutInBatch(batch, item) 148 db.pushIndex.DeleteInBatch(batch, item) 149 db.gcIndex.PutInBatch(batch, item) 150 gcSizeChange++ 151 152 case modeSetRemove: 153 // delete from retrieve, pull, gc 154 155 // need to get access timestamp here as it is not 156 // provided by the access function, and it is not 157 // a property of a chunk provided to Accessor.Put. 158 159 i, err := db.retrievalAccessIndex.Get(item) 160 switch err { 161 case nil: 162 item.AccessTimestamp = i.AccessTimestamp 163 case leveldb.ErrNotFound: 164 default: 165 return err 166 } 167 i, err = db.retrievalDataIndex.Get(item) 168 if err != nil { 169 return err 170 } 171 item.StoreTimestamp = i.StoreTimestamp 172 173 db.retrievalDataIndex.DeleteInBatch(batch, item) 174 db.retrievalAccessIndex.DeleteInBatch(batch, item) 175 db.pullIndex.DeleteInBatch(batch, item) 176 db.gcIndex.DeleteInBatch(batch, item) 177 // a check is needed for decrementing gcSize 178 // as delete is not reporting if the key/value pair 179 // is deleted or not 180 if _, err := db.gcIndex.Get(item); err == nil { 181 gcSizeChange = -1 182 } 183 184 default: 185 return ErrInvalidMode 186 } 187 188 err = db.incGCSizeInBatch(batch, gcSizeChange) 189 if err != nil { 190 return err 191 } 192 193 err = db.shed.WriteBatch(batch) 194 if err != nil { 195 return err 196 } 197 if triggerPullFeed { 198 db.triggerPullSubscriptions(db.po(item.Address)) 199 } 200 return nil 201 }