Как безопасно переназначить (изменить размер) mmap в Python, пока другие потоки читают?Python

Программы на Python
Anonymous
Как безопасно переназначить (изменить размер) mmap в Python, пока другие потоки читают?

Сообщение Anonymous »

Я создаю систему хранения журналов на основе сегментов в Python с использованием модуля mmap в Python.
Я хочу расставить приоритеты:
  • Нулевое копирование, насколько это возможно
  • Параллельные чтения
  • динамический рост базового файла
Текущий подход:

Код: Выделить всё

class Entry:
"""
Owned by SegmentMemory class, provides read and write guarantees.
"""

def __init__(self, meta:SegmentMeta, init_segment_size, segment_size_inc) -> None:
self.__mmap: mmap.mmap | None = None
self.__file_obj: _io.BufferedRandom | None = None
self.__capacity: int|None = None
self.__filepath = meta.get_filepath()
self.__mutable:bool = meta.is_mutable()
self._refcount:AtomicInt = AtomicInt(0)
self._lock: threading.Lock = threading.Lock()

self.init_segment_size = init_segment_size
self.segment_size_inc = segment_size_inc

def load(self) -> None:
'''Load resource before use'''
# Never call it internally while holding the lock
with self._lock:
# Only load the file onces
if self.__mmap is None:
# ensure directory exists
os.makedirs(os.path.dirname(self.__filepath), exist_ok=True)
exists = os.path.exists(self.__filepath)
# Load the file
self.__file_obj = open(self.__filepath, 'r+b' if exists else 'wb+')
self.__capacity = os.fstat(self.__file_obj.fileno()).st_size
if(self.__capacity == 0):
# First time creating a file
# ensure file capacity
self.__file_obj.truncate(self.init_segment_size)
self.__capacity = self.init_segment_size

self.__mmap = mmap.mmap(self.__file_obj.fileno(), 0)

# Hint the os for sequential reads
set_sequential_hint(self.__mmap, self.__file_obj.fileno())

def read_bytes(self, offset: int, length: int) -> bytes:
assert(self.__mmap is not None)
return self.__mmap[offset : offset+length]

def write(self, offset: int, msg: bytes) -> None:
assert(self.__mmap is not None)
assert(self.__mutable == True)
required_capacity = offset+len(msg)
with self._lock:
self._ensure_capacity_locked(required_capacity)
self.__mmap[offset:required_capacity] = msg

def release(self) -> None:
# Not thread-safe
if self.__mmap is not None:
if self.__mutable:
self.__mmap.flush()
self.__mmap.close()
self.__mmap = None
if self.__file_obj is not None:
if self.__mutable:
self.__file_obj.flush()
self.__file_obj.close()
self.__file_obj = None

def _ensure_capacity_locked(self, capacity: int):
"""Internal function: Not thread safe """

assert(self.__capacity is not None)
assert(self.__file_obj is not None)
assert(self.__mmap is not None)
if(self.__capacity < capacity):
# Increasing the segment size
new_capacity = max(capacity, self.segment_size_inc+self.__capacity)
self.__file_obj.truncate(new_capacity)
self.__mmap.resize(new_capacity)

self.__capacity = new_capacity
Здесь я выполняю чтение без какой-либо блокировки в def read_bytes, а также мне нужно увеличить размер файла в def ensure_capacity_locked, он сначала обрезает файл, а затем изменяет размер mmap.

Но я не уверен насчет текущего поведения. Может ли отображение измениться при изменении размера и сделать одновременные чтения недействительными или вызвать SIGBUS?
В документации Python также ничего не говорится о потокобезопасности
https://docs.python.org/3/library/mmap. ... map.resize

Вернуться в «Python»