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()