Python: блокировка каталога - PullRequest
       1

Python: блокировка каталога

0 голосов
/ 15 октября 2018

AFAIK этот код можно использовать для блокировки каталога:

class LockDirectory(object):
    def __init__(self, directory):
        assert os.path.exists(directory)
        self.directory = directory

    def __enter__(self):
        self.dir_fd = os.open(self.directory, os.O_RDONLY)
        try:
            fcntl.flock(self.dir_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError as ex:
            if ex.errno != errno.EAGAIN:
                raise
            raise Exception('Somebody else is locking %r - quitting.' % self.directory)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.dir_fd.close()

Но в соответствии с ответами на этот вопрос блокировка директории невозможна: Python: блокировка каталога

Что не так с приведенным выше кодом?

Мне нужно только поддерживать текущую версию Linux.Нет Windows, Mac или другой Unix.

Ответы [ 4 ]

0 голосов
/ 24 октября 2018

Я немного изменяю ваш код, добавляю return self, как это делает большинство средств управления контекстом, затем при dup() второе управление контекстом завершится неудачно. И решение простое, раскомментируйте fcntl.flock(self.dir_fd,fcntl.LOCK_UN)

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

и вы не можете собираться в NFS.

import os
import fcntl
import time
class LockDirectory(object):
    def __init__(self, directory):
        assert os.path.exists(directory)
        self.directory = directory

    def __enter__(self):
        self.dir_fd = os.open(self.directory, os.O_RDONLY)
        try:
            fcntl.flock(self.dir_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError as ex:             
            raise Exception('Somebody else is locking %r - quitting.' % self.directory)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        # fcntl.flock(self.dir_fd,fcntl.LOCK_UN)
        os.close(self.dir_fd)

def main():
    with LockDirectory("test") as lock:
        newfd = os.dup(lock.dir_fd)
    with LockDirectory("test") as lock2:
        pass

if __name__ == '__main__':
    main()
0 голосов
/ 15 октября 2018

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

Вам необходимо изменить функцию __exit__, чтобы использовать os.close(), чтобы закрыть дескриптор файла;дескриптор файла - это просто целое число, и у целых чисел нет метода .close():

def __exit__(self, exc_type, exc_val, exc_tb):
    os.close(self.dir_fd)

Обычное замешательство для людей, которые думают, что вы не можете, это те, кто пытался использовать функцию open().Python не позволит вам открыть узел каталога с этой функцией, потому что нет смысла создавать объект файла Python для каталога.Или, возможно, существует предположение, что вы хотели, чтобы ОС обеспечивала принудительный доступ к каталогу через блокировку (в отличие от консультативной блокировки, которую кооперативный набор процессов соглашается получить в первую очередь перед попыткой доступа).

Так что нет, в коде нет ничего плохого, если все, что вам нужно, это консультативная блокировка, и хорошо, если это работает только в Linux.

Я бы отбросил отличие directory от кода.Блокировка будет работать на любом пути, к которому у вас есть доступ для чтения.Это не только для каталогов.

Недостатком блокировки каталога является то, что это не дает вам места для хранения метаданных блокировки.В то время как lsof может дать вам PID текущего владельца блокировки, вы можете захотеть передать некоторую другую информацию с помощью блокировки, чтобы помочь устранить неполадки или автоматизировать взлом блокировки.Файл .lock или символическая ссылка позволят вам записать дополнительную информацию.Например, Mercurial создаст символическую ссылку с именем хоста, идентификатором пространства имен PID (только для Linux) и PID в целевом имени;Вы можете создать такую ​​символическую ссылку атомарно, в то время как запись этих данных в файл потребует создания файла с временным именем и последующим переименованием.

0 голосов
/ 23 октября 2018

Я нашел ответ здесь: Python: Блокировка каталога

Можно заблокировать каталог с помощью этого:

fcntl.flock(self.dir_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)

Конечно, это блокировкакоторый каждый код, который играет в этой игре, должен сначала проверить.

AFAIK это называется "консультативная блокировка".

0 голосов
/ 04 октября 2018

Я бы посоветовал вам пойти с простым файлом блокировки.Как следует из вопроса в комментарии ( Как заблокировать каталог между процессами Python в Linux? ), механизм блокировки каталогов отсутствует, в отличие от файлов.
Lockфайлы используются слева и справа в Linux, они очень прозрачны и их легко отлаживать, поэтому я бы просто пошел с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...