github.com/MetalBlockchain/subnet-evm@v0.4.9/internal/shutdowncheck/shutdown_tracker.go (about)

     1  // (c) 2020-2021, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2021 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package shutdowncheck
    28  
    29  import (
    30  	"time"
    31  
    32  	"github.com/MetalBlockchain/subnet-evm/core/rawdb"
    33  	"github.com/MetalBlockchain/subnet-evm/ethdb"
    34  	"github.com/ethereum/go-ethereum/common"
    35  	"github.com/ethereum/go-ethereum/log"
    36  )
    37  
    38  // ShutdownTracker is a service that reports previous unclean shutdowns
    39  // upon start. It needs to be started after a successful start-up and stopped
    40  // after a successful shutdown, just before the db is closed.
    41  type ShutdownTracker struct {
    42  	db     ethdb.Database
    43  	stopCh chan struct{}
    44  }
    45  
    46  // NewShutdownTracker creates a new ShutdownTracker instance and has
    47  // no other side-effect.
    48  func NewShutdownTracker(db ethdb.Database) *ShutdownTracker {
    49  	return &ShutdownTracker{
    50  		db:     db,
    51  		stopCh: make(chan struct{}),
    52  	}
    53  }
    54  
    55  // MarkStartup is to be called in the beginning when the node starts. It will:
    56  // - Push a new startup marker to the db
    57  // - Report previous unclean shutdowns
    58  func (t *ShutdownTracker) MarkStartup() {
    59  	if uncleanShutdowns, discards, err := rawdb.PushUncleanShutdownMarker(t.db); err != nil {
    60  		log.Error("Could not update unclean-shutdown-marker list", "error", err)
    61  	} else {
    62  		if discards > 0 {
    63  			log.Warn("Old unclean shutdowns found", "count", discards)
    64  		}
    65  		for _, tstamp := range uncleanShutdowns {
    66  			t := time.Unix(int64(tstamp), 0)
    67  			log.Warn("Unclean shutdown detected", "booted", t,
    68  				"age", common.PrettyAge(t))
    69  		}
    70  	}
    71  }
    72  
    73  // Start runs an event loop that updates the current marker's timestamp every 5 minutes.
    74  func (t *ShutdownTracker) Start() {
    75  	go func() {
    76  		ticker := time.NewTicker(5 * time.Minute)
    77  		defer ticker.Stop()
    78  		for {
    79  			select {
    80  			case <-ticker.C:
    81  				rawdb.UpdateUncleanShutdownMarker(t.db)
    82  			case <-t.stopCh:
    83  				return
    84  			}
    85  		}
    86  	}()
    87  }
    88  
    89  // Stop will stop the update loop and clear the current marker.
    90  func (t *ShutdownTracker) Stop() {
    91  	// Stop update loop.
    92  	t.stopCh <- struct{}{}
    93  	// Clear last marker.
    94  	rawdb.PopUncleanShutdownMarker(t.db)
    95  }