| 232 | func (s sem) decr() { <-s } |
| 233 | |
| 234 | func (u *S3) uploadDirectory() error { |
| 235 | wg := sync.WaitGroup{} |
| 236 | |
| 237 | ctx := log.WithFields(log.Fields{"f": "s3upload.uploadDirectory"}) |
| 238 | ctx.Info("Uploading") |
| 239 | sem := make(sem, u.Cfg.Concurrency) |
| 240 | ctx.Info("Starting to walk...") |
| 241 | exitErr := atomic.Value{} |
| 242 | err := filepath.Walk(u.Cfg.StagingPath, func(fpath string, info os.FileInfo, walkErr error) error { |
| 243 | if walkErr != nil { |
| 244 | return walkErr |
| 245 | } |
| 246 | // If a fatal error happened in any of the goroutines, then exit immediately |
| 247 | e := exitErr.Load() |
| 248 | if e != nil { |
| 249 | return e.(error) |
| 250 | } |
| 251 | |
| 252 | if info.IsDir() { |
| 253 | return nil |
| 254 | } |
| 255 | ctx.WithFields(log.Fields{"fpath": fpath}).Info("Upload scheduled") |
| 256 | wg.Add(1) |
| 257 | sem.incr() |
| 258 | go func(fpath string) { |
| 259 | defer func() { sem.decr(); wg.Done() }() |
| 260 | |
| 261 | for i := 0; i < u.Cfg.Retries; i++ { |
| 262 | if exitErr.Load() != nil { |
| 263 | return |
| 264 | } |
| 265 | err := s3UploadFile(u.uploader, u.Cfg.Bucket, u.Cfg.Prefix, u.Cfg.StagingPath, fpath) |
| 266 | if err == nil { |
| 267 | break |
| 268 | } |
| 269 | |
| 270 | atomic.AddInt64(&u.totalerr, int64(1)) |
| 271 | if u.Cfg.ExitOnError { |
| 272 | exitErr.Store(err) |
| 273 | return |
| 274 | } |
| 275 | log.WithError(err).WithFields(log.Fields{"retry#": i + 1}).Error("failed upload") |
| 276 | } |
| 277 | // Decrease the queued elements counter both in case of success and not fatal error. |
| 278 | atomic.AddInt64(&u.queuedn, int64(-1)) |
| 279 | }(fpath) |
| 280 | return nil |
| 281 | }) |
| 282 | ctx.Info("All Scheduling done") |
| 283 | wg.Wait() |
| 284 | |
| 285 | ctx.Info("All upload done") |
| 286 | return err |
| 287 | } |
| 288 | |
| 289 | func s3UploadFile(uploader *s3manager.Uploader, bucket, prefix, localPath, fpath string) error { |
| 290 | ctx := log.WithFields(log.Fields{"localPath": localPath, "filepath": fpath}) |