Я сталкиваюсь со странной ошибкой, которая, похоже, возникает у многих людей в совершенно ином контексте.В случаях, которые я обнаружил, это в основном связано с вызовом mkdir
с путем, в котором существует файл.
Но в моем случае я просто вызываю open("meta.yml", "r")
в существующем текстовом файле.Трассировка стека четко указывает на строку, которая просто вызывает open
, в частности
File "some-path/experiment.py", line 348, in deserialize
with open("meta.yml", "r") as f:
FileExistsError: [Errno 17] File exists: 'meta.yml'
Сама функция тривиальна
def deserialize() -> "Experiment":
with open("meta.yml", "r") as f:
contents = f.read()
obj = yaml.load(contents, Loader=yaml.Loader)
# ...
, и ошибка происходит в строке с open
call.
Я совершенно уверен, что и файл существует, и что нет каталога с таким именем. Важно отметить, что это не дает сбоя 100% времени. По сути, я выполняю код в цикле (с перерывом в несколько секунд), и это занимает довольно много времени.чтобы исключение произошло.Нет никакого другого процесса, обращающегося к этому файлу, и до сих пор каждый раз, когда я позволяю ему работать некоторое время, скажем час, я получаю ошибку (иногда раньше).
Мне удалось запуститьошибка через strace, и вот несколько последних вызовов перед самой ошибкой
openat(AT_FDCWD, "/proc/37871/stat", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
ioctl(4, TCGETS, 0x7ffcabed25a0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(4, 0, SEEK_CUR) = 0
lseek(4, 0, SEEK_CUR) = 0
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(4, "37871 (polkitd) S 1 37871 37871 "..., 8192) = 175
read(4, "", 8017) = 0
close(4) = 0
select(0, NULL, NULL, NULL, {tv_sec=1, tv_usec=0}) = 0 (Timeout)
openat(AT_FDCWD, ".lockfile", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0777) = 4
flock(4, LOCK_EX|LOCK_NB) = 0
openat(AT_FDCWD, "meta.yml", O_RDONLY|O_CLOEXEC) = -1 EEXIST (File exists) # <- here it fails
flock(4, LOCK_UN) = 0
close(4) = 0
Как видите, openat
возвращает EEXIST
с дескриптором -1.Интересно то, что в одном и том же ряду есть 60 случаев, когда этот же точный системный вызов возвращается.Вот один пример
select(0, NULL, NULL, NULL, {tv_sec=1, tv_usec=0}) = 0 (Timeout)
openat(AT_FDCWD, ".lockfile", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0777) = 4
flock(4, LOCK_EX|LOCK_NB) = 0
openat(AT_FDCWD, "meta.yml", O_RDONLY|O_CLOEXEC) = 5 # <- here it's ok
fstat(5, {st_mode=S_IFREG|0664, st_size=5194, ...}) = 0
ioctl(5, TCGETS, 0x7ffcabed2ec0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(5, 0, SEEK_CUR) = 0
ioctl(5, TCGETS, 0x7ffcabed2ea0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(5, 0, SEEK_CUR) = 0
lseek(5, 0, SEEK_CUR) = 0
fstat(5, {st_mode=S_IFREG|0664, st_size=5194, ...}) = 0
read(5, "gp_config: !!python/object:bopt."..., 5195) = 5194
read(5, "", 1) = 0
close(5) = 0
Основываясь на странице руководства, я не могу понять, как это могло произойти.Стоит отметить, что это происходит в сетевой файловой системе, хотя доступ к файлу возможен только из одного процесса на одном компьютере.