WL#3337 (Event scheduler new architecture)

This patch introduces specialized Event data objects
Event_basic as parent.
Event_queue_element used for queue storage
Event_timed used for SHOW EVENTS/ I_S.EVENTS / SHOW CREATE EVENT
Event_job_data using during execution.
Methods were moved out of Event_timed to other classes.

This patch also introduces Events::LOCK_event_metadata.
This patch gives new implementation of Events::dump_internal_status().
Now both the Event_scheduler and Event_queue return information during
their ::dump_internal_status().

Shortened a bit the runtime for executing events test cases.


mysql-test/r/events.result:
  update results
mysql-test/r/events_bugs.result:
  update results
mysql-test/r/events_logs_tests.result:
  update results
mysql-test/r/events_scheduling.result:
  update results
mysql-test/t/events.test:
  update test
  make --sleep more appropriate . saving some time could mean failure on loaded boxes though :(
  add tests for previously uncovered branches.
mysql-test/t/events_bugs.test:
  update test
  make --sleep more appropriate . saving some time could mean failure on loaded boxes though :(
  add tests for previously uncovered branches.
mysql-test/t/events_logs_tests.test:
  make the test shorter by time
mysql-test/t/events_scheduling.test:
  when selecting always use ORDER BY
mysql-test/t/events_stress.test:
  sleep 2.5secs for shorter stress test
sql/event_data_objects.cc:
  Event_timed is no more used during execution.
  Event_timed is no more used during in the memory queue.
  Event_timed is only used for SHOW CREATE EVENT/ I_S.EVENTS/ SHOW EVENTS
  Event_basic is the parent of almost all Event data objects.
  Event_basic -> Event_queue_element (used for the memory queue) -> Event_timed
  Event_basic -> Event_job_data (the object used for execution)
  Sql_alloc -> Event_parse_data (used during parsing)
sql/event_data_objects.h:
  Event_timed is no more used during execution.
  Event_timed is no more used during in the memory queue.
  Event_timed is only used for SHOW CREATE EVENT/ I_S.EVENTS/ SHOW EVENTS
  Event_basic is the parent of almost all Event data objects.
  Event_basic -> Event_queue_element (used for the memory queue) -> Event_timed
  Event_basic -> Event_job_data (the object used for execution)
  Sql_alloc -> Event_parse_data (used during parsing)
sql/event_db_repository.cc:
  Cosmetics.
  load_named_event now uses Event_basic, for polymorphism
  find_event uses Event_basic, to be polymorphic.
  use Field **fields= table->field and then index fields[...]
  Add documentation.
  Fix documentation.
sql/event_db_repository.h:
  Event_db_repository depends only on Event_basic's interface
sql/event_queue.cc:
  Cosmetics.
  Don't use Event_timed for the queue and giving back object for execution.
  Event_queue_element is for the queue, Event_job_data is for execution.
  Add Event_queue::dump_internal_status() for SHOW SCHEDULER STATUS command
sql/event_queue.h:
  Cosmetics.
  Don't use Event_timed for the queue and giving back object for execution.
  Event_queue_element is for the queue, Event_job_data is for execution.
  Add Event_queue::dump_internal_status() for SHOW SCHEDULER STATUS command
sql/event_scheduler_ng.cc:
  Add back Event_scheduler::cond_wait()
  Add back Event_scheduler::dump_internal_status()
  Using Event_job_data for execution. Make the scheduler thread unkillable (thd->command= COM_DAEMON).
  Add a lot of documentation.
sql/event_scheduler_ng.h:
  Add back Event_scheduler::cond_wait()
  Add back Event_scheduler::dump_internal_status()
  Using Event_job_data for execution.
sql/events.cc:
  Documentation
  Add LOCK_event_metadata
sql/events.h:
  Change the signature of Events::drop_event() not to use sp_name but LEX_STRING
sql/share/errmsg.txt:
  Fix error message
sql/sql_parse.cc:
  Events::drop_event() has new signature
This commit is contained in:
unknown 2006-07-10 13:44:43 +02:00
parent b9a7fe2757
commit 974eecc246
21 changed files with 2305 additions and 1702 deletions

View File

@ -87,7 +87,6 @@ events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLE
DROP EVENT event_starts_test;
create table test_nested(a int);
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
alter event e_43 do alter event e_43 do set @a = 4;
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
alter event e_43 do
@ -207,6 +206,10 @@ ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
SHOW EVENTS;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
drop event root22;
create event root23 on schedule every -100 year do select 1;
ERROR HY000: INTERVAL is either not positive or too big
create event root23 on schedule every 222222222222222222222 year do select 1;
ERROR HY000: INTERVAL is either not positive or too big
drop event root6;
drop event root7;
drop event root8;
@ -342,7 +345,7 @@ create event закачка on schedule every 10 hour do select get_lock("test_l
"Should have only 2 processes: the scheduler and the locked event"
select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Waiting for next activation NULL
event_scheduler localhost NULL Daemon Waiting for next activation NULL
root localhost events_test Connect User lock select get_lock("test_lock2", 20)
"Release the mutex, the event worker should finish."
"Release the mutex, the event worker should finish."
@ -358,7 +361,7 @@ create event закачка21 on schedule every 10 hour do select get_lock("test
"Should have only 3 processes: the scheduler, our conn and the locked event"
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Waiting for next activation NULL
event_scheduler localhost NULL Daemon Waiting for next activation NULL
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
set global event_scheduler=2;
"Should have only our process now:"

View File

@ -24,8 +24,19 @@ create event e_55 on schedule every 10 hour starts 99990101000000 do drop table
ERROR HY000: Incorrect STARTS value: '99990101000000'
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
ERROR HY000: ENDS is either invalid or before STARTS
create event e_55 on schedule at 10000101000000 do drop table t;
ERROR HY000: Activation (AT) time is in the past
create event e_55 on schedule at 20000101000000 do drop table t;
ERROR HY000: Activation (AT) time is in the past
create event e_55 on schedule at 20200101000000 starts 10000101000000 do drop table t;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'starts 10000101000000 do drop table t' at line 1
create event e_55 on schedule at 20200101000000 ends 10000101000000 do drop table t;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ends 10000101000000 do drop table t' at line 1
create event e_55 on schedule at 20200101000000 starts 10000101000000 ends 10000101000000 do drop table t;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'starts 10000101000000 ends 10000101000000 do drop table t' at line 1
create event e_55 on schedule every 10 hour starts 10000101000000 do drop table t;
ERROR HY000: Incorrect STARTS value: '10000101000000'
set global event_scheduler=2;
"Wait a bit to settle down"
delete from mysql.event;
set global event_scheduler= 1;
set @old_sql_mode:=@@sql_mode;
@ -41,7 +52,7 @@ end|
"Now if everything is fine the event has compiled and is locked
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Waiting for next activation NULL
event_scheduler localhost NULL Daemon Waiting for next activation NULL
root localhost events_test Connect User lock select get_lock('test_bug16407', 60)
select release_lock('test_bug16407');
release_lock('test_bug16407')
@ -57,6 +68,11 @@ select event_schema, event_name, sql_mode from information_schema.events order b
event_schema event_name sql_mode
events_test e_16407 STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
drop event e_16407;
set sql_mode="ansi";
select get_lock('ee_16407_2', 60);
get_lock('ee_16407_2', 60)
1
set global event_scheduler= 1;
"Another sql_mode test"
set sql_mode="traditional";
create table events_smode_test(ev_name char(10), a date) engine=myisam;
@ -64,6 +80,7 @@ create table events_smode_test(ev_name char(10), a date) engine=myisam;
create event ee_16407_2 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_2*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values('ee_16407_2','1980-19-02');
end|
insert into events_smode_test values ('test','1980-19-02')|
@ -72,6 +89,7 @@ ERROR 22007: Incorrect date value: '1980-19-02' for column 'a' at row 1
create event ee_16407_3 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_3*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-19');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
end|
@ -80,6 +98,7 @@ set sql_mode=""|
create event ee_16407_4 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_4*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_4','10-11-1956');
end|
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
@ -87,14 +106,9 @@ event_schema event_name sql_mode
events_test ee_16407_2 STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
events_test ee_16407_3 STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
events_test ee_16407_4
set sql_mode="ansi";
select get_lock('ee_16407_2', 60);
get_lock('ee_16407_2', 60)
1
set global event_scheduler= 1;
select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Waiting for next activation NULL
event_scheduler localhost NULL Daemon Waiting for next activation NULL
root localhost events_test Connect User lock select get_lock('ee_16407_2', 60) /*ee_16407_2*/
root localhost events_test Connect User lock select get_lock('ee_16407_2', 60) /*ee_16407_3*/
root localhost events_test Connect User lock select get_lock('ee_16407_2', 60) /*ee_16407_4*/
@ -103,7 +117,7 @@ release_lock('ee_16407_2')
1
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Waiting for next activation NULL
event_scheduler localhost NULL Daemon Waiting for next activation NULL
set global event_scheduler= 2;
select * from events_smode_test order by ev_name, a;
ev_name a
@ -121,28 +135,30 @@ drop event ee_16407_3;
drop event ee_16407_4;
"And now one last test regarding sql_mode and call of SP from an event"
delete from events_smode_test;
set sql_mode='ansi';
select get_lock('ee_16407_5', 60);
get_lock('ee_16407_5', 60)
1
set global event_scheduler= 1;
set sql_mode='traditional';
create procedure ee_16407_5_pendant() begin insert into events_test.events_smode_test values('ee_16407_5','2001-02-29'); end|
create procedure ee_16407_6_pendant() begin insert into events_test.events_smode_test values('ee_16407_6','2004-02-29'); end|
create event ee_16407_5 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
select release_lock('ee_16407_5');
call events_test.ee_16407_5_pendant();
end|
create event ee_16407_6 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
select release_lock('ee_16407_5');
call events_test.ee_16407_6_pendant();
end|
set sql_mode='ansi';
select get_lock('ee_16407_5', 60);
get_lock('ee_16407_5', 60)
1
set global event_scheduler= 1;
"Should have 2 locked processes"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Waiting for next activation NULL
event_scheduler localhost NULL Daemon Waiting for next activation NULL
root localhost events_test Connect User lock select get_lock('ee_16407_5', 60) /*ee_16407_5*/
root localhost events_test Connect User lock select get_lock('ee_16407_5', 60) /*ee_16407_6*/
select release_lock('ee_16407_5');
@ -151,7 +167,7 @@ release_lock('ee_16407_5')
"Should have 0 processes locked"
select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Waiting for next activation NULL
event_scheduler localhost NULL Daemon Waiting for next activation NULL
select * from events_smode_test order by ev_name, a;
ev_name a
ee_16407_6 2004-02-29

View File

@ -9,7 +9,7 @@ SELECT user_host, argument FROM mysql.general_log WHERE argument LIKE '%alabala%
END|
"Check General Query Log"
SET GLOBAL event_scheduler=2;
create event log_general on schedule every 1 minute do SELect 'alabala', sleep(3) from dual;
create event log_general on schedule every 1 minute do SELect 'alabala', sleep(1) from dual;
TRUNCATE mysql.general_log;
"1 row, the current statement!"
call select_general_log();
@ -19,7 +19,7 @@ SET GLOBAL event_scheduler=1;
"Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
call select_general_log();
user_host argument
USER_HOST SELect 'alabala', sleep(3) from dual
USER_HOST SELect 'alabala', sleep(1) from dual
DROP PROCEDURE select_general_log;
DROP EVENT log_general;
SET GLOBAL event_scheduler=2;
@ -49,13 +49,13 @@ USER_HOST SLEEPVAL events_test SELECT SLEEP(2)
SET SESSION long_query_time=300;
"Make it quite long"
TRUNCATE mysql.slow_log;
SET SESSION long_query_time=1;
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
"This won't go to the slow log"
CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(3);
SELECT * FROM slow_event_test;
slo_val val
SET SESSION long_query_time=1;
SET GLOBAL event_scheduler=1;
CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(1.5);
"Sleep some more time than the actual event run will take"
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
@ -64,7 +64,7 @@ event_scheduler 1
SELECT * FROM slow_event_test;
slo_val val
4 0
"Check slow log. Should not see anything because 3 is under the threshold of 4 for GLOBAL, though over SESSION which is 2"
"Check slow log. Should not see anything because 1.5 is under the threshold of 300 for GLOBAL, though over SESSION which is 2"
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
"This should go to the slow log"

View File

@ -39,7 +39,7 @@ DROP EVENT start_n_end;
DROP EVENT only_one_time;
ERROR HY000: Unknown event 'only_one_time'
"Should be preserved"
SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS;
SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS ORDER BY EVENT_NAME;
EVENT_NAME STATUS
E19170 ENABLED
two_time DISABLED

View File

@ -18,7 +18,7 @@ CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE x_table;
connection default;
SHOW DATABASES LIKE 'db_x';
SET GLOBAL event_scheduler=1;
--sleep 1.5
--sleep 0.8
SHOW DATABASES LIKE 'db_x';
SHOW TABLES FROM db_x;
SET GLOBAL event_scheduler=2;
@ -83,7 +83,6 @@ DROP EVENT event_starts_test;
#
create table test_nested(a int);
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
--error 1562
alter event e_43 do alter event e_43 do set @a = 4;
delimiter |;
@ -94,7 +93,7 @@ begin
end|
delimiter ;|
set global event_scheduler = 1;
--sleep 1
--sleep 3
select db, name, body, status, interval_field, interval_value from mysql.event;
drop event e_43;
drop table test_nested;
@ -102,7 +101,7 @@ drop table test_nested;
--echo "Let's check whether we can use non-qualified names"
create table non_qualif(a int);
create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values (800219);
--sleep 1
--sleep 0.5
select * from non_qualif;
drop event non_qualif_ev;
drop table non_qualif;
@ -165,6 +164,10 @@ show create event root22;
--error ER_NOT_SUPPORTED_YET
SHOW EVENTS;
drop event root22;
--error ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG
create event root23 on schedule every -100 year do select 1;
--error ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG
create event root23 on schedule every 222222222222222222222 year do select 1;
drop event root6;
drop event root7;
drop event root8;
@ -294,7 +297,7 @@ select get_lock("test_lock2", 20);
--echo "Create an event which tries to acquire a mutex. The event locks on the mutex"
create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
--echo "Let some time pass to the event starts"
--sleep 1
--sleep 0.5
--echo "Should have only 2 processes: the scheduler and the locked event"
select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;--echo "Release the mutex, the event worker should finish."
--echo "Release the mutex, the event worker should finish."
@ -312,10 +315,11 @@ drop event закачка;
set global event_scheduler=1;
select get_lock("test_lock2_1", 20);
create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
--sleep 1
--sleep 0.5
--echo "Should have only 3 processes: the scheduler, our conn and the locked event"
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
set global event_scheduler=2;
--sleep 0.3
--echo "Should have only our process now:"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
drop event закачка21;

View File

@ -45,6 +45,19 @@ create event e_55 on schedule at 99990101000000 do drop table t;
create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;
--error ER_EVENT_ENDS_BEFORE_STARTS
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
--error ER_EVENT_EXEC_TIME_IN_THE_PAST
create event e_55 on schedule at 10000101000000 do drop table t;
--error ER_EVENT_EXEC_TIME_IN_THE_PAST
create event e_55 on schedule at 20000101000000 do drop table t;
--error ER_PARSE_ERROR
create event e_55 on schedule at 20200101000000 starts 10000101000000 do drop table t;
--error ER_PARSE_ERROR
create event e_55 on schedule at 20200101000000 ends 10000101000000 do drop table t;
--error ER_PARSE_ERROR
create event e_55 on schedule at 20200101000000 starts 10000101000000 ends 10000101000000 do drop table t;
--error ER_WRONG_VALUE
create event e_55 on schedule every 10 hour starts 10000101000000 do drop table t;
#
# End - 16396: Events: Distant-future dates become past dates
#
@ -53,8 +66,6 @@ create event e_55 on schedule every 10 minute ends 99990101000000 do drop table
# Start - 16407: Events: Changes in sql_mode won't be taken into account
#
set global event_scheduler=2;
--echo "Wait a bit to settle down"
--sleep 1
delete from mysql.event;
set global event_scheduler= 1;
set @old_sql_mode:=@@sql_mode;
@ -67,11 +78,13 @@ begin
drop table "hashed_num";
end|
delimiter ;|
--sleep 1
--sleep 0.5
--echo "Now if everything is fine the event has compiled and is locked
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('test_bug16407');
set global event_scheduler= 2;
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
--echo "Let's check whether we change the sql_mode on ALTER EVENT"
set sql_mode='traditional';
@ -79,6 +92,10 @@ alter event e_16407 do select 1;
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
drop event e_16407;
set sql_mode="ansi";
select get_lock('ee_16407_2', 60);
set global event_scheduler= 1;
--echo "Another sql_mode test"
set sql_mode="traditional";
create table events_smode_test(ev_name char(10), a date) engine=myisam;
@ -87,6 +104,7 @@ delimiter |;
create event ee_16407_2 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_2*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values('ee_16407_2','1980-19-02');
end|
--error ER_TRUNCATED_WRONG_VALUE
@ -95,6 +113,7 @@ insert into events_smode_test values ('test','1980-19-02')|
create event ee_16407_3 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_3*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-19');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
end|
@ -103,17 +122,15 @@ set sql_mode=""|
create event ee_16407_4 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_4*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_4','10-11-1956');
end|
delimiter ;|
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
set sql_mode="ansi";
select get_lock('ee_16407_2', 60);
set global event_scheduler= 1;
--sleep 1
--sleep 0.5
select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_2');
--sleep 2
--sleep 0.8
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
set global event_scheduler= 2;
select * from events_smode_test order by ev_name, a;
@ -126,6 +143,11 @@ drop event ee_16407_4;
--echo "And now one last test regarding sql_mode and call of SP from an event"
delete from events_smode_test;
set sql_mode='ansi';
select get_lock('ee_16407_5', 60);
set global event_scheduler= 1;
set sql_mode='traditional';
delimiter |;
create procedure ee_16407_5_pendant() begin insert into events_test.events_smode_test values('ee_16407_5','2001-02-29'); end|
@ -133,22 +155,21 @@ create procedure ee_16407_6_pendant() begin insert into events_test.events_smode
create event ee_16407_5 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
select release_lock('ee_16407_5');
call events_test.ee_16407_5_pendant();
end|
create event ee_16407_6 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
select release_lock('ee_16407_5');
call events_test.ee_16407_6_pendant();
end|
delimiter ;|
set sql_mode='ansi';
select get_lock('ee_16407_5', 60);
set global event_scheduler= 1;
--sleep 1
--sleep 0.5
--echo "Should have 2 locked processes"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_5');
--sleep 2
--sleep 0.8
--echo "Should have 0 processes locked"
select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select * from events_smode_test order by ev_name, a;

View File

@ -14,7 +14,7 @@ END|
delimiter ;|
--echo "Check General Query Log"
SET GLOBAL event_scheduler=2;
create event log_general on schedule every 1 minute do SELect 'alabala', sleep(3) from dual;
create event log_general on schedule every 1 minute do SELect 'alabala', sleep(1) from dual;
TRUNCATE mysql.general_log;
--echo "1 row, the current statement!"
--replace_column 1 USER_HOST
@ -22,13 +22,12 @@ call select_general_log();
SET GLOBAL event_scheduler=1;
--echo "Wait the scheduler to start"
--echo "Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
--sleep 2
--sleep 0.7
--replace_column 1 USER_HOST
call select_general_log();
DROP PROCEDURE select_general_log;
DROP EVENT log_general;
SET GLOBAL event_scheduler=2;
--sleep 1
--echo "Check slow query log"
--disable_query_log
@ -69,18 +68,18 @@ SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
SET SESSION long_query_time=300;
--echo "Make it quite long"
TRUNCATE mysql.slow_log;
SET SESSION long_query_time=1;
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
--echo "This won't go to the slow log"
CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(3);
SELECT * FROM slow_event_test;
SET SESSION long_query_time=1;
SET GLOBAL event_scheduler=1;
CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(1.5);
--echo "Sleep some more time than the actual event run will take"
--sleep 5
--sleep 2
SHOW VARIABLES LIKE 'event_scheduler';
--echo "Check our table. Should see 1 row"
SELECT * FROM slow_event_test;
--echo "Check slow log. Should not see anything because 3 is under the threshold of 4 for GLOBAL, though over SESSION which is 2"
--echo "Check slow log. Should not see anything because 1.5 is under the threshold of 300 for GLOBAL, though over SESSION which is 2"
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
--echo "This should go to the slow log"
DROP EVENT long_event;
@ -88,7 +87,7 @@ SET SESSION long_query_time=10;
SET GLOBAL long_query_time=1;
CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2);
--echo "Sleep some more time than the actual event run will take"
--sleep 3
--sleep 2.5
--echo "Check our table. Should see 2 rows"
SELECT * FROM slow_event_test;
--echo "Check slow log. Should see 1 row because 4 is over the threshold of 3 for GLOBAL, though under SESSION which is 10"

View File

@ -34,7 +34,7 @@ DROP EVENT start_n_end;
--error ER_EVENT_DOES_NOT_EXIST
DROP EVENT only_one_time;
--echo "Should be preserved"
SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS;
SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS ORDER BY EVENT_NAME;
DROP EVENT two_time;
DROP TABLE table_1;
DROP TABLE table_2;

View File

@ -61,7 +61,7 @@ while ($1)
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
SET GLOBAL event_scheduler=1;
--sleep 12
--sleep 2.5
DROP DATABASE events_conn1_test2;
SET GLOBAL event_scheduler=2;
@ -100,7 +100,7 @@ while ($1)
}
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
--sleep 12
--sleep 2.5
connection conn2;
--send
DROP DATABASE events_conn2_db;

File diff suppressed because it is too large Load Diff

View File

@ -47,30 +47,46 @@
class sp_head;
class Sql_alloc;
class Event_timed;
class Event_basic;
/* Compares only the schema part of the identifier */
bool
event_timed_db_equal(Event_timed *et, LEX_STRING *db);
event_basic_db_equal( LEX_STRING *db, Event_basic *et);
/* Compares the whole identifier*/
bool
event_timed_identifier_equal(LEX_STRING db, LEX_STRING name, Event_timed *b);
event_basic_identifier_equal(LEX_STRING db, LEX_STRING name, Event_basic *b);
class Event_timed
class Event_basic
{
Event_timed(const Event_timed &); /* Prevent use of these */
void operator=(Event_timed &);
bool status_changed;
bool last_executed_changed;
protected:
MEM_ROOT mem_root;
public:
THD *thd;
LEX_STRING dbname;
LEX_STRING name;
LEX_STRING definer;// combination of user and host
Event_basic();
virtual ~Event_basic();
virtual int
load_from_row(TABLE *table) = 0;
protected:
bool
load_string_fields(Field **fields, ...);
};
class Event_queue_element : public Event_basic
{
protected:
bool status_changed;
bool last_executed_changed;
public:
enum enum_status
{
ENABLED = 1,
@ -83,17 +99,10 @@ public:
ON_COMPLETION_PRESERVE
};
enum enum_on_completion on_completion;
enum enum_status status;
TIME last_executed;
LEX_STRING dbname;
LEX_STRING name;
LEX_STRING body;
LEX_STRING definer_user;
LEX_STRING definer_host;
LEX_STRING definer;// combination of user and host
LEX_STRING comment;
TIME starts;
TIME ends;
TIME execute_at;
@ -104,42 +113,14 @@ public:
longlong expression;
interval_type interval;
ulonglong created;
ulonglong modified;
enum enum_on_completion on_completion;
enum enum_status status;
sp_head *sphead;
ulong sql_mode;
bool dropped;
uint flags;//all kind of purposes
static void *operator new(size_t size)
{
void *p;
DBUG_ENTER("Event_timed::new(size)");
p= my_malloc(size, MYF(0));
DBUG_PRINT("info", ("alloc_ptr=0x%lx", p));
DBUG_RETURN(p);
}
bool dropped;
static void operator delete(void *ptr, size_t size)
{
DBUG_ENTER("Event_timed::delete(ptr,size)");
DBUG_PRINT("enter", ("free_ptr=0x%lx", ptr));
TRASH(ptr, size);
my_free((gptr) ptr, MYF(0));
DBUG_VOID_RETURN;
}
Event_queue_element();
virtual ~Event_queue_element();
Event_timed();
~Event_timed();
void
init();
int
virtual int
load_from_row(TABLE *table);
bool
@ -152,27 +133,97 @@ public:
mark_last_executed(THD *thd);
bool
update_fields(THD *thd);
update_timing_fields(THD *thd);
static void *operator new(size_t size)
{
void *p;
DBUG_ENTER("Event_queue_element::new(size)");
p= my_malloc(size, MYF(0));
DBUG_PRINT("info", ("alloc_ptr=0x%lx", p));
DBUG_RETURN(p);
}
static void operator delete(void *ptr, size_t size)
{
DBUG_ENTER("Event_queue_element::delete(ptr,size)");
DBUG_PRINT("enter", ("free_ptr=0x%lx", ptr));
TRASH(ptr, size);
my_free((gptr) ptr, MYF(0));
DBUG_VOID_RETURN;
}
};
class Event_timed : public Event_queue_element
{
Event_timed(const Event_timed &); /* Prevent use of these */
void operator=(Event_timed &);
public:
LEX_STRING body;
LEX_STRING definer_user;
LEX_STRING definer_host;
LEX_STRING comment;
ulonglong created;
ulonglong modified;
ulong sql_mode;
Event_timed();
virtual ~Event_timed();
void
init();
virtual int
load_from_row(TABLE *table);
int
get_create_event(THD *thd, String *buf);
};
class Event_job_data : public Event_basic
{
public:
THD *thd;
sp_head *sphead;
LEX_STRING body;
LEX_STRING definer_user;
LEX_STRING definer_host;
ulong sql_mode;
Event_job_data();
virtual ~Event_job_data();
virtual int
load_from_row(TABLE *table);
int
execute(THD *thd, MEM_ROOT *mem_root);
private:
int
get_fake_create_event(THD *thd, String *buf);
int
compile(THD *thd, MEM_ROOT *mem_root);
void
free_sp();
Event_job_data(const Event_job_data &); /* Prevent use of these */
void operator=(Event_job_data &);
};
class Event_parse_data : public Sql_alloc
{
Event_parse_data(const Event_parse_data &); /* Prevent use of these */
void operator=(Event_parse_data &);
public:
enum enum_status
{
@ -185,7 +236,6 @@ public:
ON_COMPLETION_DROP = 1,
ON_COMPLETION_PRESERVE
};
enum enum_on_completion on_completion;
enum enum_status status;
@ -193,8 +243,8 @@ public:
LEX_STRING dbname;
LEX_STRING name;
LEX_STRING body;
LEX_STRING definer;// combination of user and host
LEX_STRING body;
LEX_STRING comment;
Item* item_starts;
@ -216,59 +266,41 @@ public:
static Event_parse_data *
new_instance(THD *thd);
Event_parse_data();
~Event_parse_data();
bool
check_parse_data(THD *);
void
init_body(THD *thd);
private:
int
init_definer(THD *thd);
int
init_execute_at(THD *thd, Item *expr);
int
init_interval(THD *thd, Item *expr, interval_type new_interval);
void
init_name(THD *thd, sp_name *spn);
int
init_starts(THD *thd, Item *starts);
init_execute_at(THD *thd);
int
init_ends(THD *thd, Item *ends);
init_interval(THD *thd);
int
init_starts(THD *thd);
int
init_ends(THD *thd);
Event_parse_data();
~Event_parse_data();
void
init_body(THD *thd);
report_bad_value(const char *item_name, Item *bad_item);
Event_parse_data(const Event_parse_data &); /* Prevent use of these */
void operator=(Event_parse_data &);
};
class Event_job_data
{
public:
LEX_STRING dbname;
LEX_STRING name;
sp_head *sphead;
LEX_STRING definer;
LEX_STRING body;
ulong sql_mode;
THD *thd;
Event_job_data(){}
~Event_job_data(){}
int
execute();
private:
int
load_from_disk();
int
compile();
Event_job_data(const Event_job_data &); /* Prevent use of these */
void operator=(Event_job_data &);
};
#endif /* _EVENT_DATA_OBJECTS_H_ */

View File

@ -29,7 +29,8 @@
time_t mysql_event_last_create_time= 0L;
static
TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] =
{
{
{(char *) STRING_WITH_LEN("db")},
{(char *) STRING_WITH_LEN("char(64)")},
@ -128,50 +129,49 @@ TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
Puts some data common to CREATE and ALTER EVENT into a row.
SYNOPSIS
evex_fill_row()
mysql_event_fill_row()
thd THD
table The row to fill out
et Event's data
is_update CREATE EVENT or ALTER EVENT
RETURN VALUE
0 - OK
EVEX_GENERAL_ERROR - bad data
EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
0 OK
EVEX_GENERAL_ERROR Bad data
EVEX_GET_FIELD_FAILED Field count does not match. table corrupted?
DESCRIPTION
Used both when an event is created and when it is altered.
*/
static int
evex_fill_row(THD *thd, TABLE *table, Event_parse_data *et, my_bool is_update)
mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
my_bool is_update)
{
CHARSET_INFO *scs= system_charset_info;
enum enum_events_table_field field_num;
enum enum_events_table_field f_num;
Field **fields= table->field;
DBUG_ENTER("evex_fill_row");
DBUG_ENTER("mysql_event_fill_row");
DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
DBUG_PRINT("info", ("name =[%s]", et->name.str));
DBUG_PRINT("info", ("body =[%s]", et->body.str));
if (table->field[field_num= ET_FIELD_DEFINER]->
if (fields[f_num= ET_FIELD_DEFINER]->
store(et->definer.str, et->definer.length, scs))
goto err_truncate;
if (table->field[field_num= ET_FIELD_DB]->
store(et->dbname.str, et->dbname.length, scs))
if (fields[f_num= ET_FIELD_DB]->store(et->dbname.str, et->dbname.length, scs))
goto err_truncate;
if (table->field[field_num= ET_FIELD_NAME]->
store(et->name.str, et->name.length, scs))
if (fields[f_num= ET_FIELD_NAME]->store(et->name.str, et->name.length, scs))
goto err_truncate;
/* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
table->field[ET_FIELD_ON_COMPLETION]->
store((longlong)et->on_completion, true);
fields[ET_FIELD_ON_COMPLETION]->store((longlong)et->on_completion, TRUE);
table->field[ET_FIELD_STATUS]->store((longlong)et->status, true);
fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE);
/*
Change the SQL_MODE only if body was present in an ALTER EVENT and of course
@ -179,52 +179,46 @@ evex_fill_row(THD *thd, TABLE *table, Event_parse_data *et, my_bool is_update)
*/
if (et->body.str)
{
table->field[ET_FIELD_SQL_MODE]->
store((longlong)thd->variables.sql_mode, true);
if (table->field[field_num= ET_FIELD_BODY]->
store(et->body.str, et->body.length, scs))
fields[ET_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode, TRUE);
if (fields[f_num= ET_FIELD_BODY]->store(et->body.str, et->body.length, scs))
goto err_truncate;
}
if (et->expression)
{
table->field[ET_FIELD_INTERVAL_EXPR]->set_notnull();
table->field[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, true);
fields[ET_FIELD_INTERVAL_EXPR]->set_notnull();
fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE);
table->field[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull();
fields[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull();
/*
In the enum (C) intervals start from 0 but in mysql enum valid values start
from 1. Thus +1 offset is needed!
In the enum (C) intervals start from 0 but in mysql enum valid values
start from 1. Thus +1 offset is needed!
*/
table->field[ET_FIELD_TRANSIENT_INTERVAL]->
store((longlong)et->interval+1, true);
fields[ET_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1, TRUE);
table->field[ET_FIELD_EXECUTE_AT]->set_null();
fields[ET_FIELD_EXECUTE_AT]->set_null();
if (!et->starts_null)
{
table->field[ET_FIELD_STARTS]->set_notnull();
table->field[ET_FIELD_STARTS]->
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
fields[ET_FIELD_STARTS]->set_notnull();
fields[ET_FIELD_STARTS]->store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
}
if (!et->ends_null)
{
table->field[ET_FIELD_ENDS]->set_notnull();
table->field[ET_FIELD_ENDS]->
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
fields[ET_FIELD_ENDS]->set_notnull();
fields[ET_FIELD_ENDS]->store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
}
}
else if (et->execute_at.year)
{
table->field[ET_FIELD_INTERVAL_EXPR]->set_null();
table->field[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
table->field[ET_FIELD_STARTS]->set_null();
table->field[ET_FIELD_ENDS]->set_null();
fields[ET_FIELD_INTERVAL_EXPR]->set_null();
fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
fields[ET_FIELD_STARTS]->set_null();
fields[ET_FIELD_ENDS]->set_null();
table->field[ET_FIELD_EXECUTE_AT]->set_notnull();
table->field[ET_FIELD_EXECUTE_AT]->
fields[ET_FIELD_EXECUTE_AT]->set_notnull();
fields[ET_FIELD_EXECUTE_AT]->
store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
}
else
@ -236,47 +230,23 @@ evex_fill_row(THD *thd, TABLE *table, Event_parse_data *et, my_bool is_update)
*/
}
((Field_timestamp *)table->field[ET_FIELD_MODIFIED])->set_time();
((Field_timestamp *)fields[ET_FIELD_MODIFIED])->set_time();
if (et->comment.str)
{
if (table->field[field_num= ET_FIELD_COMMENT]->
if (fields[f_num= ET_FIELD_COMMENT]->
store(et->comment.str, et->comment.length, scs))
goto err_truncate;
}
DBUG_RETURN(0);
err_truncate:
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name);
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), fields[f_num]->field_name);
DBUG_RETURN(EVEX_GENERAL_ERROR);
}
/*
Find row in open mysql.event table representing event
SYNOPSIS
evex_db_find_event_by_name()
thd Thread context
dbname Name of event's database
rname Name of the event inside the db
table TABLE object for open mysql.event table.
RETURN VALUE
0 - Routine found
EVEX_KEY_NOT_FOUND - No routine with given name
*/
int
evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
const LEX_STRING ev_name,
TABLE *table)
{
return Events::get_instance()->db_repository->
find_event_by_name(thd, dbname, ev_name, table);
}
/*
Performs an index scan of event_table (mysql.event) and fills schema_table.
@ -313,7 +283,7 @@ Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table,
if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
{
ret= 1;
/* don't send error, it would be done by sql_alloc_error_handler() */
/* Don't send error, it would be done by sql_alloc_error_handler() */
}
else
{
@ -440,100 +410,14 @@ Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables, char *db)
}
/*
Looks for a named event in mysql.event and in case of success returns
an object will data loaded from the table.
SYNOPSIS
Event_db_repository::find_event()
thd THD
name the name of the event to find
ett event's data if event is found
tbl TABLE object to use when not NULL
root On which root to load the event
NOTES
1) Use sp_name for look up, return in **ett if found
2) tbl is not closed at exit
RETURN VALUE
0 ok In this case *ett is set to the event
# error *ett == 0
*/
int
Event_db_repository::find_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
Event_timed **ett, TABLE *tbl)
{
TABLE *table;
int ret;
Event_timed *et= NULL;
DBUG_ENTER("Event_db_repository::find_event");
DBUG_PRINT("enter", ("name: %*s", name.length, name.str));
if (tbl)
table= tbl;
else if (open_event_table(thd, TL_READ, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
ret= EVEX_GENERAL_ERROR;
goto done;
}
if ((ret= evex_db_find_event_by_name(thd, dbname, name, table)))
{
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
goto done;
}
et= new Event_timed;
/*
1)The table should not be closed beforehand. ::load_from_row() only loads
and does not compile
2)::load_from_row() is silent on error therefore we emit error msg here
*/
if ((ret= et->load_from_row(table)))
{
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
goto done;
}
done:
if (ret)
{
delete et;
et= NULL;
}
/* don't close the table if we haven't opened it ourselves */
if (!tbl && table)
close_thread_tables(thd);
*ett= et;
DBUG_RETURN(ret);
}
int
Event_db_repository::init_repository()
{
return 0;
}
void
Event_db_repository::deinit_repository()
{
}
/*
Open mysql.event table for read
SYNOPSIS
Events::open_event_table()
thd Thread context
lock_type How to lock the table
table We will store the open table here
thd [in] Thread context
lock_type [in] How to lock the table
table [out] We will store the open table here
RETURN VALUE
1 Cannot lock table
@ -574,33 +458,26 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
Checks parameters which we got from the parsing phase.
SYNOPSIS
evex_check_params()
check_parse_params()
thd THD
et event's data
RETURNS
0 OK
EVEX_BAD_PARAMS Error
REMARKS
Issues error messages
EVEX_BAD_PARAMS Error (reported)
*/
int
evex_check_params(THD *thd, Event_parse_data *parse_data)
static int
check_parse_params(THD *thd, Event_parse_data *parse_data)
{
const char *pos= NULL;
Item *bad_item;
int res;
DBUG_ENTER("evex_check_params");
DBUG_PRINT("info", ("execute_at=0x%d expr=0x%d starts=0x%d ends=0x%d",
parse_data->item_execute_at,
parse_data->item_expression,
parse_data->item_starts,
parse_data->item_ends));
DBUG_ENTER("check_parse_params");
parse_data->init_name(thd, parse_data->identifier);
parse_data->init_definer(thd);
if (parse_data->check_parse_data(thd))
DBUG_RETURN(EVEX_BAD_PARAMS);
if (!parse_data->dbname.str ||
(thd->lex->sql_command == SQLCOM_ALTER_EVENT && thd->lex->spname &&
@ -617,68 +494,7 @@ evex_check_params(THD *thd, Event_parse_data *parse_data)
is_schema_db(thd->lex->spname->m_db.str)))))
DBUG_RETURN(EVEX_BAD_PARAMS);
if (parse_data->item_execute_at)
{
DBUG_PRINT("info", ("ONE TIME"));
if (parse_data->init_execute_at(thd, parse_data->item_execute_at))
{
pos= "AT";
bad_item= parse_data->item_execute_at;
goto wrong_value;
}
}
else
{
int res;
DBUG_PRINT("info", ("RECURRING"));
if (parse_data->item_expression &&
(res= parse_data->init_interval(thd, parse_data->item_expression,
parse_data->interval)))
{
switch (res) {
case EVEX_BAD_PARAMS:
my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
break;
case EVEX_MICROSECOND_UNSUP:
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
break;
default:
pos= "INTERVAL";
bad_item= parse_data->item_expression;
goto wrong_value;
}
DBUG_RETURN(EVEX_BAD_PARAMS);
}
if (parse_data->item_starts &&
parse_data->init_starts(thd, parse_data->item_starts))
{
pos= "STARTS";
bad_item= parse_data->item_starts;
goto wrong_value;
}
if (parse_data->item_ends &&
parse_data->init_ends(thd, parse_data->item_ends))
{
/*
despite the error name the value is
eng "ENDS is either invalid or before STARTS"
*/
my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
DBUG_RETURN(EVEX_BAD_PARAMS);
}
}
DBUG_RETURN(0);
wrong_value:
{
char buff[120];
String str(buff,(uint32) sizeof(buff), system_charset_info);
String *str2= bad_item->fixed? bad_item->val_str(&str):NULL;
my_error(ER_WRONG_VALUE, MYF(0), pos, str2? str2->c_ptr():"NULL");
DBUG_RETURN(EVEX_BAD_PARAMS);
}
}
@ -687,18 +503,18 @@ wrong_value:
SYNOPSIS
Event_db_repository::create_event()
thd THD
et Event_timed object containing information for the event
create_if_not If an warning should be generated in case event exists
rows_affected How many rows were affected
thd [in] THD
et [in] Object containing info about the event
create_if_not [in] Whether to generate anwarning in case event exists
rows_affected [out] How many rows were affected
RETURN VALUE
0 - OK
EVEX_GENERAL_ERROR - Failure
DESCRIPTION
Creates an event. Relies on evex_fill_row which is shared with
db_update_event. The name of the event is inside "et".
Creates an event. Relies on mysql_event_fill_row which is shared with
::update_event. The name of the event is inside "et".
*/
int
@ -709,7 +525,7 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
CHARSET_INFO *scs= system_charset_info;
TABLE *table;
char olddb[128];
bool dbchanged= false;
bool dbchanged= FALSE;
DBUG_ENTER("Event_db_repository::create_event");
*rows_affected= 0;
@ -720,15 +536,14 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
goto err;
}
if (evex_check_params(thd, parse_data))
if (check_parse_params(thd, parse_data))
goto err;
DBUG_PRINT("info", ("name: %.*s", parse_data->name.length,
parse_data->name.str));
DBUG_PRINT("info", ("check existance of an event with the same name"));
if (!evex_db_find_event_by_name(thd, parse_data->dbname,
parse_data->name, table))
if (!find_event_by_name(thd, parse_data->dbname, parse_data->name, table))
{
if (create_if_not)
{
@ -784,10 +599,10 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
((Field_timestamp *)table->field[ET_FIELD_CREATED])->set_time();
/*
evex_fill_row() calls my_error() in case of error so no need to
mysql_event_fill_row() calls my_error() in case of error so no need to
handle it here
*/
if ((ret= evex_fill_row(thd, table, parse_data, false)))
if ((ret= mysql_event_fill_row(thd, table, parse_data, FALSE)))
goto err;
/* Close active transaction only if We are going to modify disk */
@ -800,16 +615,6 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
goto err;
}
#ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED
if (mysql_bin_log.is_open())
{
thd->clear_error();
/* Such a statement can always go directly to binlog, no trans cache */
thd->binlog_query(THD::MYSQL_QUERY_TYPE, thd->query, thd->query_length,
FALSE, FALSE);
}
#endif
*rows_affected= 1;
ok:
if (dbchanged)
@ -838,7 +643,7 @@ err:
RETURN VALUE
0 OK
EVEX_GENERAL_ERROR Error occured (my_error() called)
EVEX_GENERAL_ERROR Error occured and reported
NOTES
sp_name is passed since this is the name of the event to
@ -860,7 +665,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
goto err;
}
if (evex_check_params(thd, parse_data))
if (check_parse_params(thd, parse_data))
goto err;
DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
@ -879,7 +684,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
goto err;
}
if (!evex_db_find_event_by_name(thd,new_name->m_db,new_name->m_name,table))
if (!find_event_by_name(thd, new_name->m_db, new_name->m_name, table))
{
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
goto err;
@ -904,10 +709,10 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
/*
evex_fill_row() calls my_error() in case of error so no need to
mysql_event_fill_row() calls my_error() in case of error so no need to
handle it here
*/
if ((ret= evex_fill_row(thd, table, parse_data, true)))
if ((ret= mysql_event_fill_row(thd, table, parse_data, TRUE)))
goto err;
if (new_name)
@ -944,11 +749,12 @@ err:
SYNOPSIS
Event_db_repository::drop_event()
thd THD
db database name
name event's name
drop_if_exists if set and the event not existing => warning onto the stack
rows_affected affected number of rows is returned heres
thd [in] THD
db [in] Database name
name [in] Event's name
drop_if_exists [in] If set and the event not existing => warning
onto the stack
rows_affected [out] Affected number of rows is returned heres
RETURN VALUE
0 OK
@ -974,17 +780,16 @@ Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
goto done;
}
if (!(ret= evex_db_find_event_by_name(thd, db, name, table)))
{
/* Close active transaction only if We are going to modify disk */
switch ((ret= find_event_by_name(thd, db, name, table))) {
case 0:
/* Close active transaction only if we are actually going to modify disk */
if ((ret= end_active_trans(thd)))
goto done;
break;
if ((ret= table->file->ha_delete_row(table->record[0])))
my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
}
else if (ret == EVEX_KEY_NOT_FOUND)
{
break;
case EVEX_KEY_NOT_FOUND:
if (drop_if_exists)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
@ -993,19 +798,34 @@ Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
ret= 0;
} else
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
break;
default:
;
}
done:
/*
evex_drop_event() is used by Event_timed::drop therefore
we have to close our thread tables.
*/
close_thread_tables(thd);
thd->restore_backup_open_tables_state(&backup);
DBUG_RETURN(ret);
}
/*
Positions the internal pointer of `table` to the place where (db, name)
is stored.
SYNOPSIS
Event_db_repository::find_event_by_name()
thd Thread
db Schema
name Event name
table Opened mysql.event
RETURN VALUE
0 OK
EVEX_KEY_NOT_FOUND No such event
*/
int
Event_db_repository::find_event_by_name(THD *thd, LEX_STRING db,
LEX_STRING name, TABLE *table)
@ -1043,6 +863,19 @@ Event_db_repository::find_event_by_name(THD *thd, LEX_STRING db,
}
/*
Drops all events in the selected database, from mysql.event.
SYNOPSIS
Event_db_repository::drop_schema_events()
thd Thread
schema The database to clean from events
RETURN VALUE
0 OK
!0 Error (Reported)
*/
int
Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
{
@ -1050,18 +883,11 @@ Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
}
int
Event_db_repository::drop_user_events(THD *thd, LEX_STRING definer)
{
return drop_events_by_field(thd, ET_FIELD_DEFINER, definer);
}
/*
Drops all events in the selected database, from mysql.event.
Drops all events by field which has specific value of the field
SYNOPSIS
drop_events_from_table_by_field()
Event_db_repository::drop_events_by_field()
thd Thread
table mysql.event TABLE
field Which field of the row to use for matching
@ -1116,56 +942,63 @@ Event_db_repository::drop_events_by_field(THD *thd,
/*
Looks for a named event in mysql.event and then loads it from
the table, compiles and inserts it into the cache.
Looks for a named event in mysql.event and in case of success returns
an object will data loaded from the table.
SYNOPSIS
Event_db_repository::load_named_event_timed()
thd THD
etn The name of the event to load and compile on scheduler's root
etn_new The loaded event
Event_db_repository::find_event()
thd [in] THD
name [in] The name of the event to find
ett [out] Event's data if event is found
tbl [in] TABLE object to use when not NULL
NOTES
1) Use sp_name for look up, return in **ett if found
2) tbl is not closed at exit
RETURN VALUE
NULL Error during compile or the event is non-enabled.
otherwise Address
0 ok In this case *ett is set to the event
# error *ett == 0
*/
int
Event_db_repository::load_named_event_timed(THD *thd, LEX_STRING dbname,
LEX_STRING name,
Event_timed **etn_new)
Event_db_repository::find_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
Event_basic *et)
{
int ret= 0;
MEM_ROOT *tmp_mem_root;
Event_timed *et_loaded= NULL;
Open_tables_state backup;
TABLE *table;
int ret;
DBUG_ENTER("Event_db_repository::find_event");
DBUG_PRINT("enter", ("name: %*s", name.length, name.str));
DBUG_ENTER("Event_db_repository::load_named_event_timed");
DBUG_PRINT("enter",("thd=%p name:%*s",thd, name.length, name.str));
thd->reset_n_backup_open_tables_state(&backup);
/* No need to use my_error() here because db_find_event() has done it */
ret= find_event(thd, dbname, name, &et_loaded, NULL);
thd->restore_backup_open_tables_state(&backup);
/* In this case no memory was allocated so we don't need to clean */
if (ret)
DBUG_RETURN(OP_LOAD_ERROR);
if (et_loaded->status != Event_timed::ENABLED)
if (open_event_table(thd, TL_READ, &table))
{
/*
We don't load non-enabled events.
In db_find_event() `et_new` was allocated on the heap and not on
scheduler_root therefore we delete it here.
*/
delete et_loaded;
DBUG_RETURN(OP_DISABLED_EVENT);
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
ret= EVEX_GENERAL_ERROR;
goto done;
}
et_loaded->compute_next_execution_time();
*etn_new= et_loaded;
if ((ret= find_event_by_name(thd, dbname, name, table)))
{
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
goto done;
}
/*
1)The table should not be closed beforehand. ::load_from_row() only loads
and does not compile
DBUG_RETURN(OP_OK);
2)::load_from_row() is silent on error therefore we emit error msg here
*/
if ((ret= et->load_from_row(table)))
{
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
goto done;
}
done:
if (table)
close_thread_tables(thd);
DBUG_RETURN(ret);
}
@ -1174,50 +1007,34 @@ Event_db_repository::load_named_event_timed(THD *thd, LEX_STRING dbname,
the table, compiles and inserts it into the cache.
SYNOPSIS
Event_db_repository::load_named_event_job()
thd THD
etn The name of the event to load and compile on scheduler's root
etn_new The loaded event
Event_db_repository::load_named_event()
thd [in] THD
dbname [in] Event's db name
name [in] Event's name
etn_new [out] The loaded event
RETURN VALUE
NULL Error during compile or the event is non-enabled.
otherwise Address
OP_OK OK
OP_LOAD_ERROR Error during loading from disk
*/
int
Event_db_repository::load_named_event_job(THD *thd, LEX_STRING dbname,
LEX_STRING name,
Event_job_data **etn_new)
Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
LEX_STRING name, Event_basic *etn)
{
int ret= 0;
MEM_ROOT *tmp_mem_root;
Event_timed *et_loaded= NULL;
Open_tables_state backup;
DBUG_ENTER("Event_db_repository::load_named_event_job");
DBUG_PRINT("enter",("thd=%p name:%*s",thd, name.length, name.str));
#if 0
DBUG_ENTER("Event_db_repository::load_named_event");
DBUG_PRINT("enter",("thd=0x%lx name:%*s",thd, name.length, name.str));
thd->reset_n_backup_open_tables_state(&backup);
/* No need to use my_error() here because db_find_event() has done it */
ret= find_event(thd, dbname, name, &et_loaded, NULL);
/* No need to use my_error() here because find_event() has done it */
ret= find_event(thd, dbname, name, etn);
thd->restore_backup_open_tables_state(&backup);
/* In this case no memory was allocated so we don't need to clean */
if (ret)
DBUG_RETURN(OP_LOAD_ERROR);
if (et_loaded->status != Event_timed::ENABLED)
{
/*
We don't load non-enabled events.
In db_find_event() `et_new` was allocated on the heap and not on
scheduler_root therefore we delete it here.
*/
delete et_loaded;
DBUG_RETURN(OP_DISABLED_EVENT);
}
et_loaded->compute_next_execution_time();
*etn_new= et_loaded;
#endif
DBUG_RETURN(OP_OK);
}

