[H-04][medium] 批量导入串行算哈希、校验与插入之间有竞态;CSV 报错行号不准 #47

Closed
opened 2026-09-30 13:57:02 +08:00 by nixevol · 1 comment
Owner

编号:H-04 严重级:medium 工作线:管理后端(internal/admin) + 后台网页(web/) 来源:审查 A-07、A-19
依赖:无 被依赖:无

结论与统一方案

后端(本 issue):

  1. 有界并发算哈希,上限取 max(1, NumCPU-1),给 MQTT 密码登录留槽位;结果按行下标收集,保持顺序。
  2. 批量插入遇到 UNIQUE 冲突时重新校验,返回 409 并附行号;哈希失败返回 500/503,不当作行错误返回 400。
  3. 行号:改为逐条 Read(),用 reader.FieldPos(0) 取物理行号;*csv.ParseError 用其中的行号。(审查 A-19)

界面部分(导入中禁用按钮、显示"正在校验并计算密码,约需 N 秒"、错误用可内部滚动的表格弹窗)由网页线在 W-05 完成。

改动文件

internal/admin/endpoints_csv.go。

与其他问题的交互 / 冲突说明

与 H-01(导入上限 413)、H-05(默认延迟校验)同文件,管理后端线内顺序合入;哈希池与端登录共用,并发上限要留余量。

验收与测试

  • 注入记录最大并发的 HashPool,断言并发大于 1;用假哈希导入 1000 行。
  • 并发占用编号时返回 409 且带行号。
  • 错误行前有空行、未闭合引号时,行号正确。

问题明细(各区审查原文,证据含文件与行号)

以下是本次复审各区审查报告的原文段落。A、M、I、P、S 开头的是原始发现编号(A 管理后台与网页、M 消息核心、I 身份认证群在线、P 传输平台部署、S SDK)。解决方案以本 issue 上方的"结论与统一方案"为准;原文里的方案与之不一致时,按上方执行。

[A-07] 批量导入串行算哈希、没有进度、可以重复提交,错误用 toast 显示

  • 严重级:medium
  • 分类:质量 / 与PRD不符 / 界面
  • 现象与影响:
    • 每行 1–2 次 argon2(19 MiB),在单个 goroutine 里串行提交,哈希池的并发用不上。1000 行大约需要 30–120 秒(估算),走 60 秒超时的反向代理时会失败。
    • 前端没有加载状态,用户容易再点一次。对编号留空的行,重复导入会再开出 1000 个端。
    • 最多 1000 条校验错误被拼进一个会自动消失的 toast,看不全也复制不了。
    • 校验通过到插入之间的时间窗(就是算哈希的这几十秒)里,若编号被自助注册占用,事务会以 UNIQUE 失败返回 500,没有行号。
  • 证据:
    • endpoints_csv.go:243-300 在 for 循环里逐个 h.hash.Hash(...)。
    • internal/auth/pool.go:17-37 是信号量池。
    • endpoints_csv.go:227-241 与 62-66 之间存在上述时间窗。
    • EndpointsView.vue:310-336,354-356 没有 loading;329-331 用 toast 拼接错误。
  • 文档依据:DEVELOPMENT §8(约 923 行)"密码哈希在第 12 节的并发池里算,1000 行可能要十几秒:前端显示进度";PRD F01 验收"一次批量开通 1000 个端成功"。
  • 为何不是故意设计:DEVIATIONS 没有相关条目。
  • 解决方案:
    1. 后端用有界并发算哈希,并发上限取 max(1, NumCPU-1),不要把池占满,给 MQTT 密码登录留槽位。结果按行下标收集,保持顺序。
    2. 批量插入遇到 UNIQUE 冲突时重新校验,返回 409 并附行号。哈希失败返回 500/503,不要当成行错误返回 400。
    3. 前端加 importing 状态:禁用导入按钮,显示"正在校验并计算密码,约需 N 秒"。
    4. 校验错误用弹窗加可内部滚动的表格展示(行号、原因)。
  • 改动文件:internal/admin/endpoints_csv.go、EndpointsView.vue。
  • 交互/冲突风险:哈希池与端登录共用,并发上限要留余量。
  • 需补测试:
    • 注入会记录最大并发的 HashPool,断言并发大于 1。
    • 用假哈希导入 1000 行。
    • 并发占用编号时返回 409。
    • 组件测试:导入期间按钮禁用,错误弹窗能正确显示。
  • 置信度:代码阅读确定(耗时是估算)

[A-19] CSV 校验报错的行号不准

  • 严重级:low
  • 分类:逻辑
  • 现象与影响:encoding/csv 会跳过空行,带引号的字段可以跨行,但代码用 i+2 算行号,报出的行号会偏移。解析错误一律报"第 1 行"。
  • 证据:endpoints_csv.go:126-129,171-172。
  • 文档依据:PRD F01 验收"指出是哪一行"。
  • 为何不是故意设计:DEVIATIONS 没有相关条目。
  • 解决方案:改为逐条 Read(),用 reader.FieldPos(0) 取物理行号;遇到 *csv.ParseError 时用其中的 StartLine 或 Line。
  • 改动文件:internal/admin/endpoints_csv.go。
  • 交互/冲突风险:无。
  • 需补测试:错误行前有空行时报出正确行号;未闭合引号时行号正确。
  • 置信度:代码阅读确定

复审基线:main 4059a15(2026-09-30)。编号说明、各工作线的合并顺序、共享文件归属见总览 #7。

**编号**:H-04 **严重级**:medium **工作线**:管理后端(internal/admin) + 后台网页(web/) **来源**:审查 A-07、A-19 **依赖**:无 **被依赖**:无 ### 结论与统一方案 后端(本 issue): 1. 有界并发算哈希,上限取 `max(1, NumCPU-1)`,给 MQTT 密码登录留槽位;结果按行下标收集,保持顺序。 2. 批量插入遇到 UNIQUE 冲突时重新校验,返回 409 并附行号;哈希失败返回 500/503,不当作行错误返回 400。 3. 行号:改为逐条 `Read()`,用 `reader.FieldPos(0)` 取物理行号;`*csv.ParseError` 用其中的行号。(审查 A-19) 界面部分(导入中禁用按钮、显示"正在校验并计算密码,约需 N 秒"、错误用可内部滚动的表格弹窗)由网页线在 W-05 完成。 ### 改动文件 `internal/admin/endpoints_csv.go`。 ### 与其他问题的交互 / 冲突说明 与 H-01(导入上限 413)、H-05(默认延迟校验)同文件,管理后端线内顺序合入;哈希池与端登录共用,并发上限要留余量。 ### 验收与测试 - 注入记录最大并发的 HashPool,断言并发大于 1;用假哈希导入 1000 行。 - 并发占用编号时返回 409 且带行号。 - 错误行前有空行、未闭合引号时,行号正确。 --- ### 问题明细(各区审查原文,证据含文件与行号) > 以下是本次复审各区审查报告的原文段落。A、M、I、P、S 开头的是原始发现编号(A 管理后台与网页、M 消息核心、I 身份认证群在线、P 传输平台部署、S SDK)。**解决方案以本 issue 上方的"结论与统一方案"为准**;原文里的方案与之不一致时,按上方执行。 #### [A-07] 批量导入串行算哈希、没有进度、可以重复提交,错误用 toast 显示 - 严重级:medium - 分类:质量 / 与PRD不符 / 界面 - 现象与影响: - 每行 1–2 次 argon2(19 MiB),在单个 goroutine 里串行提交,哈希池的并发用不上。1000 行大约需要 30–120 秒(估算),走 60 秒超时的反向代理时会失败。 - 前端没有加载状态,用户容易再点一次。对编号留空的行,重复导入会再开出 1000 个端。 - 最多 1000 条校验错误被拼进一个会自动消失的 toast,看不全也复制不了。 - 校验通过到插入之间的时间窗(就是算哈希的这几十秒)里,若编号被自助注册占用,事务会以 UNIQUE 失败返回 500,没有行号。 - 证据: - `endpoints_csv.go:243-300` 在 `for` 循环里逐个 `h.hash.Hash(...)`。 - `internal/auth/pool.go:17-37` 是信号量池。 - `endpoints_csv.go:227-241` 与 `62-66` 之间存在上述时间窗。 - `EndpointsView.vue:310-336,354-356` 没有 loading;`329-331` 用 toast 拼接错误。 - 文档依据:DEVELOPMENT §8(约 923 行)"密码哈希在第 12 节的并发池里算,1000 行可能要十几秒:前端显示进度";PRD F01 验收"一次批量开通 1000 个端成功"。 - 为何不是故意设计:DEVIATIONS 没有相关条目。 - 解决方案: 1. 后端用有界并发算哈希,并发上限取 `max(1, NumCPU-1)`,不要把池占满,给 MQTT 密码登录留槽位。结果按行下标收集,保持顺序。 2. 批量插入遇到 UNIQUE 冲突时重新校验,返回 409 并附行号。哈希失败返回 500/503,不要当成行错误返回 400。 3. 前端加 `importing` 状态:禁用导入按钮,显示"正在校验并计算密码,约需 N 秒"。 4. 校验错误用弹窗加可内部滚动的表格展示(行号、原因)。 - 改动文件:`internal/admin/endpoints_csv.go`、`EndpointsView.vue`。 - 交互/冲突风险:哈希池与端登录共用,并发上限要留余量。 - 需补测试: - 注入会记录最大并发的 HashPool,断言并发大于 1。 - 用假哈希导入 1000 行。 - 并发占用编号时返回 409。 - 组件测试:导入期间按钮禁用,错误弹窗能正确显示。 - 置信度:代码阅读确定(耗时是估算) #### [A-19] CSV 校验报错的行号不准 - 严重级:low - 分类:逻辑 - 现象与影响:`encoding/csv` 会跳过空行,带引号的字段可以跨行,但代码用 `i+2` 算行号,报出的行号会偏移。解析错误一律报"第 1 行"。 - 证据:`endpoints_csv.go:126-129,171-172`。 - 文档依据:PRD F01 验收"指出是哪一行"。 - 为何不是故意设计:DEVIATIONS 没有相关条目。 - 解决方案:改为逐条 `Read()`,用 `reader.FieldPos(0)` 取物理行号;遇到 `*csv.ParseError` 时用其中的 `StartLine` 或 `Line`。 - 改动文件:`internal/admin/endpoints_csv.go`。 - 交互/冲突风险:无。 - 需补测试:错误行前有空行时报出正确行号;未闭合引号时行号正确。 - 置信度:代码阅读确定 --- <sub>复审基线:main `4059a15`(2026-09-30)。编号说明、各工作线的合并顺序、共享文件归属见总览 #7。</sub>
nixevol added the P2-mediumlane/adminlane/webreview-2026-09-30 labels 2026-09-30 13:57:02 +08:00
Author
Owner

已合入 origin/main 0c9b459。落地提交 43f8474 fix: 批量导入并发哈希并校正 CSV 行号 (#47)。

已合入 origin/main `0c9b459`。落地提交 `43f8474` fix: 批量导入并发哈希并校正 CSV 行号 (#47)。
Sign in to join this conversation.