write 成功以后,还欠哪些保证¶
write 返回 5,并不自动形成一条五字节的业务消息,也不证明对端处理完成。对配置文件而言,还要区分进程能看到新内容和断电后仍能看到新内容。这些差别会影响解帧、重试和保存顺序。
本节使用 labs/mechanisms.c 的 stream_lab()、partial_write_lab()、persistent_file(),以及 labs/extra.c:buffering()。先取得源码,按环境说明运行。
用九个字节拆开流的边界¶
实验发出两条带两字节长度头的消息:
发送端先写一个字节,再写剩下八个字节;接收端每次最多读两个字节,累计后核对完整内容。应用消息边界来自协议头,而不是两次 write 的边界。TCP 同样提供有序字节流,应用需要自行分帧。TCP 接口说明
如果换成 datagram,情况又不同。实验发送五字节 ABCDE,但只给接收端两字节容量:本次取出 AB,尾部不留给下一次 recv;切成非阻塞以后,下一次返回 EAGAIN。这不是“下一块消息尚未到达”,而是本次接收容量不足造成截断。
部分写需要记录进度¶
非阻塞 stream 发送大缓冲时,send 可以只推进一部分;发送缓冲满后返回 EAGAIN。恢复时必须从尚未发送的位置开始。下面是行为示意,错误分支需按接口进一步展开:
while (sent < total) {
ssize_t n = send(fd, bytes + sent, total - sent, MSG_NOSIGNAL);
if (n > 0)
sent += (size_t)n;
else if (n < 0 && errno == EAGAIN)
break; /* 保存 sent,等待可写后继续 */
else
handle_error();
}
不能从头重发已经成功的前缀,否则接收端会得到重复内容。也不能把这个流式循环直接用于拆分一条 TAP 以太网帧:报文接口的发送边界另有约定。网络与 TAP继续讨论帧边界。
配置替换的两个对象:文件与目录项¶
persistent_file() 在自己创建的临时目录中执行:
文件同步请求覆盖文件数据及相关元数据;文件名替换改变目录项,还需要对目录 fd 同步。rename 的可见原子性与介质上的持久性是不同保证。fsync 手册
实际实现还要处理每一步的错误,确保临时文件与目标在允许原子替换的文件系统范围内,并定义失败时保留旧配置还是恢复备份。实验只验证这组调用及可见结果,没有通过物理断电测试存储设备的承诺。
fflush 处理 stdio 的用户态缓冲。buffering() 对比正常 exit 与 _exit:未主动 flush 的 stdio 内容在后一条路径中没有写出。即使 flush 成功,仍需按用途考虑文件同步和介质保证。
运行与观察¶
容器内源码根目录:
make -C labs all
./build/labs/mechanisms stream
./build/labs/mechanisms partial-write
./build/labs/mechanisms save
./build/labs/mechanisms extra
strace -f -e trace=%file,fsync,write,close \
-o build/io-syscalls.log ./build/labs/mechanisms save
对应测试通过时输出以下记录:
L1-L6-stream-vs-datagram-boundary
L3-partial-write-EAGAIN-offset
L1-save-rename-file-directory-fsync
L1-stdio-exit-vs-unflushed-exit
每条记录都有 result: PASS。extra 同时包含 stdio、公平性、旧 ready 身份和权限补充实验。trace 中查找 platform-save- 路径,核对文件与目录分别被同步;%file 也捕获目标架构使用的 renameat 等路径调用。实际 partial-write 的分块大小由 socket 缓冲和环境决定,测试关心完整内容、没有重发前缀和确实经历 EAGAIN。全部回归另执行 make -C labs test。
接口上写清成功属于哪一层¶
| 返回 / 事件 | 本层可以承诺什么 | 后续仍需什么 |
|---|---|---|
| API 入队成功 | 本地队列接收了输入 | owner 处理及容量判断 |
| stream 写入成功 | 本次字节进入该发送接口 | 对端读取、解帧 |
| 业务响应 | 对端给出了协议规定结果 | 按产品语义确认执行或持久化 |
| 文件同步完成 | OS/文件系统按接口完成同步请求 | 实际设备的掉电验证 |
RTOS flash 文件系统的介质、磨损管理和缓存路径可能不同,不能凭 Linux 顺序直接扩大为另一平台的掉电保证。SDK 契约把这类分层成功用于接受、完成、取消和停止的定义。