Commit 127fee99 authored by Daniel-Solo's avatar Daniel-Solo Committed by Sergey Vojtovich

MDEV-10569: Add RELEASE_ALL_LOCKS function. Implementing the SQL

function to release all named locks
parent 98adcffe
......@@ -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
#
# 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
......@@ -1765,6 +1765,15 @@ class Create_func_rand : public Create_native_func
};
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)},
......
......@@ -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);
}
......@@ -4075,6 +4075,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
......
......@@ -2654,19 +2654,13 @@ class Item_func_udf_str :public Item_func
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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment