| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Minio Cloud Storage, (C) 2016 Minio, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2016-12-29 19:13:51 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/minio/minio/pkg/disk" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2017-12-17 00:25:29 +08:00
										 |  |  | 	// NOTE: Values indicated here are based on manual testing and
 | 
					
						
							|  |  |  | 	// for best case scenarios under wide array of setups. If you
 | 
					
						
							|  |  |  | 	// encounter changes in future feel free to change these values.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Attempt to retry only this many number of times before
 | 
					
						
							|  |  |  | 	// giving up on the remote disk entirely during initialization.
 | 
					
						
							|  |  |  | 	globalStorageInitRetryThreshold = 2 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | 	// Attempt to retry only this many number of times before
 | 
					
						
							|  |  |  | 	// giving up on the remote disk entirely after initialization.
 | 
					
						
							|  |  |  | 	globalStorageRetryThreshold = 1 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Interval to check health status of a node whether it has
 | 
					
						
							| 
									
										
										
										
											2017-12-17 00:25:29 +08:00
										 |  |  | 	// come back up online during initialization.
 | 
					
						
							|  |  |  | 	globalStorageInitHealthCheckInterval = 15 * time.Minute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Interval to check health status of a node whether it has
 | 
					
						
							|  |  |  | 	// come back up online.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	globalStorageHealthCheckInterval = 5 * time.Minute | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | // Converts rpc.ServerError to underlying error. This function is
 | 
					
						
							|  |  |  | // written so that the storageAPI errors are consistent across network
 | 
					
						
							|  |  |  | // disks as well.
 | 
					
						
							|  |  |  | func retryToStorageErr(err error) error { | 
					
						
							|  |  |  | 	if err == errDiskNotFoundFromNetError || err == errDiskNotFoundFromRPCShutdown { | 
					
						
							|  |  |  | 		return errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | // Retry storage is an instance of StorageAPI which
 | 
					
						
							|  |  |  | // additionally verifies upon network shutdown if the
 | 
					
						
							|  |  |  | // underlying storage is available and is really
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | // formatted. After the initialization phase it will
 | 
					
						
							|  |  |  | // also cache when the underlying storage is offline
 | 
					
						
							|  |  |  | // to prevent needless calls and recheck the health of
 | 
					
						
							|  |  |  | // underlying storage in regular intervals.
 | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | type retryStorage struct { | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | 	remoteStorage    StorageAPI | 
					
						
							|  |  |  | 	maxRetryAttempts int | 
					
						
							| 
									
										
										
										
											2017-12-17 00:25:29 +08:00
										 |  |  | 	retryInterval    time.Duration | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | 	retryUnit        time.Duration | 
					
						
							|  |  |  | 	retryCap         time.Duration | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	offline          bool      // Mark whether node is offline
 | 
					
						
							|  |  |  | 	offlineTimestamp time.Time // Last timestamp of checking status of node
 | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // String representation of remoteStorage.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) String() string { | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	return f.remoteStorage.String() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | // Reconnects to underlying remote storage.
 | 
					
						
							|  |  |  | func (f *retryStorage) Init() (err error) { | 
					
						
							|  |  |  | 	return retryToStorageErr(f.remoteStorage.Init()) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Closes the underlying remote storage connection.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) Close() (err error) { | 
					
						
							|  |  |  | 	return retryToStorageErr(f.remoteStorage.Close()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Return whether the underlying remote storage is offline
 | 
					
						
							|  |  |  | // and, if so, try to reconnect at regular intervals to
 | 
					
						
							|  |  |  | // restore the connection
 | 
					
						
							|  |  |  | func (f *retryStorage) IsOffline() bool { | 
					
						
							|  |  |  | 	// Check if offline and whether enough time has lapsed since most recent check
 | 
					
						
							| 
									
										
										
										
											2017-12-17 00:25:29 +08:00
										 |  |  | 	if f.offline && UTCNow().Sub(f.offlineTimestamp) >= f.retryInterval { | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 		f.offlineTimestamp = UTCNow() // reset timestamp
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if e := f.reInit(nil); e == nil { | 
					
						
							|  |  |  | 			// Connection has been re-established
 | 
					
						
							|  |  |  | 			f.offline = false // Mark node as back online
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return f.offline | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DiskInfo - a retryable implementation of disk info.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) DiskInfo() (info disk.Info, err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return info, errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	info, err = f.remoteStorage.DiskInfo() | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		info, err = f.remoteStorage.DiskInfo() | 
					
						
							|  |  |  | 		return info, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return info, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MakeVol - a retryable implementation of creating a volume.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) MakeVol(volume string) (err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	err = f.remoteStorage.MakeVol(volume) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		return retryToStorageErr(f.remoteStorage.MakeVol(volume)) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListVols - a retryable implementation of listing all the volumes.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) ListVols() (vols []VolInfo, err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return vols, errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	vols, err = f.remoteStorage.ListVols() | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		vols, err = f.remoteStorage.ListVols() | 
					
						
							|  |  |  | 		return vols, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return vols, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StatVol - a retryable implementation of stating a volume.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) StatVol(volume string) (vol VolInfo, err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return vol, errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	vol, err = f.remoteStorage.StatVol(volume) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		vol, err = f.remoteStorage.StatVol(volume) | 
					
						
							|  |  |  | 		return vol, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return vol, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DeleteVol - a retryable implementation of deleting a volume.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) DeleteVol(volume string) (err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	err = f.remoteStorage.DeleteVol(volume) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		return retryToStorageErr(f.remoteStorage.DeleteVol(volume)) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // PrepareFile - a retryable implementation of preparing a file.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) PrepareFile(volume, path string, length int64) (err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	err = f.remoteStorage.PrepareFile(volume, path, length) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		return retryToStorageErr(f.remoteStorage.PrepareFile(volume, path, length)) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AppendFile - a retryable implementation of append to a file.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) AppendFile(volume, path string, buffer []byte) (err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	err = f.remoteStorage.AppendFile(volume, path, buffer) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		return retryToStorageErr(f.remoteStorage.AppendFile(volume, path, buffer)) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StatFile - a retryable implementation of stating a file.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) StatFile(volume, path string) (fileInfo FileInfo, err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return fileInfo, errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	fileInfo, err = f.remoteStorage.StatFile(volume, path) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		fileInfo, err = f.remoteStorage.StatFile(volume, path) | 
					
						
							|  |  |  | 		return fileInfo, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return fileInfo, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ReadAll - a retryable implementation of reading all the content from a file.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) ReadAll(volume, path string) (buf []byte, err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return buf, errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	buf, err = f.remoteStorage.ReadAll(volume, path) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		buf, err = f.remoteStorage.ReadAll(volume, path) | 
					
						
							|  |  |  | 		return buf, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return buf, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ReadFile - a retryable implementation of reading at offset from a file.
 | 
					
						
							| 
									
										
										
										
											2017-09-26 02:32:56 +08:00
										 |  |  | func (f *retryStorage) ReadFile(volume, path string, offset int64, buffer []byte, verifier *BitrotVerifier) (m int64, err error) { | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return m, errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-26 02:32:56 +08:00
										 |  |  | 	m, err = f.remoteStorage.ReadFile(volume, path, offset, buffer, verifier) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							| 
									
										
										
										
											2017-09-26 02:32:56 +08:00
										 |  |  | 		m, err = f.remoteStorage.ReadFile(volume, path, offset, buffer, verifier) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 		return m, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return m, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListDir - a retryable implementation of listing directory entries.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) ListDir(volume, path string) (entries []string, err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return entries, errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	entries, err = f.remoteStorage.ListDir(volume, path) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		entries, err = f.remoteStorage.ListDir(volume, path) | 
					
						
							|  |  |  | 		return entries, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return entries, retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DeleteFile - a retryable implementation of deleting a file.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) DeleteFile(volume, path string) (err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	err = f.remoteStorage.DeleteFile(volume, path) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		return retryToStorageErr(f.remoteStorage.DeleteFile(volume, path)) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return retryToStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RenameFile - a retryable implementation of renaming a file.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) (err error) { | 
					
						
							|  |  |  | 	if f.IsOffline() { | 
					
						
							|  |  |  | 		return errDiskNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	err = f.remoteStorage.RenameFile(srcVolume, srcPath, dstVolume, dstPath) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	if f.reInitUponDiskNotFound(err) { | 
					
						
							|  |  |  | 		return retryToStorageErr(f.remoteStorage.RenameFile(srcVolume, srcPath, dstVolume, dstPath)) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 	return retryToStorageErr(err) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Try to reinitialize the connection when we have some form of DiskNotFound error
 | 
					
						
							|  |  |  | func (f *retryStorage) reInitUponDiskNotFound(err error) bool { | 
					
						
							|  |  |  | 	if err == errDiskNotFound || err == errDiskNotFoundFromNetError || err == errDiskNotFoundFromRPCShutdown { | 
					
						
							|  |  |  | 		return f.reInit(err) == nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-12-29 19:13:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-17 00:25:29 +08:00
										 |  |  | // Connect and attempt to load the format from a disconnected node.
 | 
					
						
							|  |  |  | // Additionally upon failure, we retry maxRetryAttempts times before
 | 
					
						
							|  |  |  | // giving up. Essentially as a whole it would mean we are infact
 | 
					
						
							|  |  |  | // performing 1 + maxRetryAttempts times reInit.
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | func (f *retryStorage) reInit(e error) (err error) { | 
					
						
							| 
									
										
										
										
											2017-12-17 00:25:29 +08:00
										 |  |  | 	// Check whether node has gone offline.
 | 
					
						
							|  |  |  | 	if UTCNow().Sub(f.offlineTimestamp) >= f.retryInterval { | 
					
						
							| 
									
										
										
										
											2017-08-12 02:38:46 +08:00
										 |  |  | 		if e == errDiskNotFoundFromNetError { // Make node offline due to network error
 | 
					
						
							|  |  |  | 			f.offline = true // Marking node offline
 | 
					
						
							|  |  |  | 			f.offlineTimestamp = UTCNow() | 
					
						
							|  |  |  | 			return errDiskNotFound | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Continue for other errors like RPC shutdown (and retry connection below)
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-29 19:13:51 +08:00
										 |  |  | 	// Close the underlying connection.
 | 
					
						
							|  |  |  | 	f.remoteStorage.Close() // Error here is purposefully ignored.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 18:16:29 +08:00
										 |  |  | 	// Done channel is used to close any lingering retry routine, as soon
 | 
					
						
							|  |  |  | 	// as this function returns.
 | 
					
						
							| 
									
										
										
										
											2016-12-29 19:13:51 +08:00
										 |  |  | 	doneCh := make(chan struct{}) | 
					
						
							|  |  |  | 	defer close(doneCh) | 
					
						
							| 
									
										
										
										
											2017-02-07 18:16:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for i := range newRetryTimer(f.retryUnit, f.retryCap, doneCh) { | 
					
						
							| 
									
										
										
										
											2016-12-29 19:13:51 +08:00
										 |  |  | 		// Initialize and make a new login attempt.
 | 
					
						
							|  |  |  | 		err = f.remoteStorage.Init() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			// No need to return error until the retry count
 | 
					
						
							|  |  |  | 			// threshold has reached.
 | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | 			if i < f.maxRetryAttempts { | 
					
						
							| 
									
										
										
										
											2016-12-29 19:13:51 +08:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-29 19:13:51 +08:00
										 |  |  | 		// Attempt to load format to see if the disk is really
 | 
					
						
							|  |  |  | 		// a formatted disk and part of the cluster.
 | 
					
						
							| 
									
										
										
										
											2017-12-17 00:25:29 +08:00
										 |  |  | 		if _, err = loadFormat(f.remoteStorage); err != nil { | 
					
						
							| 
									
										
										
										
											2016-12-29 19:13:51 +08:00
										 |  |  | 			// No need to return error until the retry count
 | 
					
						
							|  |  |  | 			// threshold has reached.
 | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | 			if i < f.maxRetryAttempts { | 
					
						
							| 
									
										
										
										
											2016-12-29 19:13:51 +08:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-29 19:13:51 +08:00
										 |  |  | 		// Login and loading format was a success, break and proceed forward.
 | 
					
						
							|  |  |  | 		break | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } |