gcache.page文件mysql清楚_使用go语言绕过page cache读写文件

有时候,我们希望我们的数据不通过page cache的缓冲直接落盘。go语言里,用参数DIRECT打开文件可以实现这一点要求。

但这样做有一个硬性的要求,就是在读写的时候,对应的数据在内存中的地址一定要满足512对齐,即首地址的2进制形式中后面至少要有9个0结尾,且数据长度为512字节的整数倍,否则读写会失败。

我们用go语言中的切片slice来验证这件事。

首先我们建立一个go语言的切片并随便赋一些值:

buf := make([]byte, 8192)

for i := 0; i < 20; i++ {

buf[i] = byte(i)

}

我们首先尝试一下正常的读写文件过程,先不使用DIRECT参数绕开page cache。

func writeWithoutAlignmentWithoutDIRECT(buf []byte) {

// open file

file, err := os.OpenFile("/dev/sdb",

os.O_WRONLY|os.O_CREATE, 0666)

if err != nil {

fmt.Printf("An error occurred with file opening or creation\n")

return

}

defer file.Close()

// write file

fmt.Println("buffer ", unsafe.Pointer(&buf))

fmt.Println("buffer[0] ", unsafe.Pointer(&buf[0]))

buf2 := buf[4:516]

fmt.Println("write with buffer ", unsafe.Pointer(&buf2[0]))

_, err = file.WriteAt(buf2, 512)

if err != nil {

fmt.Println("write error ", err)

} else {

fmt.Println("write succeed")

}

}

这段代码的运行结果如下:

buffer 0xc42000a2a0

buffer[0] 0xc42005a000

write with buffer 0xc42005a004

write succeed

可以看出,这个切片的地址是0xc42000a2a0,这个切片内数据的首地址是0xc42005a000,这是一个与c语言不同的地方,c语言的数据首地址即为其中数据的首地址,而go语言中,切片的地址和切片内数据首地址是不同的。

我们要写入的数据的首地址是从切片的第5个元素开始,其首地址为0xc42005a004,虽然并没有512对齐,但是由于我们没有尝试绕过page cache,所以根据WriteAt函数的返回值err可以看到,我们的写入操作是成功的。

下面我们尝试一下使用DIRECT参数打开文件,绕过page cache进行写数据操作,其他参数不变。

func writeWithoutAlignmentWithDIRECT(buf []byte) {

// open file

file, err := os.OpenFile("/dev/sdc",

os.O_WRONLY|os.O_CREATE|syscall.O_DIRECT, 0666)

if err != nil {

fmt.Printf("An error occurred with file opening or creation\n")

return

}

defer file.Close()

// write file

fmt.Println("buffer ", unsafe.Pointer(&buf))

fmt.Println("buffer[0] ", unsafe.Pointer(&buf[0]))

buf2 := buf[4:516]

fmt.Println("write with buffer ", unsafe.Pointer(&buf2[0]))

_, err = file.WriteAt(buf2, 512)

if err != nil {

fmt.Println("write error ", err)

} else {

fmt.Println("write succeed")

}

}

这段代码运行后,我们可以看到如下结果。

buffer 0xc42000a2e0

buffer[0] 0xc42005a000

write with buffer 0xc42005a004

write error write /dev/sdc: invalid argument

看到了write error,WriteAt函数这次的返回值给出的并不是nil了,我们的写入操作失败了,其返回值返回了一个不可理解的invalid argument(非法参数)。

but我们的参数毫无问题啊!下面我们尝试一下把要写入的数据改为512对齐。

func writeWithAlignmentWithDIRECT(buf []byte) {

// open file

file, err := os.OpenFile("/dev/sdd",

os.O_WRONLY|os.O_CREATE|syscall.O_DIRECT, 0666)

if err != nil {

fmt.Printf("An error occurred with file opening or creation\n")

return

}

defer file.Close()

// write file

fmt.Println("buffer ", unsafe.Pointer(&buf))

fmt.Println("buffer[0] ", unsafe.Pointer(&buf[0]))

buf2 := buf[512 : 512+512]

fmt.Println("write with buffer ", unsafe.Pointer(&buf2[0]))

_, err = file.WriteAt(buf2, 512)

if err != nil {

fmt.Println("write error ", err)

} else {

fmt.Println("write succeed")

}

}

