github.com/weaviate/weaviate@v1.24.6/modules/backup-filesystem/backup.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package modstgfs 13 14 import ( 15 "context" 16 "fmt" 17 "io" 18 "os" 19 "path" 20 "path/filepath" 21 22 "github.com/pkg/errors" 23 "github.com/weaviate/weaviate/entities/backup" 24 "github.com/weaviate/weaviate/usecases/monitoring" 25 ) 26 27 func (m *Module) GetObject(ctx context.Context, backupID, key string) ([]byte, error) { 28 metaPath, err := m.getObjectPath(ctx, backupID, key) 29 if err != nil { 30 return nil, err 31 } 32 33 contents, err := os.ReadFile(metaPath) 34 if err != nil { 35 return nil, backup.NewErrInternal(errors.Wrapf(err, "get object '%s'", metaPath)) 36 } 37 38 metric, err := monitoring.GetMetrics().BackupRestoreDataTransferred.GetMetricWithLabelValues(m.Name(), "class") 39 if err == nil { 40 metric.Add(float64(len(contents))) 41 } 42 43 return contents, nil 44 } 45 46 func (m *Module) getObjectPath(ctx context.Context, backupID, key string) (string, error) { 47 metaPath := filepath.Join(m.backupsPath, backupID, key) 48 49 if err := ctx.Err(); err != nil { 50 return "", backup.NewErrContextExpired(errors.Wrapf(err, "get object '%s'", metaPath)) 51 } 52 53 if _, err := os.Stat(metaPath); errors.Is(err, os.ErrNotExist) { 54 return "", backup.NewErrNotFound(errors.Wrapf(err, "get object '%s'", metaPath)) 55 } else if err != nil { 56 return "", backup.NewErrInternal(errors.Wrapf(err, "get object '%s'", metaPath)) 57 } 58 59 return metaPath, nil 60 } 61 62 func (m *Module) PutFile(ctx context.Context, backupID, key, srcPath string) error { 63 sourcePath := path.Join(m.dataPath, srcPath) 64 backupPath := path.Join(m.makeBackupDirPath(backupID), key) 65 66 bytesWritten, err := m.copyFile(sourcePath, backupPath) 67 if err != nil { 68 return err 69 } 70 71 metric, err := monitoring.GetMetrics().BackupStoreDataTransferred.GetMetricWithLabelValues(m.Name(), "class") 72 if err == nil { 73 metric.Add(float64(bytesWritten)) 74 } 75 76 return nil 77 } 78 79 func (m *Module) copyFile(sourcePath, destinationPath string) (int64, error) { 80 source, err := os.Open(sourcePath) 81 defer func() error { 82 return source.Close() 83 }() 84 if err != nil { 85 return 0, errors.Wrapf(err, "open file '%s'", sourcePath) 86 } 87 88 if _, err := os.Stat(destinationPath); err != nil { 89 if err := os.MkdirAll(path.Dir(destinationPath), os.ModePerm); err != nil { 90 return 0, errors.Wrapf(err, "make dir '%s'", destinationPath) 91 } 92 } 93 94 destination, err := os.Create(destinationPath) 95 defer func() error { 96 return destination.Close() 97 }() 98 if err != nil { 99 return 0, errors.Wrapf(err, "create destination file '%s'", destinationPath) 100 } 101 102 written, err := io.Copy(destination, source) 103 if err != nil { 104 return 0, errors.Wrapf(err, "copy file from '%s' to '%s'", sourcePath, destinationPath) 105 } 106 107 return written, nil 108 } 109 110 func (m *Module) PutObject(ctx context.Context, backupID, key string, byes []byte) error { 111 backupPath := path.Join(m.makeBackupDirPath(backupID), key) 112 113 dir := path.Dir(backupPath) 114 115 if err := os.MkdirAll(dir, os.ModePerm); err != nil { 116 return errors.Wrapf(err, "make dir '%s'", dir) 117 } 118 119 if err := os.WriteFile(backupPath, byes, os.ModePerm); err != nil { 120 return errors.Wrapf(err, "write file '%s'", backupPath) 121 } 122 123 metric, err := monitoring.GetMetrics().BackupStoreDataTransferred.GetMetricWithLabelValues(m.Name(), "class") 124 if err == nil { 125 metric.Add(float64(len(byes))) 126 } 127 128 return nil 129 } 130 131 func (m *Module) Initialize(ctx context.Context, backupID string) error { 132 // TODO: does anything need to be done here? 133 return nil 134 } 135 136 func (m *Module) WriteToFile(ctx context.Context, backupID, key, destPath string) error { 137 sourcePath, err := m.getObjectPath(ctx, backupID, key) 138 if err != nil { 139 return err 140 } 141 142 bytesWritten, err := m.copyFile(sourcePath, destPath) 143 if err != nil { 144 return err 145 } 146 147 metric, err := monitoring.GetMetrics().BackupRestoreDataTransferred.GetMetricWithLabelValues(m.Name(), "class") 148 if err == nil { 149 metric.Add(float64(bytesWritten)) 150 } 151 152 return nil 153 } 154 155 func (m *Module) Write(ctx context.Context, backupID, key string, r io.ReadCloser) (int64, error) { 156 defer r.Close() 157 backupPath := path.Join(m.makeBackupDirPath(backupID), key) 158 dir := path.Dir(backupPath) 159 if err := os.MkdirAll(dir, os.ModePerm); err != nil { 160 return 0, fmt.Errorf("make dir %q: %w", dir, err) 161 } 162 f, err := os.OpenFile(backupPath, os.O_RDWR|os.O_CREATE, os.ModePerm) 163 if err != nil { 164 return 0, fmt.Errorf("open file %q: %w", backupPath, err) 165 } 166 defer f.Close() 167 168 written, err := io.Copy(f, r) 169 if err != nil { 170 return 0, fmt.Errorf("write file %q: %w", backupPath, err) 171 } 172 if metric, err := monitoring.GetMetrics().BackupStoreDataTransferred. 173 GetMetricWithLabelValues(m.Name(), "class"); err == nil { 174 metric.Add(float64(written)) 175 } 176 177 return written, err 178 } 179 180 func (m *Module) Read(ctx context.Context, backupID, key string, w io.WriteCloser) (int64, error) { 181 defer w.Close() 182 sourcePath, err := m.getObjectPath(ctx, backupID, key) 183 if err != nil { 184 return 0, fmt.Errorf("source path %s/%s: %w", backupID, key, err) 185 } 186 187 // open file 188 f, err := os.Open(sourcePath) 189 if err != nil { 190 return 0, fmt.Errorf("open file %q: %w", sourcePath, err) 191 } 192 defer f.Close() 193 194 // copy file 195 read, err := io.Copy(w, f) 196 if err != nil { 197 return 0, fmt.Errorf("write : %w", err) 198 } 199 200 if metric, err := monitoring.GetMetrics().BackupRestoreDataTransferred. 201 GetMetricWithLabelValues(m.Name(), "class"); err == nil { 202 metric.Add(float64(read)) 203 } 204 return read, err 205 } 206 207 func (m *Module) SourceDataPath() string { 208 return m.dataPath 209 } 210 211 func (m *Module) initBackupBackend(ctx context.Context, backupsPath string) error { 212 if backupsPath == "" { 213 return fmt.Errorf("empty backup path provided") 214 } 215 backupsPath = filepath.Clean(backupsPath) 216 if !filepath.IsAbs(backupsPath) { 217 return fmt.Errorf("relative backup path provided") 218 } 219 if err := m.createBackupsDir(backupsPath); err != nil { 220 return errors.Wrap(err, "invalid backup path provided") 221 } 222 m.backupsPath = backupsPath 223 224 return nil 225 } 226 227 func (m *Module) createBackupsDir(backupsPath string) error { 228 if err := os.MkdirAll(backupsPath, os.ModePerm); err != nil { 229 m.logger.WithField("module", m.Name()). 230 WithField("action", "create_backups_dir"). 231 WithError(err). 232 Errorf("failed creating backups directory %v", backupsPath) 233 return backup.NewErrInternal(errors.Wrap(err, "make backups dir")) 234 } 235 return nil 236 }