| 
									
										
										
										
											2016-04-29 16:29:09 +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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | import ( | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2016-05-17 05:31:28 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-08-24 10:19:24 +08:00
										 |  |  | 	pathutil "path" | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	"runtime" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2017-10-13 18:01:15 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 	"github.com/minio/dsync" | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	"github.com/minio/lsync" | 
					
						
							| 
									
										
										
										
											2018-01-23 02:25:10 +08:00
										 |  |  | 	"github.com/minio/minio-go/pkg/set" | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	"github.com/minio/minio/cmd/logger" | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	xnet "github.com/minio/minio/pkg/net" | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | // Global name space lock.
 | 
					
						
							| 
									
										
										
										
											2016-12-11 08:15:12 +08:00
										 |  |  | var globalNSMutex *nsLockMap | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-23 02:25:10 +08:00
										 |  |  | // Global lock server one per server.
 | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | var globalLockServer *lockRPCReceiver | 
					
						
							| 
									
										
										
										
											2018-01-23 02:25:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Instance of dsync for distributed clients.
 | 
					
						
							|  |  |  | var globalDsync *dsync.Dsync | 
					
						
							| 
									
										
										
										
											2017-06-06 03:25:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | // RWLocker - locker interface to introduce GetRLock, RUnlock.
 | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | type RWLocker interface { | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	GetLock(timeout *dynamicTimeout) (timedOutErr error) | 
					
						
							|  |  |  | 	Unlock() | 
					
						
							|  |  |  | 	GetRLock(timeout *dynamicTimeout) (timedOutErr error) | 
					
						
							|  |  |  | 	RUnlock() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RWLockerSync - internal locker interface.
 | 
					
						
							|  |  |  | type RWLockerSync interface { | 
					
						
							|  |  |  | 	GetLock(timeout time.Duration) bool | 
					
						
							|  |  |  | 	Unlock() | 
					
						
							|  |  |  | 	GetRLock(timeout time.Duration) bool | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	RUnlock() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | // Initialize distributed locking only in case of distributed setup.
 | 
					
						
							| 
									
										
										
										
											2017-06-06 03:25:04 +08:00
										 |  |  | // Returns lock clients and the node index for the current server.
 | 
					
						
							|  |  |  | func newDsyncNodes(endpoints EndpointList) (clnts []dsync.NetLocker, myNode int) { | 
					
						
							|  |  |  | 	myNode = -1 | 
					
						
							| 
									
										
										
										
											2018-01-23 02:25:10 +08:00
										 |  |  | 	seenHosts := set.NewStringSet() | 
					
						
							|  |  |  | 	for _, endpoint := range endpoints { | 
					
						
							|  |  |  | 		if seenHosts.Contains(endpoint.Host) { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		seenHosts.Add(endpoint.Host) | 
					
						
							| 
									
										
										
										
											2017-06-06 03:25:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 		var locker dsync.NetLocker | 
					
						
							|  |  |  | 		if endpoint.IsLocal { | 
					
						
							|  |  |  | 			myNode = len(clnts) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			receiver := &lockRPCReceiver{ | 
					
						
							|  |  |  | 				ll: localLocker{ | 
					
						
							|  |  |  | 					serverAddr:      endpoint.Host, | 
					
						
							|  |  |  | 					serviceEndpoint: lockServicePath, | 
					
						
							|  |  |  | 					lockMap:         make(map[string][]lockRequesterInfo), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			globalLockServer = receiver | 
					
						
							|  |  |  | 			locker = &(receiver.ll) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			host, err := xnet.ParseHost(endpoint.Host) | 
					
						
							| 
									
										
										
										
											2018-06-15 01:17:07 +08:00
										 |  |  | 			logger.FatalIf(err, "Unable to parse Lock RPC Host", context.Background()) | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 			locker, err = NewLockRPCClient(host) | 
					
						
							| 
									
										
										
										
											2018-06-15 01:17:07 +08:00
										 |  |  | 			logger.FatalIf(err, "Unable to initialize Lock RPC Client", context.Background()) | 
					
						
							| 
									
										
										
										
											2017-06-06 03:25:04 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 		clnts = append(clnts, locker) | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 03:25:04 +08:00
										 |  |  | 	return clnts, myNode | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-13 12:34:52 +08:00
										 |  |  | // newNSLock - return a new name space lock map.
 | 
					
						
							|  |  |  | func newNSLock(isDistXL bool) *nsLockMap { | 
					
						
							|  |  |  | 	nsMutex := nsLockMap{ | 
					
						
							| 
									
										
										
										
											2016-12-11 08:15:12 +08:00
										 |  |  | 		isDistXL: isDistXL, | 
					
						
							|  |  |  | 		lockMap:  make(map[nsParam]*nsLock), | 
					
						
							| 
									
										
										
										
											2016-12-27 02:29:55 +08:00
										 |  |  | 		counters: &lockStat{}, | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-28 05:35:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-11 15:50:27 +08:00
										 |  |  | 	// Initialize nsLockMap with entry for instrumentation information.
 | 
					
						
							| 
									
										
										
										
											2016-09-28 05:35:43 +08:00
										 |  |  | 	// Entries of <volume,path> -> stateInfo of locks
 | 
					
						
							| 
									
										
										
										
											2018-01-13 12:34:52 +08:00
										 |  |  | 	nsMutex.debugLockMap = make(map[nsParam]*debugLockInfoPerVolumePath) | 
					
						
							|  |  |  | 	return &nsMutex | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // initNSLock - initialize name space lock map.
 | 
					
						
							|  |  |  | func initNSLock(isDistXL bool) { | 
					
						
							|  |  |  | 	globalNSMutex = newNSLock(isDistXL) | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | // nsParam - carries name space resource.
 | 
					
						
							|  |  |  | type nsParam struct { | 
					
						
							|  |  |  | 	volume string | 
					
						
							|  |  |  | 	path   string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // nsLock - provides primitives for locking critical namespace regions.
 | 
					
						
							|  |  |  | type nsLock struct { | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	RWLockerSync | 
					
						
							| 
									
										
										
										
											2016-09-16 15:30:55 +08:00
										 |  |  | 	ref uint | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // nsLockMap - namespace lock map, provides primitives to Lock,
 | 
					
						
							|  |  |  | // Unlock, RLock and RUnlock.
 | 
					
						
							|  |  |  | type nsLockMap struct { | 
					
						
							| 
									
										
										
										
											2016-10-11 15:50:27 +08:00
										 |  |  | 	// Lock counter used for lock debugging.
 | 
					
						
							| 
									
										
										
										
											2016-12-27 02:29:55 +08:00
										 |  |  | 	counters     *lockStat | 
					
						
							|  |  |  | 	debugLockMap map[nsParam]*debugLockInfoPerVolumePath // Info for instrumentation on locks.
 | 
					
						
							| 
									
										
										
										
											2016-09-20 04:14:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	// Indicates if namespace is part of a distributed setup.
 | 
					
						
							| 
									
										
										
										
											2016-12-11 08:15:12 +08:00
										 |  |  | 	isDistXL     bool | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 	lockMap      map[nsParam]*nsLock | 
					
						
							|  |  |  | 	lockMapMutex sync.Mutex | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | // Lock the namespace resource.
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | func (n *nsLockMap) lock(volume, path string, lockSource, opsID string, readLock bool, timeout time.Duration) (locked bool) { | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 	var nsLk *nsLock | 
					
						
							|  |  |  | 	n.lockMapMutex.Lock() | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	param := nsParam{volume, path} | 
					
						
							|  |  |  | 	nsLk, found := n.lockMap[param] | 
					
						
							|  |  |  | 	if !found { | 
					
						
							|  |  |  | 		nsLk = &nsLock{ | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 			RWLockerSync: func() RWLockerSync { | 
					
						
							| 
									
										
										
										
											2016-12-11 08:15:12 +08:00
										 |  |  | 				if n.isDistXL { | 
					
						
							| 
									
										
										
										
											2018-01-23 02:25:10 +08:00
										 |  |  | 					return dsync.NewDRWMutex(pathJoin(volume, path), globalDsync) | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 				return &lsync.LRWMutex{} | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 			}(), | 
					
						
							|  |  |  | 			ref: 0, | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 		n.lockMap[param] = nsLk | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-02 07:43:31 +08:00
										 |  |  | 	nsLk.ref++ // Update ref count here to avoid multiple races.
 | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-28 05:35:43 +08:00
										 |  |  | 	// Change the state of the lock to be blocked for the given
 | 
					
						
							|  |  |  | 	// pair of <volume, path> and <OperationID> till the lock
 | 
					
						
							| 
									
										
										
										
											2016-12-11 08:15:12 +08:00
										 |  |  | 	// unblocks. The lock for accessing `globalNSMutex` is held inside
 | 
					
						
							| 
									
										
										
										
											2016-09-28 05:35:43 +08:00
										 |  |  | 	// the function itself.
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	n.statusNoneToBlocked(param, lockSource, opsID, readLock) | 
					
						
							| 
									
										
										
										
											2016-09-20 04:14:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	// Unlock map before Locking NS which might block.
 | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 	n.lockMapMutex.Unlock() | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	// Locking here will block (until timeout).
 | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	if readLock { | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 		locked = nsLk.GetRLock(timeout) | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 		locked = nsLk.GetLock(timeout) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !locked { // We failed to get the lock
 | 
					
						
							|  |  |  | 		n.lockMapMutex.Lock() | 
					
						
							|  |  |  | 		defer n.lockMapMutex.Unlock() | 
					
						
							|  |  |  | 		// Changing the status of the operation from blocked to none
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 		n.statusBlockedToNone(param, lockSource, opsID, readLock) | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		nsLk.ref-- // Decrement ref count since we failed to get the lock
 | 
					
						
							|  |  |  | 		// delete the lock state entry for given operation ID.
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 		n.deleteLockInfoEntryForOps(param, opsID) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 		if nsLk.ref == 0 { | 
					
						
							|  |  |  | 			// Remove from the map if there are no more references.
 | 
					
						
							|  |  |  | 			delete(n.lockMap, param) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// delete the lock state entry for given
 | 
					
						
							|  |  |  | 			// <volume, path> pair.
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 			n.deleteLockInfoEntryForVolumePath(param) | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-28 05:35:43 +08:00
										 |  |  | 	// Changing the status of the operation from blocked to
 | 
					
						
							|  |  |  | 	// running.  change the state of the lock to be running (from
 | 
					
						
							| 
									
										
										
										
											2016-10-11 15:50:27 +08:00
										 |  |  | 	// blocked) for the given pair of <volume, path> and <OperationID>.
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	n.statusBlockedToRunning(param, lockSource, opsID, readLock) | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	return | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | // Unlock the namespace resource.
 | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | func (n *nsLockMap) unlock(volume, path, opsID string, readLock bool) { | 
					
						
							| 
									
										
										
										
											2016-09-28 05:35:43 +08:00
										 |  |  | 	// nsLk.Unlock() will not block, hence locking the map for the
 | 
					
						
							|  |  |  | 	// entire function is fine.
 | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 	n.lockMapMutex.Lock() | 
					
						
							|  |  |  | 	defer n.lockMapMutex.Unlock() | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	param := nsParam{volume, path} | 
					
						
							|  |  |  | 	if nsLk, found := n.lockMap[param]; found { | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 		if readLock { | 
					
						
							| 
									
										
										
										
											2016-09-16 15:30:55 +08:00
										 |  |  | 			nsLk.RUnlock() | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2016-09-16 15:30:55 +08:00
										 |  |  | 			nsLk.Unlock() | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if nsLk.ref == 0 { | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 			logger.LogIf(context.Background(), errors.New("Namespace reference count cannot be 0")) | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 		if nsLk.ref != 0 { | 
					
						
							|  |  |  | 			nsLk.ref-- | 
					
						
							| 
									
										
										
										
											2016-09-28 05:35:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// delete the lock state entry for given operation ID.
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 			n.deleteLockInfoEntryForOps(param, opsID) | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 		if nsLk.ref == 0 { | 
					
						
							|  |  |  | 			// Remove from the map if there are no more references.
 | 
					
						
							|  |  |  | 			delete(n.lockMap, param) | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-28 05:35:43 +08:00
										 |  |  | 			// delete the lock state entry for given
 | 
					
						
							|  |  |  | 			// <volume, path> pair.
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 			n.deleteLockInfoEntryForVolumePath(param) | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | // Lock - locks the given resource for writes, using a previously
 | 
					
						
							|  |  |  | // allocated name space lock or initializing a new one.
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | func (n *nsLockMap) Lock(volume, path, opsID string, timeout time.Duration) (locked bool) { | 
					
						
							| 
									
										
										
										
											2016-10-11 15:50:27 +08:00
										 |  |  | 	readLock := false // This is a write lock.
 | 
					
						
							| 
									
										
										
										
											2016-09-28 05:35:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	lockSource := getSource() // Useful for debugging
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	return n.lock(volume, path, lockSource, opsID, readLock, timeout) | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | // Unlock - unlocks any previously acquired write locks.
 | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | func (n *nsLockMap) Unlock(volume, path, opsID string) { | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	readLock := false | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | 	n.unlock(volume, path, opsID, readLock) | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | // RLock - locks any previously acquired read locks.
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | func (n *nsLockMap) RLock(volume, path, opsID string, timeout time.Duration) (locked bool) { | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	readLock := true | 
					
						
							| 
									
										
										
										
											2016-09-28 05:35:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	lockSource := getSource() // Useful for debugging
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	return n.lock(volume, path, lockSource, opsID, readLock, timeout) | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RUnlock - unlocks any previously acquired read locks.
 | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | func (n *nsLockMap) RUnlock(volume, path, opsID string) { | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	readLock := true | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | 	n.unlock(volume, path, opsID, readLock) | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-10-20 00:27:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ForceUnlock - forcefully unlock a lock based on name.
 | 
					
						
							|  |  |  | func (n *nsLockMap) ForceUnlock(volume, path string) { | 
					
						
							|  |  |  | 	n.lockMapMutex.Lock() | 
					
						
							|  |  |  | 	defer n.lockMapMutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-21 04:15:28 +08:00
										 |  |  | 	// Clarification on operation:
 | 
					
						
							| 
									
										
										
										
											2016-12-11 08:15:12 +08:00
										 |  |  | 	// - In case of FS or XL we call ForceUnlock on the local globalNSMutex
 | 
					
						
							| 
									
										
										
										
											2016-10-21 04:15:28 +08:00
										 |  |  | 	//   (since there is only a single server) which will cause the 'stuck'
 | 
					
						
							|  |  |  | 	//   mutex to be removed from the map. Existing operations for this
 | 
					
						
							|  |  |  | 	//   will continue to be blocked (and timeout). New operations on this
 | 
					
						
							|  |  |  | 	//   resource will use a new mutex and proceed normally.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// - In case of Distributed setup (using dsync), there is no need to call
 | 
					
						
							|  |  |  | 	//   ForceUnlock on the server where the lock was acquired and is presumably
 | 
					
						
							|  |  |  | 	//   'stuck'. Instead dsync.ForceUnlock() will release the underlying locks
 | 
					
						
							|  |  |  | 	//   that participated in granting the lock. Any pending dsync locks that
 | 
					
						
							|  |  |  | 	//   are blocking can now proceed as normal and any new locks will also
 | 
					
						
							|  |  |  | 	//   participate normally.
 | 
					
						
							| 
									
										
										
										
											2016-12-11 08:15:12 +08:00
										 |  |  | 	if n.isDistXL { // For distributed mode, broadcast ForceUnlock message.
 | 
					
						
							| 
									
										
										
										
											2018-01-23 02:25:10 +08:00
										 |  |  | 		dsync.NewDRWMutex(pathJoin(volume, path), globalDsync).ForceUnlock() | 
					
						
							| 
									
										
										
										
											2016-10-20 00:27:36 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	param := nsParam{volume, path} | 
					
						
							|  |  |  | 	if _, found := n.lockMap[param]; found { | 
					
						
							|  |  |  | 		// Remove lock from the map.
 | 
					
						
							|  |  |  | 		delete(n.lockMap, param) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-16 22:19:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// delete the lock state entry for given
 | 
					
						
							|  |  |  | 	// <volume, path> pair. Ignore error as there
 | 
					
						
							|  |  |  | 	// is no way to report it back
 | 
					
						
							|  |  |  | 	n.deleteLockInfoEntryForVolumePath(param) | 
					
						
							| 
									
										
										
										
											2016-10-20 00:27:36 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // lockInstance - frontend/top-level interface for namespace locks.
 | 
					
						
							|  |  |  | type lockInstance struct { | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	ns                  *nsLockMap | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | 	volume, path, opsID string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewNSLock - returns a lock instance for a given volume and
 | 
					
						
							|  |  |  | // path. The returned lockInstance object encapsulates the nsLockMap,
 | 
					
						
							|  |  |  | // volume, path and operation ID.
 | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | func (n *nsLockMap) NewNSLock(volume, path string) RWLocker { | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | 	return &lockInstance{n, volume, path, getOpsID()} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | // Lock - block until write lock is taken or timeout has occurred.
 | 
					
						
							|  |  |  | func (li *lockInstance) GetLock(timeout *dynamicTimeout) (timedOutErr error) { | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	lockSource := getSource() | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	start := UTCNow() | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | 	readLock := false | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	if !li.ns.lock(li.volume, li.path, lockSource, li.opsID, readLock, timeout.Timeout()) { | 
					
						
							|  |  |  | 		timeout.LogFailure() | 
					
						
							|  |  |  | 		return OperationTimedOut{Path: li.path} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	timeout.LogSuccess(UTCNow().Sub(start)) | 
					
						
							|  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Unlock - block until write lock is released.
 | 
					
						
							|  |  |  | func (li *lockInstance) Unlock() { | 
					
						
							|  |  |  | 	readLock := false | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	li.ns.unlock(li.volume, li.path, li.opsID, readLock) | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | // RLock - block until read lock is taken or timeout has occurred.
 | 
					
						
							|  |  |  | func (li *lockInstance) GetRLock(timeout *dynamicTimeout) (timedOutErr error) { | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	lockSource := getSource() | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	start := UTCNow() | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | 	readLock := true | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	if !li.ns.lock(li.volume, li.path, lockSource, li.opsID, readLock, timeout.Timeout()) { | 
					
						
							|  |  |  | 		timeout.LogFailure() | 
					
						
							|  |  |  | 		return OperationTimedOut{Path: li.path} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	timeout.LogSuccess(UTCNow().Sub(start)) | 
					
						
							|  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RUnlock - block until read lock is released.
 | 
					
						
							|  |  |  | func (li *lockInstance) RUnlock() { | 
					
						
							|  |  |  | 	readLock := true | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	li.ns.unlock(li.volume, li.path, li.opsID, readLock) | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func getSource() string { | 
					
						
							|  |  |  | 	var funcName string | 
					
						
							|  |  |  | 	pc, filename, lineNum, ok := runtime.Caller(2) | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		filename = pathutil.Base(filename) | 
					
						
							|  |  |  | 		funcName = strings.TrimPrefix(runtime.FuncForPC(pc).Name(), | 
					
						
							|  |  |  | 			"github.com/minio/minio/cmd.") | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		filename = "<unknown>" | 
					
						
							|  |  |  | 		lineNum = 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return fmt.Sprintf("[%s:%d:%s()]", filename, lineNum, funcName) | 
					
						
							|  |  |  | } |