У меня есть модуль кэширования urllib2, который спорадически выходит из строя из-за следующего кода:
if not os.path.exists(self.cache_location):
os.mkdir(self.cache_location)
Проблема заключается в том, что к моменту выполнения второй строки папка может существовать и будет иметь ошибку:
File ".../cache.py", line 103, in __init__
os.mkdir(self.cache_location)
OSError: [Errno 17] File exists: '/tmp/examplecachedir/'
Это связано с тем, что script одновременно запускается много раз, сторонним кодом у меня нет контроля.
Код (до того, как я попытался исправить ошибку) можно найти здесь, на github
Я не могу использовать tempfile.mkstemp, поскольку он решает условие гонки, используя случайно названный каталог (tempfile.py источник здесь), что приведет к поражению цели кеша.
Я не хочу просто отбрасывать ошибку, так как ошибка при ошибке Errno 17 возникает, если имя папки существует как файл (другая ошибка), например:
$ touch blah
$ python
>>> import os
>>> os.mkdir("blah")
Traceback (most recent call last):
File "", line 1, in
OSError: [Errno 17] File exists: 'blah'
>>>
Я не могу использовать threading.RLock, поскольку код вызывается из нескольких процессов.
Итак, я попробовал написать простую блокировку на основе файлов (эту версию можно найти здесь), но это имеет проблему: она создает файл блокировки на один уровень вверх, поэтому /tmp/example.lock для /tmp/example/, который прерывается, если вы используете /tmp/ в качестве кеша dir (поскольку он пытается сделать /tmp.lock)..
Короче, мне нужно кэшировать ответы urllib2 на диск. Для этого мне нужно получить доступ к известному каталогу (создав его, если требуется), безопасным способом многопроцессорности. Он должен работать на OS X, Linux и Windows.
Мысли? Единственное альтернативное решение, о котором я могу думать, - это переписать модуль кэша с использованием хранилища SQLite3, а не файлов.