@@ -237,6 +237,16 @@ function extend(target, source) {
237
237
function isArray ( arr ) {
238
238
return arr instanceof Array ;
239
239
}
240
+ function isInArray ( arr , item ) {
241
+ var flag = false ;
242
+ for ( var i = 0 ; i < arr . length ; i ++ ) {
243
+ if ( item === arr [ i ] ) {
244
+ flag = true ;
245
+ break ;
246
+ }
247
+ }
248
+ return flag ;
249
+ }
240
250
function each ( obj , fn ) {
241
251
for ( var i in obj ) {
242
252
if ( obj . hasOwnProperty ( i ) ) {
@@ -464,6 +474,7 @@ var util = {
464
474
binaryBase64 : binaryBase64 ,
465
475
extend : extend ,
466
476
isArray : isArray ,
477
+ isInArray : isInArray ,
467
478
each : each ,
468
479
map : map ,
469
480
filter : filter ,
@@ -1461,7 +1472,7 @@ var initTask = function (cos) {
1461
1472
return ;
1462
1473
}
1463
1474
task . state = switchToState ;
1464
- cos . emit ( 'inner-kill-task' , { TaskId : id } ) ;
1475
+ cos . emit ( 'inner-kill-task' , { TaskId : id , toState : switchToState } ) ;
1465
1476
emitListUpdate ( ) ;
1466
1477
if ( running ) {
1467
1478
uploadingFileCount -- ;
@@ -8035,28 +8046,36 @@ function sliceUploadFile(params, callback) {
8035
8046
} ) ;
8036
8047
8037
8048
// 上传分块完成,开始 uploadSliceComplete 操作
8038
- ep . on ( 'upload_slice_complete' , function ( data ) {
8049
+ ep . on ( 'upload_slice_complete' , function ( UploadData ) {
8039
8050
uploadSliceComplete . call ( self , {
8040
8051
Bucket : Bucket ,
8041
8052
Region : Region ,
8042
8053
Key : Key ,
8043
- UploadId : data . UploadId ,
8044
- SliceList : data . SliceList
8054
+ UploadId : UploadData . UploadId ,
8055
+ SliceList : UploadData . SliceList
8045
8056
} , function ( err , data ) {
8046
8057
if ( ! self . _isRunningTask ( TaskId ) ) return ;
8058
+ delete uploadIdUsing [ UploadData . UploadId ] ;
8047
8059
if ( err ) {
8048
8060
return ep . emit ( 'error' , err ) ;
8049
8061
}
8062
+ removeUploadId . call ( self , UploadData . UploadId ) ;
8050
8063
ep . emit ( 'upload_complete' , data ) ;
8051
8064
} ) ;
8052
8065
} ) ;
8053
8066
8054
8067
// 获取 UploadId 完成,开始上传每个分片
8055
8068
ep . on ( 'get_upload_data_finish' , function ( UploadData ) {
8056
- if ( UploadData . UploadId ) {
8057
- var uuid = getFileUuid ( Body , params . ChunkSize ) ;
8058
- uuid && setUploadId . call ( self , uuid , UploadData . UploadId ) ;
8059
- }
8069
+
8070
+ // 处理 UploadId 缓存
8071
+ var uuid = getFileUuid ( Body , params . ChunkSize ) ;
8072
+ uuid && setUploadId . call ( self , uuid , UploadData . UploadId ) ; // 缓存 UploadId
8073
+ uploadIdUsing [ UploadData . UploadId ] = true ; // 标记 UploadId 为正在使用
8074
+ TaskId && self . on ( 'inner-kill-task' , function ( data ) {
8075
+ if ( data . TaskId === TaskId && data . toState === 'canceled' ) {
8076
+ delete uploadIdUsing [ UploadData . UploadId ] ; // 去除 UploadId 正在使用的标记
8077
+ }
8078
+ } ) ;
8060
8079
8061
8080
// 获取 UploadId
8062
8081
uploadSliceList . call ( self , {
@@ -8126,6 +8145,7 @@ function sliceUploadFile(params, callback) {
8126
8145
params . ChunkSize = params . SliceSize = ChunkSize = Math . max ( ChunkSize , AutoChunkSize ) ;
8127
8146
} ) ( ) ;
8128
8147
8148
+ // 开始上传
8129
8149
if ( FileSize === 0 ) {
8130
8150
params . Body = '' ;
8131
8151
self . putObject ( params , callback ) ;
@@ -8135,14 +8155,26 @@ function sliceUploadFile(params, callback) {
8135
8155
}
8136
8156
8137
8157
// 按照文件特征值,缓存 UploadId
8158
+ var uploadIdCache ;
8159
+ var uploadIdUsing = { } ;
8138
8160
var uploadIdCacheKey = 'cos_sdk_upload_cache' ;
8139
- var uploadIdCache = [ ] ;
8140
- try {
8141
- uploadIdCache = JSON . parse ( localStorage . getItem ( uploadIdCacheKey ) ) || [ ] ;
8142
- } catch ( e ) { }
8143
- function setUploadId ( uuid , UploadId ) {
8161
+ function initUploadId ( ) {
8162
+ var cacheLimit = this . options . UploadIdCacheLimit ;
8163
+ if ( ! uploadIdCache ) {
8164
+ if ( cacheLimit ) {
8165
+ try {
8166
+ uploadIdCache = JSON . parse ( localStorage . getItem ( uploadIdCacheKey ) ) || [ ] ;
8167
+ } catch ( e ) { }
8168
+ }
8169
+ if ( ! uploadIdCache ) {
8170
+ uploadIdCache = [ ] ;
8171
+ }
8172
+ }
8173
+ }
8174
+ function setUploadId ( uuid , UploadId , isDisabled ) {
8175
+ initUploadId . call ( this ) ;
8144
8176
for ( var i = uploadIdCache . length - 1 ; i >= 0 ; i -- ) {
8145
- if ( uploadIdCache [ i ] [ 0 ] === uuid ) {
8177
+ if ( uploadIdCache [ i ] [ 0 ] === uuid && uploadIdCache [ i ] [ 1 ] === UploadId ) {
8146
8178
uploadIdCache . splice ( i , 1 ) ;
8147
8179
}
8148
8180
}
@@ -8157,15 +8189,37 @@ function setUploadId(uuid, UploadId) {
8157
8189
} catch ( e ) { }
8158
8190
} ) ;
8159
8191
}
8192
+ function removeUploadId ( UploadId ) {
8193
+ initUploadId . call ( this ) ;
8194
+ delete uploadIdUsing [ UploadId ] ;
8195
+ for ( var i = uploadIdCache . length - 1 ; i >= 0 ; i -- ) {
8196
+ if ( uploadIdCache [ i ] [ 1 ] === UploadId ) {
8197
+ uploadIdCache . splice ( i , 1 ) ;
8198
+ }
8199
+ }
8200
+ var cacheLimit = this . options . UploadIdCacheLimit ;
8201
+ if ( uploadIdCache . length > cacheLimit ) {
8202
+ uploadIdCache . splice ( cacheLimit ) ;
8203
+ }
8204
+ cacheLimit && setTimeout ( function ( ) {
8205
+ try {
8206
+ if ( uploadIdCache . length ) {
8207
+ localStorage . setItem ( uploadIdCacheKey , JSON . stringify ( uploadIdCache ) ) ;
8208
+ } else {
8209
+ localStorage . removeItem ( uploadIdCacheKey ) ;
8210
+ }
8211
+ } catch ( e ) { }
8212
+ } ) ;
8213
+ }
8160
8214
function getUploadId ( uuid ) {
8161
- var UploadId ;
8215
+ initUploadId . call ( this ) ;
8216
+ var CacheUploadIdList = [ ] ;
8162
8217
for ( var i = 0 ; i < uploadIdCache . length ; i ++ ) {
8163
8218
if ( uploadIdCache [ i ] [ 0 ] === uuid ) {
8164
- UploadId = uploadIdCache [ i ] [ 1 ] ;
8165
- break ;
8219
+ CacheUploadIdList . push ( uploadIdCache [ i ] [ 1 ] ) ;
8166
8220
}
8167
8221
}
8168
- return UploadId ;
8222
+ return CacheUploadIdList . length ? CacheUploadIdList : null ;
8169
8223
}
8170
8224
function getFileUuid ( file , ChunkSize ) {
8171
8225
// 如果信息不完整,不获取
@@ -8318,14 +8372,23 @@ function getUploadIdAndPartList(params, callback) {
8318
8372
UploadIdList = UploadIdList . reverse ( ) ;
8319
8373
Async . eachLimit ( UploadIdList , 1 , function ( UploadId , asyncCallback ) {
8320
8374
if ( ! self . _isRunningTask ( TaskId ) ) return ;
8375
+ // 如果正在上传,跳过
8376
+ if ( uploadIdUsing [ UploadId ] ) {
8377
+ asyncCallback ( ) ; // 检查下一个 UploadId
8378
+ return ;
8379
+ }
8380
+ // 判断 UploadId 是否可用
8321
8381
wholeMultipartListPart . call ( self , {
8322
8382
Bucket : Bucket ,
8323
8383
Region : Region ,
8324
8384
Key : Key ,
8325
8385
UploadId : UploadId
8326
8386
} , function ( err , PartListData ) {
8327
8387
if ( ! self . _isRunningTask ( TaskId ) ) return ;
8328
- if ( err ) return ep . emit ( 'error' , err ) ;
8388
+ if ( err ) {
8389
+ removeUploadId . call ( self , UploadId ) ;
8390
+ return ep . emit ( 'error' , err ) ;
8391
+ }
8329
8392
var PartList = PartListData . PartList ;
8330
8393
PartList . forEach ( function ( item ) {
8331
8394
item . PartNumber *= 1 ;
@@ -8356,24 +8419,58 @@ function getUploadIdAndPartList(params, callback) {
8356
8419
} ) ;
8357
8420
} ) ;
8358
8421
8359
- // 获取缓存的 UploadId
8360
- var uuid = getFileUuid ( params . Body , params . ChunkSize ) ,
8361
- UploadId ;
8362
- if ( uuid && ( UploadId = getUploadId ( uuid ) ) ) {
8363
- wholeMultipartListPart . call ( self , {
8364
- Bucket : Bucket ,
8365
- Region : Region ,
8366
- Key : Key ,
8367
- UploadId : UploadId
8368
- } , function ( err , PartListData ) {
8369
- if ( ! self . _isRunningTask ( TaskId ) ) return ;
8370
- if ( err ) return ep . emit ( 'error' , err ) ;
8371
- ep . emit ( 'upload_id_ready' , {
8372
- UploadId : UploadId ,
8373
- PartList : PartListData . PartList
8374
- } ) ;
8375
- } ) ;
8376
- } else {
8422
+ // 在本地缓存找可用的 UploadId
8423
+ ep . on ( 'seek_local_avail_upload_id' , function ( RemoteUploadIdList ) {
8424
+ // 在本地找可用的 UploadId
8425
+ var uuid = getFileUuid ( params . Body , params . ChunkSize ) ,
8426
+ LocalUploadIdList ;
8427
+ if ( uuid && ( LocalUploadIdList = getUploadId . call ( self , uuid ) ) ) {
8428
+ var next = function ( index ) {
8429
+ // 如果找不到,到线上列出 UploadId
8430
+ if ( index >= LocalUploadIdList . length ) {
8431
+ ep . emit ( 'has_upload_id' , RemoteUploadIdList ) ;
8432
+ return ;
8433
+ }
8434
+ var UploadId = LocalUploadIdList [ index ] ;
8435
+ // 如果不在远端 UploadId 列表里,跳过并删除
8436
+ if ( ! util . isInArray ( RemoteUploadIdList , UploadId ) ) {
8437
+ removeUploadId . call ( self , UploadId ) ;
8438
+ next ( index + 1 ) ;
8439
+ return ;
8440
+ }
8441
+ // 如果正在上传,跳过
8442
+ if ( uploadIdUsing [ UploadId ] ) {
8443
+ next ( index + 1 ) ;
8444
+ return ;
8445
+ }
8446
+ // 判断 UploadId 是否存在线上
8447
+ wholeMultipartListPart . call ( self , {
8448
+ Bucket : Bucket ,
8449
+ Region : Region ,
8450
+ Key : Key ,
8451
+ UploadId : UploadId
8452
+ } , function ( err , PartListData ) {
8453
+ if ( ! self . _isRunningTask ( TaskId ) ) return ;
8454
+ if ( err ) {
8455
+ removeUploadId . call ( self , UploadId ) ;
8456
+ next ( index + 1 ) ;
8457
+ } else {
8458
+ // 找到可用 UploadId
8459
+ ep . emit ( 'upload_id_ready' , {
8460
+ UploadId : UploadId ,
8461
+ PartList : PartListData . PartList
8462
+ } ) ;
8463
+ }
8464
+ } ) ;
8465
+ } ;
8466
+ next ( 0 ) ;
8467
+ } else {
8468
+ ep . emit ( 'has_upload_id' , RemoteUploadIdList ) ;
8469
+ }
8470
+ } ) ;
8471
+
8472
+ // 获取线上 UploadId 列表
8473
+ ep . on ( 'get_remote_upload_id_list' , function ( RemoteUploadIdList ) {
8377
8474
// 获取符合条件的 UploadId 列表,因为同一个文件可以有多个上传任务。
8378
8475
wholeMultipartList . call ( self , {
8379
8476
Bucket : Bucket ,
@@ -8384,18 +8481,29 @@ function getUploadIdAndPartList(params, callback) {
8384
8481
if ( err ) {
8385
8482
return ep . emit ( 'error' , err ) ;
8386
8483
}
8387
- var UploadIdList = data . UploadList . filter ( function ( item ) {
8484
+ // 整理远端 UploadId 列表
8485
+ var RemoteUploadIdList = data . UploadList . filter ( function ( item ) {
8388
8486
return item . Key === Key && ( ! StorageClass || item . StorageClass . toUpperCase ( ) === StorageClass . toUpperCase ( ) ) ;
8389
8487
} ) . reverse ( ) . map ( function ( item ) {
8390
8488
return item . UploadId || item . UploadID ;
8391
8489
} ) ;
8392
- if ( UploadIdList . length ) {
8393
- ep . emit ( 'has_upload_id ' , UploadIdList ) ;
8490
+ if ( RemoteUploadIdList . length ) {
8491
+ ep . emit ( 'seek_local_avail_upload_id ' , RemoteUploadIdList ) ;
8394
8492
} else {
8493
+ var uuid = getFileUuid ( params . Body , params . ChunkSize ) ,
8494
+ LocalUploadIdList ;
8495
+ if ( uuid && ( LocalUploadIdList = getUploadId . call ( self , uuid ) ) ) {
8496
+ util . each ( LocalUploadIdList , function ( UploadId ) {
8497
+ removeUploadId . call ( self , UploadId ) ;
8498
+ } ) ;
8499
+ }
8395
8500
ep . emit ( 'no_available_upload_id' ) ;
8396
8501
}
8397
8502
} ) ;
8398
- }
8503
+ } ) ;
8504
+
8505
+ // 开始找可用 UploadId
8506
+ ep . emit ( 'get_remote_upload_id_list' ) ;
8399
8507
}
8400
8508
8401
8509
// 获取符合条件的全部上传任务 (条件包括 Bucket, Region, Prefix)
0 commit comments