mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
Change query param name to duration in list/clear locks API (#3664)
Following is a sample list lock API request schematic, /?lock&bucket=mybucket&prefix=myprefix&duration=holdDuration x-minio-operation: list The response would contain the list of locks held on mybucket matching myprefix for a duration longer than holdDuration.
This commit is contained in:
parent
6a6c930f5b
commit
0472e5c1e1
@ -36,14 +36,14 @@ type mgmtQueryKey string
|
|||||||
|
|
||||||
// Only valid query params for list/clear locks management APIs.
|
// Only valid query params for list/clear locks management APIs.
|
||||||
const (
|
const (
|
||||||
mgmtBucket mgmtQueryKey = "bucket"
|
mgmtBucket mgmtQueryKey = "bucket"
|
||||||
mgmtObject mgmtQueryKey = "object"
|
mgmtObject mgmtQueryKey = "object"
|
||||||
mgmtPrefix mgmtQueryKey = "prefix"
|
mgmtPrefix mgmtQueryKey = "prefix"
|
||||||
mgmtOlderThan mgmtQueryKey = "older-than"
|
mgmtLockDuration mgmtQueryKey = "duration"
|
||||||
mgmtDelimiter mgmtQueryKey = "delimiter"
|
mgmtDelimiter mgmtQueryKey = "delimiter"
|
||||||
mgmtMarker mgmtQueryKey = "marker"
|
mgmtMarker mgmtQueryKey = "marker"
|
||||||
mgmtMaxKey mgmtQueryKey = "max-key"
|
mgmtMaxKey mgmtQueryKey = "max-key"
|
||||||
mgmtDryRun mgmtQueryKey = "dry-run"
|
mgmtDryRun mgmtQueryKey = "dry-run"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServerVersion - server version
|
// ServerVersion - server version
|
||||||
@ -185,7 +185,7 @@ func (adminAPI adminAPIHandlers) ServiceCredentialsHandler(w http.ResponseWriter
|
|||||||
func validateLockQueryParams(vars url.Values) (string, string, time.Duration, APIErrorCode) {
|
func validateLockQueryParams(vars url.Values) (string, string, time.Duration, APIErrorCode) {
|
||||||
bucket := vars.Get(string(mgmtBucket))
|
bucket := vars.Get(string(mgmtBucket))
|
||||||
prefix := vars.Get(string(mgmtPrefix))
|
prefix := vars.Get(string(mgmtPrefix))
|
||||||
relTimeStr := vars.Get(string(mgmtOlderThan))
|
durationStr := vars.Get(string(mgmtLockDuration))
|
||||||
|
|
||||||
// N B empty bucket name is invalid
|
// N B empty bucket name is invalid
|
||||||
if !IsValidBucketName(bucket) {
|
if !IsValidBucketName(bucket) {
|
||||||
@ -198,24 +198,24 @@ func validateLockQueryParams(vars url.Values) (string, string, time.Duration, AP
|
|||||||
|
|
||||||
// If older-than parameter was empty then set it to 0s to list
|
// If older-than parameter was empty then set it to 0s to list
|
||||||
// all locks older than now.
|
// all locks older than now.
|
||||||
if relTimeStr == "" {
|
if durationStr == "" {
|
||||||
relTimeStr = "0s"
|
durationStr = "0s"
|
||||||
}
|
}
|
||||||
relTime, err := time.ParseDuration(relTimeStr)
|
duration, err := time.ParseDuration(durationStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "Failed to parse duration passed as query value.")
|
errorIf(err, "Failed to parse duration passed as query value.")
|
||||||
return "", "", time.Duration(0), ErrInvalidDuration
|
return "", "", time.Duration(0), ErrInvalidDuration
|
||||||
}
|
}
|
||||||
|
|
||||||
return bucket, prefix, relTime, ErrNone
|
return bucket, prefix, duration, ErrNone
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListLocksHandler - GET /?lock&bucket=mybucket&prefix=myprefix&older-than=rel_time
|
// ListLocksHandler - GET /?lock&bucket=mybucket&prefix=myprefix&duration=duration
|
||||||
// - bucket is a mandatory query parameter
|
// - bucket is a mandatory query parameter
|
||||||
// - prefix and older-than are optional query parameters
|
// - prefix and older-than are optional query parameters
|
||||||
// HTTP header x-minio-operation: list
|
// HTTP header x-minio-operation: list
|
||||||
// ---------
|
// ---------
|
||||||
// Lists locks held on a given bucket, prefix and relative time.
|
// Lists locks held on a given bucket, prefix and duration it was held for.
|
||||||
func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http.Request) {
|
func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
@ -224,15 +224,15 @@ func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http
|
|||||||
}
|
}
|
||||||
|
|
||||||
vars := r.URL.Query()
|
vars := r.URL.Query()
|
||||||
bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars)
|
bucket, prefix, duration, adminAPIErr := validateLockQueryParams(vars)
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
writeErrorResponse(w, adminAPIErr, r.URL)
|
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch lock information of locks matching bucket/prefix that
|
// Fetch lock information of locks matching bucket/prefix that
|
||||||
// are available since relTime.
|
// are available for longer than duration.
|
||||||
volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime)
|
volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, duration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
errorIf(err, "Failed to fetch lock information from remote nodes.")
|
errorIf(err, "Failed to fetch lock information from remote nodes.")
|
||||||
@ -248,16 +248,16 @@ func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reply with list of locks held on bucket, matching prefix
|
// Reply with list of locks held on bucket, matching prefix
|
||||||
// older than relTime supplied, as json.
|
// held longer than duration supplied, as json.
|
||||||
writeSuccessResponseJSON(w, jsonBytes)
|
writeSuccessResponseJSON(w, jsonBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearLocksHandler - POST /?lock&bucket=mybucket&prefix=myprefix&older-than=relTime
|
// ClearLocksHandler - POST /?lock&bucket=mybucket&prefix=myprefix&duration=duration
|
||||||
// - bucket is a mandatory query parameter
|
// - bucket is a mandatory query parameter
|
||||||
// - prefix and older-than are optional query parameters
|
// - prefix and older-than are optional query parameters
|
||||||
// HTTP header x-minio-operation: clear
|
// HTTP header x-minio-operation: clear
|
||||||
// ---------
|
// ---------
|
||||||
// Clear locks held on a given bucket, prefix and relative time.
|
// Clear locks held on a given bucket, prefix and duration it was held for.
|
||||||
func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *http.Request) {
|
func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
@ -266,15 +266,15 @@ func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *htt
|
|||||||
}
|
}
|
||||||
|
|
||||||
vars := r.URL.Query()
|
vars := r.URL.Query()
|
||||||
bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars)
|
bucket, prefix, duration, adminAPIErr := validateLockQueryParams(vars)
|
||||||
if adminAPIErr != ErrNone {
|
if adminAPIErr != ErrNone {
|
||||||
writeErrorResponse(w, adminAPIErr, r.URL)
|
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch lock information of locks matching bucket/prefix that
|
// Fetch lock information of locks matching bucket/prefix that
|
||||||
// are available since relTime.
|
// are held for longer than duration.
|
||||||
volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime)
|
volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, duration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||||
errorIf(err, "Failed to fetch lock information from remote nodes.")
|
errorIf(err, "Failed to fetch lock information from remote nodes.")
|
||||||
@ -289,7 +289,7 @@ func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *htt
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove lock matching bucket/prefix older than relTime.
|
// Remove lock matching bucket/prefix held longer than duration.
|
||||||
for _, volLock := range volLocks {
|
for _, volLock := range volLocks {
|
||||||
globalNSMutex.ForceUnlock(volLock.Bucket, volLock.Object)
|
globalNSMutex.ForceUnlock(volLock.Bucket, volLock.Object)
|
||||||
}
|
}
|
||||||
|
@ -334,12 +334,12 @@ func TestServiceSetCreds(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mkLockQueryVal - helper function to build lock query param.
|
// mkLockQueryVal - helper function to build lock query param.
|
||||||
func mkLockQueryVal(bucket, prefix, relTimeStr string) url.Values {
|
func mkLockQueryVal(bucket, prefix, durationStr string) url.Values {
|
||||||
qVal := url.Values{}
|
qVal := url.Values{}
|
||||||
qVal.Set("lock", "")
|
qVal.Set("lock", "")
|
||||||
qVal.Set(string(mgmtBucket), bucket)
|
qVal.Set(string(mgmtBucket), bucket)
|
||||||
qVal.Set(string(mgmtPrefix), prefix)
|
qVal.Set(string(mgmtPrefix), prefix)
|
||||||
qVal.Set(string(mgmtOlderThan), relTimeStr)
|
qVal.Set(string(mgmtLockDuration), durationStr)
|
||||||
return qVal
|
return qVal
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,41 +364,41 @@ func TestListLocksHandler(t *testing.T) {
|
|||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
bucket string
|
bucket string
|
||||||
prefix string
|
prefix string
|
||||||
relTime string
|
duration string
|
||||||
expectedStatus int
|
expectedStatus int
|
||||||
}{
|
}{
|
||||||
// Test 1 - valid testcase
|
// Test 1 - valid testcase
|
||||||
{
|
{
|
||||||
bucket: "mybucket",
|
bucket: "mybucket",
|
||||||
prefix: "myobject",
|
prefix: "myobject",
|
||||||
relTime: "1s",
|
duration: "1s",
|
||||||
expectedStatus: http.StatusOK,
|
expectedStatus: http.StatusOK,
|
||||||
},
|
},
|
||||||
// Test 2 - invalid duration
|
// Test 2 - invalid duration
|
||||||
{
|
{
|
||||||
bucket: "mybucket",
|
bucket: "mybucket",
|
||||||
prefix: "myprefix",
|
prefix: "myprefix",
|
||||||
relTime: "invalidDuration",
|
duration: "invalidDuration",
|
||||||
expectedStatus: http.StatusBadRequest,
|
expectedStatus: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
// Test 3 - invalid bucket name
|
// Test 3 - invalid bucket name
|
||||||
{
|
{
|
||||||
bucket: `invalid\\Bucket`,
|
bucket: `invalid\\Bucket`,
|
||||||
prefix: "myprefix",
|
prefix: "myprefix",
|
||||||
relTime: "1h",
|
duration: "1h",
|
||||||
expectedStatus: http.StatusBadRequest,
|
expectedStatus: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
// Test 4 - invalid prefix
|
// Test 4 - invalid prefix
|
||||||
{
|
{
|
||||||
bucket: "mybucket",
|
bucket: "mybucket",
|
||||||
prefix: `invalid\\Prefix`,
|
prefix: `invalid\\Prefix`,
|
||||||
relTime: "1h",
|
duration: "1h",
|
||||||
expectedStatus: http.StatusBadRequest,
|
expectedStatus: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range testCases {
|
for i, test := range testCases {
|
||||||
queryVal := mkLockQueryVal(test.bucket, test.prefix, test.relTime)
|
queryVal := mkLockQueryVal(test.bucket, test.prefix, test.duration)
|
||||||
req, err := newTestRequest("GET", "/?"+queryVal.Encode(), 0, nil)
|
req, err := newTestRequest("GET", "/?"+queryVal.Encode(), 0, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Test %d - Failed to construct list locks request - %v", i+1, err)
|
t.Fatalf("Test %d - Failed to construct list locks request - %v", i+1, err)
|
||||||
@ -436,41 +436,41 @@ func TestClearLocksHandler(t *testing.T) {
|
|||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
bucket string
|
bucket string
|
||||||
prefix string
|
prefix string
|
||||||
relTime string
|
duration string
|
||||||
expectedStatus int
|
expectedStatus int
|
||||||
}{
|
}{
|
||||||
// Test 1 - valid testcase
|
// Test 1 - valid testcase
|
||||||
{
|
{
|
||||||
bucket: "mybucket",
|
bucket: "mybucket",
|
||||||
prefix: "myobject",
|
prefix: "myobject",
|
||||||
relTime: "1s",
|
duration: "1s",
|
||||||
expectedStatus: http.StatusOK,
|
expectedStatus: http.StatusOK,
|
||||||
},
|
},
|
||||||
// Test 2 - invalid duration
|
// Test 2 - invalid duration
|
||||||
{
|
{
|
||||||
bucket: "mybucket",
|
bucket: "mybucket",
|
||||||
prefix: "myprefix",
|
prefix: "myprefix",
|
||||||
relTime: "invalidDuration",
|
duration: "invalidDuration",
|
||||||
expectedStatus: http.StatusBadRequest,
|
expectedStatus: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
// Test 3 - invalid bucket name
|
// Test 3 - invalid bucket name
|
||||||
{
|
{
|
||||||
bucket: `invalid\\Bucket`,
|
bucket: `invalid\\Bucket`,
|
||||||
prefix: "myprefix",
|
prefix: "myprefix",
|
||||||
relTime: "1h",
|
duration: "1h",
|
||||||
expectedStatus: http.StatusBadRequest,
|
expectedStatus: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
// Test 4 - invalid prefix
|
// Test 4 - invalid prefix
|
||||||
{
|
{
|
||||||
bucket: "mybucket",
|
bucket: "mybucket",
|
||||||
prefix: `invalid\\Prefix`,
|
prefix: `invalid\\Prefix`,
|
||||||
relTime: "1h",
|
duration: "1h",
|
||||||
expectedStatus: http.StatusBadRequest,
|
expectedStatus: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range testCases {
|
for i, test := range testCases {
|
||||||
queryVal := mkLockQueryVal(test.bucket, test.prefix, test.relTime)
|
queryVal := mkLockQueryVal(test.bucket, test.prefix, test.duration)
|
||||||
req, err := newTestRequest("POST", "/?"+queryVal.Encode(), 0, nil)
|
req, err := newTestRequest("POST", "/?"+queryVal.Encode(), 0, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Test %d - Failed to construct clear locks request - %v", i+1, err)
|
t.Fatalf("Test %d - Failed to construct clear locks request - %v", i+1, err)
|
||||||
|
@ -37,7 +37,7 @@ type remoteAdminClient struct {
|
|||||||
// commands like service stop and service restart.
|
// commands like service stop and service restart.
|
||||||
type adminCmdRunner interface {
|
type adminCmdRunner interface {
|
||||||
Restart() error
|
Restart() error
|
||||||
ListLocks(bucket, prefix string, relTime time.Duration) ([]VolumeLockInfo, error)
|
ListLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error)
|
||||||
ReInitDisks() error
|
ReInitDisks() error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +49,8 @@ func (lc localAdminClient) Restart() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListLocks - Fetches lock information from local lock instrumentation.
|
// ListLocks - Fetches lock information from local lock instrumentation.
|
||||||
func (lc localAdminClient) ListLocks(bucket, prefix string, relTime time.Duration) ([]VolumeLockInfo, error) {
|
func (lc localAdminClient) ListLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) {
|
||||||
return listLocksInfo(bucket, prefix, relTime), nil
|
return listLocksInfo(bucket, prefix, duration), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restart - Sends restart command to remote server via RPC.
|
// Restart - Sends restart command to remote server via RPC.
|
||||||
@ -61,11 +61,11 @@ func (rc remoteAdminClient) Restart() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListLocks - Sends list locks command to remote server via RPC.
|
// ListLocks - Sends list locks command to remote server via RPC.
|
||||||
func (rc remoteAdminClient) ListLocks(bucket, prefix string, relTime time.Duration) ([]VolumeLockInfo, error) {
|
func (rc remoteAdminClient) ListLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) {
|
||||||
listArgs := ListLocksQuery{
|
listArgs := ListLocksQuery{
|
||||||
bucket: bucket,
|
bucket: bucket,
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
relTime: relTime,
|
duration: duration,
|
||||||
}
|
}
|
||||||
var reply ListLocksReply
|
var reply ListLocksReply
|
||||||
if err := rc.Call("Admin.ListLocks", &listArgs, &reply); err != nil {
|
if err := rc.Call("Admin.ListLocks", &listArgs, &reply); err != nil {
|
||||||
@ -175,8 +175,8 @@ func sendServiceCmd(cps adminPeers, cmd serviceSignal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// listPeerLocksInfo - fetch list of locks held on the given bucket,
|
// listPeerLocksInfo - fetch list of locks held on the given bucket,
|
||||||
// matching prefix older than relTime from all peer servers.
|
// matching prefix held longer than duration from all peer servers.
|
||||||
func listPeerLocksInfo(peers adminPeers, bucket, prefix string, relTime time.Duration) ([]VolumeLockInfo, error) {
|
func listPeerLocksInfo(peers adminPeers, bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) {
|
||||||
// Used to aggregate volume lock information from all nodes.
|
// Used to aggregate volume lock information from all nodes.
|
||||||
allLocks := make([][]VolumeLockInfo, len(peers))
|
allLocks := make([][]VolumeLockInfo, len(peers))
|
||||||
errs := make([]error, len(peers))
|
errs := make([]error, len(peers))
|
||||||
@ -188,11 +188,11 @@ func listPeerLocksInfo(peers adminPeers, bucket, prefix string, relTime time.Dur
|
|||||||
go func(idx int, remotePeer adminPeer) {
|
go func(idx int, remotePeer adminPeer) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
// `remotePeers` is right-shifted by one position relative to `peers`
|
// `remotePeers` is right-shifted by one position relative to `peers`
|
||||||
allLocks[idx], errs[idx] = remotePeer.cmdRunner.ListLocks(bucket, prefix, relTime)
|
allLocks[idx], errs[idx] = remotePeer.cmdRunner.ListLocks(bucket, prefix, duration)
|
||||||
}(i+1, remotePeer)
|
}(i+1, remotePeer)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
allLocks[0], errs[0] = localPeer.cmdRunner.ListLocks(bucket, prefix, relTime)
|
allLocks[0], errs[0] = localPeer.cmdRunner.ListLocks(bucket, prefix, duration)
|
||||||
|
|
||||||
// Summarizing errors received for ListLocks RPC across all
|
// Summarizing errors received for ListLocks RPC across all
|
||||||
// nodes. N B the possible unavailability of quorum in errors
|
// nodes. N B the possible unavailability of quorum in errors
|
||||||
|
@ -37,9 +37,9 @@ type adminCmd struct {
|
|||||||
// ListLocksQuery - wraps ListLocks API's query values to send over RPC.
|
// ListLocksQuery - wraps ListLocks API's query values to send over RPC.
|
||||||
type ListLocksQuery struct {
|
type ListLocksQuery struct {
|
||||||
AuthRPCArgs
|
AuthRPCArgs
|
||||||
bucket string
|
bucket string
|
||||||
prefix string
|
prefix string
|
||||||
relTime time.Duration
|
duration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListLocksReply - wraps ListLocks response over RPC.
|
// ListLocksReply - wraps ListLocks response over RPC.
|
||||||
@ -63,7 +63,7 @@ func (s *adminCmd) ListLocks(query *ListLocksQuery, reply *ListLocksReply) error
|
|||||||
if err := query.IsAuthenticated(); err != nil {
|
if err := query.IsAuthenticated(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
volLocks := listLocksInfo(query.bucket, query.prefix, query.relTime)
|
volLocks := listLocksInfo(query.bucket, query.prefix, query.duration)
|
||||||
*reply = ListLocksReply{volLocks: volLocks}
|
*reply = ListLocksReply{volLocks: volLocks}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -483,7 +483,7 @@ var errorCodeResponse = map[APIErrorCode]APIError{
|
|||||||
},
|
},
|
||||||
ErrInvalidDuration: {
|
ErrInvalidDuration: {
|
||||||
Code: "InvalidDuration",
|
Code: "InvalidDuration",
|
||||||
Description: "Relative duration provided in the request is invalid.",
|
Description: "Duration provided in the request is invalid.",
|
||||||
HTTPStatusCode: http.StatusBadRequest,
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -68,8 +68,8 @@ type OpsLockState struct {
|
|||||||
Duration time.Duration `json:"duration"` // Duration since the lock was held.
|
Duration time.Duration `json:"duration"` // Duration since the lock was held.
|
||||||
}
|
}
|
||||||
|
|
||||||
// listLocksInfo - Fetches locks held on bucket, matching prefix older than relTime.
|
// listLocksInfo - Fetches locks held on bucket, matching prefix held for longer than duration.
|
||||||
func listLocksInfo(bucket, prefix string, relTime time.Duration) []VolumeLockInfo {
|
func listLocksInfo(bucket, prefix string, duration time.Duration) []VolumeLockInfo {
|
||||||
globalNSMutex.lockMapMutex.Lock()
|
globalNSMutex.lockMapMutex.Lock()
|
||||||
defer globalNSMutex.lockMapMutex.Unlock()
|
defer globalNSMutex.lockMapMutex.Unlock()
|
||||||
|
|
||||||
@ -95,11 +95,12 @@ func listLocksInfo(bucket, prefix string, relTime time.Duration) []VolumeLockInf
|
|||||||
}
|
}
|
||||||
// Filter locks that are held on bucket, prefix.
|
// Filter locks that are held on bucket, prefix.
|
||||||
for opsID, lockInfo := range debugLock.lockInfo {
|
for opsID, lockInfo := range debugLock.lockInfo {
|
||||||
|
// filter locks that were held for longer than duration.
|
||||||
elapsed := timeNow.Sub(lockInfo.since)
|
elapsed := timeNow.Sub(lockInfo.since)
|
||||||
if elapsed < relTime {
|
if elapsed < duration {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Add locks that are older than relTime.
|
// Add locks that are held for longer than duration.
|
||||||
volLockInfo.LockDetailsOnObject = append(volLockInfo.LockDetailsOnObject,
|
volLockInfo.LockDetailsOnObject = append(volLockInfo.LockDetailsOnObject,
|
||||||
OpsLockState{
|
OpsLockState{
|
||||||
OperationID: opsID,
|
OperationID: opsID,
|
||||||
|
@ -45,34 +45,34 @@ func TestListLocksInfo(t *testing.T) {
|
|||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
bucket string
|
bucket string
|
||||||
prefix string
|
prefix string
|
||||||
relTime time.Duration
|
duration time.Duration
|
||||||
numLocks int
|
numLocks int
|
||||||
}{
|
}{
|
||||||
// Test 1 - Matches all the locks acquired above.
|
// Test 1 - Matches all the locks acquired above.
|
||||||
{
|
{
|
||||||
bucket: "bucket1",
|
bucket: "bucket1",
|
||||||
prefix: "prefix1",
|
prefix: "prefix1",
|
||||||
relTime: time.Duration(0 * time.Second),
|
duration: time.Duration(0 * time.Second),
|
||||||
numLocks: 20,
|
numLocks: 20,
|
||||||
},
|
},
|
||||||
// Test 2 - Bucket doesn't match.
|
// Test 2 - Bucket doesn't match.
|
||||||
{
|
{
|
||||||
bucket: "bucket",
|
bucket: "bucket",
|
||||||
prefix: "prefix1",
|
prefix: "prefix1",
|
||||||
relTime: time.Duration(0 * time.Second),
|
duration: time.Duration(0 * time.Second),
|
||||||
numLocks: 0,
|
numLocks: 0,
|
||||||
},
|
},
|
||||||
// Test 3 - Prefix doesn't match.
|
// Test 3 - Prefix doesn't match.
|
||||||
{
|
{
|
||||||
bucket: "bucket1",
|
bucket: "bucket1",
|
||||||
prefix: "prefix11",
|
prefix: "prefix11",
|
||||||
relTime: time.Duration(0 * time.Second),
|
duration: time.Duration(0 * time.Second),
|
||||||
numLocks: 0,
|
numLocks: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range testCases {
|
for i, test := range testCases {
|
||||||
actual := listLocksInfo(test.bucket, test.prefix, test.relTime)
|
actual := listLocksInfo(test.bucket, test.prefix, test.duration)
|
||||||
if len(actual) != test.numLocks {
|
if len(actual) != test.numLocks {
|
||||||
t.Errorf("Test %d - Expected %d locks but observed %d locks",
|
t.Errorf("Test %d - Expected %d locks but observed %d locks",
|
||||||
i+1, test.numLocks, len(actual))
|
i+1, test.numLocks, len(actual))
|
||||||
|
@ -66,9 +66,9 @@
|
|||||||
|
|
||||||
### Lock Management APIs
|
### Lock Management APIs
|
||||||
* ListLocks
|
* ListLocks
|
||||||
- GET /?lock&bucket=mybucket&prefix=myprefix&older-than=rel_time
|
- GET /?lock&bucket=mybucket&prefix=myprefix&duration=duration
|
||||||
- x-minio-operation: list
|
- x-minio-operation: list
|
||||||
- Response: On success 200, json encoded response containing all locks held, older than rel_time. e.g, older than 3 hours.
|
- Response: On success 200, json encoded response containing all locks held, for longer than duration.
|
||||||
- Possible error responses
|
- Possible error responses
|
||||||
- ErrInvalidBucketName
|
- ErrInvalidBucketName
|
||||||
<Error>
|
<Error>
|
||||||
@ -95,7 +95,7 @@
|
|||||||
- ErrInvalidDuration
|
- ErrInvalidDuration
|
||||||
<Error>
|
<Error>
|
||||||
<Code>InvalidDuration</Code>
|
<Code>InvalidDuration</Code>
|
||||||
<Message>Relative duration provided in the request is invalid.</Message>
|
<Message>Duration provided in the request is invalid.</Message>
|
||||||
<Key></Key>
|
<Key></Key>
|
||||||
<BucketName></BucketName>
|
<BucketName></BucketName>
|
||||||
<Resource>/</Resource>
|
<Resource>/</Resource>
|
||||||
@ -105,9 +105,9 @@
|
|||||||
|
|
||||||
|
|
||||||
* ClearLocks
|
* ClearLocks
|
||||||
- POST /?lock&bucket=mybucket&prefix=myprefix&older-than=rel_time
|
- POST /?lock&bucket=mybucket&prefix=myprefix&duration=duration
|
||||||
- x-minio-operation: clear
|
- x-minio-operation: clear
|
||||||
- Response: On success 200, json encoded response containing all locks cleared, older than rel_time. e.g, older than 3 hours.
|
- Response: On success 200, json encoded response containing all locks cleared, for longer than duration.
|
||||||
- Possible error responses, similar to errors listed in ListLocks.
|
- Possible error responses, similar to errors listed in ListLocks.
|
||||||
- ErrInvalidBucketName
|
- ErrInvalidBucketName
|
||||||
- ErrInvalidObjectName
|
- ErrInvalidObjectName
|
||||||
|
@ -120,8 +120,8 @@ If successful restarts the running minio service, for distributed setup restarts
|
|||||||
|
|
||||||
```
|
```
|
||||||
<a name="ListLocks"></a>
|
<a name="ListLocks"></a>
|
||||||
### ListLocks(bucket, prefix string, olderThan time.Duration) ([]VolumeLockInfo, error)
|
### ListLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error)
|
||||||
If successful returns information on the list of locks held on ``bucket`` matching ``prefix`` older than ``olderThan`` seconds.
|
If successful returns information on the list of locks held on ``bucket`` matching ``prefix`` for longer than ``duration`` seconds.
|
||||||
|
|
||||||
__Example__
|
__Example__
|
||||||
|
|
||||||
@ -135,8 +135,8 @@ __Example__
|
|||||||
```
|
```
|
||||||
|
|
||||||
<a name="ClearLocks"></a>
|
<a name="ClearLocks"></a>
|
||||||
### ClearLocks(bucket, prefix string, olderThan time.Duration) ([]VolumeLockInfo, error)
|
### ClearLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error)
|
||||||
If successful returns information on the list of locks cleared on ``bucket`` matching ``prefix`` older than ``olderThan`` seconds.
|
If successful returns information on the list of locks cleared on ``bucket`` matching ``prefix`` for longer than ``duration`` seconds.
|
||||||
|
|
||||||
__Example__
|
__Example__
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ func main() {
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear locks held on mybucket/myprefix older than olderThan seconds.
|
// Clear locks held on mybucket/myprefix for longer than 30s.
|
||||||
olderThan := time.Duration(30 * time.Second)
|
olderThan := time.Duration(30 * time.Second)
|
||||||
locksCleared, err := madmClnt.ClearLocks("mybucket", "myprefix", olderThan)
|
locksCleared, err := madmClnt.ClearLocks("mybucket", "myprefix", olderThan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -37,7 +37,7 @@ func main() {
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List locks held on mybucket/myprefix older than 30s.
|
// List locks held on mybucket/myprefix for longer than 30s.
|
||||||
locksHeld, err := madmClnt.ListLocks("mybucket", "myprefix", time.Duration(30*time.Second))
|
locksHeld, err := madmClnt.ListLocks("mybucket", "myprefix", time.Duration(30*time.Second))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
|
Loading…
Reference in New Issue
Block a user