Improved fallocate and posix_fadvise no-ops when unavailable.

This commit is contained in:
Michael Barton 2010-07-29 00:44:21 +00:00
parent 93ce826e41
commit 179eeb29f7
2 changed files with 32 additions and 15 deletions

View File

@ -45,19 +45,9 @@ logging.thread = eventlet.green.thread
logging.threading = eventlet.green.threading
logging._lock = logging.threading.RLock()
libc = ctypes.CDLL(ctypes.util.find_library('c'))
try: # Not portable, and not available before linux 2.6.23.
sys_fallocate = libc.fallocate
except AttributeError:
def sys_fallocate(fd, mode, offset, len_):
pass
try: # Not yet available on all OSs, or linux before 2.5.60.
posix_fadvise = libc.posix_fadvise
except AttributeError:
def posix_fadvise(fd, offset, len_, advice):
pass
# These are lazily pulled from libc elsewhere
_sys_fallocate = None
_posix_fadvise = None
# Used by hash_path to offer a bit more security when generating hashes for
# paths. It simply appends this value to all paths; guessing the hash a path
@ -65,6 +55,22 @@ except AttributeError:
HASH_PATH_SUFFIX = os.environ.get('SWIFT_HASH_PATH_SUFFIX', 'endcap')
def load_libc_function(func_name):
"""
Attempt to find the function in libc, otherwise return a no-op func.
:param func_name: name of the function to pull from libc.
"""
try:
libc = ctypes.CDLL(ctypes.util.find_library('c'))
return getattr(libc, func_name)
except AttributeError:
print "Unable to locate %s in libc. Leaving as a no-op." % func_name
def noop_libc_function(*args):
return 0
return noop_libc_function
def get_param(req, name, default=None):
"""
Get parameters from an HTTP request ensuring proper handling UTF-8
@ -88,9 +94,12 @@ def fallocate(fd, size):
:param fd: file descriptor
:param size: size to allocate (in bytes)
"""
global _sys_fallocate
if _sys_fallocate is None:
_sys_fallocate = load_libc_function('fallocate')
if size > 0:
# 1 means "FALLOC_FL_KEEP_SIZE", which means it pre-allocates invisibly
ret = sys_fallocate(fd, 1, 0, ctypes.c_uint64(size))
ret = _sys_fallocate(fd, 1, 0, ctypes.c_uint64(size))
# XXX: in (not very thorough) testing, errno always seems to be 0?
err = ctypes.get_errno()
if ret and err not in (0, errno.ENOSYS):
@ -105,8 +114,11 @@ def drop_buffer_cache(fd, offset, length):
:param offset: start offset
:param length: length
"""
global _posix_fadvise
if _posix_fadvise is None:
_posix_fadvise = load_libc_function('posix_fadvise')
# 4 means "POSIX_FADV_DONTNEED"
ret = posix_fadvise(fd, ctypes.c_uint64(offset),
ret = _posix_fadvise(fd, ctypes.c_uint64(offset),
ctypes.c_uint64(length), 4)
if ret != 0:
print "posix_fadvise(%s, %s, %s, 4) -> %s" % (fd, offset, length, ret)

View File

@ -241,6 +241,11 @@ class TestUtils(unittest.TestCase):
'\x06\xfb\xf0\xb5\x14\xe5\x19\x9d\xfcN\x00\xf4.\xb5\xea\x83')
self.assertRaises(ValueError, utils.hash_path, 'a', object='o')
def test_load_libc_function(self):
self.assert_(callable(
utils.load_libc_function('printf')))
self.assert_(callable(
utils.load_libc_function('some_not_real_function')))
if __name__ == '__main__':
unittest.main()