From 3dba681005c28b7f1e49404e7e53b9de32f543c4 Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Fri, 27 Jun 2025 09:01:54 -0700 Subject: [PATCH] Fix traceback in invalidate_hash Change-Id: I80142c6c0654b65b5755e7e828bcc4969a10f4f1 --- swift/obj/diskfile.py | 12 ++++++++++-- test/unit/obj/test_diskfile.py | 19 +++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/swift/obj/diskfile.py b/swift/obj/diskfile.py index b1e0abf836..45d490988e 100644 --- a/swift/obj/diskfile.py +++ b/swift/obj/diskfile.py @@ -474,8 +474,16 @@ def invalidate_hash(suffix_dir): invalidations_file = join(partition_dir, HASH_INVALIDATIONS_FILE) if not isinstance(suffix, bytes): suffix = suffix.encode('utf-8') - with lock_path(partition_dir), open(invalidations_file, 'ab') as inv_fh: - inv_fh.write(suffix + b"\n") + with lock_path(partition_dir): + try: + inv_fh = open(invalidations_file, 'ab') + except FileNotFoundError: + # Was previously locked for replication off a handoff, and has now + # been deleted -- I guess? + pass + else: + with inv_fh: + inv_fh.write(suffix + b"\n") def relink_paths(target_path, new_target_path, ignore_missing=True): diff --git a/test/unit/obj/test_diskfile.py b/test/unit/obj/test_diskfile.py index 3e75c45e65..66842fe557 100644 --- a/test/unit/obj/test_diskfile.py +++ b/test/unit/obj/test_diskfile.py @@ -38,7 +38,7 @@ from contextlib import closing, contextmanager from gzip import GzipFile import pyeclib.ec_iface -from eventlet import hubs, timeout, tpool +from eventlet import hubs, timeout, tpool, spawn, sleep from swift.obj.diskfile import update_auditor_status, EUCLEAN from test import BaseTestCase from test.debug_logger import debug_logger @@ -48,7 +48,7 @@ from test.unit import (mock as unit_mock, temptree, mock_check_drive, encode_frag_archive_bodies, skip_if_no_xattrs) from swift.obj import diskfile from swift.common import utils -from swift.common.utils import hash_path, mkdirs, Timestamp, \ +from swift.common.utils import hash_path, mkdirs, Timestamp, lock_path, \ encode_timestamps, O_TMPFILE, md5 as _md5, MD5_OF_EMPTY_STRING from swift.common import ring from swift.common.splice import splice @@ -7674,6 +7674,21 @@ class TestSuffixHashes(unittest.TestCase): # invalidate_hash tests - behavior + def test_invalidate_hash_race_with_partition_delete(self): + part_dir = os.path.join(self.testdir, '0') + suffix_dir = os.path.join(part_dir, 'fff') + os.makedirs(suffix_dir) + + def replicatorish(): + with lock_path(part_dir): + sleep(0.01) + rmtree(part_dir) + sleep(0.01) + + spawn(replicatorish) + sleep(0) # make sure thread starts + diskfile.invalidate_hash(suffix_dir) + def test_invalidate_hash_file_does_not_exist(self): for policy in self.iter_policies(): df_mgr = self.df_router[policy]