#hadoop #go #named-pipes #fuse
#hadoop #Вперед #именованные каналы #предохранитель
Вопрос:
У меня есть закрытое приложение soruce, которое принимает файл в качестве входных данных, вычисляет его хэш и выполняет некоторые другие действия, которые я не могу контролировать. Изменение исходного кода или обратный инжиниринг невозможны.
Программа предназначена для работы с обычными файлами, однако мне нужно предоставить очень большой файл из HDFS. Копирование файла займет слишком много времени и места на диске. Итак, я думал об использовании FUSE, но я не нашел хорошего решения. Я попытался использовать именованный канал следующим образом:
func readFile(namenode, path string, pipe *os.File) {
client, err := hdfs.New(namenode)
log.Println(err, client)
hdfsFile, err := client.Open(path)
if err != nil {
log.Fatal(err)
}
log.Println(hdfsFile)
// written, err := io.Copy(pipe, hdfsFile)
bytes := make([]byte, 4096)
for {
read, err := hdfsFile.Read(bytes)
log.Println(read, err)
if err != nil {
break
}
written, err := pipe.Write(bytes)
log.Println(written, err)
}
err = pipe.Close()
log.Println(err)
}
Я знаю, что приведенный выше код неполон, тестовый файл составляет 10 МБ, однако после чтения 8 раз 4096 байт именованный буфер канала заполняется, а другая программа берет все это и закрывает канал.
Но через некоторое время другая программа, которая считывает канал, закрывает канал, и я получаю ошибку неработающего канала. Есть ли какая-либо возможность создания виртуального файла, отличного от fuse и pipe?
Ответ №1:
Я думаю, что у вас действительно была правильная идея с FUSE. Без исходных текстов для вашего вышестоящего приложения трудно сказать, какую файловую семантику оно пытается использовать (хотя некоторое время со strace может помочь прояснить, что происходит. Может быть …).
В любом случае, я бы взглянул на проект Go-FUSE, в частности на пример hello.go, который точно показывает, как очень хорошо обрабатывать случай с одним файлом.
Ответ №2:
Я понимаю, проблема в том, что программа с закрытым исходным кодом2 ожидает имя файла и не принимает ввод непосредственно из stdin?
Вы можете использовать стандартный конвейер в стиле Unix при запуске программ для соединения stdin и stdout процессов вместе. Именованные каналы могут быть проблематичными, и использование FUSE для этого слишком сложно.
Вы могли бы настроить вывод вашей программы1 в стандартный вывод. и укажите программе с закрытым исходным кодом2 имя виртуального файла /dev/stdin
следующим образом:
program1 | program2 /dev/stdin
Предполагается, что вы работаете в Linux (вы не указали, но я предполагаю, что это так, потому что вы говорите о FUSE).
Если program2 заботится об имени файла (например, ожидает определенного расширения имени), вы могли бы обойти это, создав символическую ссылку с желаемым именем, указывающим на /dev/stdin
, и указав имя символической ссылки в качестве аргумента для program2:
ln -s /dev/stdin file.ext
program1 | program2 file.ext
rm -f file.ext
Ничего из этого не сработает, если program2 ожидает реального файла, который он может stat, но в данном случае это не должно быть проблемой (как известно из вопроса, что program2 принимает именованный канал).
Также, если program2 ожидает ввода с клавиатуры из stdin, этот подход не будет работать.