| 
									
										
										
										
											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/>.
 | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-07-30 14:15:34 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/dsync" | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // lockRequesterInfo stores various info from the client for each lock that is requested.
 | 
					
						
							|  |  |  | type lockRequesterInfo struct { | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 	Name            string    // name of the resource lock was requested for
 | 
					
						
							|  |  |  | 	Writer          bool      // Bool whether write or read lock.
 | 
					
						
							|  |  |  | 	UID             string    // UID to uniquely identify request of client.
 | 
					
						
							|  |  |  | 	Timestamp       time.Time // Timestamp set at the time of initialization.
 | 
					
						
							|  |  |  | 	TimeLastRefresh time.Time // Timestamp for last lock refresh.
 | 
					
						
							|  |  |  | 	Source          string    // Contains line, function and filename reqesting the lock.
 | 
					
						
							|  |  |  | 	Group           bool      // indicates if it was a group lock.
 | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 	// Owner represents the UUID of the owner who originally requested the lock
 | 
					
						
							|  |  |  | 	// useful in expiry.
 | 
					
						
							|  |  |  | 	Owner string | 
					
						
							| 
									
										
										
										
											2020-10-25 04:23:16 +08:00
										 |  |  | 	// Quorum represents the quorum required for this lock to be active.
 | 
					
						
							|  |  |  | 	Quorum int | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // isWriteLock returns whether the lock is a write or read lock.
 | 
					
						
							|  |  |  | func isWriteLock(lri []lockRequesterInfo) bool { | 
					
						
							| 
									
										
										
										
											2019-01-24 23:22:14 +08:00
										 |  |  | 	return len(lri) == 1 && lri[0].Writer | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-14 04:17:45 +08:00
										 |  |  | // localLocker implements Dsync.NetLocker
 | 
					
						
							|  |  |  | type localLocker struct { | 
					
						
							| 
									
										
										
										
											2020-12-10 23:28:37 +08:00
										 |  |  | 	mutex   sync.Mutex | 
					
						
							|  |  |  | 	lockMap map[string][]lockRequesterInfo | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-14 04:17:45 +08:00
										 |  |  | func (l *localLocker) String() string { | 
					
						
							| 
									
										
										
										
											2020-12-10 23:28:37 +08:00
										 |  |  | 	return globalEndpoints.Localhost() | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | func (l *localLocker) canTakeUnlock(resources ...string) bool { | 
					
						
							|  |  |  | 	var lkCnt int | 
					
						
							|  |  |  | 	for _, resource := range resources { | 
					
						
							|  |  |  | 		isWriteLockTaken := isWriteLock(l.lockMap[resource]) | 
					
						
							|  |  |  | 		if isWriteLockTaken { | 
					
						
							|  |  |  | 			lkCnt++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return lkCnt == len(resources) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (l *localLocker) canTakeLock(resources ...string) bool { | 
					
						
							|  |  |  | 	var noLkCnt int | 
					
						
							|  |  |  | 	for _, resource := range resources { | 
					
						
							|  |  |  | 		_, lockTaken := l.lockMap[resource] | 
					
						
							|  |  |  | 		if !lockTaken { | 
					
						
							|  |  |  | 			noLkCnt++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return noLkCnt == len(resources) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-30 14:15:34 +08:00
										 |  |  | func (l *localLocker) Lock(ctx context.Context, args dsync.LockArgs) (reply bool, err error) { | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 	l.mutex.Lock() | 
					
						
							|  |  |  | 	defer l.mutex.Unlock() | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 	if !l.canTakeLock(args.Resources...) { | 
					
						
							|  |  |  | 		// Not all locks can be taken on resources,
 | 
					
						
							|  |  |  | 		// reject it completely.
 | 
					
						
							|  |  |  | 		return false, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 	// No locks held on the all resources, so claim write
 | 
					
						
							|  |  |  | 	// lock on all resources at once.
 | 
					
						
							|  |  |  | 	for _, resource := range args.Resources { | 
					
						
							|  |  |  | 		l.lockMap[resource] = []lockRequesterInfo{ | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 				Name:            resource, | 
					
						
							|  |  |  | 				Writer:          true, | 
					
						
							|  |  |  | 				Source:          args.Source, | 
					
						
							|  |  |  | 				Owner:           args.Owner, | 
					
						
							|  |  |  | 				UID:             args.UID, | 
					
						
							|  |  |  | 				Timestamp:       UTCNow(), | 
					
						
							|  |  |  | 				TimeLastRefresh: UTCNow(), | 
					
						
							|  |  |  | 				Group:           len(args.Resources) > 1, | 
					
						
							|  |  |  | 				Quorum:          args.Quorum, | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 	return true, nil | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 17:11:29 +08:00
										 |  |  | func (l *localLocker) Unlock(_ context.Context, args dsync.LockArgs) (reply bool, err error) { | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	l.mutex.Lock() | 
					
						
							|  |  |  | 	defer l.mutex.Unlock() | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if !l.canTakeUnlock(args.Resources...) { | 
					
						
							|  |  |  | 		// Unless it is a write lock reject it.
 | 
					
						
							|  |  |  | 		return reply, fmt.Errorf("Unlock attempted on a read locked entity: %s", args.Resources) | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 	for _, resource := range args.Resources { | 
					
						
							| 
									
										
										
										
											2020-10-27 01:29:29 +08:00
										 |  |  | 		lri, ok := l.lockMap[resource] | 
					
						
							|  |  |  | 		if ok { | 
					
						
							|  |  |  | 			l.removeEntry(resource, args, &lri) | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return true, nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-14 04:17:45 +08:00
										 |  |  | // removeEntry based on the uid of the lock message, removes a single entry from the
 | 
					
						
							|  |  |  | // lockRequesterInfo array or the whole array from the map (in case of a write lock
 | 
					
						
							|  |  |  | // or last read lock)
 | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | func (l *localLocker) removeEntry(name string, args dsync.LockArgs, lri *[]lockRequesterInfo) bool { | 
					
						
							| 
									
										
										
										
											2019-11-14 04:17:45 +08:00
										 |  |  | 	// Find correct entry to remove based on uid.
 | 
					
						
							|  |  |  | 	for index, entry := range *lri { | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 		if entry.UID == args.UID && entry.Owner == args.Owner { | 
					
						
							| 
									
										
										
										
											2019-11-14 04:17:45 +08:00
										 |  |  | 			if len(*lri) == 1 { | 
					
						
							|  |  |  | 				// Remove the write lock.
 | 
					
						
							|  |  |  | 				delete(l.lockMap, name) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				// Remove the appropriate read lock.
 | 
					
						
							|  |  |  | 				*lri = append((*lri)[:index], (*lri)[index+1:]...) | 
					
						
							|  |  |  | 				l.lockMap[name] = *lri | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// None found return false, perhaps entry removed in previous run.
 | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-30 14:15:34 +08:00
										 |  |  | func (l *localLocker) RLock(ctx context.Context, args dsync.LockArgs) (reply bool, err error) { | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 	l.mutex.Lock() | 
					
						
							|  |  |  | 	defer l.mutex.Unlock() | 
					
						
							| 
									
										
										
										
											2021-01-26 02:01:27 +08:00
										 |  |  | 	resource := args.Resources[0] | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 	lrInfo := lockRequesterInfo{ | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 		Name:            resource, | 
					
						
							|  |  |  | 		Writer:          false, | 
					
						
							|  |  |  | 		Source:          args.Source, | 
					
						
							|  |  |  | 		Owner:           args.Owner, | 
					
						
							|  |  |  | 		UID:             args.UID, | 
					
						
							|  |  |  | 		Timestamp:       UTCNow(), | 
					
						
							|  |  |  | 		TimeLastRefresh: UTCNow(), | 
					
						
							|  |  |  | 		Quorum:          args.Quorum, | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if lri, ok := l.lockMap[resource]; ok { | 
					
						
							|  |  |  | 		if reply = !isWriteLock(lri); reply { | 
					
						
							|  |  |  | 			// Unless there is a write lock
 | 
					
						
							|  |  |  | 			l.lockMap[resource] = append(l.lockMap[resource], lrInfo) | 
					
						
							| 
									
										
										
										
											2020-07-30 14:15:34 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		// No locks held on the given name, so claim (first) read lock
 | 
					
						
							|  |  |  | 		l.lockMap[resource] = []lockRequesterInfo{lrInfo} | 
					
						
							|  |  |  | 		reply = true | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-09-26 10:21:52 +08:00
										 |  |  | 	return reply, nil | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 17:11:29 +08:00
										 |  |  | func (l *localLocker) RUnlock(_ context.Context, args dsync.LockArgs) (reply bool, err error) { | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	l.mutex.Lock() | 
					
						
							|  |  |  | 	defer l.mutex.Unlock() | 
					
						
							|  |  |  | 	var lri []lockRequesterInfo | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	resource := args.Resources[0] | 
					
						
							|  |  |  | 	if lri, reply = l.lockMap[resource]; !reply { | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 		// No lock is held on the given name
 | 
					
						
							| 
									
										
										
										
											2020-10-27 01:29:29 +08:00
										 |  |  | 		return true, nil | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if reply = !isWriteLock(lri); !reply { | 
					
						
							|  |  |  | 		// A write-lock is held, cannot release a read lock
 | 
					
						
							| 
									
										
										
										
											2020-02-21 13:59:57 +08:00
										 |  |  | 		return reply, fmt.Errorf("RUnlock attempted on a write locked entity: %s", resource) | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-10-27 01:29:29 +08:00
										 |  |  | 	l.removeEntry(resource, args, &lri) | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	return reply, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 23:22:14 +08:00
										 |  |  | func (l *localLocker) DupLockMap() map[string][]lockRequesterInfo { | 
					
						
							|  |  |  | 	l.mutex.Lock() | 
					
						
							|  |  |  | 	defer l.mutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-10 23:28:37 +08:00
										 |  |  | 	lockCopy := map[string][]lockRequesterInfo{} | 
					
						
							| 
									
										
										
										
											2019-01-24 23:22:14 +08:00
										 |  |  | 	for k, v := range l.lockMap { | 
					
						
							| 
									
										
										
										
											2019-02-13 20:59:36 +08:00
										 |  |  | 		lockCopy[k] = append(lockCopy[k], v...) | 
					
						
							| 
									
										
										
										
											2019-01-24 23:22:14 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return lockCopy | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-11-14 04:17:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func (l *localLocker) Close() error { | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-09 03:32:32 +08:00
										 |  |  | // IsOnline - local locker is always online.
 | 
					
						
							| 
									
										
										
										
											2019-11-20 09:42:27 +08:00
										 |  |  | func (l *localLocker) IsOnline() bool { | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-09 03:32:32 +08:00
										 |  |  | // IsLocal - local locker returns true.
 | 
					
						
							|  |  |  | func (l *localLocker) IsLocal() bool { | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 02:01:27 +08:00
										 |  |  | func (l *localLocker) ForceUnlock(ctx context.Context, args dsync.LockArgs) (reply bool, err error) { | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-ctx.Done(): | 
					
						
							|  |  |  | 		return false, ctx.Err() | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		l.mutex.Lock() | 
					
						
							|  |  |  | 		defer l.mutex.Unlock() | 
					
						
							|  |  |  | 		if len(args.UID) != 0 { | 
					
						
							|  |  |  | 			return false, fmt.Errorf("ForceUnlock called with non-empty UID: %s", args.UID) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for _, resource := range args.Resources { | 
					
						
							|  |  |  | 			delete(l.lockMap, resource) // Remove the lock (irrespective of write or read lock)
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | func (l *localLocker) Refresh(ctx context.Context, args dsync.LockArgs) (refreshed bool, err error) { | 
					
						
							| 
									
										
										
										
											2020-07-30 14:15:34 +08:00
										 |  |  | 	select { | 
					
						
							|  |  |  | 	case <-ctx.Done(): | 
					
						
							|  |  |  | 		return false, ctx.Err() | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		l.mutex.Lock() | 
					
						
							|  |  |  | 		defer l.mutex.Unlock() | 
					
						
							| 
									
										
										
										
											2019-11-26 08:39:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 		resource := args.Resources[0] // refresh check is always per resource.
 | 
					
						
							| 
									
										
										
										
											2021-01-26 02:01:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-30 14:15:34 +08:00
										 |  |  | 		// Lock found, proceed to verify if belongs to given uid.
 | 
					
						
							| 
									
										
										
										
											2021-01-26 02:01:27 +08:00
										 |  |  | 		lri, ok := l.lockMap[resource] | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 			// lock doesn't exist yet, return false
 | 
					
						
							| 
									
										
										
										
											2021-02-06 11:23:48 +08:00
										 |  |  | 			return false, nil | 
					
						
							| 
									
										
										
										
											2021-01-26 02:01:27 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Check whether uid is still active
 | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 		for i := range lri { | 
					
						
							|  |  |  | 			if lri[i].UID == args.UID && lri[i].Owner == args.Owner { | 
					
						
							|  |  |  | 				lri[i].TimeLastRefresh = UTCNow() | 
					
						
							|  |  |  | 				return true, nil | 
					
						
							| 
									
										
										
										
											2019-11-26 08:39:43 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-01-26 02:01:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 		return false, nil | 
					
						
							| 
									
										
										
										
											2019-11-26 08:39:43 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Similar to removeEntry but only removes an entry only if the lock entry exists in map.
 | 
					
						
							|  |  |  | // Caller must hold 'l.mutex' lock.
 | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | func (l *localLocker) expireOldLocks(interval time.Duration) { | 
					
						
							| 
									
										
										
										
											2020-10-27 01:29:29 +08:00
										 |  |  | 	l.mutex.Lock() | 
					
						
							|  |  |  | 	defer l.mutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-04 10:36:43 +08:00
										 |  |  | 	for _, lris := range l.lockMap { | 
					
						
							|  |  |  | 		for _, lri := range lris { | 
					
						
							|  |  |  | 			if time.Since(lri.TimeLastRefresh) > interval { | 
					
						
							|  |  |  | 				l.removeEntry(lri.Name, dsync.LockArgs{Owner: lri.Owner, UID: lri.UID}, &lris) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-11-26 08:39:43 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-10 23:28:37 +08:00
										 |  |  | func newLocker() *localLocker { | 
					
						
							| 
									
										
										
										
											2019-11-14 04:17:45 +08:00
										 |  |  | 	return &localLocker{ | 
					
						
							| 
									
										
										
										
											2020-12-10 23:28:37 +08:00
										 |  |  | 		lockMap: make(map[string][]lockRequesterInfo), | 
					
						
							| 
									
										
										
										
											2019-11-14 04:17:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |