Skip to content

fix(driver): fix 189 & 189pc fastcopy form local storage#2471

Merged
PIKACHUIM merged 3 commits into
mainfrom
fix-189fastcopy
May 12, 2026
Merged

fix(driver): fix 189 & 189pc fastcopy form local storage#2471
PIKACHUIM merged 3 commits into
mainfrom
fix-189fastcopy

Conversation

@PIKACHUIM
Copy link
Copy Markdown
Member

@PIKACHUIM PIKACHUIM commented May 12, 2026

Description / 描述

修复 189 和 189pc 驱动在从本地存储(或其他不提供 MD5 Hash 的存储)复制文件到天翼云时,即使云端已存在相同文件也无法触发秒传的问题。

修改后,两个驱动在上传前会先计算文件完整 MD5 和分片 MD5(sliceMd5),在 initMultiUpload 请求中携带这些信息,使天翼云服务端能够正确判断文件是否已存在,从而实现秒传。

Motivation and Context / 背景

问题现象

用户从本地存储复制文件到天翼云(189/189pc)时,即使云端已存在完全相同的文件,也无法触发秒传,必须重新上传整个文件。

根本原因

问题由 三层原因 叠加导致:

  1. 本地驱动不提供 MD5 Hash:本地驱动(Local)创建的 model.Object 不包含 HashInfoGetHash() 返回空值。

  2. 复制流程原样传递空 Hashcopy_move.go 中创建 SeekableStream 时直接使用源文件对象(srcObj),Hash 信息为空被原样传递到目标驱动。

  3. 上传方法未携带 MD5 参数

    • 189pc(StreamUpload):默认上传方式为 streamStreamUploadinitMultiUpload 请求中不传递 fileMd5sliceMd5 参数(只传 lazyCheck: "1"),服务端无法判断文件是否已存在。
    • 189(newUpload):原实现同样在 initMultiUpload 中只传 lazyCheck: "1",不传 fileMd5,无法触发秒传。

对比分析

参数 修改前(StreamUpload/newUpload) 修改后
parentFolderId
fileName
fileSize
sliceSize
fileMd5 ❌ 缺失
sliceMd5 ❌ 缺失
lazyCheck "1" 移除(改为传递实际 MD5)

Relates to: 从本地复制到天翼云无法秒传

修改逻辑

1. 189pc 驱动 (drivers/189pc/driver.go)

Put 方法的 case "stream" 分支中,增加秒传预判断逻辑:

// 尝试秒传:如果已有MD5则用RapidUpload,否则走FastUpload(会计算MD5并尝试秒传)
if !stream.IsForceStreamUpload() {
    fileMd5 := stream.GetHash().GetHash(utils.MD5)
    if len(fileMd5) >= utils.MD5.Width {
        // 源文件已有MD5(如从天翼云自身复制),直接尝试RapidUpload
        if newObj, err := y.RapidUpload(ctx, dstDir, stream, isFamily, overwrite); err == nil {
            return newObj, nil
        }
    } else {
        // 源文件无MD5(如从本地复制),走FastUpload
        // FastUpload会完整读取文件计算fileMd5和sliceMd5,然后尝试秒传
        return y.FastUpload(ctx, dstDir, stream, up, isFamily, overwrite)
    }
}

关键点FastUpload 内部会:

  • 逐片读取文件,同时计算每个分片的 MD5 和文件整体 MD5
  • 将所有分片 MD5 用 \n 拼接后再取 MD5 得到 sliceMd5
  • initMultiUpload 中传递 fileMd5sliceMd5
  • 检查响应中的 FileDataExists == 1 判断是否秒传成功

如果秒传失败(FileDataExists != 1),FastUpload 会继续正常分片上传。
如果 RapidUpload 失败,会 fallthrough 到 StreamUpload 正常上传。

2. 189 驱动 (drivers/189/util.go)

重构 newUpload 方法,在 initMultiUpload 之前增加 MD5 预计算逻辑:

Step 1 - 计算文件 MD5 和分片 MD5

fileMd5Hex := file.GetHash().GetHash(utils.MD5)
if len(fileMd5Hex) < utils.MD5.Width {
    // 缓存整个文件流,同时计算文件完整MD5
    fileMd5Hash := md5.New()
    cache, err := file.CacheFullAndWriter(nil, fileMd5Hash)
    fileMd5Hex = hex.EncodeToString(fileMd5Hash.Sum(nil))

    // 从缓存中逐片读取,计算每个分片的MD5
    sliceMd5Hash := md5.New()
    for i := 1; i <= count; i++ {
        // 读取分片数据,计算分片MD5
        sliceMd5Hash.Reset()
        sliceMd5Hash.Write(buf)
        md5s = append(md5s, strings.ToUpper(hex.EncodeToString(sliceMd5Hash.Sum(nil))))
    }
    cache.Seek(0, io.SeekStart) // seek回起始位置供后续上传使用
}

// 计算sliceMd5(多片时为所有分片MD5拼接后的MD5,单片时等于fileMd5)
if fileSize > DEFAULT {
    sliceMd5Hex = utils.GetMD5EncodeStr(strings.Join(md5s, "\n"))
} else {
    sliceMd5Hex = fileMd5Hex
}

