| 
									
										
										
										
											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 ( | 
					
						
							| 
									
										
										
										
											2016-05-17 05:31:28 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-08-24 10:19:24 +08:00
										 |  |  | 	pathutil "path" | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 03:25:04 +08:00
										 |  |  | // Global lock servers
 | 
					
						
							|  |  |  | var globalLockServers []*lockServer | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2017-11-30 05:12:47 +08:00
										 |  |  | 	cred := globalServerConfig.GetCredential() | 
					
						
							| 
									
										
										
										
											2017-06-06 03:25:04 +08:00
										 |  |  | 	clnts = make([]dsync.NetLocker, len(endpoints)) | 
					
						
							|  |  |  | 	myNode = -1 | 
					
						
							|  |  |  | 	for index, endpoint := range endpoints { | 
					
						
							|  |  |  | 		if !endpoint.IsLocal { | 
					
						
							|  |  |  | 			// For a remote endpoints setup a lock RPC client.
 | 
					
						
							|  |  |  | 			clnts[index] = newLockRPCClient(authConfig{ | 
					
						
							|  |  |  | 				accessKey:       cred.AccessKey, | 
					
						
							|  |  |  | 				secretKey:       cred.SecretKey, | 
					
						
							|  |  |  | 				serverAddr:      endpoint.Host, | 
					
						
							|  |  |  | 				secureConn:      globalIsSSL, | 
					
						
							|  |  |  | 				serviceEndpoint: pathutil.Join(minioReservedBucketPath, lockServicePath, endpoint.Path), | 
					
						
							|  |  |  | 				serviceName:     lockServiceName, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Local endpoint
 | 
					
						
							|  |  |  | 		if myNode == -1 { | 
					
						
							| 
									
										
										
											
												lock: slice length of lock clients should be precisely urls. (#3254)
This patch fixes a possible bug, reproduced rarely only seen
once.
```
panic: runtime error: index out of range
goroutine 136 [running]:
panic(0xac1a40, 0xc4200120b0)
    /usr/local/go/src/runtime/panic.go:500 +0x1a1
github.com/minio/minio/vendor/github.com/minio/dsync.lock.func1(0xc4203d2240, 0x4, 0xc420474080, 0x4, 0x4, 0xc4202abb60, 0x0, 0xa86d01, 0xefcfc0, 0xc420417a80)
    /go/src/github.com/minio/minio/vendor/github.com/minio/dsync/drwmutex.go:170 +0x69b
created by github.com/minio/minio/vendor/github.com/minio/dsync.lock
    /go/src/github.com/minio/minio/vendor/github.com/minio/dsync/drwmutex.go:191 +0xf4
```
											
										 
											2016-11-15 02:18:56 +08:00
										 |  |  | 			myNode = index | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-06 03:25:04 +08:00
										 |  |  | 		// For a local endpoint, setup a local lock server to
 | 
					
						
							|  |  |  | 		// avoid network requests.
 | 
					
						
							|  |  |  | 		localLockServer := lockServer{ | 
					
						
							|  |  |  | 			AuthRPCServer: AuthRPCServer{}, | 
					
						
							|  |  |  | 			ll: localLocker{ | 
					
						
							|  |  |  | 				mutex:           sync.Mutex{}, | 
					
						
							|  |  |  | 				serviceEndpoint: endpoint.Path, | 
					
						
							|  |  |  | 				serverAddr:      endpoint.Host, | 
					
						
							|  |  |  | 				lockMap:         make(map[string][]lockRequesterInfo), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		globalLockServers = append(globalLockServers, &localLockServer) | 
					
						
							|  |  |  | 		clnts[index] = &(localLockServer.ll) | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // initNSLock - initialize name space lock map.
 | 
					
						
							| 
									
										
										
										
											2016-12-11 08:15:12 +08:00
										 |  |  | func initNSLock(isDistXL bool) { | 
					
						
							|  |  |  | 	globalNSMutex = &nsLockMap{ | 
					
						
							|  |  |  | 		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
 | 
					
						
							| 
									
										
										
										
											2016-12-11 08:15:12 +08:00
										 |  |  | 	globalNSMutex.debugLockMap = make(map[nsParam]*debugLockInfoPerVolumePath) | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							|  |  |  | 					return dsync.NewDRWMutex(pathJoin(volume, path)) | 
					
						
							| 
									
										
										
										
											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.
 | 
					
						
							| 
									
										
										
										
											2016-11-24 08:36:26 +08:00
										 |  |  | 	if err := n.statusNoneToBlocked(param, lockSource, opsID, readLock); err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 		errorIf(err, fmt.Sprintf("Failed to set lock state to blocked (param = %v; opsID = %s)", param, opsID)) | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											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
 | 
					
						
							|  |  |  | 		if err := n.statusBlockedToNone(param, lockSource, opsID, readLock); err != nil { | 
					
						
							|  |  |  | 			errorIf(err, fmt.Sprintf("Failed to clear the lock state (param = %v; opsID = %s)", param, opsID)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		nsLk.ref-- // Decrement ref count since we failed to get the lock
 | 
					
						
							|  |  |  | 		// delete the lock state entry for given operation ID.
 | 
					
						
							|  |  |  | 		err := n.deleteLockInfoEntryForOps(param, opsID) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errorIf(err, fmt.Sprintf("Failed to delete lock info entry (param = %v; opsID = %s)", param, opsID)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		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.
 | 
					
						
							|  |  |  | 			err := n.deleteLockInfoEntryForVolumePath(param) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				errorIf(err, fmt.Sprintf("Failed to delete lock info entry (param = %v)", param)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		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>.
 | 
					
						
							| 
									
										
										
										
											2016-11-24 08:36:26 +08:00
										 |  |  | 	if err := n.statusBlockedToRunning(param, lockSource, opsID, readLock); err != nil { | 
					
						
							| 
									
										
										
										
											2016-11-16 10:14:23 +08:00
										 |  |  | 		errorIf(err, "Failed to set the lock state to running") | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2016-11-16 10:14:23 +08:00
										 |  |  | 			errorIf(errors.New("Namespace reference count cannot be 0"), | 
					
						
							|  |  |  | 				"Invalid reference count detected") | 
					
						
							| 
									
										
										
										
											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.
 | 
					
						
							|  |  |  | 			err := n.deleteLockInfoEntryForOps(param, opsID) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2016-11-16 10:14:23 +08:00
										 |  |  | 				errorIf(err, "Failed to delete lock info entry") | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											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.
 | 
					
						
							|  |  |  | 			err := n.deleteLockInfoEntryForVolumePath(param) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2016-11-16 10:14:23 +08:00
										 |  |  | 				errorIf(err, "Failed to delete lock info entry") | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											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.
 | 
					
						
							|  |  |  | 		dsync.NewDRWMutex(pathJoin(volume, path)).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
										 |  |  | } |