You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
2.3 KiB

8 years ago
8 years ago
8 years ago
  1. package consensus
  2. import (
  3. "time"
  4. auto "github.com/tendermint/go-autofile"
  5. . "github.com/tendermint/go-common"
  6. "github.com/tendermint/go-wire"
  7. "github.com/tendermint/tendermint/types"
  8. )
  9. //--------------------------------------------------------
  10. // types and functions for savings consensus messages
  11. type TimedWALMessage struct {
  12. Time time.Time `json:"time"`
  13. Msg WALMessage `json:"msg"`
  14. }
  15. type WALMessage interface{}
  16. var _ = wire.RegisterInterface(
  17. struct{ WALMessage }{},
  18. wire.ConcreteType{types.EventDataRoundState{}, 0x01},
  19. wire.ConcreteType{msgInfo{}, 0x02},
  20. wire.ConcreteType{timeoutInfo{}, 0x03},
  21. )
  22. //--------------------------------------------------------
  23. // Simple write-ahead logger
  24. // Write ahead logger writes msgs to disk before they are processed.
  25. // Can be used for crash-recovery and deterministic replay
  26. // TODO: currently the wal is overwritten during replay catchup
  27. // give it a mode so it's either reading or appending - must read to end to start appending again
  28. // TODO: #HEIGHT 1 is never printed ...
  29. type WAL struct {
  30. BaseService
  31. group *auto.Group
  32. light bool // ignore block parts
  33. }
  34. func NewWAL(walDir string, light bool) (*WAL, error) {
  35. head, err := auto.OpenAutoFile(walDir + "/wal")
  36. if err != nil {
  37. return nil, err
  38. }
  39. group, err := auto.OpenGroup(head)
  40. if err != nil {
  41. return nil, err
  42. }
  43. wal := &WAL{
  44. group: group,
  45. light: light,
  46. }
  47. wal.BaseService = *NewBaseService(log, "WAL", wal)
  48. return wal, nil
  49. }
  50. func (wal *WAL) OnStop() {
  51. wal.BaseService.OnStop()
  52. wal.group.Head.Close()
  53. wal.group.Close()
  54. }
  55. // called in newStep and for each pass in receiveRoutine
  56. func (wal *WAL) Save(wmsg WALMessage) {
  57. if wal == nil {
  58. return
  59. }
  60. if wal.light {
  61. // in light mode we only write new steps, timeouts, and our own votes (no proposals, block parts)
  62. if mi, ok := wmsg.(msgInfo); ok {
  63. _ = mi
  64. if mi.PeerKey != "" {
  65. return
  66. }
  67. }
  68. }
  69. // Write #HEIGHT: XYZ if new height
  70. if edrs, ok := wmsg.(types.EventDataRoundState); ok {
  71. if edrs.Step == RoundStepNewHeight.String() {
  72. wal.group.WriteLine(Fmt("#HEIGHT: %v", edrs.Height))
  73. }
  74. }
  75. // Write the wal message
  76. var wmsgBytes = wire.JSONBytes(TimedWALMessage{time.Now(), wmsg})
  77. err := wal.group.WriteLine(string(wmsgBytes))
  78. if err != nil {
  79. PanicQ(Fmt("Error writing msg to consensus wal. Error: %v \n\nMessage: %v", err, wmsg))
  80. }
  81. }