diff options
author | Daniel-Solo <dansolo@mail.ru> | 2020-01-15 15:08:42 +0300 |
---|---|---|
committer | Sergey Vojtovich <svoj@mariadb.org> | 2020-02-27 14:37:19 +0400 |
commit | 127fee998f7275485aeca91ad82030e6f796d809 (patch) | |
tree | aca553e1416a10111f0bb68218d3573b3980ddfe | |
parent | 98adcffe460447c43a86afdf6588e31379b7f52d (diff) | |
download | mariadb-git-127fee998f7275485aeca91ad82030e6f796d809.tar.gz |
MDEV-10569: Add RELEASE_ALL_LOCKS function. Implementing the SQL
function to release all named locks
-rw-r--r-- | mysql-test/main/func_misc.result | 91 | ||||
-rw-r--r-- | mysql-test/main/func_misc.test | 59 | ||||
-rw-r--r-- | sql/item_create.cc | 22 | ||||
-rw-r--r-- | sql/item_func.cc | 28 | ||||
-rw-r--r-- | sql/item_func.h | 66 |
5 files changed, 237 insertions, 29 deletions
diff --git a/mysql-test/main/func_misc.result b/mysql-test/main/func_misc.result index ae6686ecadc..311b9c083fa 100644 --- a/mysql-test/main/func_misc.result +++ b/mysql-test/main/func_misc.result @@ -1641,3 +1641,94 @@ DROP TABLE t1; # # End of 10.4 tests # +# +# MDEV-10569 Add RELEASE_ALL_LOCKS SQL-function +# +# Test function without any locks +SELECT RELEASE_ALL_LOCKS(); +RELEASE_ALL_LOCKS() +0 +# Test function with one lock only +SELECT GET_LOCK('l1',10); +GET_LOCK('l1',10) +1 +SELECT RELEASE_ALL_LOCKS(); +RELEASE_ALL_LOCKS() +1 +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA +FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA; +LOCK_MODE LOCK_TYPE TABLE_SCHEMA +# Test function with multiple locks +SELECT GET_LOCK('l01',10), +GET_LOCK('l02',10), +GET_LOCK('l03',10), +GET_LOCK('l04',10), +GET_LOCK('l05',10), +GET_LOCK('l06',10), +GET_LOCK('l07',10), +GET_LOCK('l08',10), +GET_LOCK('l09',10), +GET_LOCK('l10',10), +GET_LOCK('l11',10), +GET_LOCK('l12',10), +GET_LOCK('l13',10), +GET_LOCK('l14',10), +GET_LOCK('l15',10); +GET_LOCK('l01',10) GET_LOCK('l02',10) GET_LOCK('l03',10) GET_LOCK('l04',10) GET_LOCK('l05',10) GET_LOCK('l06',10) GET_LOCK('l07',10) GET_LOCK('l08',10) GET_LOCK('l09',10) GET_LOCK('l10',10) GET_LOCK('l11',10) GET_LOCK('l12',10) GET_LOCK('l13',10) GET_LOCK('l14',10) GET_LOCK('l15',10) +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA +FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA; +LOCK_MODE LOCK_TYPE TABLE_SCHEMA +MDL_SHARED_NO_WRITE User lock l01 +MDL_SHARED_NO_WRITE User lock l02 +MDL_SHARED_NO_WRITE User lock l03 +MDL_SHARED_NO_WRITE User lock l04 +MDL_SHARED_NO_WRITE User lock l05 +MDL_SHARED_NO_WRITE User lock l06 +MDL_SHARED_NO_WRITE User lock l07 +MDL_SHARED_NO_WRITE User lock l08 +MDL_SHARED_NO_WRITE User lock l09 +MDL_SHARED_NO_WRITE User lock l10 +MDL_SHARED_NO_WRITE User lock l11 +MDL_SHARED_NO_WRITE User lock l12 +MDL_SHARED_NO_WRITE User lock l13 +MDL_SHARED_NO_WRITE User lock l14 +MDL_SHARED_NO_WRITE User lock l15 +SELECT RELEASE_ALL_LOCKS(); +RELEASE_ALL_LOCKS() +15 +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA +FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA; +LOCK_MODE LOCK_TYPE TABLE_SCHEMA +# Test function with recursive locks +SELECT GET_LOCK('l1',10), +GET_LOCK('l2',10), +GET_LOCK('l2',10), +GET_LOCK('l3',10), +GET_LOCK('l3',10), +GET_LOCK('l3',10), +GET_LOCK('l4',10), +GET_LOCK('l4',10), +GET_LOCK('l4',10), +GET_LOCK('l4',10), +GET_LOCK('l5',10), +GET_LOCK('l5',10), +GET_LOCK('l5',10), +GET_LOCK('l5',10), +GET_LOCK('l5',10); +GET_LOCK('l1',10) GET_LOCK('l2',10) GET_LOCK('l2',10) GET_LOCK('l3',10) GET_LOCK('l3',10) GET_LOCK('l3',10) GET_LOCK('l4',10) GET_LOCK('l4',10) GET_LOCK('l4',10) GET_LOCK('l4',10) GET_LOCK('l5',10) GET_LOCK('l5',10) GET_LOCK('l5',10) GET_LOCK('l5',10) GET_LOCK('l5',10) +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA +FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA; +LOCK_MODE LOCK_TYPE TABLE_SCHEMA +MDL_SHARED_NO_WRITE User lock l1 +MDL_SHARED_NO_WRITE User lock l2 +MDL_SHARED_NO_WRITE User lock l3 +MDL_SHARED_NO_WRITE User lock l4 +MDL_SHARED_NO_WRITE User lock l5 +SELECT RELEASE_ALL_LOCKS(); +RELEASE_ALL_LOCKS() +15 +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA +FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA; +LOCK_MODE LOCK_TYPE TABLE_SCHEMA diff --git a/mysql-test/main/func_misc.test b/mysql-test/main/func_misc.test index 7d19c9e58af..951553705ab 100644 --- a/mysql-test/main/func_misc.test +++ b/mysql-test/main/func_misc.test @@ -1,7 +1,7 @@ # # Testing of misc functions # - +--source include/have_metadata_lock_info.inc --source include/default_optimizer_switch.inc --disable_warnings DROP TABLE IF EXISTS t1, t2; @@ -1278,3 +1278,60 @@ DROP TABLE t1; --echo # --echo # End of 10.4 tests --echo # + +--echo # +--echo # MDEV-10569 Add RELEASE_ALL_LOCKS SQL-function +--echo # + +--echo # Test function without any locks +SELECT RELEASE_ALL_LOCKS(); + +--echo # Test function with one lock only +SELECT GET_LOCK('l1',10); +SELECT RELEASE_ALL_LOCKS(); +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA +FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA; + +--echo # Test function with multiple locks +SELECT GET_LOCK('l01',10), + GET_LOCK('l02',10), + GET_LOCK('l03',10), + GET_LOCK('l04',10), + GET_LOCK('l05',10), + GET_LOCK('l06',10), + GET_LOCK('l07',10), + GET_LOCK('l08',10), + GET_LOCK('l09',10), + GET_LOCK('l10',10), + GET_LOCK('l11',10), + GET_LOCK('l12',10), + GET_LOCK('l13',10), + GET_LOCK('l14',10), + GET_LOCK('l15',10); +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA +FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA; +SELECT RELEASE_ALL_LOCKS(); +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA +FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA; + +--echo # Test function with recursive locks +SELECT GET_LOCK('l1',10), + GET_LOCK('l2',10), + GET_LOCK('l2',10), + GET_LOCK('l3',10), + GET_LOCK('l3',10), + GET_LOCK('l3',10), + GET_LOCK('l4',10), + GET_LOCK('l4',10), + GET_LOCK('l4',10), + GET_LOCK('l4',10), + GET_LOCK('l5',10), + GET_LOCK('l5',10), + GET_LOCK('l5',10), + GET_LOCK('l5',10), + GET_LOCK('l5',10); +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA +FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA; +SELECT RELEASE_ALL_LOCKS(); +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA +FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA;
\ No newline at end of file diff --git a/sql/item_create.cc b/sql/item_create.cc index 486f4fc591e..57e402999ea 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1765,6 +1765,15 @@ protected: }; +class Create_func_release_all_locks : public Create_func_arg0 +{ +public: + virtual Item *create_builder(THD *thd); + + static Create_func_release_all_locks s_singleton; +}; + + class Create_func_release_lock : public Create_func_arg1 { public: @@ -4762,6 +4771,17 @@ Create_func_rand::create_native(THD *thd, LEX_CSTRING *name, } +Create_func_release_all_locks Create_func_release_all_locks::s_singleton; + +Item* +Create_func_release_all_locks::create_builder(THD *thd) +{ + thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); + return new (thd->mem_root) Item_func_release_all_locks(thd); +} + + Create_func_release_lock Create_func_release_lock::s_singleton; Item* @@ -5525,6 +5545,8 @@ static Native_func_registry func_array[] = { { STRING_WITH_LEN("REGEXP_SUBSTR") }, BUILDER(Create_func_regexp_substr)}, { { STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)}, { { STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)}, + { { STRING_WITH_LEN("RELEASE_ALL_LOCKS") }, + BUILDER(Create_func_release_all_locks)}, { { STRING_WITH_LEN("RELEASE_LOCK") }, BUILDER(Create_func_release_lock)}, { { STRING_WITH_LEN("REPLACE_ORACLE") }, BUILDER(Create_func_replace_oracle)}, diff --git a/sql/item_func.cc b/sql/item_func.cc index 0419d55cc58..14a17bd09de 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4028,7 +4028,7 @@ longlong Item_func_get_lock::val_int() MDL_request ull_request; ull_request.init(MDL_key::USER_LOCK, res->c_ptr_safe(), "", MDL_SHARED_NO_WRITE, MDL_EXPLICIT); - MDL_key *ull_key = &ull_request.key; + MDL_key *ull_key= &ull_request.key; if ((ull= (User_level_lock*) @@ -4036,7 +4036,7 @@ longlong Item_func_get_lock::val_int() { /* Recursive lock */ ull->refs++; - null_value = 0; + null_value= 0; DBUG_PRINT("info", ("recursive lock, ref-count: %d", (int) ull->refs)); DBUG_RETURN(1); } @@ -4076,6 +4076,30 @@ longlong Item_func_get_lock::val_int() /** + Release all user level locks. + @return + - N if N-lock released + - 0 if lock wasn't held +*/ +longlong Item_func_release_all_locks::val_int() +{ + DBUG_ASSERT(fixed == 1); + THD *thd= current_thd; + ulong num_unlocked= 0; + DBUG_ENTER("Item_func_release_all_locks::val_int"); + for (size_t i= 0; i < thd->ull_hash.records; i++) + { + auto ull= (User_level_lock *) my_hash_element(&thd->ull_hash, i); + thd->mdl_context.release_lock(ull->lock); + num_unlocked+= ull->refs; + my_free(ull); + } + my_hash_free(&thd->ull_hash); + DBUG_RETURN(num_unlocked); +} + + +/** Release a user level lock. @return - 1 if lock released diff --git a/sql/item_func.h b/sql/item_func.h index dced158bb86..2ff806492cf 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2654,19 +2654,13 @@ public: void mysql_ull_cleanup(THD *thd); void mysql_ull_set_explicit_lock_duration(THD *thd); -class Item_func_get_lock :public Item_long_func + +class Item_func_lock :public Item_long_func { - bool check_arguments() const - { - return args[0]->check_type_general_purpose_string(func_name()) || - args[1]->check_type_can_return_real(func_name()); - } - String value; public: - Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_long_func(thd, a, b) {} - longlong val_int(); - const char *func_name() const { return "get_lock"; } - bool fix_length_and_dec() { max_length=1; maybe_null=1; return FALSE; } + Item_func_lock(THD *thd): Item_long_func(thd) { } + Item_func_lock(THD *thd, Item *a): Item_long_func(thd, a) {} + Item_func_lock(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} table_map used_tables() const { return used_tables_cache | RAND_TABLE_BIT; @@ -2677,34 +2671,54 @@ class Item_func_get_lock :public Item_long_func { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } - Item *get_copy(THD *thd) +}; + + +class Item_func_get_lock final :public Item_func_lock +{ + bool check_arguments() const + { + return args[0]->check_type_general_purpose_string(func_name()) || + args[1]->check_type_can_return_real(func_name()); + } + String value; + public: + Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_func_lock(thd, a, b) {} + longlong val_int() final; + const char *func_name() const final { return "get_lock"; } + bool fix_length_and_dec() { max_length= 1; maybe_null= 1; return FALSE; } + Item *get_copy(THD *thd) final { return get_item_copy<Item_func_get_lock>(thd, this); } }; -class Item_func_release_lock :public Item_long_func + +class Item_func_release_all_locks final :public Item_func_lock +{ +public: + Item_func_release_all_locks(THD *thd): Item_func_lock(thd) + { unsigned_flag= 1; } + longlong val_int() final; + const char *func_name() const final { return "release_all_locks"; } + Item *get_copy(THD *thd) final + { return get_item_copy<Item_func_release_all_locks>(thd, this); } +}; + + +class Item_func_release_lock final :public Item_func_lock { bool check_arguments() const { return args[0]->check_type_general_purpose_string(func_name()); } String value; public: - Item_func_release_lock(THD *thd, Item *a): Item_long_func(thd, a) {} - longlong val_int(); + Item_func_release_lock(THD *thd, Item *a): Item_func_lock(thd, a) {} + longlong val_int() final; const char *func_name() const { return "release_lock"; } bool fix_length_and_dec() { max_length= 1; maybe_null= 1; return FALSE; } - table_map used_tables() const - { - return used_tables_cache | RAND_TABLE_BIT; - } - bool const_item() const { return 0; } - bool is_expensive() { return 1; } - bool check_vcol_func_processor(void *arg) - { - return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); - } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) final { return get_item_copy<Item_func_release_lock>(thd, this); } }; + /* replication functions */ class Item_master_pos_wait :public Item_longlong_func |