From 396380f3406bdcd842e85a66cb346bf219cbb4f3 Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Thu, 2 Nov 2017 11:43:16 -0700 Subject: [PATCH] Better handle missing files in _construct_from_data_file There's a window between when we list the files on disk and when we actually try to open the .data file where another process could delete it. That should raise a DiskFileNotExist error, not an IOError. Change-Id: I1b43fef35949cb6f71997874e4e6b7646eeec8fe Closes-Bug: 1712662 --- swift/obj/diskfile.py | 7 ++++++- test/unit/obj/test_diskfile.py | 20 ++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/swift/obj/diskfile.py b/swift/obj/diskfile.py index 96f45954f4..fc542a9f0a 100644 --- a/swift/obj/diskfile.py +++ b/swift/obj/diskfile.py @@ -2468,7 +2468,12 @@ class BaseDiskFile(object): :raises DiskFileError: various exceptions from :func:`swift.obj.diskfile.DiskFile._verify_data_file` """ - fp = open(data_file, 'rb') + try: + fp = open(data_file, 'rb') + except IOError as e: + if e.errno == errno.ENOENT: + raise DiskFileNotExist() + raise self._datafile_metadata = self._failsafe_read_metadata( fp, data_file, add_missing_checksum=modernize) diff --git a/test/unit/obj/test_diskfile.py b/test/unit/obj/test_diskfile.py index 9829393919..8b05efc603 100644 --- a/test/unit/obj/test_diskfile.py +++ b/test/unit/obj/test_diskfile.py @@ -2235,11 +2235,11 @@ class TestECDiskFileManager(DiskFileManagerMixin, unittest.TestCase): rmtree(df._datadir, ignore_errors=True) # sanity - files = [ + good_files = [ '0000000006.00000.meta', '0000000006.00000#1#d.data' ] - with create_files(class_under_test, files): + with create_files(class_under_test, good_files): class_under_test.open() scenarios = [['0000000007.00000.meta'], @@ -2263,6 +2263,22 @@ class TestECDiskFileManager(DiskFileManagerMixin, unittest.TestCase): self.fail('expected DiskFileNotExist opening %s with %r' % ( class_under_test.__class__.__name__, files)) + # Simulate another process deleting the data after we list contents + # but before we actually open them + orig_listdir = os.listdir + + def deleting_listdir(d): + result = orig_listdir(d) + for f in result: + os.unlink(os.path.join(d, f)) + return result + + with create_files(class_under_test, good_files), \ + mock.patch('swift.obj.diskfile.os.listdir', + side_effect=deleting_listdir), \ + self.assertRaises(DiskFileNotExist): + class_under_test.open() + def test_verify_ondisk_files(self): # _verify_ondisk_files should only return False if get_ondisk_files # has produced a bad set of files due to a bug, so to test it we need