| 
									
										
										
										
											2016-08-31 10:22:27 +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-11-03 06:27:36 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	"github.com/minio/mc/pkg/console" | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Following table lists different possible states the backend could be in. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   * In a single-node, multi-disk setup, "Online" would refer to disks' status. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   * In a multi-node setup, it could refer to disks' or network connectivity | 
					
						
							|  |  |  |   between the nodes, or both. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   +----------+--------------------------+-----------------------+ | 
					
						
							|  |  |  |   | Online   | Format status  		| Course of action      | | 
					
						
							|  |  |  |   |          | 		             	|                   	| | 
					
						
							|  |  |  |   -----------+--------------------------+-----------------------+ | 
					
						
							|  |  |  |   | All      | All Formatted	 	|  			| | 
					
						
							|  |  |  |   +----------+--------------------------+  initObjectLayer 	| | 
					
						
							|  |  |  |   | Quorum   | Quorum Formatted    	|                   	| | 
					
						
							|  |  |  |   +----------+--------------------------+-----------------------+ | 
					
						
							|  |  |  |   | All      | Quorum     		|  Print message saying | | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  |   |	     | Formatted,   		|   "Heal via control"  | | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  |   |	     | some unformatted		|  and initObjectLayer  | | 
					
						
							|  |  |  |   +----------+--------------------------+-----------------------+ | 
					
						
							|  |  |  |   | All      | None Formatted           |  FormatDisks          | | 
					
						
							|  |  |  |   |	     |				|  and initObjectLayer  | | 
					
						
							|  |  |  |   |          | 		             	|                   	| | 
					
						
							|  |  |  |   +----------+--------------------------+-----------------------+ | 
					
						
							| 
									
										
										
										
											2016-09-09 00:35:13 +08:00
										 |  |  |   | No       |          		|  Wait till enough     | | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  |   | Quorum   |          _  		|  nodes are online and | | 
					
						
							|  |  |  |   |	     |                          |  one of the above     | | 
					
						
							|  |  |  |   |          |				|  sections apply       | | 
					
						
							|  |  |  |   +----------+--------------------------+-----------------------+ | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  |   |	     |      			|                       | | 
					
						
							|  |  |  |   | Quorum   | Quorum UnFormatted   	|        Abort        	| | 
					
						
							|  |  |  |   +----------+--------------------------+-----------------------+ | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  |   A disk can be in one of the following states. | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  |    - Unformatted | 
					
						
							|  |  |  |    - Formatted | 
					
						
							|  |  |  |    - Corrupted | 
					
						
							|  |  |  |    - Offline | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // InitActions - a type synonym for enumerating initialization activities.
 | 
					
						
							|  |  |  | type InitActions int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	// FormatDisks - see above table for disk states where it
 | 
					
						
							|  |  |  | 	// is applicable.
 | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	FormatDisks InitActions = iota | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// WaitForHeal - Wait for disks to heal.
 | 
					
						
							|  |  |  | 	WaitForHeal | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// WaitForQuorum - Wait for quorum number of disks to be online.
 | 
					
						
							|  |  |  | 	WaitForQuorum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// WaitForAll - Wait for all disks to be online.
 | 
					
						
							|  |  |  | 	WaitForAll | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	// WaitForFormatting - Wait for formatting to be triggered
 | 
					
						
							|  |  |  | 	// from the '1st' server in the cluster.
 | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	WaitForFormatting | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	// WaitForConfig - Wait for all servers to have the same config
 | 
					
						
							|  |  |  | 	// including (credentials, version and time).
 | 
					
						
							| 
									
										
										
										
											2016-10-08 02:15:55 +08:00
										 |  |  | 	WaitForConfig | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	// InitObjectLayer - Initialize object layer.
 | 
					
						
							|  |  |  | 	InitObjectLayer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Abort initialization of object layer since there aren't enough good
 | 
					
						
							|  |  |  | 	// copies of format.json to recover.
 | 
					
						
							|  |  |  | 	Abort | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | // Quick error to actions converts looking for specific errors
 | 
					
						
							|  |  |  | // which need to be returned quickly and server should wait instead.
 | 
					
						
							| 
									
										
										
										
											2016-10-08 02:15:55 +08:00
										 |  |  | func quickErrToActions(errMap map[error]int) InitActions { | 
					
						
							|  |  |  | 	var action InitActions | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case errMap[errInvalidAccessKeyID] > 0: | 
					
						
							|  |  |  | 		fallthrough | 
					
						
							|  |  |  | 	case errMap[errAuthentication] > 0: | 
					
						
							|  |  |  | 		fallthrough | 
					
						
							|  |  |  | 	case errMap[errServerVersionMismatch] > 0: | 
					
						
							|  |  |  | 		fallthrough | 
					
						
							|  |  |  | 	case errMap[errServerTimeMismatch] > 0: | 
					
						
							|  |  |  | 		action = WaitForConfig | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return action | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Preparatory initialization stage for XL validates known errors.
 | 
					
						
							|  |  |  | // Converts them into specific actions. These actions have special purpose
 | 
					
						
							|  |  |  | // which caller decides on what needs to be done.
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | func prepForInitXL(firstDisk bool, sErrs []error, diskCount int) InitActions { | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	// Count errors by error value.
 | 
					
						
							|  |  |  | 	errMap := make(map[error]int) | 
					
						
							| 
									
										
										
										
											2016-09-07 04:30:05 +08:00
										 |  |  | 	for _, err := range sErrs { | 
					
						
							|  |  |  | 		errMap[err]++ | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-08 02:15:55 +08:00
										 |  |  | 	// Validates and converts specific config errors into WaitForConfig.
 | 
					
						
							|  |  |  | 	if quickErrToActions(errMap) == WaitForConfig { | 
					
						
							|  |  |  | 		return WaitForConfig | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	quorum := diskCount/2 + 1 | 
					
						
							| 
									
										
										
										
											2017-04-09 15:28:27 +08:00
										 |  |  | 	readQuorum := diskCount / 2 | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	disksOffline := errMap[errDiskNotFound] | 
					
						
							|  |  |  | 	disksFormatted := errMap[nil] | 
					
						
							|  |  |  | 	disksUnformatted := errMap[errUnformattedDisk] | 
					
						
							|  |  |  | 	disksCorrupted := errMap[errCorruptedFormat] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	// No Quorum lots of offline disks, wait for quorum.
 | 
					
						
							| 
									
										
										
										
											2017-04-09 15:28:27 +08:00
										 |  |  | 	if disksOffline > readQuorum { | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 		return WaitForQuorum | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// There is quorum or more corrupted disks, there is not enough good
 | 
					
						
							|  |  |  | 	// disks to reconstruct format.json.
 | 
					
						
							|  |  |  | 	if disksCorrupted >= quorum { | 
					
						
							|  |  |  | 		return Abort | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	// All disks are unformatted, proceed to formatting disks.
 | 
					
						
							|  |  |  | 	if disksUnformatted == diskCount { | 
					
						
							|  |  |  | 		// Only the first server formats an uninitialized setup, others wait for notification.
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 		if firstDisk { // First node always initializes.
 | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 			return FormatDisks | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return WaitForFormatting | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Total disks unformatted are in quorum verify if we have some offline disks.
 | 
					
						
							|  |  |  | 	if disksUnformatted >= quorum { | 
					
						
							|  |  |  | 		// Some disks offline and some disks unformatted, wait for all of them to come online.
 | 
					
						
							| 
									
										
										
										
											2016-10-17 23:39:55 +08:00
										 |  |  | 		if disksUnformatted+disksFormatted+disksOffline == diskCount { | 
					
						
							| 
									
										
										
										
											2016-09-09 00:35:13 +08:00
										 |  |  | 			return WaitForAll | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 		// Some disks possibly corrupted and too many unformatted disks.
 | 
					
						
							|  |  |  | 		return Abort | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	// Already formatted and in quorum, proceed to initialization of object layer.
 | 
					
						
							| 
									
										
										
										
											2017-04-09 15:28:27 +08:00
										 |  |  | 	if disksFormatted >= readQuorum { | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 		if disksFormatted+disksOffline == diskCount { | 
					
						
							| 
									
										
										
										
											2016-09-09 00:35:13 +08:00
										 |  |  | 			return InitObjectLayer | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 		// Some of the formatted disks are possibly corrupted or unformatted, heal them.
 | 
					
						
							| 
									
										
										
										
											2016-09-09 00:35:13 +08:00
										 |  |  | 		return WaitForHeal | 
					
						
							| 
									
										
										
										
											2016-10-08 02:15:55 +08:00
										 |  |  | 	} // Exhausted all our checks, un-handled errors perhaps we Abort.
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	return WaitForQuorum | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | // Prints retry message upon a specific retry count.
 | 
					
						
							|  |  |  | func printRetryMsg(sErrs []error, storageDisks []StorageAPI) { | 
					
						
							|  |  |  | 	for i, sErr := range sErrs { | 
					
						
							|  |  |  | 		switch sErr { | 
					
						
							|  |  |  | 		case errDiskNotFound, errFaultyDisk, errFaultyRemoteDisk: | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 			errorIf(sErr, "Disk %s is still unreachable", storageDisks[i]) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-19 01:35:17 +08:00
										 |  |  | // Maximum retry attempts.
 | 
					
						
							|  |  |  | const maxRetryAttempts = 5 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | // Implements a jitter backoff loop for formatting all disks during
 | 
					
						
							|  |  |  | // initialization of the server.
 | 
					
						
							| 
									
										
										
										
											2017-04-12 06:44:27 +08:00
										 |  |  | func retryFormattingXLDisks(firstDisk bool, endpoints EndpointList, storageDisks []StorageAPI) error { | 
					
						
							| 
									
										
										
										
											2016-11-02 23:51:06 +08:00
										 |  |  | 	if len(endpoints) == 0 { | 
					
						
							|  |  |  | 		return errInvalidArgument | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	if storageDisks == nil { | 
					
						
							|  |  |  | 		return errInvalidArgument | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 18:16:29 +08:00
										 |  |  | 	// Done channel is used to close any lingering retry routine, as soon
 | 
					
						
							|  |  |  | 	// as this function returns.
 | 
					
						
							|  |  |  | 	doneCh := make(chan struct{}) | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 18:16:29 +08:00
										 |  |  | 	// Indicate to our retry routine to exit cleanly, upon this function return.
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	defer close(doneCh) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-08 02:22:00 +08:00
										 |  |  | 	// prepare getElapsedTime() to calculate elapsed time since we started trying formatting disks.
 | 
					
						
							|  |  |  | 	// All times are rounded to avoid showing milli, micro and nano seconds
 | 
					
						
							|  |  |  | 	formatStartTime := time.Now().Round(time.Second) | 
					
						
							|  |  |  | 	getElapsedTime := func() string { | 
					
						
							|  |  |  | 		return time.Now().Round(time.Second).Sub(formatStartTime).String() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	// Wait on the jitter retry loop.
 | 
					
						
							| 
									
										
										
										
											2017-02-07 18:16:29 +08:00
										 |  |  | 	retryTimerCh := newRetryTimerSimple(doneCh) | 
					
						
							| 
									
										
										
										
											2016-11-03 06:27:36 +08:00
										 |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 		case retryCount := <-retryTimerCh: | 
					
						
							|  |  |  | 			// Attempt to load all `format.json` from all disks.
 | 
					
						
							| 
									
										
										
										
											2016-11-03 06:27:36 +08:00
										 |  |  | 			formatConfigs, sErrs := loadAllFormats(storageDisks) | 
					
						
							| 
									
										
										
										
											2017-04-19 01:35:17 +08:00
										 |  |  | 			if retryCount > maxRetryAttempts { | 
					
						
							|  |  |  | 				// After max retry attempts we start printing
 | 
					
						
							|  |  |  | 				// actual errors for disks not being available.
 | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 				printRetryMsg(sErrs, storageDisks) | 
					
						
							| 
									
										
										
										
											2016-10-27 07:09:06 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-12-12 07:18:55 +08:00
										 |  |  | 			// Pre-emptively check if one of the formatted disks
 | 
					
						
							|  |  |  | 			// is invalid. This function returns success for the
 | 
					
						
							|  |  |  | 			// most part unless one of the formats is not consistent
 | 
					
						
							| 
									
										
										
										
											2017-04-19 01:35:17 +08:00
										 |  |  | 			// with expected XL format. For example if a user is
 | 
					
						
							|  |  |  | 			// trying to pool FS backend into an XL set.
 | 
					
						
							|  |  |  | 			if index, err := checkFormatXLValues(formatConfigs); err != nil { | 
					
						
							|  |  |  | 				// We will perhaps print and retry for the first 5 attempts
 | 
					
						
							|  |  |  | 				// because in XL initialization first server is the one which
 | 
					
						
							|  |  |  | 				// initializes the erasure set. This check ensures that the
 | 
					
						
							|  |  |  | 				// rest of the other servers do get a chance to see that the
 | 
					
						
							|  |  |  | 				// first server has a wrong format and exit gracefully.
 | 
					
						
							|  |  |  | 				// refer - https://github.com/minio/minio/issues/4140
 | 
					
						
							|  |  |  | 				if retryCount > maxRetryAttempts { | 
					
						
							|  |  |  | 					errorIf(err, "Detected disk (%s) in unexpected format", | 
					
						
							|  |  |  | 						storageDisks[index]) | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-12-12 07:18:55 +08:00
										 |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 			// Check if this is a XL or distributed XL, anything > 1 is considered XL backend.
 | 
					
						
							| 
									
										
										
										
											2016-12-12 07:18:55 +08:00
										 |  |  | 			switch prepForInitXL(firstDisk, sErrs, len(storageDisks)) { | 
					
						
							|  |  |  | 			case Abort: | 
					
						
							|  |  |  | 				return errCorruptedFormat | 
					
						
							|  |  |  | 			case FormatDisks: | 
					
						
							|  |  |  | 				console.Eraseline() | 
					
						
							|  |  |  | 				printFormatMsg(endpoints, storageDisks, printOnceFn()) | 
					
						
							|  |  |  | 				return initFormatXL(storageDisks) | 
					
						
							|  |  |  | 			case InitObjectLayer: | 
					
						
							| 
									
										
										
										
											2016-11-03 06:27:36 +08:00
										 |  |  | 				console.Eraseline() | 
					
						
							| 
									
										
										
										
											2016-12-12 07:18:55 +08:00
										 |  |  | 				// Validate formats loaded before proceeding forward.
 | 
					
						
							|  |  |  | 				err := genericFormatCheckXL(formatConfigs, sErrs) | 
					
						
							|  |  |  | 				if err == nil { | 
					
						
							|  |  |  | 					printRegularMsg(endpoints, storageDisks, printOnceFn()) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			case WaitForHeal: | 
					
						
							|  |  |  | 				// Validate formats loaded before proceeding forward.
 | 
					
						
							|  |  |  | 				err := genericFormatCheckXL(formatConfigs, sErrs) | 
					
						
							|  |  |  | 				if err == nil { | 
					
						
							|  |  |  | 					printHealMsg(endpoints, storageDisks, printOnceFn()) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			case WaitForQuorum: | 
					
						
							|  |  |  | 				console.Printf( | 
					
						
							|  |  |  | 					"Initializing data volume. Waiting for minimum %d servers to come online. (elapsed %s)\n", | 
					
						
							|  |  |  | 					len(storageDisks)/2+1, getElapsedTime(), | 
					
						
							|  |  |  | 				) | 
					
						
							|  |  |  | 			case WaitForConfig: | 
					
						
							|  |  |  | 				// Print configuration errors.
 | 
					
						
							|  |  |  | 				printConfigErrMsg(storageDisks, sErrs, printOnceFn()) | 
					
						
							|  |  |  | 			case WaitForAll: | 
					
						
							|  |  |  | 				console.Printf("Initializing data volume for first time. Waiting for other servers to come online (elapsed %s)\n", getElapsedTime()) | 
					
						
							|  |  |  | 			case WaitForFormatting: | 
					
						
							|  |  |  | 				console.Printf("Initializing data volume for first time. Waiting for first server to come online (elapsed %s)\n", getElapsedTime()) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-11-03 06:27:36 +08:00
										 |  |  | 		case <-globalServiceDoneCh: | 
					
						
							| 
									
										
										
										
											2016-11-16 10:14:23 +08:00
										 |  |  | 			return errors.New("Initializing data volumes gracefully stopped") | 
					
						
							| 
									
										
										
										
											2016-11-03 06:27:36 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | // Initialize storage disks based on input arguments.
 | 
					
						
							| 
									
										
										
										
											2017-04-12 06:44:27 +08:00
										 |  |  | func initStorageDisks(endpoints EndpointList) ([]StorageAPI, error) { | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	// Bootstrap disks.
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:30:52 +08:00
										 |  |  | 	storageDisks := make([]StorageAPI, len(endpoints)) | 
					
						
							| 
									
										
										
										
											2017-04-12 06:44:27 +08:00
										 |  |  | 	for index, endpoint := range endpoints { | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 		// Intentionally ignore disk not found errors. XL is designed
 | 
					
						
							|  |  |  | 		// to handle these errors internally.
 | 
					
						
							| 
									
										
										
										
											2017-04-12 06:44:27 +08:00
										 |  |  | 		storage, err := newStorageAPI(endpoint) | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 		if err != nil && err != errDiskNotFound { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		storageDisks[index] = storage | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	return storageDisks, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-09 15:28:27 +08:00
										 |  |  | // Format disks before initialization of object layer.
 | 
					
						
							| 
									
										
										
										
											2017-04-12 06:44:27 +08:00
										 |  |  | func waitForFormatXLDisks(firstDisk bool, endpoints EndpointList, storageDisks []StorageAPI) (formattedDisks []StorageAPI, err error) { | 
					
						
							| 
									
										
										
										
											2016-11-02 23:51:06 +08:00
										 |  |  | 	if len(endpoints) == 0 { | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 		return nil, errInvalidArgument | 
					
						
							| 
									
										
										
										
											2016-11-02 23:51:06 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	if storageDisks == nil { | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 		return nil, errInvalidArgument | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Retryable disks before formatting, we need to have a larger
 | 
					
						
							|  |  |  | 	// retry window so that we wait enough amount of time before
 | 
					
						
							|  |  |  | 	// the disks come online.
 | 
					
						
							|  |  |  | 	retryDisks := make([]StorageAPI, len(storageDisks)) | 
					
						
							|  |  |  | 	for i, storage := range storageDisks { | 
					
						
							|  |  |  | 		retryDisks[i] = &retryStorage{ | 
					
						
							|  |  |  | 			remoteStorage:    storage, | 
					
						
							|  |  |  | 			maxRetryAttempts: globalStorageInitRetryThreshold, | 
					
						
							|  |  |  | 			retryUnit:        time.Second, | 
					
						
							|  |  |  | 			retryCap:         time.Second * 30, // 30 seconds.
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 03:48:07 +08:00
										 |  |  | 	// Start retry loop retrying until disks are formatted properly, until we have reached
 | 
					
						
							|  |  |  | 	// a conditional quorum of formatted disks.
 | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	err = retryFormattingXLDisks(firstDisk, endpoints, retryDisks) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	// Initialize the disk into a formatted disks wrapper.
 | 
					
						
							|  |  |  | 	formattedDisks = make([]StorageAPI, len(storageDisks)) | 
					
						
							|  |  |  | 	for i, storage := range storageDisks { | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | 		// After formatting is done we need a smaller time
 | 
					
						
							|  |  |  | 		// window and lower retry value before formatting.
 | 
					
						
							|  |  |  | 		formattedDisks[i] = &retryStorage{ | 
					
						
							|  |  |  | 			remoteStorage:    storage, | 
					
						
							|  |  |  | 			maxRetryAttempts: globalStorageRetryThreshold, | 
					
						
							|  |  |  | 			retryUnit:        time.Millisecond, | 
					
						
							|  |  |  | 			retryCap:         time.Millisecond * 5, // 5 milliseconds.
 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-31 09:08:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Success.
 | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	return formattedDisks, nil | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | } |