vitess.io/vitess@v0.16.2/go/vt/mysqlctl/filebackupstorage/file.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package filebackupstorage implements the BackupStorage interface
    18  // for a local filesystem (which can be an NFS mount).
    19  package filebackupstorage
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"io"
    25  	"os"
    26  	"path"
    27  
    28  	"github.com/spf13/pflag"
    29  
    30  	"vitess.io/vitess/go/vt/concurrency"
    31  	"vitess.io/vitess/go/vt/mysqlctl/backupstorage"
    32  	"vitess.io/vitess/go/vt/servenv"
    33  )
    34  
    35  var (
    36  	// FileBackupStorageRoot is where the backups will go.
    37  	// Exported for test purposes.
    38  	FileBackupStorageRoot string
    39  )
    40  
    41  func registerFlags(fs *pflag.FlagSet) {
    42  	fs.StringVar(&FileBackupStorageRoot, "file_backup_storage_root", "", "Root directory for the file backup storage.")
    43  }
    44  
    45  func init() {
    46  	servenv.OnParseFor("vtbackup", registerFlags)
    47  	servenv.OnParseFor("vtctl", registerFlags)
    48  	servenv.OnParseFor("vtctld", registerFlags)
    49  	servenv.OnParseFor("vttablet", registerFlags)
    50  }
    51  
    52  // FileBackupHandle implements BackupHandle for local file system.
    53  type FileBackupHandle struct {
    54  	fbs      *FileBackupStorage
    55  	dir      string
    56  	name     string
    57  	readOnly bool
    58  	errors   concurrency.AllErrorRecorder
    59  }
    60  
    61  // RecordError is part of the concurrency.ErrorRecorder interface.
    62  func (fbh *FileBackupHandle) RecordError(err error) {
    63  	fbh.errors.RecordError(err)
    64  }
    65  
    66  // HasErrors is part of the concurrency.ErrorRecorder interface.
    67  func (fbh *FileBackupHandle) HasErrors() bool {
    68  	return fbh.errors.HasErrors()
    69  }
    70  
    71  // Error is part of the concurrency.ErrorRecorder interface.
    72  func (fbh *FileBackupHandle) Error() error {
    73  	return fbh.errors.Error()
    74  }
    75  
    76  // Directory is part of the BackupHandle interface
    77  func (fbh *FileBackupHandle) Directory() string {
    78  	return fbh.dir
    79  }
    80  
    81  // Name is part of the BackupHandle interface
    82  func (fbh *FileBackupHandle) Name() string {
    83  	return fbh.name
    84  }
    85  
    86  // AddFile is part of the BackupHandle interface
    87  func (fbh *FileBackupHandle) AddFile(ctx context.Context, filename string, filesize int64) (io.WriteCloser, error) {
    88  	if fbh.readOnly {
    89  		return nil, fmt.Errorf("AddFile cannot be called on read-only backup")
    90  	}
    91  	p := path.Join(FileBackupStorageRoot, fbh.dir, fbh.name, filename)
    92  	return os.Create(p)
    93  }
    94  
    95  // EndBackup is part of the BackupHandle interface
    96  func (fbh *FileBackupHandle) EndBackup(ctx context.Context) error {
    97  	if fbh.readOnly {
    98  		return fmt.Errorf("EndBackup cannot be called on read-only backup")
    99  	}
   100  	return nil
   101  }
   102  
   103  // AbortBackup is part of the BackupHandle interface
   104  func (fbh *FileBackupHandle) AbortBackup(ctx context.Context) error {
   105  	if fbh.readOnly {
   106  		return fmt.Errorf("AbortBackup cannot be called on read-only backup")
   107  	}
   108  	return fbh.fbs.RemoveBackup(ctx, fbh.dir, fbh.name)
   109  }
   110  
   111  // ReadFile is part of the BackupHandle interface
   112  func (fbh *FileBackupHandle) ReadFile(ctx context.Context, filename string) (io.ReadCloser, error) {
   113  	if !fbh.readOnly {
   114  		return nil, fmt.Errorf("ReadFile cannot be called on read-write backup")
   115  	}
   116  	p := path.Join(FileBackupStorageRoot, fbh.dir, fbh.name, filename)
   117  	return os.Open(p)
   118  }
   119  
   120  // FileBackupStorage implements BackupStorage for local file system.
   121  type FileBackupStorage struct{}
   122  
   123  // ListBackups is part of the BackupStorage interface
   124  func (fbs *FileBackupStorage) ListBackups(ctx context.Context, dir string) ([]backupstorage.BackupHandle, error) {
   125  	// ReadDir already sorts the results
   126  	p := path.Join(FileBackupStorageRoot, dir)
   127  	fi, err := os.ReadDir(p)
   128  	if err != nil {
   129  		if os.IsNotExist(err) {
   130  			return nil, nil
   131  		}
   132  		return nil, err
   133  	}
   134  
   135  	result := make([]backupstorage.BackupHandle, 0, len(fi))
   136  	for _, info := range fi {
   137  		if !info.IsDir() {
   138  			continue
   139  		}
   140  		if info.Name() == "." || info.Name() == ".." {
   141  			continue
   142  		}
   143  		result = append(result, &FileBackupHandle{
   144  			fbs:      fbs,
   145  			dir:      dir,
   146  			name:     info.Name(),
   147  			readOnly: true,
   148  		})
   149  	}
   150  	return result, nil
   151  }
   152  
   153  // StartBackup is part of the BackupStorage interface
   154  func (fbs *FileBackupStorage) StartBackup(ctx context.Context, dir, name string) (backupstorage.BackupHandle, error) {
   155  	// Make sure the directory exists.
   156  	p := path.Join(FileBackupStorageRoot, dir)
   157  	if err := os.MkdirAll(p, os.ModePerm); err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	// Create the subdirectory for this named backup.
   162  	p = path.Join(p, name)
   163  	if err := os.Mkdir(p, os.ModePerm); err != nil {
   164  		return nil, err
   165  	}
   166  
   167  	return &FileBackupHandle{
   168  		fbs:      fbs,
   169  		dir:      dir,
   170  		name:     name,
   171  		readOnly: false,
   172  	}, nil
   173  }
   174  
   175  // RemoveBackup is part of the BackupStorage interface
   176  func (fbs *FileBackupStorage) RemoveBackup(ctx context.Context, dir, name string) error {
   177  	p := path.Join(FileBackupStorageRoot, dir, name)
   178  	return os.RemoveAll(p)
   179  }
   180  
   181  // Close implements BackupStorage.
   182  func (fbs *FileBackupStorage) Close() error {
   183  	return nil
   184  }
   185  
   186  func init() {
   187  	backupstorage.BackupStorageMap["file"] = &FileBackupStorage{}
   188  }