| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | // Copyright (c) 2015-2021 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	"math/rand" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2021-03-27 14:24:07 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 	"sync/atomic" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-07 05:46:50 +08:00
										 |  |  | 	"github.com/minio/madmin-go/v2" | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							| 
									
										
										
										
											2022-08-09 06:18:45 +08:00
										 |  |  | 	"github.com/minio/pkg/env" | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //go:generate stringer -type=storageMetric -trimprefix=storageMetric $GOFILE
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type storageMetric uint8 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	storageMetricMakeVolBulk storageMetric = iota | 
					
						
							|  |  |  | 	storageMetricMakeVol | 
					
						
							|  |  |  | 	storageMetricListVols | 
					
						
							|  |  |  | 	storageMetricStatVol | 
					
						
							|  |  |  | 	storageMetricDeleteVol | 
					
						
							|  |  |  | 	storageMetricWalkDir | 
					
						
							|  |  |  | 	storageMetricListDir | 
					
						
							|  |  |  | 	storageMetricReadFile | 
					
						
							|  |  |  | 	storageMetricAppendFile | 
					
						
							|  |  |  | 	storageMetricCreateFile | 
					
						
							|  |  |  | 	storageMetricReadFileStream | 
					
						
							|  |  |  | 	storageMetricRenameFile | 
					
						
							|  |  |  | 	storageMetricRenameData | 
					
						
							|  |  |  | 	storageMetricCheckParts | 
					
						
							|  |  |  | 	storageMetricDelete | 
					
						
							|  |  |  | 	storageMetricDeleteVersions | 
					
						
							|  |  |  | 	storageMetricVerifyFile | 
					
						
							|  |  |  | 	storageMetricWriteAll | 
					
						
							|  |  |  | 	storageMetricDeleteVersion | 
					
						
							|  |  |  | 	storageMetricWriteMetadata | 
					
						
							| 
									
										
										
										
											2021-04-05 04:32:31 +08:00
										 |  |  | 	storageMetricUpdateMetadata | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 	storageMetricReadVersion | 
					
						
							| 
									
										
										
										
											2022-04-21 03:49:05 +08:00
										 |  |  | 	storageMetricReadXL | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 	storageMetricReadAll | 
					
						
							| 
									
										
										
										
											2021-12-03 03:29:16 +08:00
										 |  |  | 	storageMetricStatInfoFile | 
					
						
							| 
									
										
										
										
											2022-07-19 23:35:29 +08:00
										 |  |  | 	storageMetricReadMultiple | 
					
						
							| 
									
										
										
										
											2022-11-29 02:20:55 +08:00
										 |  |  | 	storageMetricDeleteAbandonedParts | 
					
						
							| 
									
										
										
										
											2022-12-02 04:10:54 +08:00
										 |  |  | 	storageMetricDiskInfo | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// .... add more
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-27 14:24:07 +08:00
										 |  |  | 	storageMetricLast | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Detects change in underlying disk.
 | 
					
						
							|  |  |  | type xlStorageDiskIDCheck struct { | 
					
						
							| 
									
										
										
										
											2022-03-18 01:57:52 +08:00
										 |  |  | 	// apiCalls should be placed first so alignment is guaranteed for atomic operations.
 | 
					
						
							|  |  |  | 	apiCalls     [storageMetricLast]uint64 | 
					
						
							| 
									
										
										
										
											2022-01-26 08:31:44 +08:00
										 |  |  | 	apiLatencies [storageMetricLast]*lockedLastMinuteLatency | 
					
						
							| 
									
										
										
										
											2021-04-02 13:12:03 +08:00
										 |  |  | 	diskID       string | 
					
						
							| 
									
										
										
										
											2022-03-18 01:57:52 +08:00
										 |  |  | 	storage      *xlStorage | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	health       *diskHealthTracker | 
					
						
							| 
									
										
										
										
											2022-07-06 02:02:30 +08:00
										 |  |  | 	metricsCache timedValue | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) getMetrics() DiskMetrics { | 
					
						
							| 
									
										
										
										
											2022-07-06 02:02:30 +08:00
										 |  |  | 	p.metricsCache.Once.Do(func() { | 
					
						
							|  |  |  | 		p.metricsCache.TTL = 100 * time.Millisecond | 
					
						
							|  |  |  | 		p.metricsCache.Update = func() (interface{}, error) { | 
					
						
							|  |  |  | 			diskMetric := DiskMetrics{ | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 				LastMinute: make(map[string]AccElem, len(p.apiLatencies)), | 
					
						
							|  |  |  | 				APICalls:   make(map[string]uint64, len(p.apiCalls)), | 
					
						
							| 
									
										
										
										
											2022-07-06 02:02:30 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			for i, v := range p.apiLatencies { | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 				diskMetric.LastMinute[storageMetric(i).String()] = v.total() | 
					
						
							| 
									
										
										
										
											2022-07-06 02:02:30 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			for i := range p.apiCalls { | 
					
						
							|  |  |  | 				diskMetric.APICalls[storageMetric(i).String()] = atomic.LoadUint64(&p.apiCalls[i]) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return diskMetric, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	m, _ := p.metricsCache.Get() | 
					
						
							|  |  |  | 	return m.(DiskMetrics) | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-26 08:31:44 +08:00
										 |  |  | type lockedLastMinuteLatency struct { | 
					
						
							|  |  |  | 	sync.Mutex | 
					
						
							|  |  |  | 	lastMinuteLatency | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-26 08:31:44 +08:00
										 |  |  | func (e *lockedLastMinuteLatency) add(value time.Duration) { | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 	e.Lock() | 
					
						
							|  |  |  | 	defer e.Unlock() | 
					
						
							| 
									
										
										
										
											2022-01-26 08:31:44 +08:00
										 |  |  | 	e.lastMinuteLatency.add(value) | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | // addSize will add a duration and size.
 | 
					
						
							|  |  |  | func (e *lockedLastMinuteLatency) addSize(value time.Duration, sz int64) { | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 	e.Lock() | 
					
						
							|  |  |  | 	defer e.Unlock() | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	e.lastMinuteLatency.addSize(value, sz) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // total returns the total call count and latency for the last minute.
 | 
					
						
							|  |  |  | func (e *lockedLastMinuteLatency) total() AccElem { | 
					
						
							|  |  |  | 	e.Lock() | 
					
						
							|  |  |  | 	defer e.Unlock() | 
					
						
							|  |  |  | 	return e.lastMinuteLatency.getTotal() | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newXLStorageDiskIDCheck(storage *xlStorage) *xlStorageDiskIDCheck { | 
					
						
							|  |  |  | 	xl := xlStorageDiskIDCheck{ | 
					
						
							|  |  |  | 		storage: storage, | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 		health:  newDiskHealthTracker(), | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for i := range xl.apiLatencies[:] { | 
					
						
							| 
									
										
										
										
											2022-01-26 08:31:44 +08:00
										 |  |  | 		xl.apiLatencies[i] = &lockedLastMinuteLatency{} | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return &xl | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) String() string { | 
					
						
							|  |  |  | 	return p.storage.String() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) IsOnline() bool { | 
					
						
							|  |  |  | 	storedDiskID, err := p.storage.GetDiskID() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return storedDiskID == p.diskID | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 00:19:15 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) LastConn() time.Time { | 
					
						
							|  |  |  | 	return p.storage.LastConn() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) IsLocal() bool { | 
					
						
							|  |  |  | 	return p.storage.IsLocal() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-29 10:39:32 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) Endpoint() Endpoint { | 
					
						
							|  |  |  | 	return p.storage.Endpoint() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) Hostname() string { | 
					
						
							|  |  |  | 	return p.storage.Hostname() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-05 06:36:23 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) Healing() *healingTracker { | 
					
						
							| 
									
										
										
										
											2020-09-29 10:39:32 +08:00
										 |  |  | 	return p.storage.Healing() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-07 23:10:40 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) NSScanner(ctx context.Context, cache dataUsageCache, updates chan<- dataUsageEntry, scanMode madmin.HealScanMode) (dataUsageCache, error) { | 
					
						
							| 
									
										
										
										
											2021-09-18 05:11:01 +08:00
										 |  |  | 	if contextCanceled(ctx) { | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 		return dataUsageCache{}, ctx.Err() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 	if err := p.checkDiskStale(); err != nil { | 
					
						
							|  |  |  | 		return dataUsageCache{}, err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-04-07 23:10:40 +08:00
										 |  |  | 	return p.storage.NSScanner(ctx, cache, updates, scanMode) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-05 06:36:23 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) GetDiskLoc() (poolIdx, setIdx, diskIdx int) { | 
					
						
							|  |  |  | 	return p.storage.GetDiskLoc() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) SetDiskLoc(poolIdx, setIdx, diskIdx int) { | 
					
						
							|  |  |  | 	p.storage.SetDiskLoc(poolIdx, setIdx, diskIdx) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) Close() error { | 
					
						
							|  |  |  | 	return p.storage.Close() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) GetDiskID() (string, error) { | 
					
						
							|  |  |  | 	return p.storage.GetDiskID() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) SetDiskID(id string) { | 
					
						
							|  |  |  | 	p.diskID = id | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) checkDiskStale() error { | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	if p.diskID == "" { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		// For empty disk-id we allow the call as the server might be
 | 
					
						
							|  |  |  | 		// coming up and trying to read format.json or create format.json
 | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	storedDiskID, err := p.storage.GetDiskID() | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		// return any error generated while reading `format.json`
 | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	if err == nil && p.diskID == storedDiskID { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 	// not the same disk we remember, take it offline.
 | 
					
						
							|  |  |  | 	return errDiskNotFound | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) DiskInfo(ctx context.Context) (info DiskInfo, err error) { | 
					
						
							| 
									
										
										
										
											2021-09-18 05:11:01 +08:00
										 |  |  | 	if contextCanceled(ctx) { | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 		return DiskInfo{}, ctx.Err() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 04:10:54 +08:00
										 |  |  | 	si := p.updateStorageMetrics(storageMetricDiskInfo) | 
					
						
							|  |  |  | 	defer si(&err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	info, err = p.storage.DiskInfo(ctx) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return info, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	info.Metrics = p.getMetrics() | 
					
						
							| 
									
										
										
										
											2020-07-16 22:30:05 +08:00
										 |  |  | 	// check cached diskID against backend
 | 
					
						
							|  |  |  | 	// only if its non-empty.
 | 
					
						
							|  |  |  | 	if p.diskID != "" { | 
					
						
							|  |  |  | 		if p.diskID != info.ID { | 
					
						
							|  |  |  | 			return info, errDiskNotFound | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if p.health.isFaulty() { | 
					
						
							|  |  |  | 		// if disk is already faulty return faulty for 'mc admin info' output and prometheus alerts.
 | 
					
						
							|  |  |  | 		return info, errFaultyDisk | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 	return info, nil | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) MakeVolBulk(ctx context.Context, volumes ...string) (err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricMakeVolBulk, volumes...) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.MakeVolBulk(ctx, volumes...) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) MakeVol(ctx context.Context, volume string) (err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricMakeVol, volume) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2021-09-18 05:11:01 +08:00
										 |  |  | 	if contextCanceled(ctx) { | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 		return ctx.Err() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 	if err = p.checkDiskStale(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.MakeVol(ctx, volume) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) ListVols(ctx context.Context) (vi []VolInfo, err error) { | 
					
						
							|  |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricListVols, "/") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.ListVols(ctx) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) StatVol(ctx context.Context, volume string) (vol VolInfo, err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricStatVol, volume) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return vol, err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.StatVol(ctx, volume) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) DeleteVol(ctx context.Context, volume string, forceDelete bool) (err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricDeleteVol, volume) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.DeleteVol(ctx, volume, forceDelete) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) ListDir(ctx context.Context, volume, dirPath string, count int) (s []string, err error) { | 
					
						
							|  |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricListDir, volume, dirPath) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.ListDir(ctx, volume, dirPath, count) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) ReadFile(ctx context.Context, volume string, path string, offset int64, buf []byte, verifier *BitrotVerifier) (n int64, err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricReadFile, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return 0, err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.ReadFile(ctx, volume, path, offset, buf, verifier) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) AppendFile(ctx context.Context, volume string, path string, buf []byte) (err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricAppendFile, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.AppendFile(ctx, volume, path, buf) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) CreateFile(ctx context.Context, volume, path string, size int64, reader io.Reader) (err error) { | 
					
						
							|  |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricCreateFile, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.CreateFile(ctx, volume, path, size, reader) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) ReadFileStream(ctx context.Context, volume, path string, offset, length int64) (io.ReadCloser, error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricReadFileStream, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.ReadFileStream(ctx, volume, path, offset, length) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) RenameFile(ctx context.Context, srcVolume, srcPath, dstVolume, dstPath string) (err error) { | 
					
						
							|  |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricRenameFile, srcVolume, srcPath, dstVolume, dstPath) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.RenameFile(ctx, srcVolume, srcPath, dstVolume, dstPath) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 07:51:37 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) RenameData(ctx context.Context, srcVolume, srcPath string, fi FileInfo, dstVolume, dstPath string) (sign uint64, err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricRenameData, srcPath, fi.DataDir, dstVolume, dstPath) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-09-06 07:51:37 +08:00
										 |  |  | 		return 0, err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-21 01:44:39 +08:00
										 |  |  | 	return p.storage.RenameData(ctx, srcVolume, srcPath, fi, dstVolume, dstPath) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) CheckParts(ctx context.Context, volume string, path string, fi FileInfo) (err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricCheckParts, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.CheckParts(ctx, volume, path, fi) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-12 00:15:54 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) Delete(ctx context.Context, volume string, path string, deleteOpts DeleteOptions) (err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricDelete, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-12 00:15:54 +08:00
										 |  |  | 	return p.storage.Delete(ctx, volume, path, deleteOpts) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-27 14:24:07 +08:00
										 |  |  | // DeleteVersions deletes slice of versions, it can be same object
 | 
					
						
							|  |  |  | // or multiple objects.
 | 
					
						
							| 
									
										
										
										
											2021-11-02 01:50:07 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) DeleteVersions(ctx context.Context, volume string, versions []FileInfoVersions) (errs []error) { | 
					
						
							|  |  |  | 	// Merely for tracing storage
 | 
					
						
							| 
									
										
										
										
											2021-03-27 14:24:07 +08:00
										 |  |  | 	path := "" | 
					
						
							|  |  |  | 	if len(versions) > 0 { | 
					
						
							|  |  |  | 		path = versions[0].Name | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	errs = make([]error, len(versions)) | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricDeleteVersions, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 		for i := range errs { | 
					
						
							|  |  |  | 			errs[i] = ctx.Err() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return errs | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							|  |  |  | 	errs = p.storage.DeleteVersions(ctx, volume, versions) | 
					
						
							|  |  |  | 	for i := range errs { | 
					
						
							|  |  |  | 		if errs[i] != nil { | 
					
						
							|  |  |  | 			err = errs[i] | 
					
						
							|  |  |  | 			break | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-27 14:24:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	return errs | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) VerifyFile(ctx context.Context, volume, path string, fi FileInfo) (err error) { | 
					
						
							|  |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricVerifyFile, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.VerifyFile(ctx, volume, path, fi) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-03 08:14:31 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) WriteAll(ctx context.Context, volume string, path string, b []byte) (err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricWriteAll, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-03 08:14:31 +08:00
										 |  |  | 	return p.storage.WriteAll(ctx, volume, path, b) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-04 02:33:43 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) DeleteVersion(ctx context.Context, volume, path string, fi FileInfo, forceDelMarker bool) (err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricDeleteVersion, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-04 02:33:43 +08:00
										 |  |  | 	return p.storage.DeleteVersion(ctx, volume, path, fi, forceDelMarker) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-05 04:32:31 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) UpdateMetadata(ctx context.Context, volume, path string, fi FileInfo) (err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricUpdateMetadata, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-05 04:32:31 +08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2021-04-05 04:32:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return p.storage.UpdateMetadata(ctx, volume, path, fi) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) WriteMetadata(ctx context.Context, volume, path string, fi FileInfo) (err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricWriteMetadata, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.WriteMetadata(ctx, volume, path, fi) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-08 11:27:31 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) ReadVersion(ctx context.Context, volume, path, versionID string, readData bool) (fi FileInfo, err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricReadVersion, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return fi, err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-08 11:27:31 +08:00
										 |  |  | 	return p.storage.ReadVersion(ctx, volume, path, versionID, readData) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) ReadAll(ctx context.Context, volume string, path string) (buf []byte, err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricReadAll, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2020-07-14 00:51:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 	return p.storage.ReadAll(ctx, volume, path) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-21 03:49:05 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) ReadXL(ctx context.Context, volume string, path string, readData bool) (rf RawFileInfo, err error) { | 
					
						
							|  |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricReadXL, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return RawFileInfo{}, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer done(&err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p.storage.ReadXL(ctx, volume, path, readData) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-02 02:50:00 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) StatInfoFile(ctx context.Context, volume, path string, glob bool) (stat []StatInfo, err error) { | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricStatInfoFile, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-10-02 02:50:00 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2021-07-10 02:29:16 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	defer done(&err) | 
					
						
							| 
									
										
										
										
											2021-07-10 02:29:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-02 02:50:00 +08:00
										 |  |  | 	return p.storage.StatInfoFile(ctx, volume, path, glob) | 
					
						
							| 
									
										
										
										
											2021-07-10 02:29:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-19 23:35:29 +08:00
										 |  |  | // ReadMultiple will read multiple files and send each back as response.
 | 
					
						
							|  |  |  | // Files are read and returned in the given order.
 | 
					
						
							|  |  |  | // The resp channel is closed before the call returns.
 | 
					
						
							|  |  |  | // Only a canceled context will return an error.
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) ReadMultiple(ctx context.Context, req ReadMultipleReq, resp chan<- ReadMultipleResp) error { | 
					
						
							|  |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricReadMultiple, req.Bucket, req.Prefix) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		close(resp) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer done(&err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p.storage.ReadMultiple(ctx, req, resp) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 02:20:55 +08:00
										 |  |  | // CleanAbandonedData will read metadata of the object on disk
 | 
					
						
							|  |  |  | // and delete any data directories and inline data that isn't referenced in metadata.
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) CleanAbandonedData(ctx context.Context, volume string, path string) error { | 
					
						
							|  |  |  | 	ctx, done, err := p.TrackDiskHealth(ctx, storageMetricDeleteAbandonedParts, volume, path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer done(&err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p.storage.CleanAbandonedData(ctx, volume, path) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 04:10:54 +08:00
										 |  |  | func storageTrace(s storageMetric, startTime time.Time, duration time.Duration, path string, err string) madmin.TraceInfo { | 
					
						
							| 
									
										
										
										
											2021-05-06 23:52:02 +08:00
										 |  |  | 	return madmin.TraceInfo{ | 
					
						
							|  |  |  | 		TraceType: madmin.TraceStorage, | 
					
						
							| 
									
										
										
										
											2021-03-27 14:24:07 +08:00
										 |  |  | 		Time:      startTime, | 
					
						
							|  |  |  | 		NodeName:  globalLocalNodeName, | 
					
						
							| 
									
										
										
										
											2021-03-28 01:07:07 +08:00
										 |  |  | 		FuncName:  "storage." + s.String(), | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 		Duration:  duration, | 
					
						
							|  |  |  | 		Path:      path, | 
					
						
							| 
									
										
										
										
											2022-12-02 04:10:54 +08:00
										 |  |  | 		Error:     err, | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 01:33:33 +08:00
										 |  |  | func scannerTrace(s scannerMetric, startTime time.Time, duration time.Duration, path string, custom map[string]string) madmin.TraceInfo { | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	return madmin.TraceInfo{ | 
					
						
							|  |  |  | 		TraceType: madmin.TraceScanner, | 
					
						
							|  |  |  | 		Time:      startTime, | 
					
						
							|  |  |  | 		NodeName:  globalLocalNodeName, | 
					
						
							|  |  |  | 		FuncName:  "scanner." + s.String(), | 
					
						
							|  |  |  | 		Duration:  duration, | 
					
						
							|  |  |  | 		Path:      path, | 
					
						
							| 
									
										
										
										
											2023-02-22 01:33:33 +08:00
										 |  |  | 		Custom:    custom, | 
					
						
							| 
									
										
										
										
											2021-03-27 14:24:07 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | // Update storage metrics
 | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | func (p *xlStorageDiskIDCheck) updateStorageMetrics(s storageMetric, paths ...string) func(err *error) { | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 	startTime := time.Now() | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	trace := globalTrace.NumSubscribers(madmin.TraceStorage) > 0 | 
					
						
							| 
									
										
										
										
											2022-12-02 04:10:54 +08:00
										 |  |  | 	return func(errp *error) { | 
					
						
							| 
									
										
										
										
											2021-03-27 14:24:07 +08:00
										 |  |  | 		duration := time.Since(startTime) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 		atomic.AddUint64(&p.apiCalls[s], 1) | 
					
						
							| 
									
										
										
										
											2022-01-26 08:31:44 +08:00
										 |  |  | 		p.apiLatencies[s].add(duration) | 
					
						
							| 
									
										
										
										
											2021-03-27 14:24:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if trace { | 
					
						
							| 
									
										
										
										
											2022-12-02 04:10:54 +08:00
										 |  |  | 			var errStr string | 
					
						
							|  |  |  | 			if errp != nil && *errp != nil { | 
					
						
							|  |  |  | 				errStr = (*errp).Error() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			paths = append([]string{p.String()}, paths...) | 
					
						
							|  |  |  | 			globalTrace.Publish(storageTrace(s, startTime, duration, strings.Join(paths, " "), errStr)) | 
					
						
							| 
									
										
										
										
											2021-03-27 14:24:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-03-17 11:06:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	diskHealthOK = iota | 
					
						
							|  |  |  | 	diskHealthFaulty | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // diskMaxConcurrent is the maximum number of running concurrent operations
 | 
					
						
							|  |  |  | // for local and (incoming) remote disk ops respectively.
 | 
					
						
							| 
									
										
										
										
											2022-03-24 07:54:24 +08:00
										 |  |  | var diskMaxConcurrent = 512 | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							| 
									
										
										
										
											2022-08-09 06:18:45 +08:00
										 |  |  | 	s := env.Get("_MINIO_DISK_MAX_CONCURRENT", "512") | 
					
						
							|  |  |  | 	diskMaxConcurrent, _ = strconv.Atoi(s) | 
					
						
							|  |  |  | 	if diskMaxConcurrent <= 0 { | 
					
						
							| 
									
										
										
										
											2022-08-09 07:13:49 +08:00
										 |  |  | 		logger.Info("invalid _MINIO_DISK_MAX_CONCURRENT value: %s, defaulting to '512'", s) | 
					
						
							| 
									
										
										
										
											2022-08-09 06:18:45 +08:00
										 |  |  | 		diskMaxConcurrent = 512 | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type diskHealthTracker struct { | 
					
						
							|  |  |  | 	// atomic time of last success
 | 
					
						
							|  |  |  | 	lastSuccess int64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// atomic time of last time a token was grabbed.
 | 
					
						
							|  |  |  | 	lastStarted int64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Atomic status of disk.
 | 
					
						
							|  |  |  | 	status int32 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Atomic number of requests blocking for a token.
 | 
					
						
							|  |  |  | 	blocked int32 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Concurrency tokens.
 | 
					
						
							|  |  |  | 	tokens chan struct{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newDiskHealthTracker creates a new disk health tracker.
 | 
					
						
							|  |  |  | func newDiskHealthTracker() *diskHealthTracker { | 
					
						
							|  |  |  | 	d := diskHealthTracker{ | 
					
						
							|  |  |  | 		lastSuccess: time.Now().UnixNano(), | 
					
						
							|  |  |  | 		lastStarted: time.Now().UnixNano(), | 
					
						
							|  |  |  | 		status:      diskHealthOK, | 
					
						
							|  |  |  | 		tokens:      make(chan struct{}, diskMaxConcurrent), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i := 0; i < diskMaxConcurrent; i++ { | 
					
						
							|  |  |  | 		d.tokens <- struct{}{} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return &d | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // logSuccess will update the last successful operation time.
 | 
					
						
							|  |  |  | func (d *diskHealthTracker) logSuccess() { | 
					
						
							|  |  |  | 	atomic.StoreInt64(&d.lastSuccess, time.Now().UnixNano()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *diskHealthTracker) isFaulty() bool { | 
					
						
							|  |  |  | 	return atomic.LoadInt32(&d.status) == diskHealthFaulty | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type ( | 
					
						
							|  |  |  | 	healthDiskCtxKey   struct{} | 
					
						
							|  |  |  | 	healthDiskCtxValue struct { | 
					
						
							|  |  |  | 		lastSuccess *int64 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // logSuccess will update the last successful operation time.
 | 
					
						
							|  |  |  | func (h *healthDiskCtxValue) logSuccess() { | 
					
						
							|  |  |  | 	atomic.StoreInt64(h.lastSuccess, time.Now().UnixNano()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // noopDoneFunc is a no-op done func.
 | 
					
						
							|  |  |  | // Can be reused.
 | 
					
						
							|  |  |  | var noopDoneFunc = func(_ *error) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TrackDiskHealth for this request.
 | 
					
						
							|  |  |  | // When a non-nil error is returned 'done' MUST be called
 | 
					
						
							|  |  |  | // with the status of the response, if it corresponds to disk health.
 | 
					
						
							|  |  |  | // If the pointer sent to done is non-nil AND the error
 | 
					
						
							|  |  |  | // is either nil or io.EOF the disk is considered good.
 | 
					
						
							|  |  |  | // So if unsure if the disk status is ok, return nil as a parameter to done.
 | 
					
						
							|  |  |  | // Shadowing will work as long as return error is named: https://go.dev/play/p/sauq86SsTN2
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) TrackDiskHealth(ctx context.Context, s storageMetric, paths ...string) (c context.Context, done func(*error), err error) { | 
					
						
							|  |  |  | 	done = noopDoneFunc | 
					
						
							|  |  |  | 	if contextCanceled(ctx) { | 
					
						
							|  |  |  | 		return ctx, done, ctx.Err() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Return early if disk is faulty already.
 | 
					
						
							|  |  |  | 	if atomic.LoadInt32(&p.health.status) == diskHealthFaulty { | 
					
						
							|  |  |  | 		return ctx, done, errFaultyDisk | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Verify if the disk is not stale
 | 
					
						
							|  |  |  | 	// - missing format.json (unformatted drive)
 | 
					
						
							|  |  |  | 	// - format.json is valid but invalid 'uuid'
 | 
					
						
							|  |  |  | 	if err = p.checkDiskStale(); err != nil { | 
					
						
							|  |  |  | 		return ctx, done, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Disallow recursive tracking to avoid deadlocks.
 | 
					
						
							|  |  |  | 	if ctx.Value(healthDiskCtxKey{}) != nil { | 
					
						
							|  |  |  | 		done = p.updateStorageMetrics(s, paths...) | 
					
						
							|  |  |  | 		return ctx, done, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-ctx.Done(): | 
					
						
							|  |  |  | 		return ctx, done, ctx.Err() | 
					
						
							|  |  |  | 	case <-p.health.tokens: | 
					
						
							|  |  |  | 		// Fast path, got token.
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		// We ran out of tokens, check health before blocking.
 | 
					
						
							|  |  |  | 		err = p.waitForToken(ctx) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return ctx, done, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// We only progress here if we got a token.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	atomic.StoreInt64(&p.health.lastStarted, time.Now().UnixNano()) | 
					
						
							|  |  |  | 	ctx = context.WithValue(ctx, healthDiskCtxKey{}, &healthDiskCtxValue{lastSuccess: &p.health.lastSuccess}) | 
					
						
							|  |  |  | 	si := p.updateStorageMetrics(s, paths...) | 
					
						
							|  |  |  | 	var once sync.Once | 
					
						
							|  |  |  | 	return ctx, func(errp *error) { | 
					
						
							|  |  |  | 		once.Do(func() { | 
					
						
							|  |  |  | 			p.health.tokens <- struct{}{} | 
					
						
							|  |  |  | 			if errp != nil { | 
					
						
							|  |  |  | 				err := *errp | 
					
						
							|  |  |  | 				if err != nil && !errors.Is(err, io.EOF) { | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				p.health.logSuccess() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			si(errp) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // waitForToken will wait for a token, while periodically
 | 
					
						
							|  |  |  | // checking the disk status.
 | 
					
						
							|  |  |  | // If nil is returned a token was picked up.
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) waitForToken(ctx context.Context) (err error) { | 
					
						
							|  |  |  | 	atomic.AddInt32(&p.health.blocked, 1) | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		atomic.AddInt32(&p.health.blocked, -1) | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	// Avoid stampeding herd...
 | 
					
						
							|  |  |  | 	ticker := time.NewTicker(5*time.Second + time.Duration(rand.Int63n(int64(5*time.Second)))) | 
					
						
							|  |  |  | 	defer ticker.Stop() | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		err = p.checkHealth(ctx) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-ticker.C: | 
					
						
							|  |  |  | 		// Ticker expired, check health again.
 | 
					
						
							|  |  |  | 		case <-ctx.Done(): | 
					
						
							|  |  |  | 			return ctx.Err() | 
					
						
							|  |  |  | 		case <-p.health.tokens: | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // checkHealth should only be called when tokens have run out.
 | 
					
						
							|  |  |  | // This will check if disk should be taken offline.
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) checkHealth(ctx context.Context) (err error) { | 
					
						
							|  |  |  | 	if atomic.LoadInt32(&p.health.status) == diskHealthFaulty { | 
					
						
							|  |  |  | 		return errFaultyDisk | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Check if there are tokens.
 | 
					
						
							|  |  |  | 	if len(p.health.tokens) > 0 { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const maxTimeSinceLastSuccess = 30 * time.Second | 
					
						
							|  |  |  | 	const minTimeSinceLastOpStarted = 15 * time.Second | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// To avoid stampeding herd (100s of simultaneous starting requests)
 | 
					
						
							|  |  |  | 	// there must be a delay between the last started request and now
 | 
					
						
							|  |  |  | 	// for the last lastSuccess to be useful.
 | 
					
						
							|  |  |  | 	t := time.Since(time.Unix(0, atomic.LoadInt64(&p.health.lastStarted))) | 
					
						
							|  |  |  | 	if t < minTimeSinceLastOpStarted { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If also more than 15 seconds since last success, take disk offline.
 | 
					
						
							|  |  |  | 	t = time.Since(time.Unix(0, atomic.LoadInt64(&p.health.lastSuccess))) | 
					
						
							|  |  |  | 	if t > maxTimeSinceLastSuccess { | 
					
						
							|  |  |  | 		if atomic.CompareAndSwapInt32(&p.health.status, diskHealthOK, diskHealthFaulty) { | 
					
						
							| 
									
										
										
										
											2022-08-05 07:10:08 +08:00
										 |  |  | 			logger.LogAlwaysIf(ctx, fmt.Errorf("taking drive %s offline, time since last response %v", p.storage.String(), t.Round(time.Millisecond))) | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 			go p.monitorDiskStatus() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return errFaultyDisk | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // monitorDiskStatus should be called once when a drive has been marked offline.
 | 
					
						
							|  |  |  | // Once the disk has been deemed ok, it will return to online status.
 | 
					
						
							|  |  |  | func (p *xlStorageDiskIDCheck) monitorDiskStatus() { | 
					
						
							|  |  |  | 	t := time.NewTicker(5 * time.Second) | 
					
						
							|  |  |  | 	defer t.Stop() | 
					
						
							|  |  |  | 	fn := mustGetUUID() | 
					
						
							|  |  |  | 	for range t.C { | 
					
						
							|  |  |  | 		if len(p.health.tokens) == 0 { | 
					
						
							|  |  |  | 			// Queue is still full, no need to check.
 | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err := p.storage.WriteAll(context.Background(), minioMetaTmpBucket, fn, []byte{10000: 42}) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b, err := p.storage.ReadAll(context.Background(), minioMetaTmpBucket, fn) | 
					
						
							|  |  |  | 		if err != nil || len(b) != 10001 { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-07-12 00:15:54 +08:00
										 |  |  | 		err = p.storage.Delete(context.Background(), minioMetaTmpBucket, fn, DeleteOptions{ | 
					
						
							|  |  |  | 			Recursive: false, | 
					
						
							|  |  |  | 			Force:     false, | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 		if err == nil { | 
					
						
							| 
									
										
										
										
											2022-10-12 02:33:56 +08:00
										 |  |  | 			logger.Info("Able to read+write+delete, bringing drive %s online. Drive was offline for %s.", p.storage.String(), | 
					
						
							|  |  |  | 				time.Since(time.Unix(0, atomic.LoadInt64(&p.health.lastSuccess)))) | 
					
						
							| 
									
										
										
										
											2022-03-10 03:38:54 +08:00
										 |  |  | 			atomic.StoreInt32(&p.health.status, diskHealthOK) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // diskHealthCheckOK will check if the provided error is nil
 | 
					
						
							|  |  |  | // and update disk status if good.
 | 
					
						
							|  |  |  | // For convenience a bool is returned to indicate any error state
 | 
					
						
							|  |  |  | // that is not io.EOF.
 | 
					
						
							|  |  |  | func diskHealthCheckOK(ctx context.Context, err error) bool { | 
					
						
							|  |  |  | 	// Check if context has a disk health check.
 | 
					
						
							|  |  |  | 	tracker, ok := ctx.Value(healthDiskCtxKey{}).(*healthDiskCtxValue) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		// No tracker, return
 | 
					
						
							|  |  |  | 		return err == nil || errors.Is(err, io.EOF) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err == nil || errors.Is(err, io.EOF) { | 
					
						
							|  |  |  | 		tracker.logSuccess() | 
					
						
							|  |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // diskHealthWrapper provides either a io.Reader or io.Writer
 | 
					
						
							|  |  |  | // that updates status of the provided tracker.
 | 
					
						
							|  |  |  | // Use through diskHealthReader or diskHealthWriter.
 | 
					
						
							|  |  |  | type diskHealthWrapper struct { | 
					
						
							|  |  |  | 	tracker *healthDiskCtxValue | 
					
						
							|  |  |  | 	r       io.Reader | 
					
						
							|  |  |  | 	w       io.Writer | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *diskHealthWrapper) Read(p []byte) (int, error) { | 
					
						
							|  |  |  | 	if d.r == nil { | 
					
						
							|  |  |  | 		return 0, fmt.Errorf("diskHealthWrapper: Read with no reader") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	n, err := d.r.Read(p) | 
					
						
							|  |  |  | 	if err == nil || err == io.EOF && n > 0 { | 
					
						
							|  |  |  | 		d.tracker.logSuccess() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return n, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *diskHealthWrapper) Write(p []byte) (int, error) { | 
					
						
							|  |  |  | 	if d.w == nil { | 
					
						
							|  |  |  | 		return 0, fmt.Errorf("diskHealthWrapper: Write with no writer") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	n, err := d.w.Write(p) | 
					
						
							|  |  |  | 	if err == nil && n == len(p) { | 
					
						
							|  |  |  | 		d.tracker.logSuccess() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return n, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // diskHealthReader provides a wrapper that will update disk health on
 | 
					
						
							|  |  |  | // ctx, on every successful read.
 | 
					
						
							|  |  |  | // This should only be used directly at the os/syscall level,
 | 
					
						
							|  |  |  | // otherwise buffered operations may return false health checks.
 | 
					
						
							|  |  |  | func diskHealthReader(ctx context.Context, r io.Reader) io.Reader { | 
					
						
							|  |  |  | 	// Check if context has a disk health check.
 | 
					
						
							|  |  |  | 	tracker, ok := ctx.Value(healthDiskCtxKey{}).(*healthDiskCtxValue) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		// No need to wrap
 | 
					
						
							|  |  |  | 		return r | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return &diskHealthWrapper{r: r, tracker: tracker} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // diskHealthWriter provides a wrapper that will update disk health on
 | 
					
						
							|  |  |  | // ctx, on every successful write.
 | 
					
						
							|  |  |  | // This should only be used directly at the os/syscall level,
 | 
					
						
							|  |  |  | // otherwise buffered operations may return false health checks.
 | 
					
						
							|  |  |  | func diskHealthWriter(ctx context.Context, w io.Writer) io.Writer { | 
					
						
							|  |  |  | 	// Check if context has a disk health check.
 | 
					
						
							|  |  |  | 	tracker, ok := ctx.Value(healthDiskCtxKey{}).(*healthDiskCtxValue) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		// No need to wrap
 | 
					
						
							|  |  |  | 		return w | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return &diskHealthWrapper{w: w, tracker: tracker} | 
					
						
							|  |  |  | } |