go.etcd.io/etcd@v3.3.27+incompatible/etcdserver/storage.go (about) 1 // Copyright 2015 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package etcdserver 16 17 import ( 18 "io" 19 20 pb "github.com/coreos/etcd/etcdserver/etcdserverpb" 21 "github.com/coreos/etcd/pkg/pbutil" 22 "github.com/coreos/etcd/pkg/types" 23 "github.com/coreos/etcd/raft/raftpb" 24 "github.com/coreos/etcd/snap" 25 "github.com/coreos/etcd/wal" 26 "github.com/coreos/etcd/wal/walpb" 27 ) 28 29 type Storage interface { 30 // Save function saves ents and state to the underlying stable storage. 31 // Save MUST block until st and ents are on stable storage. 32 Save(st raftpb.HardState, ents []raftpb.Entry) error 33 // SaveSnap function saves snapshot to the underlying stable storage. 34 SaveSnap(snap raftpb.Snapshot) error 35 // Close closes the Storage and performs finalization. 36 Close() error 37 // Release releases the locked wal files older than the provided snapshot. 38 Release(snap raftpb.Snapshot) error 39 // Sync WAL 40 Sync() error 41 } 42 43 type storage struct { 44 *wal.WAL 45 *snap.Snapshotter 46 } 47 48 func NewStorage(w *wal.WAL, s *snap.Snapshotter) Storage { 49 return &storage{w, s} 50 } 51 52 // SaveSnap saves the snapshot file to disk and writes the WAL snapshot entry. 53 func (st *storage) SaveSnap(snap raftpb.Snapshot) error { 54 walsnap := walpb.Snapshot{ 55 Index: snap.Metadata.Index, 56 Term: snap.Metadata.Term, 57 } 58 59 // save the snapshot file before writing the snapshot to the wal. 60 // This makes it possible for the snapshot file to become orphaned, but prevents 61 // a WAL snapshot entry from having no corresponding snapshot file. 62 err := st.Snapshotter.SaveSnap(snap) 63 if err != nil { 64 return err 65 } 66 67 return st.WAL.SaveSnapshot(walsnap) 68 } 69 70 // Release releases resources older than the given snap and are no longer needed: 71 // - releases the locks to the wal files that are older than the provided wal for the given snap. 72 // - deletes any .snap.db files that are older than the given snap. 73 func (st *storage) Release(snap raftpb.Snapshot) error { 74 if err := st.WAL.ReleaseLockTo(snap.Metadata.Index); err != nil { 75 return err 76 } 77 return st.Snapshotter.ReleaseSnapDBs(snap) 78 } 79 80 func readWAL(waldir string, snap walpb.Snapshot) (w *wal.WAL, id, cid types.ID, st raftpb.HardState, ents []raftpb.Entry) { 81 var ( 82 err error 83 wmetadata []byte 84 ) 85 86 repaired := false 87 for { 88 if w, err = wal.Open(waldir, snap); err != nil { 89 plog.Fatalf("open wal error: %v", err) 90 } 91 if wmetadata, st, ents, err = w.ReadAll(); err != nil { 92 w.Close() 93 // we can only repair ErrUnexpectedEOF and we never repair twice. 94 if repaired || err != io.ErrUnexpectedEOF { 95 plog.Fatalf("read wal error (%v) and cannot be repaired", err) 96 } 97 if !wal.Repair(waldir) { 98 plog.Fatalf("WAL error (%v) cannot be repaired", err) 99 } else { 100 plog.Infof("repaired WAL error (%v)", err) 101 repaired = true 102 } 103 continue 104 } 105 break 106 } 107 var metadata pb.Metadata 108 pbutil.MustUnmarshal(&metadata, wmetadata) 109 id = types.ID(metadata.NodeID) 110 cid = types.ID(metadata.ClusterID) 111 return w, id, cid, st, ents 112 }