From 74b95d1f2b982c0e33bceda9c5f6e06af0a3919c Mon Sep 17 00:00:00 2001 From: Peter Amstutz Date: Wed, 3 Apr 2024 09:57:00 -0400 Subject: [PATCH] 21639: Adjust test mocking Arvados-DCO-1.1-Signed-off-by: Peter Amstutz --- sdk/python/arvados/diskcache.py | 9 ++++- sdk/python/tests/test_keep_client.py | 50 ++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/sdk/python/arvados/diskcache.py b/sdk/python/arvados/diskcache.py index 1e885c15e2..149f5027d4 100644 --- a/sdk/python/arvados/diskcache.py +++ b/sdk/python/arvados/diskcache.py @@ -32,7 +32,14 @@ class DiskCacheSlot(object): def get(self): self.ready.wait() - if isinstance(self.content, mmap.mmap): + # 'content' can None, an empty byte string, or a nonempty mmap + # region. If it is an mmap region, we want to advise the + # kernel we're going to use it. This nudges the kernel to + # re-read most or all of the block if necessary (instead of + # just a few pages at a time), reducing the number of page + # faults and improving performance by 4x compared to not + # calling madvise. + if self.content: self.content.madvise(mmap.MADV_WILLNEED) return self.content diff --git a/sdk/python/tests/test_keep_client.py b/sdk/python/tests/test_keep_client.py index 6b1ebf56c0..d46140d811 100644 --- a/sdk/python/tests/test_keep_client.py +++ b/sdk/python/tests/test_keep_client.py @@ -11,6 +11,7 @@ from builtins import range from builtins import object import hashlib import mock +from mock import patch import os import errno import pycurl @@ -24,6 +25,7 @@ import tempfile import time import unittest import urllib.parse +import mmap import parameterized @@ -1757,21 +1759,31 @@ class KeepDiskCacheTestCase(unittest.TestCase, tutil.ApiClientMock): keep_client.get(self.locator) - @mock.patch('mmap.mmap') - def test_disk_cache_retry_write_error(self, mockmmap): + def test_disk_cache_retry_write_error(self): block_cache = arvados.keep.KeepBlockCache(disk_cache=True, disk_cache_dir=self.disk_cache_dir) keep_client = arvados.KeepClient(api_client=self.api_client, block_cache=block_cache) - mockmmap.side_effect = (OSError(errno.ENOSPC, "no space"), self.data) + called = False + realmmap = mmap.mmap + def sideeffect_mmap(*args, **kwargs): + nonlocal called + if not called: + called = True + raise OSError(errno.ENOSPC, "no space") + else: + return realmmap(*args, **kwargs) - cache_max_before = block_cache.cache_max + with patch('mmap.mmap') as mockmmap: + mockmmap.side_effect = sideeffect_mmap - with tutil.mock_keep_responses(self.data, 200) as mock: - self.assertTrue(tutil.binary_compare(keep_client.get(self.locator), self.data)) + cache_max_before = block_cache.cache_max - self.assertIsNotNone(keep_client.get_from_cache(self.locator)) + with tutil.mock_keep_responses(self.data, 200) as mock: + self.assertTrue(tutil.binary_compare(keep_client.get(self.locator), self.data)) + + self.assertIsNotNone(keep_client.get_from_cache(self.locator)) with open(os.path.join(self.disk_cache_dir, self.locator[0:3], self.locator+".keepcacheblock"), "rb") as f: self.assertTrue(tutil.binary_compare(f.read(), self.data)) @@ -1780,21 +1792,31 @@ class KeepDiskCacheTestCase(unittest.TestCase, tutil.ApiClientMock): self.assertTrue(cache_max_before > block_cache.cache_max) - @mock.patch('mmap.mmap') - def test_disk_cache_retry_write_error2(self, mockmmap): + def test_disk_cache_retry_write_error2(self): block_cache = arvados.keep.KeepBlockCache(disk_cache=True, disk_cache_dir=self.disk_cache_dir) keep_client = arvados.KeepClient(api_client=self.api_client, block_cache=block_cache) - mockmmap.side_effect = (OSError(errno.ENOMEM, "no memory"), self.data) + called = False + realmmap = mmap.mmap + def sideeffect_mmap(*args, **kwargs): + nonlocal called + if not called: + called = True + raise OSError(errno.ENOMEM, "no memory") + else: + return realmmap(*args, **kwargs) - slots_before = block_cache._max_slots + with patch('mmap.mmap') as mockmmap: + mockmmap.side_effect = sideeffect_mmap - with tutil.mock_keep_responses(self.data, 200) as mock: - self.assertTrue(tutil.binary_compare(keep_client.get(self.locator), self.data)) + slots_before = block_cache._max_slots - self.assertIsNotNone(keep_client.get_from_cache(self.locator)) + with tutil.mock_keep_responses(self.data, 200) as mock: + self.assertTrue(tutil.binary_compare(keep_client.get(self.locator), self.data)) + + self.assertIsNotNone(keep_client.get_from_cache(self.locator)) with open(os.path.join(self.disk_cache_dir, self.locator[0:3], self.locator+".keepcacheblock"), "rb") as f: self.assertTrue(tutil.binary_compare(f.read(), self.data)) -- 2.30.2