mirror of
https://github.com/minio/minio.git
synced 2024-12-24 06:05:55 -05:00
web-handlers: Support removal of multiple objects at once. (#3810)
This commit is contained in:
parent
2b0ed21f08
commit
91cf54f895
@ -36,7 +36,7 @@ test_script:
|
||||
# Unit tests
|
||||
- ps: Add-AppveyorTest "Unit Tests" -Outcome Running
|
||||
- mkdir build\coverage
|
||||
- go test -timeout 15m -race github.com/minio/minio/cmd...
|
||||
- go test -timeout 17m -race github.com/minio/minio/cmd...
|
||||
- go test -race github.com/minio/minio/pkg...
|
||||
- go test -coverprofile=build\coverage\coverage.txt -covermode=atomic github.com/minio/minio/cmd
|
||||
- ps: Update-AppveyorTest "Unit Tests" -Outcome Passed
|
||||
|
@ -249,10 +249,12 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r
|
||||
}
|
||||
|
||||
// RemoveObjectArgs - args to remove an object
|
||||
// JSON will look like:
|
||||
// '{"bucketname":"testbucket","prefix":"john/pics/","objects":["hawaii/","maldives/","sanjose.jpg"]}'
|
||||
type RemoveObjectArgs struct {
|
||||
TargetHost string `json:"targetHost"`
|
||||
BucketName string `json:"bucketName"`
|
||||
ObjectName string `json:"objectName"`
|
||||
Objects []string `json:"objects"` // can be files or sub-directories
|
||||
Prefix string `json:"prefix"` // current directory in the browser-ui
|
||||
BucketName string `json:"bucketname"` // bucket name.
|
||||
}
|
||||
|
||||
// RemoveObject - removes an object.
|
||||
@ -264,31 +266,65 @@ func (web *webAPIHandlers) RemoveObject(r *http.Request, args *RemoveObjectArgs,
|
||||
if !isHTTPRequestValid(r) {
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
|
||||
objectLock := globalNSMutex.NewNSLock(args.BucketName, args.ObjectName)
|
||||
objectLock.Lock()
|
||||
defer objectLock.Unlock()
|
||||
|
||||
if err := objectAPI.DeleteObject(args.BucketName, args.ObjectName); err != nil {
|
||||
if isErrObjectNotFound(err) {
|
||||
// Ignore object not found error.
|
||||
reply.UIVersion = browser.UIVersion
|
||||
return nil
|
||||
if args.BucketName == "" || len(args.Objects) == 0 {
|
||||
return toJSONError(errUnexpected)
|
||||
}
|
||||
var err error
|
||||
objectLoop:
|
||||
for _, object := range args.Objects {
|
||||
remove := func(objectName string) error {
|
||||
objectLock := globalNSMutex.NewNSLock(args.BucketName, objectName)
|
||||
objectLock.Lock()
|
||||
defer objectLock.Unlock()
|
||||
err = objectAPI.DeleteObject(args.BucketName, objectName)
|
||||
if err == nil {
|
||||
// Notify object deleted event.
|
||||
eventNotify(eventData{
|
||||
Type: ObjectRemovedDelete,
|
||||
Bucket: args.BucketName,
|
||||
ObjInfo: ObjectInfo{
|
||||
Name: objectName,
|
||||
},
|
||||
ReqParams: map[string]string{
|
||||
"sourceIPAddress": r.RemoteAddr,
|
||||
},
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
||||
if !hasSuffix(object, slashSeparator) {
|
||||
// If not a directory, compress the file and write it to response.
|
||||
err = remove(pathJoin(args.Prefix, object))
|
||||
if err != nil {
|
||||
break objectLoop
|
||||
}
|
||||
continue
|
||||
}
|
||||
// For directories, list the contents recursively and remove.
|
||||
marker := ""
|
||||
for {
|
||||
var lo ListObjectsInfo
|
||||
lo, err = objectAPI.ListObjects(args.BucketName, pathJoin(args.Prefix, object), marker, "", 1000)
|
||||
if err != nil {
|
||||
break objectLoop
|
||||
}
|
||||
marker = lo.NextMarker
|
||||
for _, obj := range lo.Objects {
|
||||
err = remove(obj.Name)
|
||||
if err != nil {
|
||||
break objectLoop
|
||||
}
|
||||
}
|
||||
if !lo.IsTruncated {
|
||||
break
|
||||
}
|
||||
}
|
||||
return toJSONError(err, args.BucketName, args.ObjectName)
|
||||
}
|
||||
|
||||
// Notify object deleted event.
|
||||
eventNotify(eventData{
|
||||
Type: ObjectRemovedDelete,
|
||||
Bucket: args.BucketName,
|
||||
ObjInfo: ObjectInfo{
|
||||
Name: args.ObjectName,
|
||||
},
|
||||
ReqParams: map[string]string{
|
||||
"sourceIPAddress": r.RemoteAddr,
|
||||
},
|
||||
})
|
||||
if err != nil && !isErrObjectNotFound(err) {
|
||||
// Ignore object not found error.
|
||||
return toJSONError(err, args.BucketName, "")
|
||||
}
|
||||
|
||||
reply.UIVersion = browser.UIVersion
|
||||
return nil
|
||||
|
@ -468,7 +468,14 @@ func testRemoveObjectWebHandler(obj ObjectLayer, instanceType string, t TestErrH
|
||||
t.Fatalf("Was not able to upload an object, %v", err)
|
||||
}
|
||||
|
||||
removeObjectRequest := RemoveObjectArgs{BucketName: bucketName, ObjectName: objectName}
|
||||
objectName = "a/object"
|
||||
_, err = obj.PutObject(bucketName, objectName, int64(len(data)), bytes.NewReader(data),
|
||||
map[string]string{"md5Sum": "c9a34cfc85d982698c6ac89f76071abd"}, "")
|
||||
if err != nil {
|
||||
t.Fatalf("Was not able to upload an object, %v", err)
|
||||
}
|
||||
|
||||
removeObjectRequest := RemoveObjectArgs{BucketName: bucketName, Prefix: "", Objects: []string{"a/", "object"}}
|
||||
removeObjectReply := &WebGenericRep{}
|
||||
req, err := newTestWebRPCRequest("Web.RemoveObject", authorization, removeObjectRequest)
|
||||
if err != nil {
|
||||
@ -483,7 +490,7 @@ func testRemoveObjectWebHandler(obj ObjectLayer, instanceType string, t TestErrH
|
||||
t.Fatalf("Failed, %v", err)
|
||||
}
|
||||
|
||||
removeObjectRequest = RemoveObjectArgs{BucketName: bucketName, ObjectName: objectName}
|
||||
removeObjectRequest = RemoveObjectArgs{BucketName: bucketName, Prefix: "", Objects: []string{"a/", "object"}}
|
||||
removeObjectReply = &WebGenericRep{}
|
||||
req, err = newTestWebRPCRequest("Web.RemoveObject", authorization, removeObjectRequest)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user