Generate and call MultiDelete S3 requests based on entries received from objectsCh
(ctx context.Context, bucketName string, objectsCh <-chan ObjectInfo, resultCh chan<- RemoveObjectResult, opts RemoveObjectsOptions)
| 563 | |
| 564 | // Generate and call MultiDelete S3 requests based on entries received from objectsCh |
| 565 | func (c *Client) removeObjects(ctx context.Context, bucketName string, objectsCh <-chan ObjectInfo, resultCh chan<- RemoveObjectResult, opts RemoveObjectsOptions) { |
| 566 | // Close result channel when delete finishes. |
| 567 | defer close(resultCh) |
| 568 | |
| 569 | // NOTE: GCS does not support multi-object delete, use single DELETE requests. |
| 570 | if !c.useMultiDeleteForBulkDelete() { |
| 571 | c.removeObjectsSingle(ctx, bucketName, objectsCh, resultCh, opts) |
| 572 | return |
| 573 | } |
| 574 | |
| 575 | maxEntries := 1000 |
| 576 | finish := false |
| 577 | urlValues := make(url.Values) |
| 578 | urlValues.Set("delete", "") |
| 579 | |
| 580 | // Loop over entries by 1000 and call MultiDelete requests |
| 581 | for !finish { |
| 582 | count := 0 |
| 583 | var batch []ObjectInfo |
| 584 | |
| 585 | // Try to gather 1000 entries |
| 586 | for object := range objectsCh { |
| 587 | if hasInvalidXMLChar(object.Key) { |
| 588 | // Use single DELETE so the object name will be in the request URL instead of the multi-delete XML document. |
| 589 | removeResult := c.removeObject(ctx, bucketName, object.Key, RemoveObjectOptions{ |
| 590 | VersionID: object.VersionID, |
| 591 | GovernanceBypass: opts.GovernanceBypass, |
| 592 | }) |
| 593 | if err := removeResult.Err; err != nil { |
| 594 | // Version does not exist is not an error ignore and continue. |
| 595 | switch ToErrorResponse(err).Code { |
| 596 | case InvalidArgument, NoSuchVersion: |
| 597 | continue |
| 598 | } |
| 599 | resultCh <- removeResult |
| 600 | } |
| 601 | |
| 602 | resultCh <- removeResult |
| 603 | continue |
| 604 | } |
| 605 | |
| 606 | batch = append(batch, object) |
| 607 | if count++; count >= maxEntries { |
| 608 | break |
| 609 | } |
| 610 | } |
| 611 | if count == 0 { |
| 612 | // Multi Objects Delete API doesn't accept empty object list, quit immediately |
| 613 | break |
| 614 | } |
| 615 | if count < maxEntries { |
| 616 | // We didn't have 1000 entries, so this is the last batch |
| 617 | finish = true |
| 618 | } |
| 619 | |
| 620 | // Build headers. |
| 621 | headers := make(http.Header) |
| 622 | if opts.GovernanceBypass { |
no test coverage detected