| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | // Copyright (c) 2015-2021 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2020-05-19 08:33:35 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2016-08-24 10:19:24 +08:00
										 |  |  | 	pathutil "path" | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2017-10-13 18:01:15 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/dsync" | 
					
						
							|  |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							|  |  |  | 	"github.com/minio/minio/internal/lsync" | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-14 04:17:45 +08:00
										 |  |  | // local lock servers
 | 
					
						
							| 
									
										
										
										
											2020-12-10 23:28:37 +08:00
										 |  |  | var globalLockServer *localLocker | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 	GetLock(ctx context.Context, timeout *dynamicTimeout) (lkCtx LockContext, timedOutErr error) | 
					
						
							| 
									
										
										
										
											2022-12-24 11:49:07 +08:00
										 |  |  | 	Unlock(lkCtx LockContext) | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 	GetRLock(ctx context.Context, timeout *dynamicTimeout) (lkCtx LockContext, timedOutErr error) | 
					
						
							| 
									
										
										
										
											2022-12-24 11:49:07 +08:00
										 |  |  | 	RUnlock(lkCtx LockContext) | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | // LockContext lock context holds the lock backed context and canceler for the context.
 | 
					
						
							|  |  |  | type LockContext struct { | 
					
						
							|  |  |  | 	ctx    context.Context | 
					
						
							|  |  |  | 	cancel context.CancelFunc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Context returns lock context
 | 
					
						
							|  |  |  | func (l LockContext) Context() context.Context { | 
					
						
							|  |  |  | 	return l.ctx | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Cancel function calls cancel() function
 | 
					
						
							|  |  |  | func (l LockContext) Cancel() { | 
					
						
							|  |  |  | 	if l.cancel != nil { | 
					
						
							|  |  |  | 		l.cancel() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-13 12:34:52 +08:00
										 |  |  | // newNSLock - return a new name space lock map.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func newNSLock(isDistErasure bool) *nsLockMap { | 
					
						
							| 
									
										
										
										
											2018-01-13 12:34:52 +08:00
										 |  |  | 	nsMutex := nsLockMap{ | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 		isDistErasure: isDistErasure, | 
					
						
							| 
									
										
										
										
											2016-08-11 04:08:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	if isDistErasure { | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | 		return &nsMutex | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 	nsMutex.lockMap = make(map[string]*nsLock) | 
					
						
							| 
									
										
										
										
											2018-01-13 12:34:52 +08:00
										 |  |  | 	return &nsMutex | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | // nsLock - provides primitives for locking critical namespace regions.
 | 
					
						
							|  |  |  | type nsLock struct { | 
					
						
							| 
									
										
										
										
											2020-05-19 08:33:35 +08:00
										 |  |  | 	ref int32 | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | 	*lsync.LRWMutex | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // nsLockMap - namespace lock map, provides primitives to Lock,
 | 
					
						
							|  |  |  | // Unlock, RLock and RUnlock.
 | 
					
						
							|  |  |  | type nsLockMap struct { | 
					
						
							| 
									
										
										
										
											2017-01-17 09:05:00 +08:00
										 |  |  | 	// Indicates if namespace is part of a distributed setup.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	isDistErasure bool | 
					
						
							|  |  |  | 	lockMap       map[string]*nsLock | 
					
						
							|  |  |  | 	lockMapMutex  sync.Mutex | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | // Lock the namespace resource.
 | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | func (n *nsLockMap) lock(ctx context.Context, volume string, path string, lockSource, opsID string, readLock bool, timeout time.Duration) (locked bool) { | 
					
						
							|  |  |  | 	resource := pathJoin(volume, path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-06 11:25:25 +08:00
										 |  |  | 	n.lockMapMutex.Lock() | 
					
						
							| 
									
										
										
										
											2020-05-19 08:33:35 +08:00
										 |  |  | 	nsLk, found := n.lockMap[resource] | 
					
						
							|  |  |  | 	if !found { | 
					
						
							|  |  |  | 		nsLk = &nsLock{ | 
					
						
							| 
									
										
										
										
											2020-06-14 22:43:10 +08:00
										 |  |  | 			LRWMutex: lsync.NewLRWMutex(), | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-19 08:33:35 +08:00
										 |  |  | 		// Add a count to indicate that a parallel unlock doesn't clear this entry.
 | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-19 08:33:35 +08:00
										 |  |  | 	nsLk.ref++ | 
					
						
							|  |  |  | 	n.lockMap[resource] = nsLk | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2020-06-14 22:43:10 +08:00
										 |  |  | 		locked = nsLk.GetRLock(ctx, opsID, lockSource, timeout) | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2020-06-14 22:43:10 +08:00
										 |  |  | 		locked = nsLk.GetLock(ctx, opsID, lockSource, timeout) | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !locked { // We failed to get the lock
 | 
					
						
							| 
									
										
										
										
											2018-08-06 11:25:25 +08:00
										 |  |  | 		// Decrement ref count since we failed to get the lock
 | 
					
						
							| 
									
										
										
										
											2020-05-19 08:33:35 +08:00
										 |  |  | 		n.lockMapMutex.Lock() | 
					
						
							|  |  |  | 		n.lockMap[resource].ref-- | 
					
						
							|  |  |  | 		if n.lockMap[resource].ref < 0 { | 
					
						
							|  |  |  | 			logger.CriticalIf(GlobalContext, errors.New("resource reference count was lower than 0")) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if n.lockMap[resource].ref == 0 { | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 			// Remove from the map if there are no more references.
 | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 			delete(n.lockMap, resource) | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-19 08:33:35 +08:00
										 |  |  | 		n.lockMapMutex.Unlock() | 
					
						
							| 
									
										
										
										
											2016-04-30 02:39:20 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-19 08:33:35 +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.
 | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | func (n *nsLockMap) unlock(volume string, path string, readLock bool) { | 
					
						
							|  |  |  | 	resource := pathJoin(volume, path) | 
					
						
							| 
									
										
										
										
											2020-05-15 14:59:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	n.lockMapMutex.Lock() | 
					
						
							|  |  |  | 	defer n.lockMapMutex.Unlock() | 
					
						
							|  |  |  | 	if _, found := n.lockMap[resource]; !found { | 
					
						
							| 
									
										
										
										
											2018-08-06 11:25:25 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if readLock { | 
					
						
							| 
									
										
										
										
											2020-05-15 14:59:07 +08:00
										 |  |  | 		n.lockMap[resource].RUnlock() | 
					
						
							| 
									
										
										
										
											2018-08-06 11:25:25 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2020-05-15 14:59:07 +08:00
										 |  |  | 		n.lockMap[resource].Unlock() | 
					
						
							| 
									
										
										
										
											2018-08-06 11:25:25 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-19 08:33:35 +08:00
										 |  |  | 	n.lockMap[resource].ref-- | 
					
						
							|  |  |  | 	if n.lockMap[resource].ref < 0 { | 
					
						
							|  |  |  | 		logger.CriticalIf(GlobalContext, errors.New("resource reference count was lower than 0")) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n.lockMap[resource].ref == 0 { | 
					
						
							| 
									
										
										
										
											2020-05-15 14:59:07 +08:00
										 |  |  | 		// Remove from the map if there are no more references.
 | 
					
						
							|  |  |  | 		delete(n.lockMap, resource) | 
					
						
							| 
									
										
										
										
											2016-04-29 16:29:09 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | // dsync's distributed lock instance.
 | 
					
						
							|  |  |  | type distLockInstance struct { | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 	rwMutex *dsync.DRWMutex | 
					
						
							|  |  |  | 	opsID   string | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Lock - block until write lock is taken or timeout has occurred.
 | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | func (di *distLockInstance) GetLock(ctx context.Context, timeout *dynamicTimeout) (LockContext, error) { | 
					
						
							| 
									
										
										
										
											2020-05-15 14:59:07 +08:00
										 |  |  | 	lockSource := getSource(2) | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | 	start := UTCNow() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 	newCtx, cancel := context.WithCancel(ctx) | 
					
						
							|  |  |  | 	if !di.rwMutex.GetLock(newCtx, cancel, di.opsID, lockSource, dsync.Options{ | 
					
						
							| 
									
										
										
										
											2022-08-20 07:21:05 +08:00
										 |  |  | 		Timeout:       timeout.Timeout(), | 
					
						
							|  |  |  | 		RetryInterval: timeout.RetryInterval(), | 
					
						
							| 
									
										
										
										
											2020-08-15 09:17:14 +08:00
										 |  |  | 	}) { | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | 		timeout.LogFailure() | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 		cancel() | 
					
						
							| 
									
										
										
										
											2022-03-19 06:32:45 +08:00
										 |  |  | 		switch err := newCtx.Err(); err { | 
					
						
							|  |  |  | 		case context.Canceled: | 
					
						
							|  |  |  | 			return LockContext{ctx: ctx, cancel: func() {}}, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 		return LockContext{ctx: ctx, cancel: func() {}}, OperationTimedOut{} | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	timeout.LogSuccess(UTCNow().Sub(start)) | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 	return LockContext{ctx: newCtx, cancel: cancel}, nil | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Unlock - block until write lock is released.
 | 
					
						
							| 
									
										
										
										
											2022-12-24 11:49:07 +08:00
										 |  |  | func (di *distLockInstance) Unlock(lc LockContext) { | 
					
						
							|  |  |  | 	if lc.cancel != nil { | 
					
						
							|  |  |  | 		lc.cancel() | 
					
						
							| 
									
										
										
										
											2021-04-28 07:12:50 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-12-24 11:49:07 +08:00
										 |  |  | 	di.rwMutex.Unlock(lc.ctx) | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RLock - block until read lock is taken or timeout has occurred.
 | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | func (di *distLockInstance) GetRLock(ctx context.Context, timeout *dynamicTimeout) (LockContext, error) { | 
					
						
							| 
									
										
										
										
											2020-05-15 14:59:07 +08:00
										 |  |  | 	lockSource := getSource(2) | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | 	start := UTCNow() | 
					
						
							| 
									
										
										
										
											2020-08-15 09:17:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 	newCtx, cancel := context.WithCancel(ctx) | 
					
						
							|  |  |  | 	if !di.rwMutex.GetRLock(ctx, cancel, di.opsID, lockSource, dsync.Options{ | 
					
						
							| 
									
										
										
										
											2022-08-20 07:21:05 +08:00
										 |  |  | 		Timeout:       timeout.Timeout(), | 
					
						
							|  |  |  | 		RetryInterval: timeout.RetryInterval(), | 
					
						
							| 
									
										
										
										
											2020-08-15 09:17:14 +08:00
										 |  |  | 	}) { | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | 		timeout.LogFailure() | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 		cancel() | 
					
						
							| 
									
										
										
										
											2022-03-19 06:32:45 +08:00
										 |  |  | 		switch err := newCtx.Err(); err { | 
					
						
							|  |  |  | 		case context.Canceled: | 
					
						
							|  |  |  | 			return LockContext{ctx: ctx, cancel: func() {}}, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 		return LockContext{ctx: ctx, cancel: func() {}}, OperationTimedOut{} | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	timeout.LogSuccess(UTCNow().Sub(start)) | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 	return LockContext{ctx: newCtx, cancel: cancel}, nil | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RUnlock - block until read lock is released.
 | 
					
						
							| 
									
										
										
										
											2022-12-24 11:49:07 +08:00
										 |  |  | func (di *distLockInstance) RUnlock(lc LockContext) { | 
					
						
							|  |  |  | 	if lc.cancel != nil { | 
					
						
							|  |  |  | 		lc.cancel() | 
					
						
							| 
									
										
										
										
											2021-04-28 07:12:50 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-12-24 11:49:07 +08:00
										 |  |  | 	di.rwMutex.RUnlock(lc.ctx) | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // localLockInstance - frontend/top-level interface for namespace locks.
 | 
					
						
							|  |  |  | type localLockInstance struct { | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 	ns     *nsLockMap | 
					
						
							|  |  |  | 	volume string | 
					
						
							|  |  |  | 	paths  []string | 
					
						
							|  |  |  | 	opsID  string | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewNSLock - returns a lock instance for a given volume and
 | 
					
						
							|  |  |  | // path. The returned lockInstance object encapsulates the nsLockMap,
 | 
					
						
							|  |  |  | // volume, path and operation ID.
 | 
					
						
							| 
									
										
										
										
											2020-11-05 00:25:42 +08:00
										 |  |  | func (n *nsLockMap) NewNSLock(lockers func() ([]dsync.NetLocker, string), volume string, paths ...string) RWLocker { | 
					
						
							| 
									
										
										
										
											2018-08-03 01:39:42 +08:00
										 |  |  | 	opsID := mustGetUUID() | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	if n.isDistErasure { | 
					
						
							| 
									
										
										
										
											2020-06-14 22:43:10 +08:00
										 |  |  | 		drwmutex := dsync.NewDRWMutex(&dsync.Dsync{ | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 			GetLockers: lockers, | 
					
						
							| 
									
										
										
										
											2022-03-02 03:14:28 +08:00
										 |  |  | 			Timeouts:   dsync.DefaultTimeouts, | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 		}, pathsJoinPrefix(volume, paths...)...) | 
					
						
							| 
									
										
										
										
											2020-11-05 00:25:42 +08:00
										 |  |  | 		return &distLockInstance{drwmutex, opsID} | 
					
						
							| 
									
										
										
										
											2019-04-03 03:27:20 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 	sort.Strings(paths) | 
					
						
							| 
									
										
										
										
											2020-11-05 00:25:42 +08:00
										 |  |  | 	return &localLockInstance{n, volume, paths, opsID} | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | // Lock - block until write lock is taken or timeout has occurred.
 | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | func (li *localLockInstance) GetLock(ctx context.Context, timeout *dynamicTimeout) (_ LockContext, timedOutErr error) { | 
					
						
							| 
									
										
										
										
											2020-05-15 14:59:07 +08:00
										 |  |  | 	lockSource := getSource(2) | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	start := UTCNow() | 
					
						
							| 
									
										
										
										
											2020-11-05 00:25:42 +08:00
										 |  |  | 	const readLock = false | 
					
						
							| 
									
										
										
										
											2021-04-13 04:45:06 +08:00
										 |  |  | 	success := make([]int, len(li.paths)) | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 	for i, path := range li.paths { | 
					
						
							| 
									
										
										
										
											2020-11-05 00:25:42 +08:00
										 |  |  | 		if !li.ns.lock(ctx, li.volume, path, lockSource, li.opsID, readLock, timeout.Timeout()) { | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 			timeout.LogFailure() | 
					
						
							| 
									
										
										
										
											2021-04-13 04:45:06 +08:00
										 |  |  | 			for si, sint := range success { | 
					
						
							|  |  |  | 				if sint == 1 { | 
					
						
							|  |  |  | 					li.ns.unlock(li.volume, li.paths[si], readLock) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-03-19 06:32:45 +08:00
										 |  |  | 			switch err := ctx.Err(); err { | 
					
						
							|  |  |  | 			case context.Canceled: | 
					
						
							|  |  |  | 				return LockContext{}, err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 			return LockContext{}, OperationTimedOut{} | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-04-13 04:45:06 +08:00
										 |  |  | 		success[i] = 1 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	timeout.LogSuccess(UTCNow().Sub(start)) | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 	return LockContext{ctx: ctx, cancel: func() {}}, nil | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Unlock - block until write lock is released.
 | 
					
						
							| 
									
										
										
										
											2022-12-24 11:49:07 +08:00
										 |  |  | func (li *localLockInstance) Unlock(lc LockContext) { | 
					
						
							|  |  |  | 	if lc.cancel != nil { | 
					
						
							|  |  |  | 		lc.cancel() | 
					
						
							| 
									
										
										
										
											2021-04-28 07:12:50 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-05 00:25:42 +08:00
										 |  |  | 	const readLock = false | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 	for _, path := range li.paths { | 
					
						
							|  |  |  | 		li.ns.unlock(li.volume, path, 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.
 | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | func (li *localLockInstance) GetRLock(ctx context.Context, timeout *dynamicTimeout) (_ LockContext, timedOutErr error) { | 
					
						
							| 
									
										
										
										
											2020-05-15 14:59:07 +08:00
										 |  |  | 	lockSource := getSource(2) | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	start := UTCNow() | 
					
						
							| 
									
										
										
										
											2020-11-05 00:25:42 +08:00
										 |  |  | 	const readLock = true | 
					
						
							| 
									
										
										
										
											2021-04-13 04:45:06 +08:00
										 |  |  | 	success := make([]int, len(li.paths)) | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 	for i, path := range li.paths { | 
					
						
							| 
									
										
										
										
											2020-11-05 00:25:42 +08:00
										 |  |  | 		if !li.ns.lock(ctx, li.volume, path, lockSource, li.opsID, readLock, timeout.Timeout()) { | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 			timeout.LogFailure() | 
					
						
							| 
									
										
										
										
											2021-04-13 04:45:06 +08:00
										 |  |  | 			for si, sint := range success { | 
					
						
							|  |  |  | 				if sint == 1 { | 
					
						
							|  |  |  | 					li.ns.unlock(li.volume, li.paths[si], readLock) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-03-19 06:32:45 +08:00
										 |  |  | 			switch err := ctx.Err(); err { | 
					
						
							|  |  |  | 			case context.Canceled: | 
					
						
							|  |  |  | 				return LockContext{}, err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 			return LockContext{}, OperationTimedOut{} | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-04-13 04:45:06 +08:00
										 |  |  | 		success[i] = 1 | 
					
						
							| 
									
										
										
										
											2017-09-01 02:29:22 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	timeout.LogSuccess(UTCNow().Sub(start)) | 
					
						
							| 
									
										
										
										
											2021-04-30 11:55:21 +08:00
										 |  |  | 	return LockContext{ctx: ctx, cancel: func() {}}, nil | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RUnlock - block until read lock is released.
 | 
					
						
							| 
									
										
										
										
											2022-12-24 11:49:07 +08:00
										 |  |  | func (li *localLockInstance) RUnlock(lc LockContext) { | 
					
						
							|  |  |  | 	if lc.cancel != nil { | 
					
						
							|  |  |  | 		lc.cancel() | 
					
						
							| 
									
										
										
										
											2021-04-28 07:12:50 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-05 00:25:42 +08:00
										 |  |  | 	const readLock = true | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 	for _, path := range li.paths { | 
					
						
							|  |  |  | 		li.ns.unlock(li.volume, path, readLock) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-10 02:58:41 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-15 14:59:07 +08:00
										 |  |  | func getSource(n int) string { | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	var funcName string | 
					
						
							| 
									
										
										
										
											2020-05-15 14:59:07 +08:00
										 |  |  | 	pc, filename, lineNum, ok := runtime.Caller(n) | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	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) | 
					
						
							|  |  |  | } |