github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/internal/shutdowncheck/shutdown_tracker.go (about) 1 // Copyright 2021 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 shutdowncheck 18 19 import ( 20 "time" 21 22 "github.com/tirogen/go-ethereum/common" 23 "github.com/tirogen/go-ethereum/core/rawdb" 24 "github.com/tirogen/go-ethereum/ethdb" 25 "github.com/tirogen/go-ethereum/log" 26 ) 27 28 // ShutdownTracker is a service that reports previous unclean shutdowns 29 // upon start. It needs to be started after a successful start-up and stopped 30 // after a successful shutdown, just before the db is closed. 31 type ShutdownTracker struct { 32 db ethdb.Database 33 stopCh chan struct{} 34 } 35 36 // NewShutdownTracker creates a new ShutdownTracker instance and has 37 // no other side-effect. 38 func NewShutdownTracker(db ethdb.Database) *ShutdownTracker { 39 return &ShutdownTracker{ 40 db: db, 41 stopCh: make(chan struct{}), 42 } 43 } 44 45 // MarkStartup is to be called in the beginning when the node starts. It will: 46 // - Push a new startup marker to the db 47 // - Report previous unclean shutdowns 48 func (t *ShutdownTracker) MarkStartup() { 49 if uncleanShutdowns, discards, err := rawdb.PushUncleanShutdownMarker(t.db); err != nil { 50 log.Error("Could not update unclean-shutdown-marker list", "error", err) 51 } else { 52 if discards > 0 { 53 log.Warn("Old unclean shutdowns found", "count", discards) 54 } 55 for _, tstamp := range uncleanShutdowns { 56 t := time.Unix(int64(tstamp), 0) 57 log.Warn("Unclean shutdown detected", "booted", t, 58 "age", common.PrettyAge(t)) 59 } 60 } 61 } 62 63 // Start runs an event loop that updates the current marker's timestamp every 5 minutes. 64 func (t *ShutdownTracker) Start() { 65 go func() { 66 ticker := time.NewTicker(5 * time.Minute) 67 defer ticker.Stop() 68 for { 69 select { 70 case <-ticker.C: 71 rawdb.UpdateUncleanShutdownMarker(t.db) 72 case <-t.stopCh: 73 return 74 } 75 } 76 }() 77 } 78 79 // Stop will stop the update loop and clear the current marker. 80 func (t *ShutdownTracker) Stop() { 81 // Stop update loop. 82 t.stopCh <- struct{}{} 83 // Clear last marker. 84 rawdb.PopUncleanShutdownMarker(t.db) 85 }