这段代码运行后,结果如下。

white with alignment and DIRECT:

buffer 0xc42000a340

buffer[0] 0xc42005a000

write with buffer 0xc42005a200

write succeed

我们的写操作成功了!而这段代码与上次未成功的不同之处只有一个,那就是将要写入数据的首地址改成了512对齐。

通过这三段go程序,我们很清晰的验证了绕过page cache写文件的条件。

类似的,下面给出验证绕过page cache读文件也需要512对齐条件的代码。

func readWithoutAlignmentWithoutDIRECT(buf []byte) {

// read file

file, err := os.OpenFile("/dev/sdb", os.O_RDONLY, 0666)

if err != nil {

fmt.Printf("An error occurred whit file ipening.\n")

return

}

defer file.Close()

buf = buf[2:514]

fmt.Println("read with buffer ", unsafe.Pointer(&buf[0]))

_, err = file.ReadAt(buf, 512)

if err != nil {

fmt.Println("read error ", err)

} else {

fmt.Println("read succeed", buf)

}

}

func readWithoutAlignmentWithDIRECT(buf []byte) {

// read file

file, err := os.OpenFile("/dev/sdc", os.O_RDONLY|syscall.O_DIRECT, 0666)

if err != nil {

fmt.Printf("An error occurred whit file ipening.\n")

return

}

defer file.Close()

buf = buf[2:514]

fmt.Println("read with buffer ", unsafe.Pointer(&buf[0]))

_, err = file.ReadAt(buf, 512)

if err != nil {

fmt.Println("read error ", err)

} else {

fmt.Println("read succeed", buf)

}

}

func readWithAlignmentWithDIRECT(buf []byte) {

// read file

file, err := os.OpenFile("/dev/sdd", os.O_RDONLY|syscall.O_DIRECT, 0666)

if err != nil {

fmt.Printf("An error occurred whit file ipening.\n")

return

}

defer file.Close()

buf = buf[512 : 512+512]

fmt.Println("read with buffer ", unsafe.Pointer(&buf[0]))

_, err = file.ReadAt(buf, 512)

if err != nil {

fmt.Println("read error ", err)

} else {

fmt.Println("read succeed", buf)

}

}

这三个函数的运行结果分如下。

read with buffer 0xc42005a002

