From c9b0795b9ecc430839eb3783327eb9c7c4aad5f8 Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Wed, 28 Jul 2021 11:21:44 -0700 Subject: [PATCH] diskfile: Stop raising ENOENT when we race to mark durable Change-Id: Ia952303a16457a5075e9a4e060806855c21577f5 --- swift/obj/diskfile.py | 4 +-- test/unit/obj/test_diskfile.py | 47 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/swift/obj/diskfile.py b/swift/obj/diskfile.py index 7ddd71e7ac..0de2e4171a 100644 --- a/swift/obj/diskfile.py +++ b/swift/obj/diskfile.py @@ -3153,8 +3153,8 @@ class ECDiskFileWriter(BaseDiskFileWriter): durables = results.get('durable_frag_set', []) if ts_info and ts_info['timestamp'] > timestamp: return - elif any(frag_set['timestamp'] > timestamp - for frag_set in durables): + elif any(frag['timestamp'] >= timestamp + for frag in durables): return if err.errno not in (errno.ENOSPC, errno.EDQUOT): diff --git a/test/unit/obj/test_diskfile.py b/test/unit/obj/test_diskfile.py index 1179f2ff3c..30111b238a 100644 --- a/test/unit/obj/test_diskfile.py +++ b/test/unit/obj/test_diskfile.py @@ -4226,6 +4226,53 @@ class DiskFileMixin(BaseDiskFileTestMixin): with df.open(), open(df._data_file, 'rb') as fp: self.assertEqual(b'dataB', fp.read()) + def test_disk_file_concurrent_marked_durable(self): + ts = self.ts() + + def threadA(df, events, errors): + try: + with df.create() as writer: + writer.write(b'dataA') + writer.put({ + 'X-Timestamp': ts.internal, + 'Content-Length': 5, + }) + events[0].set() + events[1].wait() + writer.commit(ts) + except Exception as e: + errors.append(e) + raise + + def threadB(df, events, errors): + try: + events[0].wait() + # Mark it durable just like in ssync_receiver + with df.create() as writer: + writer.commit(ts) + events[1].set() + except Exception as e: + errors.append(e) + raise + + df = self._simple_get_diskfile() + events = [threading.Event(), threading.Event()] + errors = [] + + threads = [threading.Thread(target=tgt, args=(df, events, errors)) + for tgt in (threadA, threadB)] + for thread in threads: + thread.start() + for thread in threads: + thread.join() + self.assertFalse(errors) + + with df.open(), open(df._data_file, 'rb') as fp: + if df.policy.policy_type == EC_POLICY: + # Confirm that it really *was* marked durable + self.assertTrue(df._data_file.endswith('#d.data')) + self.assertEqual(b'dataA', fp.read()) + def test_disk_file_concurrent_delete(self): def threadA(df, events, errors): try: