mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-29 03:26:37 +08:00
fix(sync): deduplicate remoteMeta by file ID to prevent deleting valid remote metadata copies
This commit is contained in:
@@ -1341,6 +1341,7 @@ func (st *strmSyncState) localSha1Matches(path, remoteSha1 string) bool {
|
||||
}
|
||||
|
||||
// recordRemoteMeta 记录远端存在的元数据索引、文件大小、文件引用及内容 SHA1(多副本聚合追加)。
|
||||
// 对同一文件 ID 严格去重,避免当 download_meta 与 upload_meta 同时开启时因重复记录引发误判与自杀式删除。
|
||||
func (st *strmSyncState) recordRemoteMeta(entry cloud.FileEntry, rel string) {
|
||||
st.mu.Lock()
|
||||
defer st.mu.Unlock()
|
||||
@@ -1349,6 +1350,13 @@ func (st *strmSyncState) recordRemoteMeta(entry cloud.FileEntry, rel string) {
|
||||
}
|
||||
key := "m:" + rel
|
||||
st.seenMeta[key] = true
|
||||
if entry.ID != "" {
|
||||
for _, existing := range st.remoteMeta[key] {
|
||||
if existing.ID == entry.ID {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
st.remoteMeta[key] = append(st.remoteMeta[key], remoteMetaItem{
|
||||
ID: entry.ID,
|
||||
Size: entry.Size,
|
||||
@@ -1624,21 +1632,23 @@ func (st *strmSyncState) scanLocalMetaForUpload() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
if matchedIdx >= 0 {
|
||||
// 远端已存在完全一致的副本,跳过上传!
|
||||
// 若远端还存在其他同名脏副本(副本总数 > 1),在 115 下收集待删除 ID,稍后按目录批量删除
|
||||
if len(entries) > 1 && st.p.Provider == model.StrmProvider115 {
|
||||
parentCID := st.uploadRemoteTarget(rel)
|
||||
if parentCID != "" {
|
||||
for i, it := range entries {
|
||||
if i != matchedIdx && it.ID != "" {
|
||||
pendingDeletes[parentCID] = append(pendingDeletes[parentCID], it.ID)
|
||||
if matchedIdx >= 0 {
|
||||
// 远端已存在完全一致的副本,跳过上传!
|
||||
// 若远端还存在其他同名脏副本(副本总数 > 1),在 115 下收集待删除 ID,稍后按目录批量删除。
|
||||
// 严禁将已命中的最新副本 ID (matchedID) 放入待删列表,杜绝误杀唯一有效副本。
|
||||
if len(entries) > 1 && st.p.Provider == model.StrmProvider115 {
|
||||
parentCID := st.uploadRemoteTarget(rel)
|
||||
if parentCID != "" {
|
||||
matchedID := entries[matchedIdx].ID
|
||||
for i, it := range entries {
|
||||
if i != matchedIdx && it.ID != "" && it.ID != matchedID {
|
||||
pendingDeletes[parentCID] = append(pendingDeletes[parentCID], it.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
remoteTarget := st.uploadRemoteTarget(rel)
|
||||
|
||||
@@ -1320,6 +1320,30 @@ func TestScanLocalMetaForUploadMultipleCopiesAllStale(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestRecordRemoteMetaDeduplication 验证当 download_meta 与 upload_meta 同时开启时,
|
||||
// 同一远端元数据被多次入账不会在 remoteMeta 中生成重复副本,杜绝误判自杀式删除。
|
||||
func TestRecordRemoteMetaDeduplication(t *testing.T) {
|
||||
st := &strmSyncState{
|
||||
seenMeta: map[string]bool{},
|
||||
remoteMeta: map[string][]remoteMetaItem{},
|
||||
}
|
||||
entry := cloud.FileEntry{
|
||||
ID: "unique-fid-1",
|
||||
Name: "test.nfo",
|
||||
Size: 100,
|
||||
Sha1: "AAAABBBBCCCC",
|
||||
MTime: 12345,
|
||||
}
|
||||
// 连续记录两次同一文件
|
||||
st.recordRemoteMeta(entry, "dir/test.nfo")
|
||||
st.recordRemoteMeta(entry, "dir/test.nfo")
|
||||
|
||||
items := st.remoteMeta["m:dir/test.nfo"]
|
||||
if len(items) != 1 {
|
||||
t.Fatalf("expected 1 item after duplicate record, got %d", len(items))
|
||||
}
|
||||
}
|
||||
|
||||
// TestWalk115AdaptiveHierarchicalFlatScan 验证自适应分治扁平化扫描:
|
||||
// 当根目录探测总数 >= 9500 时,系统自动分治展开单层直接子项,对各子目录分别执行扁平拉取,
|
||||
// 正确合并根目录直属文件与各子目录深层文件,突破 115 开放平台 10000 深度限制。
|
||||
|
||||
Reference in New Issue
Block a user