Skip to content

Commit

Permalink
chanbackup: archive old channel backups
Browse files Browse the repository at this point in the history
In this commit, we first check if a previous backup file exists,
if it does we copy it to archive folder before replacing it with
a new backup file.
  • Loading branch information
Abdulkbk committed Nov 24, 2024
1 parent 94f7ed4 commit a4d6827
Showing 1 changed file with 71 additions and 0 deletions.
71 changes: 71 additions & 0 deletions chanbackup/backupfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package chanbackup

import (
"fmt"
"io"
"os"
"path/filepath"
"time"

"github.com/lightningnetwork/lnd/keychain"
)
Expand All @@ -17,6 +19,10 @@ const (
// file that we'll use to atomically update the primary back up file
// when new channel are detected.
DefaultTempBackupFileName = "temp-dont-use.backup"

// DefaultChanBackupDirName is the default name of the directory that
// we'll use to store old channel backups.
DefaultChanBackupArchiveDirName = "channelarchives"
)

var (
Expand Down Expand Up @@ -44,6 +50,9 @@ type MultiFile struct {

// tempFile is an open handle to the temp back up file.
tempFile *os.File

// archiveDir is the directory where we'll store old channel backups.
archiveDir string
}

// NewMultiFile create a new multi-file instance at the target location on the
Expand All @@ -56,10 +65,14 @@ func NewMultiFile(fileName string) *MultiFile {
tempFileName := filepath.Join(
backupFileDir, DefaultTempBackupFileName,
)
archiveDir := filepath.Join(
backupFileDir, DefaultChanBackupArchiveDirName,
)

return &MultiFile{
fileName: fileName,
tempFileName: tempFileName,
archiveDir: archiveDir,
}
}

Expand Down Expand Up @@ -117,6 +130,19 @@ func (b *MultiFile) UpdateAndSwap(newBackup PackedMulti) error {
return fmt.Errorf("unable to close file: %w", err)
}

// We check if the main backup file exists, if it does we archive it
// before replacing it with the new backup.
if _, err := os.Stat(b.fileName); err == nil {
log.Infof("Archiving old backup file at %v", b.fileName)

if err := createArchiveFile(
b.archiveDir, b.fileName,
); err != nil {
return fmt.Errorf("unable to archive old backup file:"+
" %w", err)
}
}

// Finally, we'll attempt to atomically rename the temporary file to
// the main back up file. If this succeeds, then we'll only have a
// single file on disk once this method exits.
Expand Down Expand Up @@ -147,3 +173,48 @@ func (b *MultiFile) ExtractMulti(keyChain keychain.KeyRing) (*Multi, error) {
packedMulti := PackedMulti(multiBytes)
return packedMulti.Unpack(keyChain)
}

func createArchiveFile(archiveDir string, fileName string) error {
// Generate archive file path with timestamped name.
baseFileName := filepath.Base(fileName)
timestamp := time.Now().Format("2006-01-02-15-04-05")

archiveFileName := fmt.Sprintf("%s-%s", baseFileName, timestamp)
archiveFilePath := filepath.Join(archiveDir, archiveFileName)

oldBackupFile, err := os.Open(fileName)
if err != nil {
return fmt.Errorf("unable to open old backup file: %w", err)
}
defer func() {
if cerr := oldBackupFile.Close(); cerr != nil && err == nil {
err = fmt.Errorf("error closing old backup file: %w",
cerr)
}
}()

// Ensure the archive directory exists. If it doesn't we create it.
const archiveDirPermissions = 0o755
err = os.MkdirAll(archiveDir, archiveDirPermissions)
if err != nil {
return fmt.Errorf("unable to create archive directory: %w", err)
}

// Create new archive file.
archiveFile, err := os.Create(archiveFilePath)
if err != nil {
return fmt.Errorf("unable to create archive file: %w", err)
}
defer func() {
if cerr := archiveFile.Close(); cerr != nil && err == nil {
err = fmt.Errorf("error closing archive file: %w", cerr)
}
}()

// Copy contents of old backup to the newly created archive file.
if _, err := io.Copy(archiveFile, oldBackupFile); err != nil {
return fmt.Errorf("error copying to archive file: %w", err)
}

return nil
}

0 comments on commit a4d6827

Please sign in to comment.