View File

@ -38,11 +38,6 @@ enum enum_events_table_field
};
int
evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
const LEX_STRING ev_name,
TABLE *table);
int
events_table_index_read_for_db(THD *thd, TABLE *schema_table,
TABLE *event_table);
@ -53,22 +48,13 @@ events_table_scan_all(THD *thd, TABLE *schema_table, TABLE *event_table);
int
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
class Event_timed;
class Event_basic;
class Event_parse_data;
class Event_queue_element;
class Event_job_data;
class Event_db_repository
{
public:
Event_db_repository(){}
~Event_db_repository(){}
int
init_repository();
void
deinit_repository();
int
create_event(THD *thd, Event_parse_data *parse_data, my_bool create_if_not,
@ -85,19 +71,10 @@ public:
drop_schema_events(THD *thd, LEX_STRING schema);
int
drop_user_events(THD *thd, LEX_STRING definer);
find_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
int
find_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_timed **ett,
TABLE *tbl);
int
load_named_event_timed(THD *thd, LEX_STRING dbname, LEX_STRING name,
Event_timed **etn_new);
int
load_named_event_job(THD *thd, LEX_STRING dbname, LEX_STRING name,
Event_job_data **etn_new);
load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
int
find_event_by_name(THD *thd, LEX_STRING db, LEX_STRING name, TABLE *table);

File diff suppressed because it is too large Load Diff

View File

@ -17,13 +17,12 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class sp_name;
class Event_timed;
class Event_basic;
class Event_db_repository;
class Event_job_data;
class Event_queue_element;
class THD;
typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*);
class Event_scheduler_ng;
class Event_queue
@ -46,14 +45,14 @@ public:
/* Methods for queue management follow */
int
create_event(THD *thd, Event_parse_data *et);
create_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
int
update_event(THD *thd, Event_parse_data *et, LEX_STRING *new_schema,
LEX_STRING *new_name);
update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
LEX_STRING *new_schema, LEX_STRING *new_name);
bool
drop_event(THD *thd, sp_name *name);
void
drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
void
drop_schema_events(THD *thd, LEX_STRING schema);
@ -61,32 +60,20 @@ public:
uint
events_count();
uint
events_count_no_lock();
static bool
check_system_tables(THD *thd);
void
recalculate_queue(THD *thd);
recalculate_activation_times(THD *thd);
void
empty_queue();
Event_timed *
Event_job_data *
get_top_for_execution_if_time(THD *thd, time_t now, struct timespec *abstime);
Event_timed*
get_top();
void
remove_top();
void
top_changed();
bool
dump_internal_status(THD *thd);
protected:
Event_timed *
Event_queue_element *
find_event(LEX_STRING db, LEX_STRING name, bool remove_from_q);
int
@ -94,14 +81,16 @@ protected:
void
drop_matching_events(THD *thd, LEX_STRING pattern,
bool (*)(Event_timed *,LEX_STRING *));
bool (*)(LEX_STRING *, Event_basic *));
void
empty_queue();
/* LOCK_event_queue is the mutex which protects the access to the queue. */
pthread_mutex_t LOCK_event_queue;
Event_db_repository *db_repository;
uint mutex_last_locked_at_line;
uint mutex_last_unlocked_at_line;
const char* mutex_last_locked_in_func;
@ -123,10 +112,8 @@ protected:
Event_scheduler_ng *scheduler;
//public:
/* The sorted queue with the Event_timed objects */
/* The sorted queue with the Event_job_data objects */
QUEUE queue;
};
#endif /* _EVENT_QUEUE_H_ */

