1// Copyright 2017 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 15package etcdserver 16 17import ( 18 "fmt" 19 "os" 20 "time" 21 22 "github.com/coreos/etcd/lease" 23 "github.com/coreos/etcd/mvcc" 24 "github.com/coreos/etcd/mvcc/backend" 25 "github.com/coreos/etcd/raft/raftpb" 26 "github.com/coreos/etcd/snap" 27) 28 29func newBackend(cfg ServerConfig) backend.Backend { 30 bcfg := backend.DefaultBackendConfig() 31 bcfg.Path = cfg.backendPath() 32 if cfg.QuotaBackendBytes > 0 && cfg.QuotaBackendBytes != DefaultQuotaBytes { 33 // permit 10% excess over quota for disarm 34 bcfg.MmapSize = uint64(cfg.QuotaBackendBytes + cfg.QuotaBackendBytes/10) 35 } 36 return backend.New(bcfg) 37} 38 39// openSnapshotBackend renames a snapshot db to the current etcd db and opens it. 40func openSnapshotBackend(cfg ServerConfig, ss *snap.Snapshotter, snapshot raftpb.Snapshot) (backend.Backend, error) { 41 snapPath, err := ss.DBFilePath(snapshot.Metadata.Index) 42 if err != nil { 43 return nil, fmt.Errorf("database snapshot file path error: %v", err) 44 } 45 if err := os.Rename(snapPath, cfg.backendPath()); err != nil { 46 return nil, fmt.Errorf("rename snapshot file error: %v", err) 47 } 48 return openBackend(cfg), nil 49} 50 51// openBackend returns a backend using the current etcd db. 52func openBackend(cfg ServerConfig) backend.Backend { 53 fn := cfg.backendPath() 54 beOpened := make(chan backend.Backend) 55 go func() { 56 beOpened <- newBackend(cfg) 57 }() 58 select { 59 case be := <-beOpened: 60 return be 61 case <-time.After(10 * time.Second): 62 plog.Warningf("another etcd process is using %q and holds the file lock, or loading backend file is taking >10 seconds", fn) 63 plog.Warningf("waiting for it to exit before starting...") 64 } 65 return <-beOpened 66} 67 68// recoverBackendSnapshot recovers the DB from a snapshot in case etcd crashes 69// before updating the backend db after persisting raft snapshot to disk, 70// violating the invariant snapshot.Metadata.Index < db.consistentIndex. In this 71// case, replace the db with the snapshot db sent by the leader. 72func recoverSnapshotBackend(cfg ServerConfig, oldbe backend.Backend, snapshot raftpb.Snapshot) (backend.Backend, error) { 73 var cIndex consistentIndex 74 kv := mvcc.New(oldbe, &lease.FakeLessor{}, nil, &cIndex) 75 defer kv.Close() 76 if snapshot.Metadata.Index <= kv.ConsistentIndex() { 77 return oldbe, nil 78 } 79 oldbe.Close() 80 return openSnapshotBackend(cfg, snap.New(cfg.SnapDir()), snapshot) 81} 82