github.com/jimmyx0x/go-ethereum@v1.10.28/core/rawdb/freezer_meta.go (about) 1 // Copyright 2022 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 rawdb 18 19 import ( 20 "io" 21 "os" 22 23 "github.com/ethereum/go-ethereum/log" 24 "github.com/ethereum/go-ethereum/rlp" 25 ) 26 27 const freezerVersion = 1 // The initial version tag of freezer table metadata 28 29 // freezerTableMeta wraps all the metadata of the freezer table. 30 type freezerTableMeta struct { 31 // Version is the versioning descriptor of the freezer table. 32 Version uint16 33 34 // VirtualTail indicates how many items have been marked as deleted. 35 // Its value is equal to the number of items removed from the table 36 // plus the number of items hidden in the table, so it should never 37 // be lower than the "actual tail". 38 VirtualTail uint64 39 } 40 41 // newMetadata initializes the metadata object with the given virtual tail. 42 func newMetadata(tail uint64) *freezerTableMeta { 43 return &freezerTableMeta{ 44 Version: freezerVersion, 45 VirtualTail: tail, 46 } 47 } 48 49 // readMetadata reads the metadata of the freezer table from the 50 // given metadata file. 51 func readMetadata(file *os.File) (*freezerTableMeta, error) { 52 _, err := file.Seek(0, io.SeekStart) 53 if err != nil { 54 return nil, err 55 } 56 var meta freezerTableMeta 57 if err := rlp.Decode(file, &meta); err != nil { 58 return nil, err 59 } 60 return &meta, nil 61 } 62 63 // writeMetadata writes the metadata of the freezer table into the 64 // given metadata file. 65 func writeMetadata(file *os.File, meta *freezerTableMeta) error { 66 _, err := file.Seek(0, io.SeekStart) 67 if err != nil { 68 return err 69 } 70 return rlp.Encode(file, meta) 71 } 72 73 // loadMetadata loads the metadata from the given metadata file. 74 // Initializes the metadata file with the given "actual tail" if 75 // it's empty. 76 func loadMetadata(file *os.File, tail uint64) (*freezerTableMeta, error) { 77 stat, err := file.Stat() 78 if err != nil { 79 return nil, err 80 } 81 // Write the metadata with the given actual tail into metadata file 82 // if it's non-existent. There are two possible scenarios here: 83 // - the freezer table is empty 84 // - the freezer table is legacy 85 // In both cases, write the meta into the file with the actual tail 86 // as the virtual tail. 87 if stat.Size() == 0 { 88 m := newMetadata(tail) 89 if err := writeMetadata(file, m); err != nil { 90 return nil, err 91 } 92 return m, nil 93 } 94 m, err := readMetadata(file) 95 if err != nil { 96 return nil, err 97 } 98 // Update the virtual tail with the given actual tail if it's even 99 // lower than it. Theoretically it shouldn't happen at all, print 100 // a warning here. 101 if m.VirtualTail < tail { 102 log.Warn("Updated virtual tail", "have", m.VirtualTail, "now", tail) 103 m.VirtualTail = tail 104 if err := writeMetadata(file, m); err != nil { 105 return nil, err 106 } 107 } 108 return m, nil 109 }