code.vegaprotocol.io/vega@v0.79.0/datanode/networkhistory/store/index.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package store 17 18 import ( 19 "encoding/binary" 20 "encoding/json" 21 "errors" 22 "fmt" 23 "path/filepath" 24 "sort" 25 26 "code.vegaprotocol.io/vega/datanode/networkhistory/segment" 27 "code.vegaprotocol.io/vega/logging" 28 29 "github.com/syndtr/goleveldb/leveldb" 30 "github.com/syndtr/goleveldb/leveldb/opt" 31 "github.com/syndtr/goleveldb/leveldb/util" 32 ) 33 34 var ErrIndexEntryNotFound = errors.New("index entry not found") 35 36 type LevelDbBackedIndex struct { 37 db *leveldb.DB 38 log *logging.Logger 39 } 40 41 func NewIndex(dataDir string, log *logging.Logger) (*LevelDbBackedIndex, error) { 42 db, err := leveldb.OpenFile(filepath.Join(dataDir, "index.db"), nil) 43 if err != nil { 44 return nil, fmt.Errorf("failed to open level db file: %w", err) 45 } 46 47 return &LevelDbBackedIndex{ 48 db: db, 49 log: log, 50 }, nil 51 } 52 53 func (l LevelDbBackedIndex) Get(height int64) (segment.Full, error) { 54 value, err := l.db.Get(heightToKey(height), &opt.ReadOptions{}) 55 if errors.Is(err, leveldb.ErrNotFound) { 56 return segment.Full{}, ErrIndexEntryNotFound 57 } 58 59 if err != nil { 60 return segment.Full{}, fmt.Errorf("failed to get index entry: %w", err) 61 } 62 63 var indexEntry segment.Full 64 err = json.Unmarshal(value, &indexEntry) 65 66 if err != nil { 67 return segment.Full{}, fmt.Errorf("failed to unmarshal value: %w", err) 68 } 69 70 return indexEntry, nil 71 } 72 73 func heightToKey(height int64) []byte { 74 bytes := make([]byte, 8) 75 binary.LittleEndian.PutUint64(bytes, uint64(height)) 76 return bytes 77 } 78 79 func (l LevelDbBackedIndex) Add(indexEntry segment.Full) error { 80 bytes, err := json.Marshal(indexEntry) 81 if err != nil { 82 return fmt.Errorf("failed to marshal index entry: %w", err) 83 } 84 85 err = l.db.Put(heightToKey(indexEntry.HeightTo), bytes, &opt.WriteOptions{}) 86 if err != nil { 87 return fmt.Errorf("failed to put index entry: %w", err) 88 } 89 90 return nil 91 } 92 93 func (l LevelDbBackedIndex) Remove(indexEntry segment.Full) error { 94 if err := l.db.Delete(heightToKey(indexEntry.HeightTo), &opt.WriteOptions{}); err != nil { 95 return fmt.Errorf("failed to delete key: %w", err) 96 } 97 98 return nil 99 } 100 101 func (l LevelDbBackedIndex) ListAllEntriesOldestFirst() (segment.Segments[segment.Full], error) { 102 segments, err := l.listAllEntries() 103 if err != nil { 104 return nil, fmt.Errorf("failed to list all entries: %w", err) 105 } 106 107 sort.Slice(segments, func(i, j int) bool { 108 return segments[i].HeightFrom < segments[j].HeightFrom 109 }) 110 return segments, nil 111 } 112 113 func (l LevelDbBackedIndex) ListAllEntriesMostRecentFirst() (segment.Segments[segment.Full], error) { 114 segments, err := l.listAllEntries() 115 if err != nil { 116 return nil, fmt.Errorf("failed to list all entries: %w", err) 117 } 118 119 sort.Slice(segments, func(i, j int) bool { 120 return segments[i].HeightFrom > segments[j].HeightFrom 121 }) 122 123 return segments, nil 124 } 125 126 func (l LevelDbBackedIndex) listAllEntries() (segment.Segments[segment.Full], error) { 127 var segments []segment.Full 128 l.log.Debug("Creating iterator") 129 130 iter := l.db.NewIterator(&util.Range{ 131 Start: nil, 132 Limit: nil, 133 }, &opt.ReadOptions{}) 134 defer func() { 135 l.log.Debug("Closing iterator") 136 iter.Release() 137 }() 138 139 if !iter.Last() { 140 return segments, nil 141 } 142 143 for ok := iter.Last(); ok; ok = iter.Prev() { 144 bytes := iter.Value() 145 var indexEntry segment.Full 146 err := json.Unmarshal(bytes, &indexEntry) 147 if err != nil { 148 return nil, fmt.Errorf("failed to unmarshal index entry: %w", err) 149 } 150 151 segments = append(segments, indexEntry) 152 } 153 154 return segments, nil 155 } 156 157 func (l LevelDbBackedIndex) GetHighestBlockHeightEntry() (segment.Full, error) { 158 entries, err := l.ListAllEntriesOldestFirst() 159 if err != nil { 160 return segment.Full{}, fmt.Errorf("failed to list all entries: %w", err) 161 } 162 163 if len(entries) == 0 { 164 return segment.Full{}, ErrIndexEntryNotFound 165 } 166 167 return entries[len(entries)-1], nil 168 } 169 170 func (l LevelDbBackedIndex) Close() error { 171 return l.db.Close() 172 }