github.com/aergoio/aergo@v1.3.1/consensus/impl/raftv2/waldb.go (about) 1 package raftv2 2 3 import ( 4 "errors" 5 "github.com/aergoio/aergo/consensus" 6 "github.com/aergoio/aergo/types" 7 "github.com/aergoio/etcd/raft" 8 "github.com/aergoio/etcd/raft/raftpb" 9 ) 10 11 var ( 12 ErrInvalidEntry = errors.New("Invalid raftpb.entry") 13 ErrWalEntryTooLowTerm = errors.New("term of wal entry is too low") 14 ) 15 16 type WalDB struct { 17 consensus.ChainWAL 18 } 19 20 func NewWalDB(chainWal consensus.ChainWAL) *WalDB { 21 return &WalDB{chainWal} 22 } 23 24 func (wal *WalDB) SaveEntry(state raftpb.HardState, entries []raftpb.Entry) error { 25 if len(entries) != 0 { 26 walEnts, blocks, confChanges := wal.convertFromRaft(entries) 27 28 if err := wal.WriteRaftEntry(walEnts, blocks, confChanges); err != nil { 29 return err 30 } 31 } 32 33 // hardstate must save after entries since entries may include commited one 34 if !raft.IsEmptyHardState(state) { 35 // save hardstate 36 if err := wal.WriteHardState(&state); err != nil { 37 return err 38 } 39 } 40 41 return nil 42 } 43 44 func (wal *WalDB) convertFromRaft(entries []raftpb.Entry) ([]*consensus.WalEntry, []*types.Block, []*raftpb.ConfChange) { 45 lenEnts := len(entries) 46 if lenEnts == 0 { 47 return nil, nil, nil 48 } 49 50 getWalEntryType := func(entry *raftpb.Entry) consensus.EntryType { 51 switch entry.Type { 52 case raftpb.EntryNormal: 53 if entry.Data != nil { 54 return consensus.EntryBlock 55 } else { 56 return consensus.EntryEmpty 57 } 58 case raftpb.EntryConfChange: 59 return consensus.EntryConfChange 60 default: 61 panic("not support raftpb entrytype") 62 } 63 } 64 65 getWalData := func(entry *raftpb.Entry) (*types.Block, []byte, error) { 66 if entry.Type == raftpb.EntryNormal && entry.Data != nil { 67 block, err := unmarshalEntryData(entry.Data) 68 if err != nil { 69 logger.Error().Str("entry", types.RaftEntryToString(entry)).Msg("failed to unmarshal entry") 70 return nil, nil, ErrInvalidEntry 71 } 72 73 return block, block.BlockHash(), nil 74 } else { 75 return nil, entry.Data, nil 76 } 77 } 78 79 getConfChange := func(entry *raftpb.Entry) (*raftpb.ConfChange, error) { 80 if entry.Type == raftpb.EntryConfChange { 81 cc, _, err := unmarshalConfChangeEntry(entry) 82 if err != nil { 83 logger.Error().Str("entry", types.RaftEntryToString(entry)).Msg("failed to unmarshal entry") 84 return nil, ErrInvalidEntry 85 } 86 return cc, nil 87 } 88 89 return nil, nil 90 } 91 92 blocks := make([]*types.Block, lenEnts) 93 walents := make([]*consensus.WalEntry, lenEnts) 94 confChanges := make([]*raftpb.ConfChange, lenEnts) 95 96 var ( 97 data []byte 98 err error 99 ) 100 for i, entry := range entries { 101 if blocks[i], data, err = getWalData(&entry); err != nil { 102 panic("entry unmarshalEntryData error") 103 } 104 105 if confChanges[i], err = getConfChange(&entry); err != nil { 106 panic("entry unmarshalEntryConfChange error") 107 } 108 109 walents[i] = &consensus.WalEntry{ 110 Type: getWalEntryType(&entry), 111 Term: entry.Term, 112 Index: entry.Index, 113 Data: data, 114 } 115 } 116 117 return walents, blocks, confChanges 118 } 119 120 var ErrInvalidWalEntry = errors.New("invalid wal entry") 121 var ErrWalConvBlock = errors.New("failed to convert bytes of block from wal entry") 122 123 func (wal *WalDB) convertWalToRaft(walEntry *consensus.WalEntry) (*raftpb.Entry, error) { 124 var raftEntry = &raftpb.Entry{Term: walEntry.Term, Index: walEntry.Index} 125 126 getDataFromWalEntry := func(walEntry *consensus.WalEntry) ([]byte, error) { 127 if walEntry.Type != consensus.EntryBlock { 128 return nil, ErrWalConvBlock 129 } 130 block, err := wal.GetBlock(walEntry.Data) 131 if err != nil { 132 return nil, err 133 } 134 data, err := marshalEntryData(block) 135 if err != nil { 136 return nil, err 137 } 138 139 return data, nil 140 } 141 142 switch walEntry.Type { 143 case consensus.EntryConfChange: 144 raftEntry.Type = raftpb.EntryConfChange 145 raftEntry.Data = walEntry.Data 146 147 case consensus.EntryEmpty: 148 raftEntry.Type = raftpb.EntryNormal 149 raftEntry.Data = nil 150 151 case consensus.EntryBlock: 152 data, err := getDataFromWalEntry(walEntry) 153 if err != nil { 154 return nil, err 155 } 156 raftEntry.Data = data 157 default: 158 return nil, ErrInvalidWalEntry 159 } 160 161 return raftEntry, nil 162 } 163 164 var ( 165 ErrWalGetHardState = errors.New("failed to read hard state") 166 ErrWalGetLastIdx = errors.New("failed to read last Idx") 167 ) 168 169 // ReadAll returns hard state, all uncommitted entries 170 // - read last hard state 171 // - read all uncommited entries after snapshot index 172 func (wal *WalDB) ReadAll(snapshot *raftpb.Snapshot) (id *consensus.RaftIdentity, state *raftpb.HardState, ents []raftpb.Entry, err error) { 173 if id, err = wal.GetIdentity(); err != nil { 174 return nil, state, ents, err 175 } 176 177 state, err = wal.GetHardState() 178 if err != nil { 179 return id, state, ents, ErrWalGetHardState 180 } 181 182 commitIdx := state.Commit 183 lastIdx, err := wal.GetRaftEntryLastIdx() 184 if err != nil { 185 return id, state, ents, ErrWalGetLastIdx 186 } 187 188 var snapIdx, snapTerm uint64 189 if snapshot != nil { 190 snapIdx = snapshot.Metadata.Index 191 snapTerm = snapshot.Metadata.Term 192 } 193 194 logger.Info().Uint64("snapidx", snapIdx).Uint64("snapterm", snapTerm).Uint64("commit", commitIdx).Uint64("last", lastIdx).Msg("read all entries of wal") 195 196 start := snapIdx + 1 197 198 for i := start; i <= lastIdx; i++ { 199 walEntry, err := wal.GetRaftEntry(i) 200 // if snapshot is nil, initial confchange entry isn't saved to db 201 if err != nil { 202 logger.Error().Err(err).Uint64("idx", i).Msg("failed to get raft entry") 203 return id, state, nil, err 204 } 205 206 if walEntry.Term < snapTerm { 207 logger.Error().Str("wal", walEntry.ToString()).Err(ErrWalEntryTooLowTerm).Msg("invalid wal entry") 208 return id, state, nil, ErrWalEntryTooLowTerm 209 } 210 211 raftEntry, err := wal.convertWalToRaft(walEntry) 212 if err != nil { 213 return id, state, nil, err 214 } 215 216 logger.Debug().Str("walentry", walEntry.ToString()).Msg("read wal entry") 217 ents = append(ents, *raftEntry) 218 } 219 220 return id, state, ents, nil 221 }