View File

@ -30,6 +30,7 @@
#define LOCK_SCHEDULER_DATA() lock_data(SCHED_FUNC, __LINE__)
#define UNLOCK_SCHEDULER_DATA() unlock_data(SCHED_FUNC, __LINE__)
#define COND_STATE_WAIT(timer) cond_wait(timer, SCHED_FUNC, __LINE__)
extern pthread_attr_t connection_attrib;
@ -52,28 +53,6 @@ LEX_STRING scheduler_states_names[] =
};
class Worker_thread_param
{
public:
Event_timed *et;
pthread_mutex_t LOCK_started;
pthread_cond_t COND_started;
bool started;
Worker_thread_param(Event_timed *etn):et(etn), started(FALSE)
{
pthread_mutex_init(&LOCK_started, MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_started, NULL);
}
~Worker_thread_param()
{
pthread_mutex_destroy(&LOCK_started);
pthread_cond_destroy(&COND_started);
}
};
/*
Prints the stack of infos, warnings, errors from thd to
the console so it can be fetched by the logs-into-tables and
@ -81,12 +60,12 @@ public:
SYNOPSIS
evex_print_warnings
thd - thread used during the execution of the event
et - the event itself
thd Thread used during the execution of the event
et The event itself
*/
static void
evex_print_warnings(THD *thd, Event_timed *et)
evex_print_warnings(THD *thd, Event_job_data *et)
{
MYSQL_ERROR *err;
DBUG_ENTER("evex_print_warnings");
@ -148,23 +127,22 @@ init_scheduler_thread(THD* thd)
thd->security_ctx->db_access= 0;
thd->security_ctx->host_or_ip= (char*)my_localhost;
thd->security_ctx->set_user((char*)"event_scheduler");
my_net_init(&thd->net, 0);
my_net_init(&thd->net, NULL);
thd->net.read_timeout= slave_net_timeout;
thd->slave_thread= 0;
thd->options|= OPTION_AUTO_IS_NULL;
thd->client_capabilities|= CLIENT_MULTI_RESULTS;
VOID(pthread_mutex_lock(&LOCK_thread_count));
pthread_mutex_lock(&LOCK_thread_count);
thd->thread_id= thread_id++;
threads.append(thd);
thread_count++;
thread_running++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
pthread_mutex_unlock(&LOCK_thread_count);
/*
Guarantees that we will see the thread in SHOW PROCESSLIST though its
vio is NULL.
*/
thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
thd->proc_info= "Initialized";
thd->version= refresh_version;
@ -174,6 +152,41 @@ init_scheduler_thread(THD* thd)
}
/*
Cleans up the THD and the threaded environment of the thread.
SYNOPSIS
deinit_event_thread()
thd Thread
*/
static void
deinit_event_thread(THD *thd)
{
thd->proc_info= "Clearing";
DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net);
DBUG_PRINT("exit", ("Scheduler thread finishing"));
pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
thread_running--;
delete thd;
pthread_mutex_unlock(&LOCK_thread_count);
my_thread_end();
}
/*
Function that executes the scheduler,
SYNOPSIS
event_scheduler_ng_thread()
arg Pointer to `struct scheduler_param`
RETURN VALUE
0 OK
*/
pthread_handler_t
event_scheduler_ng_thread(void *arg)
{
@ -201,17 +214,8 @@ event_scheduler_ng_thread(void *arg)
((struct scheduler_param *) arg)->scheduler->run(thd);
end:
thd->proc_info= "Clearing";
DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net);
DBUG_PRINT("exit", ("Scheduler thread finishing"));
pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
thread_running--;
delete thd;
pthread_mutex_unlock(&LOCK_thread_count);
deinit_event_thread(thd);
my_thread_end();
DBUG_RETURN(0); // Against gcc warnings
}
@ -222,7 +226,7 @@ end:
SYNOPSIS
event_worker_ng_thread()
arg The Event_timed object to be processed
arg The Event_job_data object to be processed
RETURN VALUE
0 OK
@ -233,14 +237,12 @@ event_worker_ng_thread(void *arg)
{
/* needs to be first for thread_stack */
THD *thd;
Event_timed *event= (Event_timed *)arg;
Event_job_data *event= (Event_job_data *)arg;
int ret;
thd= event->thd;
thd->thread_stack= (char *) &thd;
DBUG_ENTER("event_worker_thread");
DBUG_PRINT("enter", ("event=[%s.%s]", event->dbname.str, event->name.str));
my_thread_init();
pthread_detach_this_thread();
@ -251,25 +253,32 @@ event_worker_ng_thread(void *arg)
goto end;
}
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
sigset_t set;
VOID(sigemptyset(&set)); // Get mask in use
VOID(pthread_sigmask(SIG_UNBLOCK, &set, &thd->block_signals));
#endif
thd->init_for_queries();
DBUG_ENTER("event_worker_ng_thread");
DBUG_PRINT("info", ("Baikonur, time is %d, BURAN reporting and operational."
"THD=0x%lx", time(NULL), thd));
sql_print_information("SCHEDULER: [%s.%s of %s] executing in thread %lu",
event->dbname.str, event->name.str,
event->definer.str, thd->thread_id);
thd->init_for_queries();
thd->enable_slow_log= TRUE;
ret= event->execute(thd, thd->mem_root);
evex_print_warnings(thd, event);
sql_print_information("SCHEDULER: [%s.%s of %s] executed. RetCode=%d",
sql_print_information("SCHEDULER: [%s.%s of %s] executed "
" in thread thread %lu. RetCode=%d",
event->dbname.str, event->name.str,
event->definer.str, ret);
event->definer.str, thd->thread_id, ret);
if (ret == EVEX_COMPILE_ERROR)
sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of %s",
event->dbname.str, event->name.str,
@ -277,36 +286,35 @@ event_worker_ng_thread(void *arg)
else if (ret == EVEX_MICROSECOND_UNSUP)
sql_print_information("SCHEDULER: MICROSECOND is not supported");
DBUG_PRINT("info", ("master_access=%d db_access=%d",
thd->security_ctx->master_access, thd->security_ctx->db_access));
end:
thd->proc_info= "Clearing";
DBUG_ASSERT(thd->net.buff != 0);
/*
Free it here because net.vio is NULL for us => THD::~THD will check it
and won't call net_end(&net); See also replication code.
*/
net_end(&thd->net);
DBUG_PRINT("info", ("Worker thread %lu exiting", thd->thread_id));
VOID(pthread_mutex_lock(&LOCK_thread_count));
thread_count--;
thread_running--;
delete thd;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
DBUG_PRINT("info", ("BURAN %s.%s is landing!", event->dbname.str,
event->name.str));
delete event;
my_thread_end();
deinit_event_thread(thd);
DBUG_RETURN(0); // Against gcc warnings
}
/*
Performs initialization of the scheduler data, outside of the
threading primitives.
SYNOPSIS
Event_scheduler_ng::init_scheduler()
*/
bool
Event_scheduler_ng::init_scheduler(Event_queue *q)
{
LOCK_SCHEDULER_DATA();
thread_id= 0;
state= INITIALIZED;
queue= q;
started_events= 0;
UNLOCK_SCHEDULER_DATA();
return FALSE;
}
@ -315,6 +323,13 @@ void
Event_scheduler_ng::deinit_scheduler() {}
/*
Inits scheduler's threading primitives.
SYNOPSIS
Event_scheduler_ng::init_mutexes()
*/
void
Event_scheduler_ng::init_mutexes()
{
@ -323,6 +338,13 @@ Event_scheduler_ng::init_mutexes()
}
/*
Deinits scheduler's threading primitives.
SYNOPSIS
Event_scheduler_ng::deinit_mutexes()
*/
void
Event_scheduler_ng::deinit_mutexes()
{
@ -331,6 +353,21 @@ Event_scheduler_ng::deinit_mutexes()
}
/*
Starts the scheduler (again). Creates a new THD and passes it to
a forked thread. Does not wait for acknowledgement from the new
thread that it has started. Asynchronous starting. Most of the
needed initializations are done in the current thread to minimize
the chance of failure in the spawned thread.
SYNOPSIS
Event_scheduler_ng::start()
RETURN VALUE
FALSE OK
TRUE Error (not reported)
*/
bool
Event_scheduler_ng::start()
{
@ -340,6 +377,7 @@ Event_scheduler_ng::start()
DBUG_ENTER("Event_scheduler_ng::start");
LOCK_SCHEDULER_DATA();
DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state]));
if (state > INITIALIZED)
goto end;
@ -349,10 +387,13 @@ Event_scheduler_ng::start()
ret= TRUE;
goto end;
}
new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
new_thd->command= COM_DAEMON;
scheduler_param_value.thd= new_thd;
scheduler_param_value.scheduler= this;
DBUG_PRINT("info", ("Forking new thread for scheduduler. THD=0x%lx", new_thd));
if (pthread_create(&th, &connection_attrib, event_scheduler_ng_thread,
(void*)&scheduler_param_value))
{
@ -360,13 +401,14 @@ Event_scheduler_ng::start()
state= INITIALIZED;
ret= TRUE;
}
DBUG_PRINT("info", ("Setting state go RUNNING"));
state= RUNNING;
end:
UNLOCK_SCHEDULER_DATA();
if (ret && new_thd)
{
DBUG_PRINT("info", ("There was an error during THD creation. Clean up"));
new_thd->proc_info= "Clearing";
DBUG_ASSERT(new_thd->net.buff != 0);
net_end(&new_thd->net);
@ -380,14 +422,27 @@ end:
}
/*
Stops the scheduler (again). Waits for acknowledgement from the
scheduler that it has stopped - synchronous stopping.
SYNOPSIS
Event_scheduler_ng::stop()
RETURN VALUE
FALSE OK
TRUE Error (not reported)
*/
bool
Event_scheduler_ng::stop()
{
THD *thd= current_thd;
DBUG_ENTER("Event_scheduler_ng::stop");
DBUG_PRINT("enter", ("thd=%p", current_thd));
DBUG_PRINT("enter", ("thd=0x%lx", current_thd));
LOCK_SCHEDULER_DATA();
DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state]));
if (state != RUNNING)
goto end;
@ -406,48 +461,75 @@ Event_scheduler_ng::stop()
"workers count=%d", scheduler_states_names[state].str,
workers_count()));
/* thd could be 0x0, when shutting down */
pthread_cond_wait(&COND_state, &LOCK_scheduler_state);
COND_STATE_WAIT(NULL);
} while (state == STOPPING);
DBUG_PRINT("info", ("Manager thread has cleaned up. Set state to INIT"));
thread_id= 0;
end:
UNLOCK_SCHEDULER_DATA();
DBUG_RETURN(FALSE);
}
/*
The main loop of the scheduler.
SYNOPSIS
Event_scheduler_ng::run()
thd Thread
RETURN VALUE
FALSE OK
TRUE Error (Serious error)
*/
bool
Event_scheduler_ng::run(THD *thd)
{
int res;
struct timespec abstime;
Event_timed *job_data;
Event_job_data *job_data;
DBUG_ENTER("Event_scheduler_ng::run");
LOCK_SCHEDULER_DATA();
thread_id= thd->thread_id;
sql_print_information("SCHEDULER: Manager thread started with id %lu",
thread_id);
/*
Recalculate the values in the queue because there could have been stops
in executions of the scheduler and some times could have passed by.
*/
queue->recalculate_activation_times(thd);
while (state == RUNNING)
{
thd->end_time();
/* Gets a minimized version */
job_data= queue->get_top_for_execution_if_time(thd, thd->query_start(),
&abstime);
DBUG_PRINT("info", ("get_top returned job_data=%p now=%d abs_time.tv_sec=%d",
job_data= queue->
get_top_for_execution_if_time(thd, thd->query_start(), &abstime);
DBUG_PRINT("info", ("get_top returned job_data=0x%lx now=%d "
"abs_time.tv_sec=%d",
job_data, thd->query_start(), abstime.tv_sec));
if (!job_data && !abstime.tv_sec)
{
DBUG_PRINT("info", ("The queue is empty. Going to sleep"));
thd->enter_cond(&COND_state, &LOCK_scheduler_state,
"Waiting on empty queue");
pthread_cond_wait(&COND_state, &LOCK_scheduler_state);
COND_STATE_WAIT(NULL);
thd->exit_cond("");
DBUG_PRINT("info", ("Woke up. Got COND_state"));
LOCK_SCHEDULER_DATA();
}
else if (abstime.tv_sec)
{
DBUG_PRINT("info", ("Have to sleep some time %u till",
abstime.tv_sec - thd->query_start(), abstime.tv_sec));
thd->enter_cond(&COND_state, &LOCK_scheduler_state,
"Waiting for next activation");
pthread_cond_timedwait(&COND_state, &LOCK_scheduler_state, &abstime);
COND_STATE_WAIT(&abstime);
/*
If we get signal we should recalculate the whether it's the right time
because there could be :
@ -461,12 +543,12 @@ Event_scheduler_ng::run(THD *thd)
}
else
{
int res;
UNLOCK_SCHEDULER_DATA();
res= execute_top(thd, job_data);
LOCK_SCHEDULER_DATA();
if (res)
break;
++started_events;
}
DBUG_PRINT("info", ("state=%s", scheduler_states_names[state].str));
}
@ -477,29 +559,47 @@ error:
UNLOCK_SCHEDULER_DATA();
sql_print_information("SCHEDULER: Stopped");
return FALSE;
DBUG_RETURN(res);
}
/*
Creates a new THD instance and then forks a new thread, while passing
the THD pointer and job_data to it.
SYNOPSIS
Event_scheduler_ng::execute_top()
RETURN VALUE
FALSE OK
TRUE Error (Serious error)
*/
bool
Event_scheduler_ng::execute_top(THD *thd, Event_timed *job_data)
Event_scheduler_ng::execute_top(THD *thd, Event_job_data *job_data)
{
THD *new_thd;
pthread_t th;
int res= 0;
DBUG_ENTER("Event_scheduler_ng::execute_top");
if (!(new_thd= new THD) || init_scheduler_thread(new_thd))
goto error;
/* Major failure */
new_thd->system_thread= SYSTEM_THREAD_EVENT_WORKER;
job_data->thd= new_thd;
DBUG_PRINT("info", ("Starting new thread for %s@%s",
DBUG_PRINT("info", ("BURAN %s@%s ready for start t-3..2..1..0..ignition",
job_data->dbname.str, job_data->name.str));
if (pthread_create(&th, &connection_attrib, event_worker_ng_thread, job_data))
/* Major failure */
if ((res= pthread_create(&th, &connection_attrib, event_worker_ng_thread,
job_data)))
goto error;
DBUG_PRINT("info", ("Launch succeeded. BURAN is in THD=0x%lx", new_thd));
DBUG_RETURN(FALSE);
error:
DBUG_PRINT("error", ("Baikonur, we have a problem! res=%d", res));
if (new_thd)
{
new_thd->proc_info= "Clearing";
@ -511,10 +611,21 @@ error:
delete new_thd;
pthread_mutex_unlock(&LOCK_thread_count);
}
delete job_data;
DBUG_RETURN(TRUE);
}
/*
Returns the current state of the scheduler
SYNOPSIS
Event_scheduler_ng::get_state()
RETURN VALUE
The state of the scheduler (INITIALIZED | RUNNING | STOPPING)
*/
enum Event_scheduler_ng::enum_state
Event_scheduler_ng::get_state()
{
@ -526,13 +637,12 @@ Event_scheduler_ng::get_state()
}
int
Event_scheduler_ng::dump_internal_status(THD *thd)
{
return 1;
}
/*
Returns the number of living event worker threads.
SYNOPSIS
Event_scheduler_ng::workers_count()
*/
uint
Event_scheduler_ng::workers_count()
@ -541,7 +651,7 @@ Event_scheduler_ng::workers_count()
uint count= 0;
DBUG_ENTER("Event_scheduler_ng::workers_count");
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
I_List_iterator<THD> it(threads);
while ((tmp=it++))
{
@ -550,7 +660,7 @@ Event_scheduler_ng::workers_count()
if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER)
++count;
}
VOID(pthread_mutex_unlock(&LOCK_thread_count));
pthread_mutex_unlock(&LOCK_thread_count);
DBUG_PRINT("exit", ("%d", count));
DBUG_RETURN(count);
}
@ -568,16 +678,27 @@ void
Event_scheduler_ng::queue_changed()
{
DBUG_ENTER("Event_scheduler_ng::queue_changed");
DBUG_PRINT("info", ("Sending COND_state"));
DBUG_PRINT("info", ("Sending COND_state. state (read wo lock)=%s ",
scheduler_states_names[state].str));
pthread_cond_signal(&COND_state);
DBUG_VOID_RETURN;
}
/*
Auxiliary function for locking LOCK_scheduler_state. Used
by the LOCK_SCHEDULER_DATA macro.
SYNOPSIS
Event_scheduler_ng::lock_data()
func Which function is requesting mutex lock
line On which line mutex lock is requested
*/
void
Event_scheduler_ng::lock_data(const char *func, uint line)
{
DBUG_ENTER("Event_scheduler_ng::lock_mutex");
DBUG_ENTER("Event_scheduler_ng::lock_data");
DBUG_PRINT("enter", ("func=%s line=%u", func, line));
pthread_mutex_lock(&LOCK_scheduler_state);
mutex_last_locked_in_func= func;
@ -587,10 +708,20 @@ Event_scheduler_ng::lock_data(const char *func, uint line)
}
/*
Auxiliary function for unlocking LOCK_scheduler_state. Used
by the UNLOCK_SCHEDULER_DATA macro.
SYNOPSIS
Event_scheduler_ng::unlock_data()
func Which function is requesting mutex unlock
line On which line mutex unlock is requested
*/
void
Event_scheduler_ng::unlock_data(const char *func, uint line)
{
DBUG_ENTER("Event_scheduler_ng::unlock_mutex");
DBUG_ENTER("Event_scheduler_ng::unlock_data");
DBUG_PRINT("enter", ("func=%s line=%u", func, line));
mutex_last_unlocked_at_line= line;
mutex_scheduler_data_locked= FALSE;
@ -598,3 +729,147 @@ Event_scheduler_ng::unlock_data(const char *func, uint line)
pthread_mutex_unlock(&LOCK_scheduler_state);
DBUG_VOID_RETURN;
}
/*
Wrapper for pthread_cond_wait/timedwait
SYNOPSIS
Event_scheduler_ng::cond_wait()
cond Conditional to wait for
mutex Mutex of the conditional
RETURN VALUE
Error code of pthread_cond_wait()
*/
void
Event_scheduler_ng::cond_wait(struct timespec *abstime,
const char *func, uint line)
{
DBUG_ENTER("Event_scheduler_ng::cond_wait");
waiting_on_cond= TRUE;
mutex_last_unlocked_at_line= line;
mutex_scheduler_data_locked= FALSE;
mutex_last_unlocked_in_func= func;
if (abstime)
pthread_cond_timedwait(&COND_state, &LOCK_scheduler_state, abstime);
else
pthread_cond_wait(&COND_state, &LOCK_scheduler_state);
mutex_last_locked_in_func= func;
mutex_last_locked_at_line= line;
mutex_scheduler_data_locked= TRUE;
waiting_on_cond= FALSE;
DBUG_VOID_RETURN;
}
/*
Dumps the internal status of the scheduler
SYNOPSIS
Event_scheduler_ng::dump_internal_status()
thd Thread
RETURN VALUE
FALSE OK
TRUE Error
*/
bool
Event_scheduler_ng::dump_internal_status(THD *thd)
{
int ret= 0;
DBUG_ENTER("Event_scheduler_ng::dump_internal_status");
#ifndef DBUG_OFF
CHARSET_INFO *scs= system_charset_info;
Protocol *protocol= thd->protocol;
char tmp_buff[5*STRING_BUFFER_USUAL_SIZE];
char int_buff[STRING_BUFFER_USUAL_SIZE];
String tmp_string(tmp_buff, sizeof(tmp_buff), scs);
String int_string(int_buff, sizeof(int_buff), scs);
tmp_string.length(0);
int_string.length(0);
protocol->prepare_for_resend();
protocol->store(STRING_WITH_LEN("scheduler state"), scs);
protocol->store(scheduler_states_names[state].str,
scheduler_states_names[state].length, scs);
if ((ret= protocol->write()))
goto end;
/* thread_id */
protocol->prepare_for_resend();
protocol->store(STRING_WITH_LEN("thread_id"), scs);
if (thread_id)
{
int_string.set((longlong) thread_id, scs);
protocol->store(&int_string);
}
else
protocol->store_null();
if ((ret= protocol->write()))
goto end;
/* last locked at*/
protocol->prepare_for_resend();
protocol->store(STRING_WITH_LEN("scheduler last locked at"), scs);
tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
tmp_string.alloced_length(), "%s::%d",
mutex_last_locked_in_func,
mutex_last_locked_at_line));
protocol->store(&tmp_string);
if ((ret= protocol->write()))
goto end;
/* last unlocked at*/
protocol->prepare_for_resend();
protocol->store(STRING_WITH_LEN("scheduler last unlocked at"), scs);
tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
tmp_string.alloced_length(), "%s::%d",
mutex_last_unlocked_in_func,
mutex_last_unlocked_at_line));
protocol->store(&tmp_string);
if ((ret= protocol->write()))
goto end;
/* waiting on */
protocol->prepare_for_resend();
protocol->store(STRING_WITH_LEN("scheduler waiting on condition"), scs);
int_string.set((longlong) waiting_on_cond, scs);
protocol->store(&int_string);
if ((ret= protocol->write()))
goto end;
/* workers_count */
protocol->prepare_for_resend();
protocol->store(STRING_WITH_LEN("scheduler workers count"), scs);
int_string.set((longlong) workers_count(), scs);
protocol->store(&int_string);
if ((ret= protocol->write()))
goto end;
/* workers_count */
protocol->prepare_for_resend();
protocol->store(STRING_WITH_LEN("scheduler executed events"), scs);
int_string.set((longlong) started_events, scs);
protocol->store(&int_string);
if ((ret= protocol->write()))
goto end;
/* scheduler_data_locked */
protocol->prepare_for_resend();
protocol->store(STRING_WITH_LEN("scheduler data locked"), scs);
int_string.set((longlong) mutex_scheduler_data_locked, scs);
protocol->store(&int_string);
ret= protocol->write();
end:
#endif
DBUG_RETURN(ret);
}

View File

@ -16,8 +16,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class Event_timed;
class Event_queue;
class Event_job_data;
class Event_scheduler_ng
{
@ -67,7 +67,7 @@ public:
void
queue_changed();
static int
bool
dump_internal_status(THD *thd);
private:
@ -76,7 +76,7 @@ private:
/* helper functions */
bool
execute_top(THD *thd, Event_timed *job_data);
execute_top(THD *thd, Event_job_data *job_data);
/* helper functions for working with mutexes & conditionals */
void
@ -85,6 +85,9 @@ private:
void
unlock_data(const char *func, uint line);
void
cond_wait(struct timespec *abstime, const char *func, uint line);
pthread_mutex_t LOCK_scheduler_state;
/* This is the current status of the life-cycle of the scheduler. */
@ -107,6 +110,9 @@ private:
const char* mutex_last_locked_in_func;
const char* mutex_last_unlocked_in_func;
bool mutex_scheduler_data_locked;
bool waiting_on_cond;
ulonglong started_events;
private:
/* Prevent use of these */

View File

@ -291,11 +291,11 @@ Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
RETURN VALUE
0 OK
!0 Error
!0 Error (Reported)
NOTES
- in case there is an event with the same name (db) and
IF NOT EXISTS is specified, an warning is put into the W stack.
In case there is an event with the same name (db) and
IF NOT EXISTS is specified, an warning is put into the stack.
*/
int
@ -304,13 +304,20 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists,
{
int ret;
DBUG_ENTER("Events::create_event");
pthread_mutex_lock(&LOCK_event_metadata);
/* On error conditions my_error() is called so no need to handle here */
if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists,
rows_affected)))
{
if ((ret= event_queue->create_event(thd, parse_data)))
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
if ((ret= event_queue->create_event(thd, parse_data->dbname,
parse_data->name)))
{
DBUG_ASSERT(ret == OP_LOAD_ERROR);
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0));
}
/* No need to close the table, it will be closed in sql_parse::do_command */
}
pthread_mutex_unlock(&LOCK_event_metadata);
DBUG_RETURN(ret);
}
@ -322,8 +329,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists,
SYNOPSIS
Events::update_event()
thd THD
et event's data
new_name set in case of RENAME TO.
et Event's data from parsing stage
new_name Set in case of RENAME TO.
RETURN VALUE
0 OK
@ -341,18 +348,23 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
{
int ret;
DBUG_ENTER("Events::update_event");
/*
db_update_event() opens & closes the table to prevent
crash later in the code when loading and compiling the new definition.
Also on error conditions my_error() is called so no need to handle here
*/
pthread_mutex_lock(&LOCK_event_metadata);
/* On error conditions my_error() is called so no need to handle here */
if (!(ret= db_repository->update_event(thd, parse_data, new_name)))
{
if ((ret= event_queue->update_event(thd, parse_data,
if ((ret= event_queue->update_event(thd,
parse_data->dbname,
parse_data->name,
new_name? &new_name->m_db: NULL,
new_name? &new_name->m_name: NULL)))
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
{
DBUG_ASSERT(ret == OP_LOAD_ERROR);
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0));
}
}
pthread_mutex_unlock(&LOCK_event_metadata);
DBUG_RETURN(ret);
}
@ -363,10 +375,15 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
SYNOPSIS
Events::drop_event()
thd THD
dbname Event's schema
name Event's name
if_exists When set and the event does not exist => warning onto
the stack
rows_affected Affected number of rows is returned heres
only_from_disk Whether to remove the event from the queue too. In case
of Event_job_data::drop() it's needed to do only disk
drop because Event_queue will handle removal from memory
queue.
RETURN VALUE
0 OK
@ -374,17 +391,52 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
*/
int
Events::drop_event(THD *thd, sp_name *name, bool if_exists, uint *rows_affected)
Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists,
uint *rows_affected, bool only_from_disk)
{
int ret;
DBUG_ENTER("Events::drop_event");
if (!(ret= db_repository->drop_event(thd, name->m_db, name->m_name, if_exists,
pthread_mutex_lock(&LOCK_event_metadata);
/* On error conditions my_error() is called so no need to handle here */
if (!(ret= db_repository->drop_event(thd, dbname, name, if_exists,
rows_affected)))
{
if ((ret= event_queue->drop_event(thd, name)))
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
if (!only_from_disk)
event_queue->drop_event(thd, dbname, name);
}
pthread_mutex_unlock(&LOCK_event_metadata);
DBUG_RETURN(ret);
}
/*
Drops all events from a schema
SYNOPSIS
Events::drop_schema_events()
thd Thread
db ASCIIZ schema name
RETURN VALUE
0 OK
!0 Error
*/
int
Events::drop_schema_events(THD *thd, char *db)
{
int ret= 0;
LEX_STRING db_lex= {db, strlen(db)};
DBUG_ENTER("evex_drop_db_events");
DBUG_PRINT("enter", ("dropping events from %s", db));
pthread_mutex_lock(&LOCK_event_metadata);
event_queue->drop_schema_events(thd, db_lex);
ret= db_repository->drop_schema_events(thd, db_lex);
pthread_mutex_unlock(&LOCK_event_metadata);
DBUG_RETURN(ret);
}
@ -406,14 +458,14 @@ int
Events::show_create_event(THD *thd, sp_name *spn)
{
int ret;
Event_timed *et= NULL;
Event_timed *et= new Event_timed();
Open_tables_state backup;
DBUG_ENTER("Events::show_create_event");
DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
thd->reset_n_backup_open_tables_state(&backup);
ret= db_repository->find_event(thd, spn->m_db, spn->m_name, &et, NULL);
ret= db_repository->find_event(thd, spn->m_db, spn->m_name, et);
thd->restore_backup_open_tables_state(&backup);
if (!ret)
@ -462,154 +514,6 @@ err:
}
/*
Drops all events from a schema
SYNOPSIS
Events::drop_schema_events()
thd Thread
db ASCIIZ schema name
RETURN VALUE
0 OK
!0 Error
*/
int
Events::drop_schema_events(THD *thd, char *db)
{
int ret= 0;
LEX_STRING db_lex= {db, strlen(db)};
DBUG_ENTER("evex_drop_db_events");
DBUG_PRINT("enter", ("dropping events from %s", db));
event_queue->drop_schema_events(thd, db_lex);
ret= db_repository->drop_schema_events(thd, db_lex);
DBUG_RETURN(ret);
}
/*
Inits the scheduler's structures.
SYNOPSIS
Events::init()
NOTES
This function is not synchronized.
RETURN VALUE
0 OK
1 Error
*/
int
Events::init()
{
int ret= 0;
Event_db_repository *db_repo;
DBUG_ENTER("Events::init");
db_repository->init_repository();
event_queue->init_queue(db_repository, scheduler_ng);
scheduler_ng->init_scheduler(event_queue);
/* it should be an assignment! */
if (opt_event_scheduler)
{
DBUG_ASSERT(opt_event_scheduler == 1 || opt_event_scheduler == 2);
if (opt_event_scheduler == 1)
DBUG_RETURN(scheduler_ng->start());
}
DBUG_RETURN(0);
}
/*
Cleans up scheduler's resources. Called at server shutdown.
SYNOPSIS
Events::deinit()
NOTES
This function is not synchronized.
*/
void
Events::deinit()
{
DBUG_ENTER("Events::deinit");
scheduler_ng->stop();
scheduler_ng->deinit_scheduler();
event_queue->deinit_queue();
db_repository->deinit_repository();
DBUG_VOID_RETURN;
}
/*
Inits Events mutexes
SYNOPSIS
Events::init_mutexes()
thd Thread
*/
void
Events::init_mutexes()
{
db_repository= new Event_db_repository;
event_queue= new Event_queue;
event_queue->init_mutexes();
scheduler_ng= new Event_scheduler_ng();
scheduler_ng->init_mutexes();
}
/*
Destroys Events mutexes
SYNOPSIS
Events::destroy_mutexes()
*/
void
Events::destroy_mutexes()
{
event_queue->deinit_mutexes();
scheduler_ng->deinit_mutexes();
delete scheduler_ng;
delete db_repository;
}
/*
Proxy for Event_scheduler::dump_internal_status
SYNOPSIS
Events::dump_internal_status()
thd Thread
RETURN VALUE
0 OK
!0 Error
*/
int
Events::dump_internal_status(THD *thd)
{
return Event_scheduler_ng::dump_internal_status(thd);
}
/*
Proxy for Event_db_repository::fill_schema_events.
Callback for I_S from sql_show.cc
@ -646,6 +550,153 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
}
/*
Inits the scheduler's structures.
SYNOPSIS
Events::init()
NOTES
This function is not synchronized.
RETURN VALUE
0 OK
1 Error
*/
int
Events::init()
{
int ret= 0;
Event_db_repository *db_repo;
DBUG_ENTER("Events::init");
event_queue->init_queue(db_repository, scheduler_ng);
scheduler_ng->init_scheduler(event_queue);
/* it should be an assignment! */
if (opt_event_scheduler)
{
DBUG_ASSERT(opt_event_scheduler == 1 || opt_event_scheduler == 2);
if (opt_event_scheduler == 1)
DBUG_RETURN(scheduler_ng->start());
}
DBUG_RETURN(0);
}
/*
Cleans up scheduler's resources. Called at server shutdown.
SYNOPSIS
Events::deinit()
NOTES
This function is not synchronized.
*/
void
Events::deinit()
{
DBUG_ENTER("Events::deinit");
scheduler_ng->stop();
scheduler_ng->deinit_scheduler();
event_queue->deinit_queue();
DBUG_VOID_RETURN;
}
/*
Inits Events mutexes
SYNOPSIS
Events::init_mutexes()
thd Thread
*/
void
Events::init_mutexes()
{
pthread_mutex_init(&LOCK_event_metadata, MY_MUTEX_INIT_FAST);
db_repository= new Event_db_repository;
event_queue= new Event_queue;
event_queue->init_mutexes();
scheduler_ng= new Event_scheduler_ng();
scheduler_ng->init_mutexes();
}
/*
Destroys Events mutexes
SYNOPSIS
Events::destroy_mutexes()
*/
void
Events::destroy_mutexes()
{
event_queue->deinit_mutexes();
scheduler_ng->deinit_mutexes();
delete scheduler_ng;
delete db_repository;
pthread_mutex_destroy(&LOCK_event_metadata);
}
/*
Proxy for Event_scheduler::dump_internal_status
SYNOPSIS
Events::dump_internal_status()
thd Thread
RETURN VALUE
FALSE OK
TRUE Error
*/
bool
Events::dump_internal_status(THD *thd)
{
DBUG_ENTER("Events::dump_internal_status");
Protocol *protocol= thd->protocol;
List<Item> field_list;
field_list.push_back(new Item_empty_string("Name", 30));
field_list.push_back(new Item_empty_string("Value",20));
if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
if (scheduler_ng->dump_internal_status(thd) ||
event_queue->dump_internal_status(thd))
DBUG_RETURN(TRUE);
send_eof(thd);
DBUG_RETURN(FALSE);
}
/*
Starts execution of events by the scheduler
SYNOPSIS
Events::start_execution_of_events()
RETURN VALUE
FALSE OK
TRUE Error
*/
bool
Events::start_execution_of_events()
{
@ -654,6 +705,19 @@ Events::start_execution_of_events()
}
/*
Stops execution of events by the scheduler.
Already running events will not be stopped. If the user needs
them stopped manual intervention is needed.
SYNOPSIS
Events::stop_execution_of_events()
RETURN VALUE
FALSE OK
TRUE Error
*/
bool
Events::stop_execution_of_events()
{
@ -661,6 +725,18 @@ Events::stop_execution_of_events()
DBUG_RETURN(scheduler_ng->stop());
}
/*
Checks whether the scheduler is running or not.
SYNOPSIS
Events::is_started()
RETURN VALUE
TRUE Yes
FALSE No
*/
bool
Events::is_started()
{

View File

@ -20,6 +20,7 @@ class sp_name;
class Event_parse_data;
class Event_db_repository;
class Event_queue;
class Event_queue_element;
class Event_scheduler_ng;
/* Return codes */
@ -41,6 +42,7 @@ sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
class Events
{
public:
friend class Event_queue_element;
/*
Quite NOT the best practice and will be removed once
Event_timed::drop() and Event_timed is fixed not do drop directly
@ -83,7 +85,8 @@ public:
uint *rows_affected);
int
drop_event(THD *thd, sp_name *name, bool if_exists, uint *rows_affected);
drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists,
uint *rows_affected, bool only_from_disk);
int
drop_schema_events(THD *thd, char *db);
@ -102,13 +105,9 @@ public:
static int
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
int
bool
dump_internal_status(THD *thd);
Event_queue *event_queue;
Event_scheduler_ng *scheduler_ng;
Event_db_repository *db_repository;
private:
/* Singleton DP is used */
Events(){}
@ -117,6 +116,12 @@ private:
/* Singleton instance */
static Events singleton;
Event_queue *event_queue;
Event_scheduler_ng *scheduler_ng;
Event_db_repository *db_repository;
pthread_mutex_t LOCK_event_metadata;
/* Prevent use of these */
Events(const Events &);
void operator=(Events &);

View File

@ -5829,7 +5829,7 @@ ER_CANT_CHANGE_TX_ISOLATION 25001
ER_DUP_ENTRY_AUTOINCREMENT_CASE
eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.64s' for key '%-.64s'"
ER_EVENT_MODIFY_QUEUE_ERROR
eng "Internal scheduler error %d"
eng "Error during loading event from disk. mysql.event damaged?"
ER_EVENT_SET_VAR_ERROR
eng "Error during starting/stopping of the scheduler."
ER_PARTITION_MERGE_ERROR

View File

@ -3886,8 +3886,12 @@ end_with_restore_list:
else
{
uint affected= 1;
if (!(res= Events::get_instance()->
drop_event(thd, lex->spname, lex->drop_if_exists, &affected)))
if (!(res= Events::get_instance()->drop_event(thd,
lex->spname->m_db,
lex->spname->m_name,
lex->drop_if_exists,
&affected,
FALSE)))
send_ok(thd, affected);
}
break;