Skip to content

Commit f35657b

Browse files
authored
Merge pull request #13 from GwonsooLee/fix_snapshot_bug
fix snapshot bug
2 parents 719e4bc + ad56b5f commit f35657b

File tree

2 files changed

+119
-81
lines changed

2 files changed

+119
-81
lines changed

internal/constants/constants.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import "os"
2121
const (
2222
DefaultRegion = "ap-northeast-2"
2323
EmptyString = ""
24+
GlacierType = "GLACIER"
2425
)
2526

2627
const (
@@ -36,9 +37,10 @@ const (
3637
)
3738

3839
var (
39-
ConfigDirectoryPath = HomeDir() + "/.escli"
40-
BaseFilePath = ConfigDirectoryPath + "/config.yaml"
41-
ValidRestoreTier = []string{"Standard", "Bulk", "Expedited"}
40+
ConfigDirectoryPath = HomeDir() + "/.escli"
41+
BaseFilePath = ConfigDirectoryPath + "/config.yaml"
42+
ValidRestoreTier = []string{"Standard", "Bulk", "Expedited"}
43+
SupportedRepositoryType = []string{"s3"}
4244
)
4345

4446
// Get Home Directory

internal/runner/snapshot.go

Lines changed: 114 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,13 @@ func (r Runner) ArchiveSnapshot(out io.Writer, args []string) error {
193193
for {
194194
for _, item := range objs.Contents {
195195
fmt.Fprintf(out, "%s\n", *item.Key)
196-
if *item.StorageClass != "GLACIER" {
196+
if *item.StorageClass != constants.GlacierType {
197197
if r.Flag.Force {
198198
color.Green("Change Storage Class to %s -> GLACIER", *item.StorageClass)
199199
wait.Add(1)
200200
go func(key string) {
201201
defer wait.Done()
202-
_, err := r.Client.TransitObject(aws.String(repository.Settings.Bucket), aws.String(key), "GLACIER")
202+
_, err := r.Client.TransitObject(aws.String(repository.Settings.Bucket), aws.String(key), constants.GlacierType)
203203
if err != nil {
204204
panic(err)
205205
}
@@ -212,7 +212,7 @@ func (r Runner) ArchiveSnapshot(out io.Writer, args []string) error {
212212

213213
color.Green("Change Storage Class to %s -> GLACIER", *item.StorageClass)
214214
wait.Add(1)
215-
_, err := r.Client.TransitObject(aws.String(repository.Settings.Bucket), item.Key, "GLACIER")
215+
_, err := r.Client.TransitObject(aws.String(repository.Settings.Bucket), item.Key, constants.GlacierType)
216216
if err != nil {
217217
panic(err)
218218
}
@@ -266,25 +266,24 @@ func (r Runner) getIndexIDFromS3(bucket *string, prefix *string) (*snapshotSchem
266266
return &snapshotsIndicesS3, nil
267267
}
268268

269-
func (r Runner) RestoreSnapshot(out io.Writer, args []string) error {
270-
maxSemaphore := r.Flag.MaxConcurrentJob
271-
if maxSemaphore == 0 {
272-
maxSemaphore = constants.DefaultMaxConcurrentJob
273-
}
274-
269+
// RestoreSnapshot is main function of restoring snapshot process
270+
func (r *Runner) RestoreSnapshot(out io.Writer, args []string) error {
275271
repositoryID := args[0]
276272
snapshotID := args[1]
277273
indexName := args[2]
278274
areAllObjectsStandard := true
279275

280276
repository := r.Client.GetRepository(repositoryID)
281277

278+
if err := checkRepositoryType(repository.Type); err != nil {
279+
return err
280+
}
281+
282282
if repository.Type == "s3" {
283283
fmt.Fprintf(out, "bucket name : %s\n", util.StringWithColor(repository.Settings.Bucket))
284284
fmt.Fprintf(out, "base path : %s\n", util.StringWithColor(repository.Settings.BasePath))
285285

286286
var basePath string
287-
var result []SegmentError
288287

289288
if repository.Settings.BasePath == constants.EmptyString {
290289
basePath = constants.EmptyString
@@ -304,78 +303,33 @@ func (r Runner) RestoreSnapshot(out io.Writer, args []string) error {
304303
metaData := snapshotsIndicesS3.Indices[indexName]
305304
prefix := repository.Settings.BasePath + "/indices/" + metaData.ID + "/"
306305

306+
// add all objects in segments
307307
segments := r.AddObjectSegments(repository.Settings.Bucket, prefix, nil)
308-
bar := pb.New(len(segments))
309-
bar.SetRefreshRate(time.Second)
310-
bar.SetWriter(out)
311-
312-
var wg sync.WaitGroup
313-
semaphore := make(chan int, maxSemaphore)
314-
output := make(chan []SegmentError)
315-
input := make(chan SegmentError)
316-
defer close(output)
317-
318-
go func(input chan SegmentError, output chan []SegmentError, wg *sync.WaitGroup, bar *pb.ProgressBar) {
319-
var ret []SegmentError
320-
for se := range input {
321-
ret = append(ret, se)
322-
bar.Add(1)
323-
wg.Done()
324-
}
325-
output <- ret
326-
}(input, output, &wg, bar)
327-
328-
f := func(out io.Writer, bucket string, segment SnapshotSegment, force bool, ch chan SegmentError, sem chan int) {
329-
sem <- 1
330-
time.Sleep(1 * time.Second)
331-
if force {
332-
//color.Green("Restore Storage Class to %s -> STANDARD", segment.StorageClass)
333-
err := r.restoreObject(out, aws.String(bucket), aws.String(segment.Key))
334-
ch <- SegmentError{
335-
Key: segment.Key,
336-
Error: err,
337-
}
338-
} else {
339-
reader := bufio.NewReader(os.Stdin)
340-
341-
color.Blue("Change Storage Class to STANDARD [y/n]: ")
342-
343-
resp, _ := reader.ReadString('\n')
344-
if strings.ToLower(strings.TrimSpace(resp)) == "y" {
345-
color.Green("Change Storage Class to %s -> STANDARD", segment.StorageClass)
346-
err := r.restoreObject(out, aws.String(bucket), aws.String(segment.Key))
347-
ch <- SegmentError{
348-
Key: segment.Key,
349-
Error: err,
350-
}
351-
} else {
352-
color.Red("Don't change storage class %s", segment.Key)
353-
}
354-
}
355-
<-sem
356-
}
357308

358-
bar.Start()
359-
for _, s := range segments {
360-
if s.StorageClass == "GLACIER" {
361-
areAllObjectsStandard = false
362-
wg.Add(1)
363-
go f(out, repository.Settings.Bucket, s, r.Flag.Force, input, semaphore)
364-
} else {
365-
bar.Add(1)
309+
if r.Flag.Force {
310+
// if --force is enabled by user, then run it concurrently
311+
areAllObjectsStandard, err = r.RunConcurrentRestore(out, repository.Settings.Bucket, segments, r.Flag.MaxConcurrentJob)
312+
if err != nil {
313+
return err
366314
}
367-
}
368-
wg.Wait()
369-
close(input)
370-
371-
bar.Finish()
315+
} else {
316+
for _, s := range segments {
317+
if s.StorageClass == "GLACIER" {
318+
areAllObjectsStandard = false
319+
reader := bufio.NewReader(os.Stdin)
372320

373-
result = <-output
321+
color.Blue("Change Storage Class to STANDARD [y/n]: ")
374322

375-
if len(result) > 0 {
376-
for _, s := range result {
377-
if s.Error != nil {
378-
s.PrintError()
323+
resp, _ := reader.ReadString('\n')
324+
if strings.ToLower(strings.TrimSpace(resp)) == "y" {
325+
color.Green("Change Storage Class to %s -> STANDARD", s.StorageClass)
326+
err := r.restoreObject(out, aws.String(repository.Settings.Bucket), aws.String(s.Key))
327+
if err != nil {
328+
return err
329+
}
330+
} else {
331+
color.Red("Don't change storage class %s", s.Key)
332+
}
379333
}
380334
}
381335
}
@@ -395,7 +349,8 @@ func (r Runner) RestoreSnapshot(out io.Writer, args []string) error {
395349
return nil
396350
}
397351

398-
func (r Runner) restoreObject(_ io.Writer, bucket *string, key *string) error {
352+
// restoreObject restores object
353+
func (r *Runner) restoreObject(_ io.Writer, bucket *string, key *string) error {
399354
resp, err := r.Client.HeadObject(bucket, key)
400355

401356
if err != nil {
@@ -435,3 +390,84 @@ func (r *Runner) AddObjectSegments(bucket, prefix string, token *string) []Snaps
435390

436391
return segments
437392
}
393+
394+
// RunConcurrentRestore runs restore process concurrently
395+
// This only runs if user uses --force option
396+
func (r *Runner) RunConcurrentRestore(out io.Writer, bucket string, segments []SnapshotSegment, maxSemaphore int64) (bool, error) {
397+
var result []SegmentError
398+
var areAllObjectsStandard bool
399+
400+
// maxSemaphore limits the number of go routines
401+
if maxSemaphore == 0 {
402+
maxSemaphore = constants.DefaultMaxConcurrentJob
403+
}
404+
405+
bar := pb.New(len(segments))
406+
bar.SetRefreshRate(time.Second)
407+
bar.SetWriter(out)
408+
409+
var wg sync.WaitGroup
410+
semaphore := make(chan int, maxSemaphore)
411+
output := make(chan []SegmentError)
412+
input := make(chan SegmentError)
413+
defer close(output)
414+
415+
go func(input chan SegmentError, output chan []SegmentError, wg *sync.WaitGroup, bar *pb.ProgressBar) {
416+
var ret []SegmentError
417+
for se := range input {
418+
ret = append(ret, se)
419+
bar.Add(1)
420+
wg.Done()
421+
}
422+
output <- ret
423+
}(input, output, &wg, bar)
424+
425+
f := func(out io.Writer, bucket string, segment SnapshotSegment, ch chan SegmentError, sem chan int) {
426+
sem <- 1
427+
time.Sleep(1 * time.Second)
428+
429+
//color.Green("Restore Storage Class to %s -> STANDARD", segment.StorageClass)
430+
err := r.restoreObject(out, aws.String(bucket), aws.String(segment.Key))
431+
ch <- SegmentError{
432+
Key: segment.Key,
433+
Error: err,
434+
}
435+
436+
<-sem
437+
}
438+
439+
bar.Start()
440+
for _, s := range segments {
441+
if s.StorageClass == "GLACIER" {
442+
areAllObjectsStandard = false
443+
wg.Add(1)
444+
go f(out, bucket, s, input, semaphore)
445+
} else {
446+
bar.Add(1)
447+
}
448+
}
449+
wg.Wait()
450+
close(input)
451+
452+
bar.Finish()
453+
454+
result = <-output
455+
456+
if len(result) > 0 {
457+
for _, s := range result {
458+
if s.Error != nil {
459+
s.PrintError()
460+
}
461+
}
462+
}
463+
464+
return areAllObjectsStandard, nil
465+
}
466+
467+
// checkRepositoryType checks if repository type is supported by escli
468+
func checkRepositoryType(repositoryType string) error {
469+
if !util.IsStringInArray(strings.ToLower(repositoryType), constants.SupportedRepositoryType) {
470+
return fmt.Errorf("unsupported repository type: %s", repositoryType)
471+
}
472+
return nil
473+
}

0 commit comments

Comments
 (0)