2015-10-13 2 views
7

Предположим, что содержимое файла Foo.txt выглядит следующим образом.Как пропустить кеш файловой системы при чтении файла в Golang?

Foo Bar Bar Foo 

Рассмотрите следующую короткую программу.

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) 
} 

Когда мы запускаем программу выше, мы не получаем ошибок, что является правильным поведением.

Теперь я изменяю строку syscall.Open следующим образом.

fd, err := syscall.Open("Foo.txt", syscall.O_RDONLY | syscall.O_SYNC | syscall.O_DIRECT, 0) 

Когда я снова запускаю программу, я получаю следующий (нежелательный) вывод.

Failed on read: invalid argument 

Как правильно передать флаги syscall.O_SYNC и syscall.O_DIRECT, как определено в open man page для пропуска кэш файловой системы?

Обратите внимание, что я использую интерфейс syscall файла непосредственно вместо интерфейса os файла, потому что я не мог найти способ передать эти флаги в функцию, предоставляемой os, но я открыт для решений, использующих os при условии, что они работают правильно, чтобы отключить кеш файловой системы при чтении.

Обратите внимание, что я запускаю Ubuntu 14.04 с ext4 в качестве моей файловой системы.


Update: Я пытался использовать пакет @Nick Крэйга-Вуда в коде ниже.

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) 
    } 
} 

Выходной сигнал является следующая

Error on read: unexpected EOF 
+1

Вы пытались сделать открытым для чтения рядом с теми, точным аргументы в чем-то еще, чем идти (возможно, C)? Из того, что я могу видеть на странице руководства, O_SYNC влияет только на операции записи, а O_DIRECT нуждается в каком-то буфере с точным размером (?) В пользовательском пространстве, это может быть проблемой, связанной с конкретным ходом, но я сначала попытаюсь получить эту работу в C ... – mrd0ll4r

+0

@ mrd0ll4r, На самом деле я запустил [эту программу] (http://man7.org/tlpi/code/online/book/filebuff/direct_read.c.html) и получил ту же ошибку 'EINVAL' on сторона С. Нет, это не так. – merlin2011

ответ

1

На странице open человека под ПРИМЕЧАНИЯ:

Флаг O_DIRECT может наложить ограничения выравнивания по длине и адрес пользовательского пространства буферов и сдвиг файлов входов/выходов. Ограничения выравнивания Linux зависят от версии файловой системы и ядра и могут отсутствовать полностью.

У вас могут возникнуть проблемы с выравниванием, будь то память или смещение файла, или размер вашего буфера может быть «неправильным». То, что выравнивания и размеры должно быть не очевидно. Страница руководства продолжается:

Однако в настоящее время нет никакого независимого от файловой системы интерфейса для приложения, чтобы обнаружить эти ограничения для данного файла или файловой системы.

И даже Линус весит, в своей обычной сдержанной манере:

«Дело в том, что всегда беспокоила меня о O_DIRECT является то, что весь интерфейс просто глупо, и, вероятно, был разработан сумасшедший обезьяны на каких-то серьезных контролирующих дух веществах ». -Linus

Удачи вам!

p.s. Удар в темноте: почему бы не прочитать 512 байт?

+0

Очень интересная информация об осложнениях использования O_DIRECT. Знаете ли вы о каком-либо решении вопроса о пропуске кеша файловой системы в Go (даже если речь идет о совершенно другом маршруте)? Я также нуждаюсь в решении. – vastlysuperiorman

5

Вы можете наслаждаться моим directio package, который я сделал именно для этой цели.

С сайта

Это библиотека для языка Go, чтобы разрешить использование прямого ввода-вывода при всех поддерживаемых операционных систем Го (кроме OpenBSD и Plan9).

Прямая IO делает IO на диск и без него без буферизации данных в ОС. Это полезно, когда вы читаете или записываете много данных, которые вы не хотите заполнять в кэш ОС.

Смотрите здесь для пакета документации

http://go.pkgdoc.org/github.com/ncw/directio

+0

Я попытался использовать ваш пакет, но при попытке прочитать, я получаю «неожиданный EOF». – merlin2011

+0

@ merlin2011 в вашем примере '' Foo.txt '' больше, чем 'directio.BlockSize'? –

+0

Он меньше, чем 'directio.BlockSize'. – merlin2011

0

вы можете попробовать использовать fadvice и madvice, но нет никакой гарантии. оба будут работать более вероятно с большими файлами/данными, потому что:

Частичные страницы намеренно сохраняются в ожидании, что лучше сохранить необходимую память, чем отбрасывать ненужную память.

см. Исходный код Linux, что-то сделает, а что нет. Например, POSIX_FADV_NOREUSE ничего не делает.

http://lxr.free-electrons.com/source/mm/fadvise.c#L62

http://lxr.free-electrons.com/source/mm/madvise.c

package main 

import "fmt" 
import "os" 
import "syscall" 

import "golang.org/x/sys/unix" 

func main() { 
    advise := false 
    if len(os.Args) > 1 && os.Args[1] == "-x" { 
     fmt.Println("setting file advise") 
     advise =true 
    } 

    data := make([]byte, 100) 
    handler, err := os.Open("Foo.txt") 
    if err != nil { 
     fmt.Println("Failed on open: ", err) 
    }; defer handler.Close() 

    if advise { 
     unix.Fadvise(int(handler.Fd()), 0, 0, 4) // 4 == POSIX_FADV_DONTNEED 
    } 

    read, err := handler.Read(data) 
    if err != nil { 
     fmt.Println("Failed on read: ", err) 
     os.Exit(1) 
    } 

    if advise { 
     syscall.Madvise(data, 4) // 4 == MADV_DONTNEED 
    } 

    fmt.Printf("read %v bytes\n", read) 
} 

/USR/бен/время -v -x ./direct

Command being timed: "./direct -x" 
User time (seconds): 0.00 
System time (seconds): 0.00 
Percent of CPU this job got: 0% 
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03 
Average shared text size (kbytes): 0 
Average unshared data size (kbytes): 0 
Average stack size (kbytes): 0 
Average total size (kbytes): 0 
Maximum resident set size (kbytes): 1832 
Average resident set size (kbytes): 0 
Major (requiring I/O) page faults: 2 
Minor (reclaiming a frame) page faults: 149 
Voluntary context switches: 2 
Involuntary context switches: 2 
Swaps: 0 
File system inputs: 200 
File system outputs: 0 
Socket messages sent: 0 
Socket messages received: 0 
Signals delivered: 0 
Page size (bytes): 4096 
Exit status: 0 
Смежные вопросы