read succeed [4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

read with buffer 0xc42005a002

read error read /dev/sdc: invalid argument

read with buffer 0xc42005a200

read succeed [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

可以看出,由于最初我们将切片的前20位分别赋值为0-20,其他位赋值默认值为0,第一个写入函数将buf[4:516]写入到/dev/sdb中,第二个写入函数写入失败,第三个写入函数将buf[512 : 512+512]写入到/dev/sdd,所以根据读取结果可以看出,我们的读取函数也是ok的。

最后,给出整段测试程序的完整代码。

package main

import (

"fmt"

"os"

"syscall"

"unsafe"

)

func main() {

buf := make([]byte, 8192)

for i := 0; i < 20; i++ {

buf[i] = byte(i)

}

fmt.Println("----------------------------------------")

fmt.Println("white without alignment and DIRECT:")

writeWithoutAlignmentWithoutDIRECT(buf)

fmt.Println("----------------------------------------")

fmt.Println("white without alignment but with DIRECT:")

writeWithoutAlignmentWithDIRECT(buf)

fmt.Println("----------------------------------------")

fmt.Println("white with alignment and DIRECT:")

writeWithAlignmentWithDIRECT(buf)

fmt.Println("----------------------------------------")

fmt.Println("read without alignment and DIRECT:")

readWithoutAlignmentWithoutDIRECT(buf)

fmt.Println("----------------------------------------")

fmt.Println("read without alignment but with DIRECT:")

readWithoutAlignmentWithDIRECT(buf)

fmt.Println("----------------------------------------")

fmt.Println("read with alignment and DIRECT:")

readWithAlignmentWithDIRECT(buf)

}

func writeWithoutAlignmentWithoutDIRECT(buf []byte) {

// open file

file, err := os.OpenFile("/dev/sdb",

os.O_WRONLY|os.O_CREATE, 0666)

if err != nil {

fmt.Printf("An error occurred with file opening or creation\n")

return

}

defer file.Close()

// write file

fmt.Println("buffer ", unsafe.Pointer(&buf))

fmt.Println("buffer[0] ", unsafe.Pointer(&buf[0]))

buf2 := buf[4:516]

fmt.Println("write with buffer ", unsafe.Pointer(&buf2[0]))

_, err = file.WriteAt(buf2, 512)

if err != nil {

fmt.Println("write error ", err)

} else {

fmt.Println("write succeed")

}

}

func writeWithoutAlignmentWithDIRECT(buf []byte) {

// open file

file, err := os.OpenFile("/dev/sdc",

os.O_WRONLY|os.O_CREATE|syscall.O_DIRECT, 0666)

if err != nil {

fmt.Printf("An error occurred with file opening or creation\n")

return

}

defer file.Close()

// write file

fmt.Println("buffer ", unsafe.Pointer(&buf))

fmt.Println("buffer[0] ", unsafe.Pointer(&buf[0]))

buf2 := buf[4:516]

fmt.Println("write with buffer ", unsafe.Pointer(&buf2[0]))

_, err = file.WriteAt(buf2, 512)

if err != nil {

fmt.Println("write error ", err)

} else {

fmt.Println("write succeed")

}

}

func writeWithAlignmentWithDIRECT(buf []byte) {

// open file

file, err := os.OpenFile("/dev/sdd",

os.O_WRONLY|os.O_CREATE|syscall.O_DIRECT, 0666)

if err != nil {

fmt.Printf("An error occurred with file opening or creation\n")

return

}

defer file.Close()

// write file

fmt.Println("buffer ", unsafe.Pointer(&buf))

fmt.Println("buffer[0] ", unsafe.Pointer(&buf[0]))

buf2 := buf[512 : 512+512]

fmt.Println("write with buffer ", unsafe.Pointer(&buf2[0]))

_, err = file.WriteAt(buf2, 512)

if err != nil {

fmt.Println("write error ", err)

} else {

fmt.Println("write succeed")

}

}

func readWithoutAlignmentWithoutDIRECT(buf []byte) {

// read file

file, err := os.OpenFile("/dev/sdb", os.O_RDONLY, 0666)

if err != nil {

fmt.Printf("An error occurred whit file ipening.\n")

return

}

defer file.Close()

buf = buf[2:514]

fmt.Println("read with buffer ", unsafe.Pointer(&buf[0]))

_, err = file.ReadAt(buf, 512)

if err != nil {

fmt.Println("read error ", err)

} else {

fmt.Println("read succeed", buf)

}

}

func readWithoutAlignmentWithDIRECT(buf []byte) {

// read file

file, err := os.OpenFile("/dev/sdc", os.O_RDONLY|syscall.O_DIRECT, 0666)

if err != nil {

fmt.Printf("An error occurred whit file ipening.\n")

return

}

defer file.Close()

buf = buf[2:514]

fmt.Println("read with buffer ", unsafe.Pointer(&buf[0]))

_, err = file.ReadAt(buf, 512)

if err != nil {

fmt.Println("read error ", err)

} else {

fmt.Println("read succeed", buf)

}

}

func readWithAlignmentWithDIRECT(buf []byte) {

// read file

file, err := os.OpenFile("/dev/sdd", os.O_RDONLY|syscall.O_DIRECT, 0666)

if err != nil {

fmt.Printf("An error occurred whit file ipening.\n")

return

}

defer file.Close()

buf = buf[512 : 512+512]

fmt.Println("read with buffer ", unsafe.Pointer(&buf[0]))

_, err = file.ReadAt(buf, 512)

if err != nil {

fmt.Println("read error ", err)

} else {

fmt.Println("read succeed", buf)

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值