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  }