shutdown_tracker.go 2.6 KB

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