github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/lock-rest-server.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "context" 22 "time" 23 24 "github.com/minio/minio/internal/dsync" 25 "github.com/minio/minio/internal/grid" 26 "github.com/minio/minio/internal/logger" 27 ) 28 29 // To abstract a node over network. 30 type lockRESTServer struct { 31 ll *localLocker 32 } 33 34 // RefreshHandler - refresh the current lock 35 func (l *lockRESTServer) RefreshHandler(args *dsync.LockArgs) (*dsync.LockResp, *grid.RemoteErr) { 36 resp := lockRPCRefresh.NewResponse() 37 refreshed, err := l.ll.Refresh(context.Background(), *args) 38 if err != nil { 39 return l.makeResp(resp, err) 40 } 41 if !refreshed { 42 return l.makeResp(resp, errLockNotFound) 43 } 44 return l.makeResp(resp, err) 45 } 46 47 // LockHandler - Acquires a lock. 48 func (l *lockRESTServer) LockHandler(args *dsync.LockArgs) (*dsync.LockResp, *grid.RemoteErr) { 49 resp := lockRPCLock.NewResponse() 50 success, err := l.ll.Lock(context.Background(), *args) 51 if err == nil && !success { 52 return l.makeResp(resp, errLockConflict) 53 } 54 return l.makeResp(resp, err) 55 } 56 57 // UnlockHandler - releases the acquired lock. 58 func (l *lockRESTServer) UnlockHandler(args *dsync.LockArgs) (*dsync.LockResp, *grid.RemoteErr) { 59 resp := lockRPCUnlock.NewResponse() 60 _, err := l.ll.Unlock(context.Background(), *args) 61 // Ignore the Unlock() "reply" return value because if err == nil, "reply" is always true 62 // Consequently, if err != nil, reply is always false 63 return l.makeResp(resp, err) 64 } 65 66 // RLockHandler - Acquires an RLock. 67 func (l *lockRESTServer) RLockHandler(args *dsync.LockArgs) (*dsync.LockResp, *grid.RemoteErr) { 68 resp := lockRPCRLock.NewResponse() 69 success, err := l.ll.RLock(context.Background(), *args) 70 if err == nil && !success { 71 err = errLockConflict 72 } 73 return l.makeResp(resp, err) 74 } 75 76 // RUnlockHandler - releases the acquired read lock. 77 func (l *lockRESTServer) RUnlockHandler(args *dsync.LockArgs) (*dsync.LockResp, *grid.RemoteErr) { 78 resp := lockRPCRUnlock.NewResponse() 79 80 // Ignore the RUnlock() "reply" return value because if err == nil, "reply" is always true. 81 // Consequently, if err != nil, reply is always false 82 _, err := l.ll.RUnlock(context.Background(), *args) 83 return l.makeResp(resp, err) 84 } 85 86 // ForceUnlockHandler - query expired lock status. 87 func (l *lockRESTServer) ForceUnlockHandler(args *dsync.LockArgs) (*dsync.LockResp, *grid.RemoteErr) { 88 resp := lockRPCForceUnlock.NewResponse() 89 90 _, err := l.ll.ForceUnlock(context.Background(), *args) 91 return l.makeResp(resp, err) 92 } 93 94 var ( 95 // Static lock handlers. 96 // All have the same signature. 97 lockRPCForceUnlock = newLockHandler(grid.HandlerLockForceUnlock) 98 lockRPCRefresh = newLockHandler(grid.HandlerLockRefresh) 99 lockRPCLock = newLockHandler(grid.HandlerLockLock) 100 lockRPCUnlock = newLockHandler(grid.HandlerLockUnlock) 101 lockRPCRLock = newLockHandler(grid.HandlerLockRLock) 102 lockRPCRUnlock = newLockHandler(grid.HandlerLockRUnlock) 103 ) 104 105 func newLockHandler(h grid.HandlerID) *grid.SingleHandler[*dsync.LockArgs, *dsync.LockResp] { 106 return grid.NewSingleHandler[*dsync.LockArgs, *dsync.LockResp](h, func() *dsync.LockArgs { 107 return &dsync.LockArgs{} 108 }, func() *dsync.LockResp { 109 return &dsync.LockResp{} 110 }) 111 } 112 113 // registerLockRESTHandlers - register lock rest router. 114 func registerLockRESTHandlers() { 115 lockServer := &lockRESTServer{ 116 ll: newLocker(), 117 } 118 119 logger.FatalIf(lockRPCForceUnlock.Register(globalGrid.Load(), lockServer.ForceUnlockHandler), "unable to register handler") 120 logger.FatalIf(lockRPCRefresh.Register(globalGrid.Load(), lockServer.RefreshHandler), "unable to register handler") 121 logger.FatalIf(lockRPCLock.Register(globalGrid.Load(), lockServer.LockHandler), "unable to register handler") 122 logger.FatalIf(lockRPCUnlock.Register(globalGrid.Load(), lockServer.UnlockHandler), "unable to register handler") 123 logger.FatalIf(lockRPCRLock.Register(globalGrid.Load(), lockServer.RLockHandler), "unable to register handler") 124 logger.FatalIf(lockRPCRUnlock.Register(globalGrid.Load(), lockServer.RUnlockHandler), "unable to register handler") 125 126 globalLockServer = lockServer.ll 127 128 go lockMaintenance(GlobalContext) 129 } 130 131 func (l *lockRESTServer) makeResp(dst *dsync.LockResp, err error) (*dsync.LockResp, *grid.RemoteErr) { 132 *dst = dsync.LockResp{Code: dsync.RespOK} 133 switch err { 134 case nil: 135 case errLockNotInitialized: 136 dst.Code = dsync.RespLockNotInitialized 137 case errLockConflict: 138 dst.Code = dsync.RespLockConflict 139 case errLockNotFound: 140 dst.Code = dsync.RespLockNotFound 141 default: 142 dst.Code = dsync.RespErr 143 dst.Err = err.Error() 144 } 145 return dst, nil 146 } 147 148 const ( 149 // Lock maintenance interval. 150 lockMaintenanceInterval = 1 * time.Minute 151 152 // Lock validity duration 153 lockValidityDuration = 1 * time.Minute 154 ) 155 156 // lockMaintenance loops over all locks and discards locks 157 // that have not been refreshed for some time. 158 func lockMaintenance(ctx context.Context) { 159 if !globalIsDistErasure { 160 return 161 } 162 163 // Initialize a new ticker with 1 minute between each ticks. 164 lkTimer := time.NewTimer(lockMaintenanceInterval) 165 // Stop the timer upon returning. 166 defer lkTimer.Stop() 167 168 for { 169 // Verifies every minute for locks held more than 2 minutes. 170 select { 171 case <-ctx.Done(): 172 return 173 case <-lkTimer.C: 174 globalLockServer.expireOldLocks(lockValidityDuration) 175 176 // Reset the timer for next cycle. 177 lkTimer.Reset(lockMaintenanceInterval) 178 } 179 } 180 }