diff options
| author | Cthulhu <[email protected]> | 2024-07-24 19:03:13 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-07-24 19:03:13 +0300 |
| commit | ded90c74dfef81f65e145352ccb84bdcc712291c (patch) | |
| tree | 117f20827af37aa4d43578e4fd40da0e7b3370dc | |
| parent | edea3060c17f2106c2a72a770b566bf776fb4f04 (diff) | |
Fix lock in Immediate Control Board #5290 (#5289)
| -rw-r--r-- | ydb/core/control/immediate_control_board_impl.cpp | 16 | ||||
| -rw-r--r-- | ydb/core/control/immediate_control_board_ut.cpp | 20 | ||||
| -rw-r--r-- | ydb/core/util/concurrent_rw_hash.h | 14 |
3 files changed, 34 insertions, 16 deletions
diff --git a/ydb/core/control/immediate_control_board_impl.cpp b/ydb/core/control/immediate_control_board_impl.cpp index 06f6dab1a83..40336f4df9e 100644 --- a/ydb/core/control/immediate_control_board_impl.cpp +++ b/ydb/core/control/immediate_control_board_impl.cpp @@ -7,16 +7,18 @@ namespace NKikimr { bool TControlBoard::RegisterLocalControl(TControlWrapper control, TString name) { - bool result = true; - if (Board.Has(name)) { - result = false; - } - Board.Insert(name, control.Control); - return result; + TIntrusivePtr<TControl> ptr; + bool result = Board.Swap(name, control.Control, ptr); + return !result; } bool TControlBoard::RegisterSharedControl(TControlWrapper& control, TString name) { - auto& ptr = Board.InsertIfAbsent(name, control.Control); + TIntrusivePtr<TControl> ptr; + if (Board.Get(name, ptr)) { + control.Control = ptr; + return false; + } + ptr = Board.InsertIfAbsent(name, control.Control); if (control.Control == ptr) { return true; } else { diff --git a/ydb/core/control/immediate_control_board_ut.cpp b/ydb/core/control/immediate_control_board_ut.cpp index dba6280ab5b..35ca7524dee 100644 --- a/ydb/core/control/immediate_control_board_ut.cpp +++ b/ydb/core/control/immediate_control_board_ut.cpp @@ -111,15 +111,17 @@ Y_UNIT_TEST_SUITE(ControlImplementationTests) { Y_UNIT_TEST(TestParallelRegisterSharedControl) { void* (*parallelJob)(void*) = [](void *controlBoard) -> void *{ - TControlBoard *Icb = reinterpret_cast<TControlBoard *>(controlBoard); - TControlWrapper control1(1, 1, 1); - Icb->RegisterSharedControl(control1, "sharedControl"); - // Useless because running this test with --sanitize=thread cannot reveal - // race condition in Icb->RegisterLocalControl(...) without mutex - TControlWrapper control2(2, 2, 2); - TControlWrapper control2_origin(control2); - Icb->RegisterLocalControl(control2, "localControl"); - UNIT_ASSERT_EQUAL(control2, control2_origin); + for (ui64 i = 0; i < 10000; ++i) { + TControlBoard *Icb = reinterpret_cast<TControlBoard *>(controlBoard); + TControlWrapper control1(1, 1, 1); + Icb->RegisterSharedControl(control1, "sharedControl"); + // Useless because running this test with --sanitize=thread cannot reveal + // race condition in Icb->RegisterLocalControl(...) without mutex + TControlWrapper control2(2, 2, 2); + TControlWrapper control2_origin(control2); + Icb->RegisterLocalControl(control2, "localControl"); + UNIT_ASSERT_EQUAL(control2, control2_origin); + } return nullptr; }; TIntrusivePtr<TControlBoard> Icb(new TControlBoard); diff --git a/ydb/core/util/concurrent_rw_hash.h b/ydb/core/util/concurrent_rw_hash.h index 2e787d1022e..bb25b7d8c32 100644 --- a/ydb/core/util/concurrent_rw_hash.h +++ b/ydb/core/util/concurrent_rw_hash.h @@ -49,6 +49,20 @@ public: bucket.Map[key] = value; } + bool Swap(const K& key, const V& value, V& out_prev_value) { + TBucket& bucket = GetBucketForKey(key); + TWriteGuard guard(bucket.RWLock); + + typename TActualMap::iterator it = bucket.Map.find(key); + if (it != bucket.Map.end()) { + out_prev_value = it->second; + it->second = value; + return true; + } + bucket.Map.insert(std::make_pair(key, value)); + return false; + } + V& InsertIfAbsent(const K& key, const V& value) { TBucket& bucket = GetBucketForKey(key); TWriteGuard guard(bucket.RWLock); |
