go.etcd.io/etcd@v3.3.27+incompatible/snap/db.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 snap 16 17 import ( 18 "errors" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "time" 25 26 "github.com/coreos/etcd/pkg/fileutil" 27 ) 28 29 var ErrNoDBSnapshot = errors.New("snap: snapshot file doesn't exist") 30 31 // SaveDBFrom saves snapshot of the database from the given reader. It 32 // guarantees the save operation is atomic. 33 func (s *Snapshotter) SaveDBFrom(r io.Reader, id uint64) (int64, error) { 34 start := time.Now() 35 36 f, err := ioutil.TempFile(s.dir, "tmp") 37 if err != nil { 38 return 0, err 39 } 40 var n int64 41 n, err = io.Copy(f, r) 42 if err == nil { 43 fsyncStart := time.Now() 44 err = fileutil.Fsync(f) 45 snapDBFsyncSec.Observe(time.Since(fsyncStart).Seconds()) 46 } 47 f.Close() 48 if err != nil { 49 os.Remove(f.Name()) 50 return n, err 51 } 52 fn := s.dbFilePath(id) 53 if fileutil.Exist(fn) { 54 os.Remove(f.Name()) 55 return n, nil 56 } 57 err = os.Rename(f.Name(), fn) 58 if err != nil { 59 os.Remove(f.Name()) 60 return n, err 61 } 62 63 plog.Infof("saved database snapshot to disk [total bytes: %d]", n) 64 65 snapDBSaveSec.Observe(time.Since(start).Seconds()) 66 return n, nil 67 } 68 69 // DBFilePath returns the file path for the snapshot of the database with 70 // given id. If the snapshot does not exist, it returns error. 71 func (s *Snapshotter) DBFilePath(id uint64) (string, error) { 72 if _, err := fileutil.ReadDir(s.dir); err != nil { 73 return "", err 74 } 75 if fn := s.dbFilePath(id); fileutil.Exist(fn) { 76 return fn, nil 77 } 78 return "", ErrNoDBSnapshot 79 } 80 81 func (s *Snapshotter) dbFilePath(id uint64) string { 82 return filepath.Join(s.dir, fmt.Sprintf("%016x.snap.db", id)) 83 }