{"action":"created","comment":{"url":"https://api.github.com/repos/docker/distribution/pulls/comments/74980402","id":74980402,"diff_hunk":"@@ -565,21 +623,109 @@ func (d *driver) List(ctx context.Context, opath string) ([]string, error) {\n // object.\n func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {\n \t/* This is terrible, but aws doesn't have an actual move. */\n-\t_, err := d.S3.CopyObject(&s3.CopyObjectInput{\n-\t\tBucket:               aws.String(d.Bucket),\n-\t\tKey:                  aws.String(d.s3Path(destPath)),\n-\t\tContentType:          d.getContentType(),\n-\t\tACL:                  d.getACL(),\n-\t\tServerSideEncryption: d.getEncryptionMode(),\n-\t\tSSEKMSKeyId:          d.getSSEKMSKeyID(),\n-\t\tStorageClass:         d.getStorageClass(),\n-\t\tCopySource:           aws.String(d.Bucket + \"/\" + d.s3Path(sourcePath)),\n-\t})\n+\tif err := d.copy(ctx, sourcePath, destPath); err != nil {\n+\t\treturn err\n+\t}\n+\treturn d.Delete(ctx, sourcePath)\n+}\n+\n+// copy copies an object stored at sourcePath to destPath.\n+func (d *driver) copy(ctx context.Context, sourcePath string, destPath string) error {\n+\t// S3 can copy objects up to 5 GB in size with a single PUT Object - Copy\n+\t// operation. For larger objects, the multipart upload API must be used.\n+\t//\n+\t// Empirically, multipart copy is fastest with 32 MB parts and is faster\n+\t// than PUT Object - Copy for objects larger than 32 MB.\n+\n+\tfileInfo, err := d.Stat(ctx, sourcePath)\n \tif err != nil {\n \t\treturn parseError(sourcePath, err)\n \t}\n \n-\treturn d.Delete(ctx, sourcePath)\n+\tif fileInfo.Size() <= d.MultipartCopyThresholdSize {\n+\t\t_, err := d.S3.CopyObject(&s3.CopyObjectInput{\n+\t\t\tBucket:               aws.String(d.Bucket),\n+\t\t\tKey:                  aws.String(d.s3Path(destPath)),\n+\t\t\tContentType:          d.getContentType(),\n+\t\t\tACL:                  d.getACL(),\n+\t\t\tServerSideEncryption: d.getEncryptionMode(),\n+\t\t\tSSEKMSKeyId:          d.getSSEKMSKeyID(),\n+\t\t\tStorageClass:         d.getStorageClass(),\n+\t\t\tCopySource:           aws.String(d.Bucket + \"/\" + d.s3Path(sourcePath)),\n+\t\t})\n+\t\tif err != nil {\n+\t\t\treturn parseError(sourcePath, err)\n+\t\t}","path":"registry/storage/driver/s3-aws/s3.go","position":261,"original_position":261,"commit_id":"6615fff1ca168549e5d561356691bb705c93b15d","original_commit_id":"6615fff1ca168549e5d561356691bb705c93b15d","user":{"login":"RichardScothern","id":922018,"avatar_url":"https://avatars.githubusercontent.com/u/922018?v=3","gravatar_id":"","url":"https://api.github.com/users/RichardScothern","html_url":"https://github.com/RichardScothern","followers_url":"https://api.github.com/users/RichardScothern/followers","following_url":"https://api.github.com/users/RichardScothern/following{/other_user}","gists_url":"https://api.github.com/users/RichardScothern/gists{/gist_id}","starred_url":"https://api.github.com/users/RichardScothern/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RichardScothern/subscriptions","organizations_url":"https://api.github.com/users/RichardScothern/orgs","repos_url":"https://api.github.com/users/RichardScothern/repos","events_url":"https://api.github.com/users/RichardScothern/events{/privacy}","received_events_url":"https://api.github.com/users/RichardScothern/received_events","type":"User","site_admin":false},"body":"return here on success so the rest of the function can be at the top level and not in the else","created_at":"2016-08-16T17:25:36Z","updated_at":"2016-08-16T17:25:36Z","html_url":"https://github.com/docker/distribution/pull/1906#discussion_r74980402","pull_request_url":"https://api.github.com/repos/docker/distribution/pulls/1906","_links":{"self":{"href":"https://api.github.com/repos/docker/distribution/pulls/comments/74980402"},"html":{"href":"https://github.com/docker/distribution/pull/1906#discussion_r74980402"},"pull_request":{"href":"https://api.github.com/repos/docker/distribution/pulls/1906"}}},"pull_request":{"url":"https://api.github.com/repos/docker/distribution/pulls/1906","id":81397307,"html_url":"https://github.com/docker/distribution/pull/1906","diff_url":"https://github.com/docker/distribution/pull/1906.diff","patch_url":"https://github.com/docker/distribution/pull/1906.patch","issue_url":"https://api.github.com/repos/docker/distribution/issues/1906","number":1906,"state":"open","locked":false,"title":"Use multipart upload API in S3 Move method","user":{"login":"nwt","id":2574448,"avatar_url":"https://avatars.githubusercontent.com/u/2574448?v=3","gravatar_id":"","url":"https://api.github.com/users/nwt","html_url":"https://github.com/nwt","followers_url":"https://api.github.com/users/nwt/followers","following_url":"https://api.github.com/users/nwt/following{/other_user}","gists_url":"https://api.github.com/users/nwt/gists{/gist_id}","starred_url":"https://api.github.com/users/nwt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nwt/subscriptions","organizations_url":"https://api.github.com/users/nwt/orgs","repos_url":"https://api.github.com/users/nwt/repos","events_url":"https://api.github.com/users/nwt/events{/privacy}","received_events_url":"https://api.github.com/users/nwt/received_events","type":"User","site_admin":false},"body":"This change to the S3 Move method uses S3's multipart upload API to copy\r\nobjects whose size exceeds a threshold.  Parts are copied concurrently.\r\nThe level of concurrency, part size, and threshold are all configurable\r\nwith reasonable defaults.\r\n\r\nUsing the multipart upload API has two benefits.\r\n\r\n* The S3 Move method can now handle objects over 5 GB, fixing #886.\r\n\r\n* Moving most objects, and espectially large ones, is faster.  For\r\n  example, moving a 1 GB object averaged 30 seconds but now averages 10.\r\n\r\nSigned-off-by: Noah Treuhaft <noah.treuhaft@docker.com>","created_at":"2016-08-16T00:18:15Z","updated_at":"2016-08-16T17:25:36Z","closed_at":null,"merged_at":null,"merge_commit_sha":"dd8e192f28755bdcc318e53d71676537b11e46eb","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/docker/distribution/pulls/1906/commits","review_comments_url":"https://api.github.com/repos/docker/distribution/pulls/1906/comments","review_comment_url":"https://api.github.com/repos/docker/distribution/pulls/comments{/number}","comments_url":"https://api.github.com/repos/docker/distribution/issues/1906/comments","statuses_url":"https://api.github.com/repos/docker/distribution/statuses/6615fff1ca168549e5d561356691bb705c93b15d","head":{"label":"nwt:s3-multipart-copy","ref":"s3-multipart-copy","sha":"6615fff1ca168549e5d561356691bb705c93b15d","user":{"login":"nwt","id":2574448,"avatar_url":"https://avatars.githubusercontent.com/u/2574448?v=3","gravatar_id":"","url":"https://api.github.com/users/nwt","html_url":"https://github.com/nwt","followers_url":"https://api.github.com/users/nwt/followers","following_url":"https://api.github.com/users/nwt/following{/other_user}","gists_url":"https://api.github.com/users/nwt/gists{/gist_id}","starred_url":"https://api.github.com/users/nwt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nwt/subscriptions","organizations_url":"https://api.github.com/users/nwt/orgs","repos_url":"https://api.github.com/users/nwt/repos","events_url":"https://api.github.com/users/nwt/events{/privacy}","received_events_url":"https://api.github.com/users/nwt/received_events","type":"User","site_admin":false},"repo":{"id":62915712,"name":"distribution","full_name":"nwt/distribution","owner":{"login":"nwt","id":2574448,"avatar_url":"https://avatars.githubusercontent.com/u/2574448?v=3","gravatar_id":"","url":"https://api.github.com/users/nwt","html_url":"https://github.com/nwt","followers_url":"https://api.github.com/users/nwt/followers","following_url":"https://api.github.com/users/nwt/following{/other_user}","gists_url":"https://api.github.com/users/nwt/gists{/gist_id}","starred_url":"https://api.github.com/users/nwt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nwt/subscriptions","organizations_url":"https://api.github.com/users/nwt/orgs","repos_url":"https://api.github.com/users/nwt/repos","events_url":"https://api.github.com/users/nwt/events{/privacy}","received_events_url":"https://api.github.com/users/nwt/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/nwt/distribution","description":"The Docker toolset to pack, ship, store, and deliver content","fork":true,"url":"https://api.github.com/repos/nwt/distribution","forks_url":"https://api.github.com/repos/nwt/distribution/forks","keys_url":"https://api.github.com/repos/nwt/distribution/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nwt/distribution/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nwt/distribution/teams","hooks_url":"https://api.github.com/repos/nwt/distribution/hooks","issue_events_url":"https://api.github.com/repos/nwt/distribution/issues/events{/number}","events_url":"https://api.github.com/repos/nwt/distribution/events","assignees_url":"https://api.github.com/repos/nwt/distribution/assignees{/user}","branches_url":"https://api.github.com/repos/nwt/distribution/branches{/branch}","tags_url":"https://api.github.com/repos/nwt/distribution/tags","blobs_url":"https://api.github.com/repos/nwt/distribution/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nwt/distribution/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nwt/distribution/git/refs{/sha}","trees_url":"https://api.github.com/repos/nwt/distribution/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nwt/distribution/statuses/{sha}","languages_url":"https://api.github.com/repos/nwt/distribution/languages","stargazers_url":"https://api.github.com/repos/nwt/distribution/stargazers","contributors_url":"https://api.github.com/repos/nwt/distribution/contributors","subscribers_url":"https://api.github.com/repos/nwt/distribution/subscribers","subscription_url":"https://api.github.com/repos/nwt/distribution/subscription","commits_url":"https://api.github.com/repos/nwt/distribution/commits{/sha}","git_commits_url":"https://api.github.com/repos/nwt/distribution/git/commits{/sha}","comments_url":"https://api.github.com/repos/nwt/distribution/comments{/number}","issue_comment_url":"https://api.github.com/repos/nwt/distribution/issues/comments{/number}","contents_url":"https://api.github.com/repos/nwt/distribution/contents/{+path}","compare_url":"https://api.github.com/repos/nwt/distribution/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nwt/distribution/merges","archive_url":"https://api.github.com/repos/nwt/distribution/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nwt/distribution/downloads","issues_url":"https://api.github.com/repos/nwt/distribution/issues{/number}","pulls_url":"https://api.github.com/repos/nwt/distribution/pulls{/number}","milestones_url":"https://api.github.com/repos/nwt/distribution/milestones{/number}","notifications_url":"https://api.github.com/repos/nwt/distribution/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nwt/distribution/labels{/name}","releases_url":"https://api.github.com/repos/nwt/distribution/releases{/id}","deployments_url":"https://api.github.com/repos/nwt/distribution/deployments","created_at":"2016-07-08T20:31:07Z","updated_at":"2016-07-08T20:31:10Z","pushed_at":"2016-08-16T00:12:29Z","git_url":"git://github.com/nwt/distribution.git","ssh_url":"git@github.com:nwt/distribution.git","clone_url":"https://github.com/nwt/distribution.git","svn_url":"https://github.com/nwt/distribution","homepage":null,"size":10406,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"docker:master","ref":"master","sha":"c810308d1bf3051521dd63cc1cdda03be9f11327","user":{"login":"docker","id":5429470,"avatar_url":"https://avatars.githubusercontent.com/u/5429470?v=3","gravatar_id":"","url":"https://api.github.com/users/docker","html_url":"https://github.com/docker","followers_url":"https://api.github.com/users/docker/followers","following_url":"https://api.github.com/users/docker/following{/other_user}","gists_url":"https://api.github.com/users/docker/gists{/gist_id}","starred_url":"https://api.github.com/users/docker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/docker/subscriptions","organizations_url":"https://api.github.com/users/docker/orgs","repos_url":"https://api.github.com/users/docker/repos","events_url":"https://api.github.com/users/docker/events{/privacy}","received_events_url":"https://api.github.com/users/docker/received_events","type":"Organization","site_admin":false},"repo":{"id":28366058,"name":"distribution","full_name":"docker/distribution","owner":{"login":"docker","id":5429470,"avatar_url":"https://avatars.githubusercontent.com/u/5429470?v=3","gravatar_id":"","url":"https://api.github.com/users/docker","html_url":"https://github.com/docker","followers_url":"https://api.github.com/users/docker/followers","following_url":"https://api.github.com/users/docker/following{/other_user}","gists_url":"https://api.github.com/users/docker/gists{/gist_id}","starred_url":"https://api.github.com/users/docker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/docker/subscriptions","organizations_url":"https://api.github.com/users/docker/orgs","repos_url":"https://api.github.com/users/docker/repos","events_url":"https://api.github.com/users/docker/events{/privacy}","received_events_url":"https://api.github.com/users/docker/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/docker/distribution","description":"The Docker toolset to pack, ship, store, and deliver content","fork":false,"url":"https://api.github.com/repos/docker/distribution","forks_url":"https://api.github.com/repos/docker/distribution/forks","keys_url":"https://api.github.com/repos/docker/distribution/keys{/key_id}","collaborators_url":"https://api.github.com/repos/docker/distribution/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/docker/distribution/teams","hooks_url":"https://api.github.com/repos/docker/distribution/hooks","issue_events_url":"https://api.github.com/repos/docker/distribution/issues/events{/number}","events_url":"https://api.github.com/repos/docker/distribution/events","assignees_url":"https://api.github.com/repos/docker/distribution/assignees{/user}","branches_url":"https://api.github.com/repos/docker/distribution/branches{/branch}","tags_url":"https://api.github.com/repos/docker/distribution/tags","blobs_url":"https://api.github.com/repos/docker/distribution/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/docker/distribution/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/docker/distribution/git/refs{/sha}","trees_url":"https://api.github.com/repos/docker/distribution/git/trees{/sha}","statuses_url":"https://api.github.com/repos/docker/distribution/statuses/{sha}","languages_url":"https://api.github.com/repos/docker/distribution/languages","stargazers_url":"https://api.github.com/repos/docker/distribution/stargazers","contributors_url":"https://api.github.com/repos/docker/distribution/contributors","subscribers_url":"https://api.github.com/repos/docker/distribution/subscribers","subscription_url":"https://api.github.com/repos/docker/distribution/subscription","commits_url":"https://api.github.com/repos/docker/distribution/commits{/sha}","git_commits_url":"https://api.github.com/repos/docker/distribution/git/commits{/sha}","comments_url":"https://api.github.com/repos/docker/distribution/comments{/number}","issue_comment_url":"https://api.github.com/repos/docker/distribution/issues/comments{/number}","contents_url":"https://api.github.com/repos/docker/distribution/contents/{+path}","compare_url":"https://api.github.com/repos/docker/distribution/compare/{base}...{head}","merges_url":"https://api.github.com/repos/docker/distribution/merges","archive_url":"https://api.github.com/repos/docker/distribution/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/docker/distribution/downloads","issues_url":"https://api.github.com/repos/docker/distribution/issues{/number}","pulls_url":"https://api.github.com/repos/docker/distribution/pulls{/number}","milestones_url":"https://api.github.com/repos/docker/distribution/milestones{/number}","notifications_url":"https://api.github.com/repos/docker/distribution/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/docker/distribution/labels{/name}","releases_url":"https://api.github.com/repos/docker/distribution/releases{/id}","deployments_url":"https://api.github.com/repos/docker/distribution/deployments","created_at":"2014-12-22T23:49:26Z","updated_at":"2016-08-16T15:06:05Z","pushed_at":"2016-08-16T13:17:19Z","git_url":"git://github.com/docker/distribution.git","ssh_url":"git@github.com:docker/distribution.git","clone_url":"https://github.com/docker/distribution.git","svn_url":"https://github.com/docker/distribution","homepage":null,"size":14050,"stargazers_count":2402,"watchers_count":2402,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":890,"mirror_url":null,"open_issues_count":229,"forks":890,"open_issues":229,"watchers":2402,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/docker/distribution/pulls/1906"},"html":{"href":"https://github.com/docker/distribution/pull/1906"},"issue":{"href":"https://api.github.com/repos/docker/distribution/issues/1906"},"comments":{"href":"https://api.github.com/repos/docker/distribution/issues/1906/comments"},"review_comments":{"href":"https://api.github.com/repos/docker/distribution/pulls/1906/comments"},"review_comment":{"href":"https://api.github.com/repos/docker/distribution/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/docker/distribution/pulls/1906/commits"},"statuses":{"href":"https://api.github.com/repos/docker/distribution/statuses/6615fff1ca168549e5d561356691bb705c93b15d"}}}}
{"actor":{"display_login":"RichardScothern"}}