| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/minio/dsync" | 
					
						
							| 
									
										
										
										
											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-01-17 09:05:00 +08:00
										 |  |  | // RWLocker - locker interface extends sync.Locker
 | 
					
						
							|  |  |  | // to introduce RLock, RUnlock.
 | 
					
						
							|  |  |  | type RWLocker interface { | 
					
						
							|  |  |  | 	sync.Locker | 
					
						
							|  |  |  | 	RLock() | 
					
						
							|  |  |  | 	RUnlock() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | // Initialize distributed locking only in case of distributed setup.
 | 
					
						
							|  |  |  | // Returns if the setup is distributed or not on success.
 | 
					
						
							| 
									
										
										
										
											2017-03-31 02:21:19 +08:00
										 |  |  | func initDsyncNodes() error { | 
					
						
							| 
									
										
										
										
											2016-08-24 10:19:24 +08:00
										 |  |  | 	cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 	// Initialize rpc lock client information only if this instance is a distributed setup.
 | 
					
						
							| 
									
										
										
										
											2017-03-31 02:21:19 +08:00
										 |  |  | 	clnts := make([]dsync.NetLocker, len(globalEndpoints)) | 
					
						
							| 
									
										
										
										
											2016-09-16 15:30:55 +08:00
										 |  |  | 	myNode := -1 | 
					
						
							| 
									
										
										
										
											2017-03-31 02:21:19 +08:00
										 |  |  | 	for index, ep := range globalEndpoints { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:30:52 +08:00
										 |  |  | 		if ep == nil { | 
					
						
							| 
									
										
										
										
											2016-10-19 03:49:24 +08:00
										 |  |  | 			return errInvalidArgument | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | 		clnts[index] = newLockRPCClient(authConfig{ | 
					
						
							|  |  |  | 			accessKey:       cred.AccessKey, | 
					
						
							|  |  |  | 			secretKey:       cred.SecretKey, | 
					
						
							|  |  |  | 			serverAddr:      ep.Host, | 
					
						
							| 
									
										
										
										
											2017-02-18 18:52:11 +08:00
										 |  |  | 			serviceEndpoint: pathutil.Join(minioReservedBucketPath, lockRPCPath, getPath(ep)), | 
					
						
							| 
									
										
										
										
											2017-01-12 05:59:51 +08:00
										 |  |  | 			secureConn:      globalIsSSL, | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | 			serviceName:     "Dsync", | 
					
						
							| 
									
										
										
											
												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
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2016-10-19 03:49:24 +08:00
										 |  |  | 		if isLocalStorage(ep) && 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
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return dsync.Init(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 { | 
					
						
							| 
									
										
										
										
											2016-09-16 15:30:55 +08:00
										 |  |  | 	RWLocker | 
					
						
							|  |  |  | 	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.
 | 
					
						
							| 
									
										
										
										
											2016-11-24 08:36:26 +08:00
										 |  |  | func (n *nsLockMap) lock(volume, path string, lockSource, opsID string, readLock 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{ | 
					
						
							| 
									
										
										
										
											2016-09-16 15:30:55 +08:00
										 |  |  | 			RWLocker: func() RWLocker { | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 				} | 
					
						
							|  |  |  | 				return &sync.RWMutex{} | 
					
						
							|  |  |  | 			}(), | 
					
						
							|  |  |  | 			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 { | 
					
						
							| 
									
										
										
										
											2016-11-16 10:14:23 +08:00
										 |  |  | 		errorIf(err, "Failed to set lock state to blocked") | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Locking here can block.
 | 
					
						
							|  |  |  | 	if readLock { | 
					
						
							| 
									
										
										
										
											2016-09-16 15:30:55 +08:00
										 |  |  | 		nsLk.RLock() | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2016-09-16 15:30:55 +08:00
										 |  |  | 		nsLk.Lock() | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											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.
 | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | func (n *nsLockMap) Lock(volume, path, opsID string) { | 
					
						
							| 
									
										
										
										
											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
 | 
					
						
							| 
									
										
										
										
											2016-11-24 08:36:26 +08:00
										 |  |  | 	n.lock(volume, path, lockSource, 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
										 |  |  | // 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.
 | 
					
						
							| 
									
										
										
										
											2016-09-01 02:39:08 +08:00
										 |  |  | func (n *nsLockMap) RLock(volume, path, opsID string) { | 
					
						
							| 
									
										
										
										
											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
 | 
					
						
							| 
									
										
										
										
											2016-11-24 08:36:26 +08:00
										 |  |  | 	n.lock(volume, path, lockSource, opsID, readLock) | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// 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-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()} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Lock - block until write lock is taken.
 | 
					
						
							|  |  |  | func (li *lockInstance) Lock() { | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	lockSource := getSource() | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | 	readLock := false | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	li.ns.lock(li.volume, li.path, lockSource, li.opsID, readLock) | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RLock - block until read lock is taken.
 | 
					
						
							|  |  |  | func (li *lockInstance) RLock() { | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	lockSource := getSource() | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | 	readLock := true | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	li.ns.lock(li.volume, li.path, lockSource, li.opsID, readLock) | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } |