Skip to content

Commit 2b0967f

Browse files
binghaiwangPeterRao
authored andcommitted
fix(Browser): multipartUpload InvalidPartOrderError by doneParts repeat (#414)
* fix(Browser): multipartUpload InvalidPartOrderError issues * fix(Browser): multipartUpload InvalidPartOrderError issues * fix: multipart doneParts repeat bug
1 parent e8a78b5 commit 2b0967f

File tree

3 files changed

+24
-10
lines changed

3 files changed

+24
-10
lines changed

lib/browser/managed_upload.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const is = require('is-type-of');
55
const util = require('util');
66
const path = require('path');
77
const mime = require('mime');
8+
const copy = require('copy-to');
89

910
const proto = exports;
1011

@@ -113,8 +114,15 @@ proto._resumeMultipart = function* _resumeMultipart(checkpoint, options) {
113114
file, fileSize, partSize, uploadId, doneParts, name,
114115
} = checkpoint;
115116

117+
const internalDoneParts = [];
118+
119+
if (doneParts.length > 0) {
120+
copy(doneParts).to(internalDoneParts);
121+
}
122+
116123
const partOffs = this._divideParts(fileSize, partSize);
117124
const numParts = partOffs.length;
125+
let multipartFinish = false;
118126

119127
const uploadPartJob = function* uploadPartJob(self, partNo) {
120128
if (!self.isCancel()) {
@@ -126,12 +134,16 @@ proto._resumeMultipart = function* _resumeMultipart(checkpoint, options) {
126134
};
127135

128136
const result = yield self._uploadPart(name, uploadId, partNo, data);
129-
if (!self.isCancel()) {
130-
doneParts.push({
137+
if (!self.isCancel() && !multipartFinish) {
138+
checkpoint.doneParts.push({
139+
number: partNo,
140+
etag: result.res.headers.etag,
141+
});
142+
143+
internalDoneParts.push({
131144
number: partNo,
132145
etag: result.res.headers.etag,
133146
});
134-
checkpoint.doneParts = doneParts;
135147

136148
if (options && options.progress) {
137149
yield options.progress(doneParts.length / numParts, checkpoint, result.res);
@@ -148,7 +160,7 @@ proto._resumeMultipart = function* _resumeMultipart(checkpoint, options) {
148160
};
149161

150162
const all = Array.from(new Array(numParts), (x, i) => i + 1);
151-
const done = doneParts.map(p => p.number);
163+
const done = internalDoneParts.map(p => p.number);
152164
const todo = all.filter(p => done.indexOf(p) < 0);
153165
const defaultParallel = 5;
154166
const parallel = options.parallel || defaultParallel;
@@ -168,7 +180,8 @@ proto._resumeMultipart = function* _resumeMultipart(checkpoint, options) {
168180
}
169181

170182
// start uploads jobs
171-
const errors = yield this._thunkPool(jobs, parallel);
183+
const errors = this._thunkPool(jobs, parallel);
184+
multipartFinish = true;
172185

173186
// check errors after all jobs are completed
174187
if (errors && errors.length > 0) {
@@ -183,7 +196,7 @@ proto._resumeMultipart = function* _resumeMultipart(checkpoint, options) {
183196
throw this._makeCancelEvent();
184197
}
185198
}
186-
return yield this.completeMultipartUpload(name, uploadId, doneParts, options);
199+
return yield this.completeMultipartUpload(name, uploadId, internalDoneParts, options);
187200
};
188201

189202

lib/common/multipart.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,11 @@ proto.uploadPart = function* uploadPart(name, uploadId, partNo, file, start, end
160160
* }
161161
*/
162162
proto.completeMultipartUpload = function* completeMultipartUpload(name, uploadId, parts, options) {
163-
parts.sort((a, b) => a.number - b.number);
163+
const completeParts = parts.concat().sort((a, b) => a.number - b.number)
164+
.filter((item, index, arr) => !index || item.number !== arr[index - 1].number);
164165
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<CompleteMultipartUpload>\n';
165-
for (let i = 0; i < parts.length; i++) {
166-
const p = parts[i];
166+
for (let i = 0; i < completeParts.length; i++) {
167+
const p = completeParts[i];
167168
xml += '<Part>\n';
168169
xml += `<PartNumber>${p.number}</PartNumber>\n`;
169170
xml += `<ETag>${p.etag}</ETag>\n`;

test/node/callback.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const config = require('../config').oss;
77
const { callbackServer } = require('../const');
88
const mm = require('mm');
99

10-
describe('test/multipart.test.js', () => {
10+
describe('test/callback.test.js', () => {
1111
const { prefix } = utils;
1212

1313
before(function* () {

0 commit comments

Comments
 (0)