1 /* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
22
23 // First include (the generated) my_config.h, to get correct platform defines.
24 #include "my_config.h"
25 #include <gtest/gtest.h>
26
27 #include "locking_service.h"
28 #include "mdl.h"
29 #include "mysqld_error.h"
30 #include "test_utils.h"
31 #include "thread_utils.h"
32
33 /*
34 Putting everything in a namespace prevents any (unintentional)
35 name clashes with the code under test.
36 */
37 namespace locking_service {
38
39 using thread::Thread;
40 using thread::Notification;
41 using my_testing::Server_initializer;
42 using my_testing::Mock_error_handler;
43
44 const char namespace1[]= "namespace1";
45 const char namespace2[]= "namespace2";
46 const char lock_name1[]= "lock1";
47 const char lock_name2[]= "lock2";
48 const char lock_name3[]= "lock3";
49 const char lock_name4[]= "lock4";
50
51 class LockingServiceTest : public ::testing::Test
52 {
53 protected:
LockingServiceTest()54 LockingServiceTest() {}
55
SetUpTestCase()56 static void SetUpTestCase()
57 {
58 m_old_error_handler_hook= error_handler_hook;
59 // Make sure my_error() ends up calling my_message_sql so that
60 // Mock_error_handler is actually triggered.
61 error_handler_hook= my_message_sql;
62 }
63
TearDownTestCase()64 static void TearDownTestCase()
65 {
66 error_handler_hook= m_old_error_handler_hook;
67 }
68
SetUp()69 virtual void SetUp()
70 {
71 mdl_init();
72 m_initializer.SetUp();
73 m_thd= m_initializer.thd();
74 // Slight hack: Makes THD::is_connected() return true.
75 // This prevents MDL_context::acquire_lock() from thinking
76 // the connection has died and the wait should be aborted.
77 m_thd->system_thread= SYSTEM_THREAD_SLAVE_IO;
78 }
79
TearDown()80 virtual void TearDown()
81 {
82 m_initializer.TearDown();
83 mdl_destroy();
84 }
85
86 Server_initializer m_initializer;
87 THD *m_thd;
88
89 static void (*m_old_error_handler_hook)(uint, const char *, myf);
90 };
91
92 void (*LockingServiceTest::m_old_error_handler_hook)(uint, const char *, myf);
93
94
95 /**
96 Test acquire and release of several read or write locks.
97 */
TEST_F(LockingServiceTest,AcquireAndRelease)98 TEST_F(LockingServiceTest, AcquireAndRelease)
99 {
100 // Take two read locks
101 const char *names1[]= { lock_name1, lock_name2 };
102 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 2,
103 LOCKING_SERVICE_READ, 3600));
104 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
105 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
106 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
107 MDL_key::LOCKING_SERVICE, namespace1, lock_name2, MDL_SHARED));
108
109 // Release the locks
110 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
111 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
112 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
113 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
114 MDL_key::LOCKING_SERVICE, namespace1, lock_name2, MDL_SHARED));
115
116 // Take one write lock
117 const char *names2[]= { lock_name3 };
118 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names2, 1,
119 LOCKING_SERVICE_WRITE, 3600));
120 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
121 MDL_key::LOCKING_SERVICE, namespace1, lock_name3, MDL_EXCLUSIVE));
122
123 // Take another write lock
124 const char *names3[]= { lock_name4 };
125 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names3, 1,
126 LOCKING_SERVICE_WRITE, 3600));
127 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
128 MDL_key::LOCKING_SERVICE, namespace1, lock_name3, MDL_EXCLUSIVE));
129 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
130 MDL_key::LOCKING_SERVICE, namespace1, lock_name4, MDL_EXCLUSIVE));
131
132 // Take the read locks again
133 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 2,
134 LOCKING_SERVICE_READ, 3600));
135 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
136 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
137 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
138 MDL_key::LOCKING_SERVICE, namespace1, lock_name2, MDL_SHARED));
139 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
140 MDL_key::LOCKING_SERVICE, namespace1, lock_name3, MDL_EXCLUSIVE));
141 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
142 MDL_key::LOCKING_SERVICE, namespace1, lock_name4, MDL_EXCLUSIVE));
143
144 // Release all locks
145 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
146 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
147 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
148 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
149 MDL_key::LOCKING_SERVICE, namespace1, lock_name2, MDL_SHARED));
150 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
151 MDL_key::LOCKING_SERVICE, namespace1, lock_name3, MDL_SHARED));
152 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
153 MDL_key::LOCKING_SERVICE, namespace1, lock_name4, MDL_SHARED));
154 }
155
156
157 /**
158 Test that names are case sensitive
159 */
TEST_F(LockingServiceTest,CaseSensitive)160 TEST_F(LockingServiceTest, CaseSensitive)
161 {
162 const char *lower[]= { "test" };
163 const char *upper[]= { "TEST" };
164
165 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, lower, 1,
166 LOCKING_SERVICE_WRITE, 3600));
167 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
168 MDL_key::LOCKING_SERVICE, namespace1, "test", MDL_EXCLUSIVE));
169 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
170 MDL_key::LOCKING_SERVICE, namespace1, "TEST", MDL_EXCLUSIVE));
171 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
172
173 EXPECT_FALSE(acquire_locking_service_locks(m_thd, "test", upper, 1,
174 LOCKING_SERVICE_WRITE, 3600));
175 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
176 MDL_key::LOCKING_SERVICE, "test", "TEST", MDL_EXCLUSIVE));
177 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
178 MDL_key::LOCKING_SERVICE, "TEST", "TEST", MDL_EXCLUSIVE));
179 EXPECT_FALSE(release_locking_service_locks(m_thd, "test"));
180 }
181
182
183 /**
184 Test verfication of name lengths.
185 */
TEST_F(LockingServiceTest,ValidNames)186 TEST_F(LockingServiceTest, ValidNames)
187 {
188 const char *ok_name[]= { "test" };
189 {
190 const char *null= NULL;
191 const char *names1[]= { null };
192 Mock_error_handler error_handler(m_thd, ER_LOCKING_SERVICE_WRONG_NAME);
193 EXPECT_TRUE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
194 LOCKING_SERVICE_READ, 3600));
195 EXPECT_TRUE(acquire_locking_service_locks(m_thd, null, ok_name, 1,
196 LOCKING_SERVICE_READ, 3600));
197 EXPECT_TRUE(release_locking_service_locks(m_thd, null));
198 EXPECT_EQ(3, error_handler.handle_called());
199 }
200
201 {
202 const char *empty= "";
203 const char *names2[]= { empty };
204 Mock_error_handler error_handler(m_thd, ER_LOCKING_SERVICE_WRONG_NAME);
205 EXPECT_TRUE(acquire_locking_service_locks(m_thd, namespace1, names2, 1,
206 LOCKING_SERVICE_READ, 3600));
207 EXPECT_TRUE(acquire_locking_service_locks(m_thd, empty, ok_name, 1,
208 LOCKING_SERVICE_READ, 3600));
209 EXPECT_TRUE(release_locking_service_locks(m_thd, empty));
210 EXPECT_EQ(3, error_handler.handle_called());
211 }
212
213 {
214 const char *long65= "12345678901234567890123456789012345678901234567890123456789012345";
215 const char *names3[]= { long65 };
216 Mock_error_handler error_handler(m_thd, ER_LOCKING_SERVICE_WRONG_NAME);
217 EXPECT_TRUE(acquire_locking_service_locks(m_thd, namespace1, names3, 1,
218 LOCKING_SERVICE_READ, 3600));
219 EXPECT_TRUE(acquire_locking_service_locks(m_thd, long65, ok_name, 1,
220 LOCKING_SERVICE_READ, 3600));
221 EXPECT_TRUE(release_locking_service_locks(m_thd, long65));
222 EXPECT_EQ(3, error_handler.handle_called());
223 }
224 }
225
226
227 /**
228 Test interaction (or lack of it) with transactional locks.
229 */
TEST_F(LockingServiceTest,TransactionInteraction)230 TEST_F(LockingServiceTest, TransactionInteraction)
231 {
232 // Releasing transactional locks should not affect lock service locks.
233 const char *names1[]= { lock_name1 };
234 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
235 LOCKING_SERVICE_READ, 3600));
236
237 m_thd->mdl_context.release_transactional_locks();
238 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
239 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
240
241 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
242 LOCKING_SERVICE_WRITE, 3600));
243 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
244 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_EXCLUSIVE));
245 m_thd->mdl_context.release_transactional_locks();
246 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
247 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_EXCLUSIVE));
248
249 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
250
251 // Releasing lock service locks should not affect transactional locks.
252 MDL_request fake_request;
253 MDL_REQUEST_INIT(&fake_request,
254 MDL_key::SCHEMA, "db", "table",
255 MDL_EXCLUSIVE,
256 MDL_TRANSACTION);
257 EXPECT_FALSE(m_thd->mdl_context.acquire_lock(&fake_request, 3600));
258
259 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
260 LOCKING_SERVICE_READ, 3600));
261
262 m_thd->mdl_context.release_transactional_locks();
263 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
264 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
265
266 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
267 }
268
269
270 /**
271 Utility thread for acquiring lock service locks with notification of
272 acquire and release.
273 */
274 class LockServiceThread : public Thread
275 {
276 public:
LockServiceThread(const char ** names,size_t num,enum_locking_service_lock_type lock_type,Notification * grabbed_arg,Notification * release_arg)277 LockServiceThread(const char **names, size_t num,
278 enum_locking_service_lock_type lock_type,
279 Notification *grabbed_arg, Notification *release_arg)
280 : m_names(names), m_num(num), m_lock_type(lock_type),
281 m_lock_grabbed(grabbed_arg), m_lock_release(release_arg)
282 {}
283
run()284 virtual void run()
285 {
286 Server_initializer m_initializer;
287 m_initializer.SetUp();
288 THD *m_thd= m_initializer.thd();
289
290 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, m_names,
291 m_num, m_lock_type, 3600));
292 if (m_lock_grabbed)
293 m_lock_grabbed->notify();
294 if (m_lock_release)
295 m_lock_release->wait_for_notification();
296
297 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
298
299 m_initializer.TearDown();
300 }
301
302 private:
303 const char **m_names;
304 size_t m_num;
305 enum_locking_service_lock_type m_lock_type;
306 Notification *m_lock_grabbed;
307 Notification *m_lock_release;
308 };
309
310
311 /**
312 Test that read locks are compatible with read locks but
313 incompatible with write locks.
314 */
TEST_F(LockingServiceTest,ReadCompatibility)315 TEST_F(LockingServiceTest, ReadCompatibility)
316 {
317 const char *names1[]= { lock_name1 };
318 Notification lock_grabbed, lock_release;
319 LockServiceThread thread(names1, 1, LOCKING_SERVICE_READ,
320 &lock_grabbed, &lock_release);
321 thread.start();
322 lock_grabbed.wait_for_notification();
323
324 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
325 LOCKING_SERVICE_READ, 3600));
326 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
327 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
328 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
329
330 {
331 Mock_error_handler error_handler(m_thd, ER_LOCKING_SERVICE_TIMEOUT);
332 EXPECT_TRUE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
333 LOCKING_SERVICE_WRITE, 2));
334 // Wait 2 seconds here so that we hit the "abs_timeout is far away"
335 // code path in MDL_context::acquire_lock() on all platforms.
336 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
337 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
338 EXPECT_EQ(1, error_handler.handle_called());
339 }
340
341 lock_release.notify();
342 thread.join();
343 }
344
345
346 /**
347 Test that write locks are incompatible with write locks.
348 */
TEST_F(LockingServiceTest,WriteCompatibility)349 TEST_F(LockingServiceTest, WriteCompatibility)
350 {
351 const char *names1[]= { lock_name1 };
352 Notification lock_grabbed, lock_release;
353 LockServiceThread thread(names1, 1, LOCKING_SERVICE_WRITE,
354 &lock_grabbed, &lock_release);
355 thread.start();
356 lock_grabbed.wait_for_notification();
357
358 {
359 Mock_error_handler error_handler(m_thd, ER_LOCKING_SERVICE_TIMEOUT);
360 EXPECT_TRUE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
361 LOCKING_SERVICE_WRITE, 1));
362 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
363 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
364 EXPECT_EQ(1, error_handler.handle_called());
365 }
366
367 lock_release.notify();
368 thread.join();
369 }
370
371
372 /**
373 Test that if acquisition of multiple locks fails because of one
374 lock conflicts, no locks are acquired.
375 */
TEST_F(LockingServiceTest,AtomicAcquire)376 TEST_F(LockingServiceTest, AtomicAcquire)
377 {
378 const char *names1[]= { lock_name1 };
379 Notification lock_grabbed, lock_release;
380 LockServiceThread thread(names1, 1, LOCKING_SERVICE_READ,
381 &lock_grabbed, &lock_release);
382 thread.start();
383 lock_grabbed.wait_for_notification();
384
385 {
386 // Conflict on lock_name1, lock_name2 should not be acquired.
387 const char *names2[]= { lock_name1, lock_name2 };
388 Mock_error_handler error_handler(m_thd, ER_LOCKING_SERVICE_TIMEOUT);
389 EXPECT_TRUE(acquire_locking_service_locks(m_thd, namespace1, names2, 2,
390 LOCKING_SERVICE_WRITE, 1));
391 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
392 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
393 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
394 MDL_key::LOCKING_SERVICE, namespace1, lock_name2, MDL_SHARED));
395 EXPECT_EQ(1, error_handler.handle_called());
396 }
397
398 {
399 // Reverse order of lock names - should give same result.
400 const char *names2[]= { lock_name2, lock_name1 };
401 Mock_error_handler error_handler(m_thd, ER_LOCKING_SERVICE_TIMEOUT);
402 EXPECT_TRUE(acquire_locking_service_locks(m_thd, namespace1, names2, 2,
403 LOCKING_SERVICE_WRITE, 1));
404 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
405 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
406 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
407 MDL_key::LOCKING_SERVICE, namespace1, lock_name2, MDL_SHARED));
408 EXPECT_EQ(1, error_handler.handle_called());
409 }
410
411 lock_release.notify();
412 thread.join();
413 }
414
415
416 /**
417 Test that namespaces are independent.
418 */
TEST_F(LockingServiceTest,Namespaces)419 TEST_F(LockingServiceTest, Namespaces)
420 {
421 const char *names1[]= { lock_name1 };
422 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
423 LOCKING_SERVICE_READ, 3600));
424 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
425 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
426 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
427 MDL_key::LOCKING_SERVICE, namespace2, lock_name1, MDL_SHARED));
428
429 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace2));
430 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
431 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_SHARED));
432 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
433
434 // Take write lock with namespace1 in a separate thread.
435 Notification lock_grabbed, lock_release;
436 LockServiceThread thread(names1, 1, LOCKING_SERVICE_WRITE,
437 &lock_grabbed, &lock_release);
438 thread.start();
439 lock_grabbed.wait_for_notification();
440
441 // We should be able to take a write lock in namespace2.
442 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace2, names1, 1,
443 LOCKING_SERVICE_WRITE, 3600));
444 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
445 MDL_key::LOCKING_SERVICE, namespace2, lock_name1, MDL_EXCLUSIVE));
446 EXPECT_FALSE(m_thd->mdl_context.owns_equal_or_stronger_lock(
447 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_EXCLUSIVE));
448
449 lock_release.notify();
450 thread.join();
451 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace2));
452 }
453
454
455 /**
456 Thread which acquires a write lock on lock_name1 and then disconnects.
457 */
458 class LockServiceDisconnectThread : public Thread
459 {
460 public:
LockServiceDisconnectThread()461 LockServiceDisconnectThread() {}
462
run()463 virtual void run()
464 {
465 Server_initializer m_initializer;
466 m_initializer.SetUp();
467 THD *m_thd= m_initializer.thd();
468
469 const char *names1[]= { lock_name1 };
470 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
471 LOCKING_SERVICE_WRITE, 3600));
472 m_initializer.TearDown();
473 }
474 };
475
476
477 /**
478 Test that locks are released automatically on disconnect.
479 */
TEST_F(LockingServiceTest,Disconnect)480 TEST_F(LockingServiceTest, Disconnect)
481 {
482 LockServiceDisconnectThread thread;
483 thread.start();
484 thread.join();
485
486 // Check that we now can acquire a write lock on name1.
487 const char *names1[]= { lock_name1 };
488 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
489 LOCKING_SERVICE_WRITE, 3600));
490 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
491 }
492
493
494 /**
495 Utility thread for deadlock tests. Acquires two locks in order.
496 */
497 class LockServiceDeadlockThread : public Thread
498 {
499 public:
LockServiceDeadlockThread(Notification * grabbed1_arg,Notification * wait_arg)500 LockServiceDeadlockThread(Notification *grabbed1_arg,
501 Notification *wait_arg)
502 : m_lock_grabbed1(grabbed1_arg), m_wait(wait_arg)
503 {}
504
run()505 virtual void run()
506 {
507 Server_initializer m_initializer;
508 m_initializer.SetUp();
509 THD *m_thd= m_initializer.thd();
510
511 const char *names1[]= { lock_name1 };
512 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
513 LOCKING_SERVICE_WRITE, 3600));
514 m_lock_grabbed1->notify();
515
516 m_wait->wait_for_notification();
517
518 {
519 // The deadlock should be resolved by aborting the wait for the read lock
520 // We should therefore fail.
521 const char *names2[]= { lock_name2 };
522 Mock_error_handler error_handler(m_thd, ER_LOCKING_SERVICE_DEADLOCK);
523 EXPECT_TRUE(acquire_locking_service_locks(m_thd, namespace1, names2, 1,
524 LOCKING_SERVICE_READ, 3600));
525 EXPECT_EQ(1, error_handler.handle_called());
526 }
527
528 // We still have the first lock
529 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
530 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_EXCLUSIVE));
531
532 // Release locks so that the other thread can continue.
533 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
534
535 m_initializer.TearDown();
536 }
537
538 private:
539 Notification *m_lock_grabbed1;
540 Notification *m_wait;
541 };
542
543
544 /**
545 Test that deadlock is detected and lock acquisition fails.
546 The wait for a read lock should be aborted in preference for
547 aborting the wait for a write lock.
548 */
TEST_F(LockingServiceTest,DeadlockRead)549 TEST_F(LockingServiceTest, DeadlockRead)
550 {
551 // Start a thread which acquires a write lock on name1
552 Notification lock_grabbed1, wait;
553 LockServiceDeadlockThread thread(&lock_grabbed1, &wait);
554 thread.start();
555 lock_grabbed1.wait_for_notification();
556
557 // Acquire write lock on name 2
558 const char *names2[]= { lock_name2 };
559 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names2, 1,
560 LOCKING_SERVICE_WRITE, 3600));
561
562 // Signal the other thread to continue, taking write lock on name1
563 wait.notify();
564
565 // The other thread will be aborted so that we will acquire the lock.
566 const char *names1[]= { lock_name1 };
567 EXPECT_FALSE(acquire_locking_service_locks(m_thd, namespace1, names1, 1,
568 LOCKING_SERVICE_WRITE, 3600));
569
570 // Both locks should now be held
571 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
572 MDL_key::LOCKING_SERVICE, namespace1, lock_name1, MDL_EXCLUSIVE));
573 EXPECT_TRUE(m_thd->mdl_context.owns_equal_or_stronger_lock(
574 MDL_key::LOCKING_SERVICE, namespace1, lock_name2, MDL_EXCLUSIVE));
575
576 thread.join();
577 EXPECT_FALSE(release_locking_service_locks(m_thd, namespace1));
578 }
579 } // namespace
580