|
3 | 3 | #include <atomic> |
4 | 4 | #include <latch> |
5 | 5 | #include <memory> |
| 6 | +#include <mutex> |
| 7 | +#include <unordered_map> |
6 | 8 | #include <thread> |
7 | 9 | #include <vector> |
8 | 10 | #include "../common/status.h" |
@@ -173,6 +175,127 @@ BOOST_AUTO_TEST_CASE(LockUnlockNoWaitTest) |
173 | 175 | } |
174 | 176 |
|
175 | 177 |
|
| 178 | +BOOST_AUTO_TEST_CASE(LockUnlockAstTest) |
| 179 | +{ |
| 180 | + struct Lock; |
| 181 | + |
| 182 | + struct ThreadData |
| 183 | + { |
| 184 | + LockManager* lockManager = nullptr; |
| 185 | + std::mutex* globalMutex = nullptr; |
| 186 | + std::mutex localMutex; |
| 187 | + std::unordered_map<SLONG, Lock*> locks; |
| 188 | + }; |
| 189 | + |
| 190 | + struct Lock |
| 191 | + { |
| 192 | + ThreadData* threadData = nullptr; |
| 193 | + unsigned key = 0; |
| 194 | + SLONG lockId = 0; |
| 195 | + }; |
| 196 | + |
| 197 | + constexpr unsigned THREAD_COUNT = 8u; |
| 198 | + constexpr unsigned ITERATION_COUNT = 10'000u; |
| 199 | + |
| 200 | + ConfigFile configFile(ConfigFile::USE_TEXT, "\n"); |
| 201 | + Config config(configFile); |
| 202 | + |
| 203 | + LockManagerTestCallbacks callbacks; |
| 204 | + const string lockManagerId(getUniqueId().c_str()); |
| 205 | + auto lockManager = std::make_unique<LockManager>(lockManagerId, &config); |
| 206 | + |
| 207 | + std::atomic_uint lockSuccess = 0u; |
| 208 | + std::atomic_uint lockFail = 0u; |
| 209 | + |
| 210 | + std::vector<std::thread> threads; |
| 211 | + std::latch latch(THREAD_COUNT); |
| 212 | + |
| 213 | + static const auto ast = [](void* astArg) -> int { |
| 214 | + const auto lock = static_cast<Lock*>(astArg); |
| 215 | + const auto threadData = lock->threadData; |
| 216 | + |
| 217 | + std::lock_guard localMutexGuard(threadData->localMutex); |
| 218 | + |
| 219 | + fb_assert(lock->lockId); |
| 220 | + |
| 221 | + if (!threadData->lockManager->dequeue(lock->lockId)) |
| 222 | + fb_assert(false); |
| 223 | + |
| 224 | + threadData->locks.erase(lock->lockId); |
| 225 | + delete lock; |
| 226 | + |
| 227 | + return 0; |
| 228 | + }; |
| 229 | + |
| 230 | + std::mutex globalMutex; |
| 231 | + |
| 232 | + for (unsigned threadNum = 0u; threadNum < THREAD_COUNT; ++threadNum) |
| 233 | + { |
| 234 | + threads.emplace_back([&, threadNum]() { |
| 235 | + ThreadData threadData; |
| 236 | + threadData.lockManager = lockManager.get(); |
| 237 | + threadData.globalMutex = &globalMutex; |
| 238 | + |
| 239 | + FbLocalStatus statusVector; |
| 240 | + LOCK_OWNER_T ownerId = threadNum + 1; |
| 241 | + SLONG ownerHandle = 0; |
| 242 | + |
| 243 | + lockManager->initializeOwner(&statusVector, ownerId, LCK_OWNER_attachment, &ownerHandle); |
| 244 | + |
| 245 | + latch.arrive_and_wait(); |
| 246 | + |
| 247 | + for (unsigned i = 0; i < ITERATION_COUNT; ++i) |
| 248 | + { |
| 249 | + std::lock_guard globalMutexGuard(globalMutex); |
| 250 | + std::lock_guard localMutexGuard(threadData.localMutex); |
| 251 | + |
| 252 | + const auto lock = new Lock(); |
| 253 | + lock->threadData = &threadData; |
| 254 | + lock->key = i; |
| 255 | + lock->lockId = lockManager->enqueue(callbacks, &statusVector, 0, |
| 256 | + LCK_expression, (const UCHAR*) &lock->key, sizeof(lock->key), LCK_EX, |
| 257 | + ast, lock, 0, LCK_WAIT, ownerHandle); |
| 258 | + |
| 259 | + if (lock->lockId) |
| 260 | + { |
| 261 | + threadData.locks.insert({ lock->lockId, lock }); |
| 262 | + ++lockSuccess; |
| 263 | + } |
| 264 | + else |
| 265 | + { |
| 266 | + fb_assert(false); |
| 267 | + delete lock; |
| 268 | + ++lockFail; |
| 269 | + } |
| 270 | + } |
| 271 | + |
| 272 | + { // scope |
| 273 | + std::lock_guard globalMutexGuard(globalMutex); |
| 274 | + std::lock_guard localMutexGuard(threadData.localMutex); |
| 275 | + |
| 276 | + for (const auto [lockId, lock] : threadData.locks) |
| 277 | + { |
| 278 | + lockManager->dequeue(lockId); |
| 279 | + delete lock; |
| 280 | + } |
| 281 | + |
| 282 | + threadData.locks.clear(); |
| 283 | + } |
| 284 | + |
| 285 | + lockManager->shutdownOwner(callbacks, &ownerHandle); |
| 286 | + }); |
| 287 | + } |
| 288 | + |
| 289 | + for (auto& thread : threads) |
| 290 | + thread.join(); |
| 291 | + |
| 292 | + BOOST_CHECK_EQUAL(lockFail.load(), 0u); |
| 293 | + BOOST_CHECK_EQUAL(lockSuccess.load(), THREAD_COUNT * ITERATION_COUNT); |
| 294 | + |
| 295 | + lockManager.reset(); |
| 296 | +} |
| 297 | + |
| 298 | + |
176 | 299 | BOOST_AUTO_TEST_SUITE_END() // LockManagerTests |
177 | 300 | BOOST_AUTO_TEST_SUITE_END() // LockManagerSuite |
178 | 301 | BOOST_AUTO_TEST_SUITE_END() // EngineSuite |
0 commit comments