// Restore takes the snapshot from the reader and attempts to apply it to the // given Raft instance. func Restore(logger *log.Logger, in io.Reader, r *raft.Raft) error { // Wrap the reader in a gzip decompressor. decomp, err := gzip.NewReader(in) if err != nil { return fmt.Errorf("failed to decompress snapshot: %v", err) } defer func() { if err := decomp.Close(); err != nil { logger.Printf("[ERR] snapshot: Failed to close snapshot decompressor: %v", err) } }() // Make a scratch file to receive the contents of the snapshot data so // we can avoid buffering in memory. snap, err := ioutil.TempFile("", "snapshot") if err != nil { return fmt.Errorf("failed to create temp snapshot file: %v", err) } defer func() { if err := snap.Close(); err != nil { logger.Printf("[ERR] snapshot: Failed to close temp snapshot: %v", err) } if err := os.Remove(snap.Name()); err != nil { logger.Printf("[ERR] snapshot: Failed to clean up temp snapshot: %v", err) } }() // Read the archive. var metadata raft.SnapshotMeta if err := read(decomp, &metadata, snap); err != nil { return fmt.Errorf("failed to read snapshot file: %v", err) } // Sync and rewind the file so it's ready to be read again. if err := snap.Sync(); err != nil { return fmt.Errorf("failed to sync temp snapshot: %v", err) } if _, err := snap.Seek(0, 0); err != nil { return fmt.Errorf("failed to rewind temp snapshot: %v", err) } // Feed the snapshot into Raft. if err := r.Restore(&metadata, snap, 60*time.Second); err != nil { return fmt.Errorf("Raft error when restoring snapshot: %v", err) } return nil }