Step 2 - 带 MD5 调用 initMultiUpload

initParams := map[string]string{
    "parentFolderId": dstDir.GetID(),
    "fileName":       encode(file.GetName()),
    "fileSize":       strconv.FormatInt(fileSize, 10),
    "sliceSize":      strconv.FormatInt(DEFAULT, 10),
    "fileMd5":        fileMd5Hex,
    "sliceMd5":       sliceMd5Hex,
}

Step 3 - 秒传判断

fileDataExists := jsoniter.Get(res, "data", "fileDataExists").ToInt()
if fileDataExists == 1 {
    // 秒传成功,直接commit
    d.uploadRequest("/person/commitMultiUploadFile", ...)
    return nil
}
// 否则继续正常分片上传

3. 189_tv 驱动 - 无需修改

189_tv 的 OldUpload 方法已内置 MD5 缺失时自动计算并尝试秒传的逻辑(CacheFullAndHash),流程本身是正确的。

How Has This Been Tested? / 测试

测试场景

  1. 本地 → 189pc(stream模式)秒传测试

    • 先通过天翼云客户端上传一个文件到云端
    • 在本地存储中准备一个完全相同的文件
    • 通过 OpenList 从本地复制该文件到 189pc 存储
    • 预期:触发秒传,几乎瞬间完成,无需实际上传数据
  2. 本地 → 189 秒传测试

    • 同上,目标改为 189 存储
    • 预期:触发秒传,几乎瞬间完成
  3. 本地 → 189pc 正常上传测试(非秒传)

    • 上传一个云端不存在的新文件
    • 预期:正常分片上传完成,功能不受影响
  4. 天翼云 → 天翼云 复制测试(已有MD5)

    • 从天翼云自身复制文件(源文件已有MD5)
    • 预期:通过 RapidUpload 秒传,行为与修改前一致
  5. 大文件秒传测试

    • 上传超过分片大小(>10MB)的文件,验证分片MD5(sliceMd5)计算正确
    • 预期:大文件也能正确触发秒传
  6. 零字节文件测试

    • 上传空文件
    • 预期:走原有 FastUpload 逻辑,不受影响

验证方法

  • 观察上传日志,确认 initMultiUpload 请求中包含 fileMd5sliceMd5 参数
  • 确认响应中 fileDataExists 字段为 1(秒传成功时)
  • 对比修改前后的上传耗时,秒传场景应显著缩短

预期效果

  1. 从本地存储复制文件到天翼云(189/189pc)时,如果云端已存在相同文件,能够正确触发秒传
  2. 秒传支持分片 MD5(sliceMd5)校验,满足天翼云服务端最新的秒传要求
  3. 非秒传场景(云端不存在相同文件)的上传行为不受影响
  4. 从天翼云自身复制(源文件已有MD5)的行为不受影响
  5. 189_tv 驱动无需修改,其现有逻辑已正确支持秒传

Checklist / 检查清单

  • I have read the CONTRIBUTING document.
    我已阅读 CONTRIBUTING 文档。
  • I have formatted my code with go fmt or prettier.
    我已使用 go fmtprettier 格式化提交的代码。
  • I have added appropriate labels to this PR (or mentioned needed labels in the description if lacking permissions).
    我已为此 PR 添加了适当的标签(如无权限或需要的标签不存在,请在描述中说明,管理员将后续处理)。
  • I have requested review from relevant code authors using the "Request review" feature when applicable.
    我已在适当情况下使用"Request review"功能请求相关代码作者进行审查。

@PIKACHUIM
Copy link
Copy Markdown
Member Author

6a33a2673e8c55bdc7c7f0b27067038b Test accepted

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Cloud189 (189) and Cloud189PC (189pc) drivers to improve “秒传/fastcopy” behavior when copying from sources that don’t provide MD5 (notably local storage), by ensuring the upload initialization request can include the required hashes.

Changes:

  • 189pc: In Put (stream mode), decide between RapidUpload (when MD5 already exists) vs FastUpload (when MD5 missing, to compute hashes and attempt 秒传).
  • 189: In newUpload, precompute fileMd5 and sliceMd5 and include them in /person/initMultiUpload, and short-circuit to commit if fileDataExists == 1.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
drivers/189pc/driver.go Adds stream-mode “秒传” branching to prefer RapidUpload when MD5 exists, otherwise FastUpload to compute hashes.
drivers/189/util.go Precomputes and passes fileMd5/sliceMd5 to initMultiUpload and commits immediately on server-side existence detection.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread drivers/189/util.go
Comment thread drivers/189/util.go Outdated
Comment thread drivers/189pc/driver.go Outdated
@PIKACHUIM PIKACHUIM requested a review from jyxjjj May 12, 2026 08:07
@jyxjjj
Copy link
Copy Markdown
Member

jyxjjj commented May 12, 2026

文字是不是改改,一会fast一会rapid

@PIKACHUIM PIKACHUIM merged commit 7feec2b into main May 12, 2026
12 checks passed
@xrgzs xrgzs deleted the fix-189fastcopy branch May 12, 2026 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants