@ -20,7 +20,6 @@ import (
"context"
"context"
"encoding/json"
"encoding/json"
"fmt"
"fmt"
"path"
"runtime"
"runtime"
"strings"
"strings"
"sync"
"sync"
@ -386,7 +385,6 @@ func (h *healSequence) stop() {
// sequence automatically resumes. The return value indicates if the
// sequence automatically resumes. The return value indicates if the
// operation succeeded.
// operation succeeded.
func ( h * healSequence ) pushHealResultItem ( r madmin . HealResultItem ) error {
func ( h * healSequence ) pushHealResultItem ( r madmin . HealResultItem ) error {
// start a timer to keep an upper time limit to find an empty
// start a timer to keep an upper time limit to find an empty
// slot to add the given heal result - if no slot is found it
// slot to add the given heal result - if no slot is found it
// means that the server is holding the maximum amount of
// means that the server is holding the maximum amount of
@ -543,24 +541,64 @@ func (h *healSequence) healConfig() error {
return errServerNotInitialized
return errServerNotInitialized
}
}
configFile := path . Join ( minioConfigPrefix , minioConfigFile )
// NOTE: Healing on configs is run regardless
configBackupFile := path . Join ( minioConfigPrefix , minioConfigBackupFile )
// of any bucket being selected, this is to ensure that
for _ , cfg := range [ ] string { configFile , configBackupFile } {
// configs are always uptodate and correct.
res , err := objectAPI . HealObject ( h . ctx , minioMetaBucket , cfg , h . settings . DryRun )
marker := ""
isTruncated := true
for isTruncated {
if globalHTTPServer != nil {
// Wait at max 1 minute for an inprogress request
// before proceeding to heal
waitCount := 60
// Any requests in progress, delay the heal.
for globalHTTPServer . GetRequestCount ( ) > 0 && waitCount > 0 {
waitCount --
time . Sleep ( 1 * time . Second )
}
}
// Lists all objects under `config` prefix.
objectInfos , err := objectAPI . ListObjectsHeal ( h . ctx , minioMetaBucket , minioConfigPrefix ,
marker , "" , 1000 )
if err != nil {
if err != nil {
return err
return errFnHealFromAPIErr ( err )
}
}
res . Type = madmin . HealItemBucketMetadata
if err = h . pushHealResultItem ( res ) ; err != nil {
for index := range objectInfos . Objects {
return err
if h . isQuitting ( ) {
return errHealStopSignalled
}
o := objectInfos . Objects [ index ]
res , herr := objectAPI . HealObject ( h . ctx , o . Bucket , o . Name , h . settings . DryRun )
// Object might have been deleted, by the time heal
// was attempted we ignore this file an move on.
if isErrObjectNotFound ( herr ) {
continue
}
if herr != nil {
return herr
}
res . Type = madmin . HealItemBucketMetadata
if err = h . pushHealResultItem ( res ) ; err != nil {
return err
}
}
}
isTruncated = objectInfos . IsTruncated
marker = objectInfos . NextMarker
}
}
return nil
return nil
}
}
// healDiskFormat - heals format.json, return value indicates if a
// healDiskFormat - heals format.json, return value indicates if a
// failure error occurred.
// failure error occurred.
func ( h * healSequence ) healDiskFormat ( ) error {
func ( h * healSequence ) healDiskFormat ( ) error {
if h . isQuitting ( ) {
return errHealStopSignalled
}
// Get current object layer instance.
// Get current object layer instance.
objectAPI := newObjectLayerFn ( )
objectAPI := newObjectLayerFn ( )
if objectAPI == nil {
if objectAPI == nil {
@ -586,6 +624,10 @@ func (h *healSequence) healDiskFormat() error {
// healBuckets - check for all buckets heal or just particular bucket.
// healBuckets - check for all buckets heal or just particular bucket.
func ( h * healSequence ) healBuckets ( ) error {
func ( h * healSequence ) healBuckets ( ) error {
if h . isQuitting ( ) {
return errHealStopSignalled
}
// 1. If a bucket was specified, heal only the bucket.
// 1. If a bucket was specified, heal only the bucket.
if h . bucket != "" {
if h . bucket != "" {
return h . healBucket ( h . bucket )
return h . healBucket ( h . bucket )
@ -613,10 +655,6 @@ func (h *healSequence) healBuckets() error {
// healBucket - traverses and heals given bucket
// healBucket - traverses and heals given bucket
func ( h * healSequence ) healBucket ( bucket string ) error {
func ( h * healSequence ) healBucket ( bucket string ) error {
if h . isQuitting ( ) {
return errHealStopSignalled
}
// Get current object layer instance.
// Get current object layer instance.
objectAPI := newObjectLayerFn ( )
objectAPI := newObjectLayerFn ( )
if objectAPI == nil {
if objectAPI == nil {
@ -641,8 +679,7 @@ func (h *healSequence) healBucket(bucket string) error {
// and if so heal it.
// and if so heal it.
_ , err = objectAPI . GetObjectInfo ( h . ctx , bucket , h . objPrefix , ObjectOptions { } )
_ , err = objectAPI . GetObjectInfo ( h . ctx , bucket , h . objPrefix , ObjectOptions { } )
if err == nil {
if err == nil {
err = h . healObject ( bucket , h . objPrefix )
if err = h . healObject ( bucket , h . objPrefix ) ; err != nil {
if err != nil {
return err
return err
}
}
}
}
@ -708,6 +745,9 @@ func (h *healSequence) healObject(bucket, object string) error {
}
}
hri , err := objectAPI . HealObject ( h . ctx , bucket , object , h . settings . DryRun )
hri , err := objectAPI . HealObject ( h . ctx , bucket , object , h . settings . DryRun )
if isErrObjectNotFound ( err ) {
return nil
}
if err != nil {
if err != nil {
hri . Detail = err . Error ( )
hri . Detail = err . Error ( )
}
}