Perl Fcntl вызывает F_SETPIPE_SZ или F_GETPIPE_SZ выдает «Неверный файловый дескриптор»

Фон:

Я пытаюсь написать небольшой скрипт, который одновременно регистрирует JSONS, если размеры файлов небольшие, все в порядке. Но когда размеры файлов большие, процессы начинают перезаписывать друг друга. Этот пост SO полезен для указания правильного направления: PIPE_BUFF. Кажется, в Windows установлено значение 1024, в Linux больше Насколько велик PIPE_BUFF?.

PS: я на WSL2 Ubuntu 20.04

Проблема

Я попытался установить значение PIPE_BUFF с помощью Константа Fcntl F_SETPIPE_SZ, однако мне это не удалось:

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Data::Dumper qw(Dumper);
use File::Basename qw(basename dirname);
use File::Spec qw(catfile file_name_is_absolute catdir);
use feature qw(say current_sub);
use Cwd qw(abs_path);
use lib dirname(abs_path $0);
use Fcntl qw(F_SETPIPE_SZ F_GETPIPE_SZ F_GETFL F_GETFD F_SETFL O_NONBLOCK O_WRONLY O_APPEND O_CREAT O_RDWR F_DUPFD F_SETOWN F_GETOWN);

open(my $fileH,">", File::Spec -> catfile(dirname(__FILE__), "blabla.txt"));
#does F_GETFD work?
my $val = fcntl($fileH, F_GETFD, 0);
say $val; #outputs 1, works
#does F_GETFL work?
my $val2 = fcntl($fileH, F_GETFL, 0);
say $val2; #outputs 32769, works
#does F_GETOWN work?
my $val3 = fcntl($fileH, F_GETOWN, 0);
say $val3; #outputs 0 but true, so it works too.
my $pid = +$$;#process id
#does F_SETOWN work?
my $val4 = fcntl($fileH, F_SETOWN, $pid) or die("error: $!");;
say $val4; #outputs 0 but true
#does getting pipe buffer work?
my $val5 = fcntl($fileH, F_GETPIPE_SZ, 0) or die("error: $!"); #"Bad file descriptor"
say $val5; #Use of uninitialized..so $val5 is undef, did not work
#does setting pipe buffer work?
my $val6 = fcntl($fileH, F_SETPIPE_SZ, 1000 * 1000) or die("error: $!"); #"Bad file descriptor"
say $val6; #undef

Некоторые константы, такие как F_GETFD или F_GETFL, работают, поэтому я предполагаю, что Fcntl работает правильно.

Однако F_SETPIPE_SZ и некоторые другие, похоже, вообще не работают. Передача fcntlfileno($fileH) вместо $fileH приводит к ошибке «дескриптор неоткрытого файла», так что это тоже ничего не меняет.

Какова основная причина этого?

Это очень похоже на XY-задача. Ваша главная проблема в том, что разные процессы записывают в один и тот же файл...?

TLP 06.04.2022 11:59

Я знаю о стаях. Поскольку я могу подтвердить, что сохранение PIPE_BUFF в пределах разумного предела, такого как 1024, никогда не приводит к перезаписи (поскольку записи являются атомарными), я отказываюсь от «Y». Меня особенно интересует, почему я не могу заставить Fcntl работать и в чем причина журналов ошибок. «Неверный файловый дескриптор» — ужасно общее сообщение.

ibrahim tanyalcin 06.04.2022 12:19

Если вы используете $! в неправильном контексте, это может привести к странным ошибкам. Вы не можете полагаться на $!, чтобы сказать, когда вы сделали что-то не так.

TLP 06.04.2022 12:29

Попробуйте например perl -lwe'print $a++ . $!; open F, "a.txt" or die $!; print $a++ . $!;'. В моей системе отображается ошибка Inappropriate I/O control operation, хотя явно все в порядке.

TLP 06.04.2022 12:31

@TLP Обновлен пример, чтобы убедиться, что я ловлю $! в правильном контексте. Все равно "Неверный файловый дескриптор". Хотя я могу нормально печатать на этот дескриптор.

ibrahim tanyalcin 06.04.2022 12:40

Я не нашел никакой документации, описывающей F_GETPIPE_SZ. Кроме того, я получаю Your vendor has not defined Fcntl macro F_GETPIPE_SZ, если пытаюсь его использовать. Это похоже на мутную воду, в которой вы ловите рыбу.

TLP 06.04.2022 12:50

@TLP Они специфичны для Linux. OP связан с соответствующей справочной страницей.

Shawn 06.04.2022 12:55

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

ibrahim tanyalcin 06.04.2022 13:08
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
49
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Флаги Linux fcntl()F_GETPIPE_SZ и F_SETPIPE_SZ, как следует из их названий, относятся к трубы. Вы пытаетесь использовать их с обычным файлом, отсюда и сбои.

Для ясности:

#!/usr/bin/env perl                                                                                                                                                                                                                               
use strict;
use warnings;
use feature qw/say/;
use Fcntl qw/F_GETPIPE_SZ/;

open my $file, ">", "/tmp/foo.txt" or die "Unable to open /tmp/foo.txt: $!\n";
pipe my $reader, my $writer or die "Unable to create pipe: $!\n";

if (my $size = fcntl($file, F_GETPIPE_SZ, 0)) {
    say "filehandle size: $size";
} else {
    say "fcntl of file failed: $!";
}

if (my $size = fcntl($reader, F_GETPIPE_SZ, 0)) {
    say "pipe size: $size";
} else {
    say "fcntl of pipe filed: $!";
}

Возможный вывод:

fcntl of file failed: Bad file descriptor
pipe size: 65536

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

ibrahim tanyalcin 06.04.2022 13:12

Вам нужно использовать блокировку файлов или какой-либо другой метод синхронизации.

Shawn 06.04.2022 13:14

flock поддерживается не во всех системах, файл с записанным в него pid не работал согласованно при высокой нагрузке (более 500 процессов), возможно, потому, что -e является системным вызовом и не всегда точен. наличие небольшого размера журнала <10 КБ никогда не создает проблем. Что-то большее, чем это, процессы начинают перезаписывать друг друга, возможно, JSON:: XS также не является потокобезопасным. Так по крайней мере я пытался..

ibrahim tanyalcin 06.04.2022 14:01

Вы вряд ли найдете реально используемую ОС, которая не поддерживает flock ни напрямую, ни через эмуляцию (даже работает в Windows). Но с таким количеством процессов серверная система журналов может работать лучше, чтобы избежать конкуренции за блокировки. Запись в какую-либо очередь сообщений (Posix, SysV, ZeroMQ и т. д.) или в локальные сокеты дейтаграммы с помощью программы на принимающей стороне, которая ведет фактическую регистрацию.

Shawn 06.04.2022 14:27

Что касается "Я хотел бы иметь аналогичную систему для ОС, чтобы контролировать, сколько байтов записывается в обычный файл.", это не то, что делает F_SETPIPE_SZ. (Я имею в виду, даже не для каналов.) Он устанавливает ограничение на количество непрочитанных байтов, которые могут быть в канале. (Простые файлы, очевидно, не имеют концепции непрочитанных байтов, поэтому она не применяется к простым файлам.)

ikegami 06.04.2022 15:30

Другие вопросы по теме