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