php方案 Direct I/O(O_DIRECT)应用场景如何在 PHP 中通过 FFI 实现并处理扇区对齐限制?
O_DIRECT是啥 普通读文件磁盘 → 内核 page cache → 你的程序O_DIRECT磁盘 → 你的程序直接绕过内核缓存 用场景-数据库MySQL InnoDB、PostgreSQL 都用自己管缓存不要内核多此一举-备份工具备份大文件不想把 page cache 全冲掉-磁盘基准测试测真实硬件速度不测缓存速度---扇区对齐限制坑在这O_DIRECT不是随便用的三个必须同时满足 ┌────────────────┬──────────────────────┐ │ 条件 │ 要求 │ ├────────────────┼──────────────────────┤ │ 缓冲区内存地址 │ 必须是块大小的整数倍 │ ├────────────────┼──────────────────────┤ │ 文件偏移量 │ 必须是块大小的整数倍 │ ├────────────────┼──────────────────────┤ │ 读写字节数 │ 必须是块大小的整数倍 │ └────────────────┴──────────────────────┘ 块大小一般512机械硬盘或4096SSD/现代盘用4096最保险。 普通 malloc 不保证对齐要用 posix_memalign。---PHPFFI实现 先准备测试文件必须是4096倍数大小 ddif/dev/urandom of/tmp/test.dat bs4096count4?php// 只有 Linux x86_64O_DIRECT 0x4000$ffiFFI::cdef( int open(const char *path, int flags); int close(int fd); ssize_t read(int fd, void *buf, size_t count); int posix_memalign(void **memptr, size_t alignment, size_t size); void free(void *ptr); ,libc.so.6);constO_RDONLY0;constO_DIRECT0x4000;constBLOCK4096;// 打开文件带 O_DIRECT$fd$ffi-open(/tmp/test.dat,O_RDONLY|O_DIRECT);if($fd0)die(open 失败errno: .posix_get_last_error().\n);// 申请 4096 字节对齐的内存不能用普通 new char[]$ptr$ffi-new(void*);if($ffi-posix_memalign(FFI::addr($ptr),BLOCK,BLOCK)!0)die(内存对齐失败\n);$bufFFI::cast(char*,$ptr);// 读一个块必须是 BLOCK 的整数倍$n$ffi-read($fd,$buf,BLOCK);echo读了$n字节\n;echobin2hex(FFI::string($buf,16)).\n;// 打印前16字节十六进制$ffi-close($fd);$ffi-free($ptr);---为什么不能用普通FFI::new(char[4096])$buf$ffi-new(char[4096]);// 地址可能是 0x7f3a1b2c3d05 ← 不对齐// O_DIRECT 的 read() 会返回 -1errno EINVALposix_memalign 保证返回的地址是4096的整数倍0x7f3a1b2c4000← 末三位永远是000---写文件版本顺带constO_WRONLY1;constO_CREAT0x40;constO_TRUNC0x200;$fd$ffi-open(/tmp/out.dat,O_WRONLY|O_CREAT|O_TRUNC|O_DIRECT,0644);// ... 同样申请对齐内存填数据write()注意写的时候如果内容不足4096字节必须补零到4096不然EINVAL。这是O_DIRECT最大的麻烦。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2438206.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!