func (s *EtcdServer) snapshot(snapi uint64, confState raftpb.ConfState) {
	clone := s.v2store.Clone()
	// commit kv to write metadata (for example: consistent index) to disk.
	// KV().commit() updates the consistent index in backend.
	// All operations that update consistent index must be called sequentially
	// from applyAll function.
	// So KV().Commit() cannot run in parallel with apply. It has to be called outside
	// the go routine created below.
	s.KV().Commit()

	s.goAttach(func() {
		lg := s.getLogger()

		d, err := clone.SaveNoCopy()
		// TODO: current store will never fail to do a snapshot
		// what should we do if the store might fail?
		if err != nil {
			if lg != nil {
				lg.Panic("failed to save v2 store", zap.Error(err))
			} else {
				plog.Panicf("store save should never fail: %v", err)
			}
		}
		snap, err := s.r.raftStorage.CreateSnapshot(snapi, &confState, d)
		if err != nil {
			// the snapshot was done asynchronously with the progress of raft.
			// raft might have already got a newer snapshot.
			if err == raft.ErrSnapOutOfDate {
				return
			}
			if lg != nil {
				lg.Panic("failed to create snapshot", zap.Error(err))
			} else {
				plog.Panicf("unexpected create snapshot error %v", err)
			}
		}
		// SaveSnap saves the snapshot and releases the locked wal files
		// to the snapshot index.
		if err = s.r.storage.SaveSnap(snap); err != nil {
			if lg != nil {
				lg.Panic("failed to save snapshot", zap.Error(err))
			} else {
				plog.Fatalf("save snapshot error: %v", err)
			}
		}
		if lg != nil {
			lg.Info(
				"saved snapshot",
				zap.Uint64("snapshot-index", snap.Metadata.Index),
			)
		} else {
			plog.Infof("saved snapshot at index %d", snap.Metadata.Index)
		}

		// When sending a snapshot, etcd will pause compaction.
		// After receives a snapshot, the slow follower needs to get all the entries right after
		// the snapshot sent to catch up. If we do not pause compaction, the log entries right after
		// the snapshot sent might already be compacted. It happens when the snapshot takes long time
		// to send and save. Pausing compaction avoids triggering a snapshot sending cycle.
		if atomic.LoadInt64(&s.inflightSnapshots) != 0 {
			if lg != nil {
				lg.Info("skip compaction since there is an inflight snapshot")
			} else {
				plog.Infof("skip compaction since there is an inflight snapshot")
			}
			return
		}

		// keep some in memory log entries for slow followers.
		compacti := uint64(1)
		if snapi > s.Cfg.SnapshotCatchUpEntries {
			compacti = snapi - s.Cfg.SnapshotCatchUpEntries
		}

		err = s.r.raftStorage.Compact(compacti)
		if err != nil {
			// the compaction was done asynchronously with the progress of raft.
			// raft log might already been compact.
			if err == raft.ErrCompacted {
				return
			}
			if lg != nil {
				lg.Panic("failed to compact", zap.Error(err))
			} else {
				plog.Panicf("unexpected compaction error %v", err)
			}
		}
		if lg != nil {
			lg.Info(
				"compacted Raft logs",
				zap.Uint64("compact-index", compacti),
			)
		} else {
			plog.Infof("compacted raft log at %d", compacti)
		}
	})
}
func (s *EtcdServer) snapshot(snapi uint64, confState raftpb.ConfState) {
	clone := s.v2store.Clone()
	// commit kv to write metadata (for example: consistent index) to disk.
	// KV().commit() updates the consistent index in backend.
	// All operations that update consistent index must be called sequentially
	// from applyAll function.
	// So KV().Commit() cannot run in parallel with apply. It has to be called outside
	// the go routine created below.
	s.KV().Commit()

	s.goAttach(func() {
		lg := s.getLogger()

		d, err := clone.SaveNoCopy()
		// TODO: current store will never fail to do a snapshot
		// what should we do if the store might fail?
		if err != nil {
			if lg != nil {
				lg.Panic("failed to save v2 store", zap.Error(err))
			} else {
				plog.Panicf("store save should never fail: %v", err)
			}
		}
		snap, err := s.r.raftStorage.CreateSnapshot(snapi, &confState, d)
		if err != nil {
			// the snapshot was done asynchronously with the progress of raft.
			// raft might have already got a newer snapshot.
			if err == raft.ErrSnapOutOfDate {
				return
			}
			if lg != nil {
				lg.Panic("failed to create snapshot", zap.Error(err))
			} else {
				plog.Panicf("unexpected create snapshot error %v", err)
			}
		}
		// SaveSnap saves the snapshot and releases the locked wal files
		// to the snapshot index.
		if err = s.r.storage.SaveSnap(snap); err != nil {
			if lg != nil {
				lg.Panic("failed to save snapshot", zap.Error(err))
			} else {
				plog.Fatalf("save snapshot error: %v", err)
			}
		}
		if lg != nil {
			lg.Info(
				"saved snapshot",
				zap.Uint64("snapshot-index", snap.Metadata.Index),
			)
		} else {
			plog.Infof("saved snapshot at index %d", snap.Metadata.Index)
		}

		// When sending a snapshot, etcd will pause compaction.
		// After receives a snapshot, the slow follower needs to get all the entries right after
		// the snapshot sent to catch up. If we do not pause compaction, the log entries right after
		// the snapshot sent might already be compacted. It happens when the snapshot takes long time
		// to send and save. Pausing compaction avoids triggering a snapshot sending cycle.
		if atomic.LoadInt64(&s.inflightSnapshots) != 0 {
			if lg != nil {
				lg.Info("skip compaction since there is an inflight snapshot")
			} else {
				plog.Infof("skip compaction since there is an inflight snapshot")
			}
			return
		}

		// keep some in memory log entries for slow followers.
		compacti := uint64(1)
		if snapi > s.Cfg.SnapshotCatchUpEntries {
			compacti = snapi - s.Cfg.SnapshotCatchUpEntries
		}

		err = s.r.raftStorage.Compact(compacti)
		if err != nil {
			// the compaction was done asynchronously with the progress of raft.
			// raft log might already been compact.
			if err == raft.ErrCompacted {
				return
			}
			if lg != nil {
				lg.Panic("failed to compact", zap.Error(err))
			} else {
				plog.Panicf("unexpected compaction error %v", err)
			}
		}
		if lg != nil {
			lg.Info(
				"compacted Raft logs",
				zap.Uint64("compact-index", compacti),
			)
		} else {
			plog.Infof("compacted raft log at %d", compacti)
		}
	})
}
// TODO: non-blocking snapshot