Assume that the contents of the file Foo.txt
are as follows.
Foo Bar Bar Foo
Consider the following short program.
package main
import "syscall"
import "fmt"
func main() {
fd, err := syscall.Open("Foo.txt", syscall.O_RDONLY, 0)
if err != nil {
fmt.Println("Failed on open: ", err)
}
data := make([]byte, 100)
_, err = syscall.Read(fd, data)
if err != nil {
fmt.Println("Failed on read: ", err)
}
syscall.Close(fd)
}
When we run the program above, we get no errors, which is correct behavior.
Now, I modify the syscall.Open
line to be the following.
fd, err := syscall.Open("Foo.txt", syscall.O_RDONLY | syscall.O_SYNC | syscall.O_DIRECT, 0)
When I run the program again, I get the following (undesirable) output.
Failed on read: invalid argument
How can I correctly pass the flags syscall.O_SYNC
and syscall.O_DIRECT
as specified by the the open
man page for skipping the filesystem cache?
Note that I am using the syscall
file interface directly instead of the os
file interface because I could not find a way to pass those flags into the functions provided by os
, but I am open to solutions that use os
provided that they work correctly to disable the filesystem cache on reads.
Note also that I am running on Ubuntu 14.04
with ext4
as my filesystem.
Update: I tried to use @Nick Craig-Wood's package in the code below.
package main
import "io"
import "github.com/ncw/directio"
import "os"
import "fmt"
func main() {
in, err := directio.OpenFile("Foo.txt", os.O_RDONLY, 0666)
if err != nil {
fmt.Println("Error on open: ", err)
}
block := directio.AlignedBlock(directio.BlockSize)
_, err = io.ReadFull(in, block)
if err != nil {
fmt.Println("Error on read: ", err)
}
}
The output is the following
Error on read: unexpected EOF
You may enjoy my directio package which I made for exactly this purpose.
From the site
This is library for the Go language to enable use of Direct IO under all supported OSes of Go (except openbsd and plan9).
Direct IO does IO to and from disk without buffering data in the OS. It is useful when you are reading or writing lots of data you don't want to fill the OS cache up with.
See here for package docs
http://go.pkgdoc.org/github.com/ncw/directio
From the open
man page, under NOTES:
The O_DIRECT flag may impose alignment restrictions on the length and address of user-space buffers and the file offset of I/Os. In Linux alignment restrictions vary by file system and kernel version and might be absent entirely.
So you could have alignment issues, of either the memory or the file offset, or your buffer size could be "wrong". What the alignments and sizes should be is not obvious. The man page continues:
However there is currently no file system-independent interface for an application to discover these restrictions for a given file or file system.
And even Linus weighs in, in his usual understated manner:
"The thing that has always disturbed me about O_DIRECT is that the whole interface is just stupid, and was probably designed by a deranged monkey on some serious mind-controlling substances." —Linus
Good luck!
p.s. Stab in the dark: why not read 512 bytes?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With