mirror of
https://github.com/facebook/sapling.git
synced 2024-10-12 01:39:21 +03:00
e2a5493b04
Summary: This is a resend of https://phab.mercurial-scm.org/D1430, without breaking Windows. I encountered "too many opened files" problem due to treemanifest packs on my laptop. This patch seems to be the easiest solution without side effects. Other choices are deleting files (seem like an non-ideal workaround), forcing a repack (could be slow), and rewriting using Rust (could take too long). The root cause is Python's `mmap` implementation has to keep a fd internally to support `mmapobj.resize` API. We only need read-only operation on the mmap object so the fd is unnecessary. Re-implement a minimal mmap interface for this purpose. Reviewed By: DurhamG Differential Revision: D6835890 fbshipit-source-id: 74c429e957cb8677682604eb02fc38b5b8d13ef7
80 lines
2.3 KiB
Cython
80 lines
2.3 KiB
Cython
# litemmap.pyx - read-only mmap implementation that does not keep a fd open
|
|
#
|
|
# Copyright 2018 Facebook, Inc.
|
|
#
|
|
# This software may be used and distributed according to the terms of the
|
|
# GNU General Public License version 2 or any later version.
|
|
|
|
import mmap as pymmap
|
|
|
|
IF UNAME_SYSNAME == "Windows":
|
|
# Not supporting windows for now - fallback to Python's mmap
|
|
mmap = pymmap.mmap
|
|
ELSE:
|
|
from cpython.bytes cimport PyBytes_FromStringAndSize
|
|
from libc.errno cimport errno
|
|
from posix cimport mman, stat
|
|
|
|
import os
|
|
|
|
cdef extern from "sys/mman.h":
|
|
cdef char *MAP_FAILED
|
|
|
|
cdef _raise_oserror(message=''):
|
|
if message:
|
|
message += ': '
|
|
message += os.strerror(errno)
|
|
return OSError(errno, message)
|
|
|
|
cdef class mmap:
|
|
cdef char *ptr
|
|
cdef size_t len
|
|
|
|
def __cinit__(self, int fd, size_t length, int
|
|
access=pymmap.ACCESS_READ):
|
|
cdef stat.struct_stat st
|
|
# Only support read-only case
|
|
if access != pymmap.ACCESS_READ:
|
|
raise RuntimeError('access %s is unsupported' % access)
|
|
|
|
# If length is 0, read size from file
|
|
if length == 0:
|
|
r = stat.fstat(fd, &st)
|
|
if r != 0:
|
|
_raise_oserror('fstat failed')
|
|
length = st.st_size
|
|
|
|
self.ptr = <char*>mman.mmap(NULL, length, mman.PROT_READ,
|
|
mman.MAP_SHARED, fd, 0)
|
|
if self.ptr == MAP_FAILED:
|
|
_raise_oserror('mmap failed')
|
|
|
|
self.len = length
|
|
|
|
cpdef close(self):
|
|
if self.ptr == NULL:
|
|
return
|
|
|
|
r = mman.munmap(self.ptr, self.len)
|
|
if r != 0:
|
|
_raise_oserror('munmap failed')
|
|
self.ptr = NULL
|
|
|
|
def __getslice__(self, Py_ssize_t i, Py_ssize_t j):
|
|
if self.ptr == NULL:
|
|
raise RuntimeError('mmap closed')
|
|
if i < 0:
|
|
i = 0
|
|
if j > self.len:
|
|
j = self.len
|
|
if i > j:
|
|
i = j
|
|
return PyBytes_FromStringAndSize(self.ptr + i, j - i)
|
|
|
|
def __len__(self):
|
|
return self.len
|
|
|
|
def __dealloc__(self):
|
|
self.close()
|
|
|