diff options
Diffstat (limited to 'storage/perfschema/unittest')
19 files changed, 5764 insertions, 0 deletions
diff --git a/storage/perfschema/unittest/CMakeLists.txt b/storage/perfschema/unittest/CMakeLists.txt new file mode 100644 index 00000000..2a22990f --- /dev/null +++ b/storage/perfschema/unittest/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright (c) 2009, 2023, Oracle and/or its affiliates. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2.0, +# as published by the Free Software Foundation. +# +# This program is also distributed with certain software (including +# but not limited to OpenSSL) that is licensed under separate terms, +# as designated in a particular file or component or in included license +# documentation. The authors of MySQL hereby grant you an additional +# permission to link the program and your derivative works with the +# separately licensed software that they have included with MySQL. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License, version 2.0, for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/include/mysql + ${PCRE_INCLUDES} + ${CMAKE_SOURCE_DIR}/sql + ${SSL_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/unittest/mytap + ${CMAKE_SOURCE_DIR}/storage/perfschema) + +ADD_DEFINITIONS(-DMYSQL_SERVER ${SSL_DEFINES}) + +ADD_CONVENIENCE_LIBRARY(pfs_server_stubs pfs_server_stubs.cc) + +ADD_DEPENDENCIES(pfs_server_stubs GenError) + +MY_ADD_TESTS(pfs_instr_class pfs_instr_class-oom pfs_instr pfs_instr-oom + pfs_account-oom pfs_host-oom pfs_timer pfs_user-oom pfs_noop pfs + pfs_misc + EXT "cc" LINK_LIBRARIES perfschema mysys pfs_server_stubs) diff --git a/storage/perfschema/unittest/conf.txt b/storage/perfschema/unittest/conf.txt new file mode 100644 index 00000000..38d1e3d3 --- /dev/null +++ b/storage/perfschema/unittest/conf.txt @@ -0,0 +1,427 @@ +# Copyright (c) 2009, 2023, Oracle and/or its affiliates. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2.0, +# as published by the Free Software Foundation. +# +# This program is also distributed with certain software (including +# but not limited to OpenSSL) that is licensed under separate terms, +# as designated in a particular file or component or in included license +# documentation. The authors of MySQL hereby grant you an additional +# permission to link the program and your derivative works with the +# separately licensed software that they have included with MySQL. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License, version 2.0, for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA + +Performance schema test configurations. +(Used internally for performance testing) + +Configuration PERFSCHEMA-COMPILED-OUT +===================================== + +Description +----------- + +Reference for timings, server built without the performance schema. + +Compiling options +----------------- + +./configure --without-perfschema + +Server start options +-------------------- + +N/A + +Configuration +------------- + +N/A + +Pre-test queries +---------------- + +select version(); + +This is just to make sure the build is not including the performance schema. + +Post-test queries +----------------- + +N/A + +Configuration PERFSCHEMA-DISABLED +================================= + +Description +----------- + +Server built with the performance schema, +but the performance schema is disabled at startup. + +Compiling options +----------------- + +./configure --with-perfschema + +Server start options +-------------------- + +./mysqld --disable-performance-schema + +Configuration +------------- + +N/A + +Pre-test queries +---------------- + +select version(); +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; +select * from performance_schema.PERFORMANCE_TIMERS; +select * from performance_schema.SETUP_CONSUMERS; +select * from performance_schema.SETUP_INSTRUMENTS; +select * from performance_schema.SETUP_TIMERS; + +Post-test queries +----------------- + +N/A + +Configuration PERFSCHEMA-ENABLED-STANDBY +======================================== + +Description +----------- + +Server built with the performance schema. +The performance schema is enabled at startup, +but configured to not record anything. +This is a "stanby" configuration, in the sense that the DBA can add +dynamically more setup options later to get data. + +Compiling options +----------------- + +./configure --with-perfschema + +Server start options +-------------------- + +./mysqld --enable-performance-schema + +Configuration +------------- + +UPDATE performance_schema.SETUP_INSTRUMENTS + set enabled='NO', timed='NO'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='NO'; + +Pre-test queries +---------------- + +select version(); +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; +select * from performance_schema.PERFORMANCE_TIMERS; +select * from performance_schema.SETUP_CONSUMERS; +select * from performance_schema.SETUP_INSTRUMENTS; +select * from performance_schema.SETUP_TIMERS; + +Post-test queries +----------------- + +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; + +Configuration PERFSCHEMA-ENABLED-CURRENT +======================================== + +Description +----------- + +Server built with the performance schema. +The performance schema is enabled at startup. +All instruments are enabled but not timed, +and only one consumer (EVENTS_WAITS_CURRENT) is set. + +Compiling options +----------------- + +./configure --with-perfschema + +Server start options +-------------------- + +./mysqld --enable-performance-schema + +Configuration +------------- + +UPDATE performance_schema.SETUP_INSTRUMENTS + set enabled='YES', timed='NO'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='NO'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='YES' where name='EVENTS_WAITS_CURRENT'; + +Pre-test queries +---------------- + +select version(); +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; +select * from performance_schema.PERFORMANCE_TIMERS; +select * from performance_schema.SETUP_CONSUMERS; +select * from performance_schema.SETUP_INSTRUMENTS; +select * from performance_schema.SETUP_TIMERS; + +Post-test queries +----------------- + +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; + +Configuration PERFSCHEMA-ENABLED-CURRENT-CYCLE +============================================== + +Description +----------- + +Server built with the performance schema. +The performance schema is enabled at startup. +All instruments are enabled and timed, +and only one consumer (EVENTS_WAITS_CURRENT) is set. +The timer used is CYCLE. + +Compiling options +----------------- + +./configure --with-perfschema + +Server start options +-------------------- + +./mysqld --enable-performance-schema + +Configuration +------------- + +UPDATE performance_schema.SETUP_INSTRUMENTS + set enabled='YES', timed='YES'; + +UPDATE performance_schema.SETUP_TIMERS + set timer_name='CYCLE'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='NO'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='YES' where name='EVENTS_WAITS_CURRENT'; + +Pre-test queries +---------------- + +select version(); +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; +select * from performance_schema.PERFORMANCE_TIMERS; +select * from performance_schema.SETUP_CONSUMERS; +select * from performance_schema.SETUP_INSTRUMENTS; +select * from performance_schema.SETUP_TIMERS; + +Post-test queries +----------------- + +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; + +Configuration PERFSCHEMA-ENABLED-HISTORY-CYCLE +============================================== + +Description +----------- + +Server built with the performance schema. +The performance schema is enabled at startup. +All instruments are enabled and timed, in CYCLE. +Two consumers (EVENTS_WAITS_CURRENT, EVENTS_WAITS_HISTORY) are set. + +Compiling options +----------------- + +./configure --with-perfschema + +Server start options +-------------------- + +./mysqld --enable-performance-schema + +Configuration +------------- + +UPDATE performance_schema.SETUP_INSTRUMENTS + set enabled='YES', timed='YES'; + +UPDATE performance_schema.SETUP_TIMERS + set timer_name='CYCLE'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='NO'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='YES' where name='EVENTS_WAITS_CURRENT'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='YES' where name='EVENTS_WAITS_HISTORY'; + +Pre-test queries +---------------- + +select version(); +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; +select * from performance_schema.PERFORMANCE_TIMERS; +select * from performance_schema.SETUP_CONSUMERS; +select * from performance_schema.SETUP_INSTRUMENTS; +select * from performance_schema.SETUP_TIMERS; + +Post-test queries +----------------- + +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; + +Configuration PERFSCHEMA-ENABLED-HISTORY_LONG-CYCLE +=================================================== + +Description +----------- + +Server built with the performance schema. +The performance schema is enabled at startup. +All instruments are enabled and timed, in CYCLE. +Two consumers (EVENTS_WAITS_CURRENT, EVENTS_WAITS_HISTORY_LONG) are set. + +Compiling options +----------------- + +./configure --with-perfschema + +Server start options +-------------------- + +./mysqld --enable-performance-schema + +Configuration +------------- + +UPDATE performance_schema.SETUP_INSTRUMENTS + set enabled='YES', timed='YES'; + +UPDATE performance_schema.SETUP_TIMERS + set timer_name='CYCLE'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='NO'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='YES' where name='EVENTS_WAITS_CURRENT'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='YES' where name='EVENTS_WAITS_HISTORY_LONG'; + +Pre-test queries +---------------- + +select version(); +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; +select * from performance_schema.PERFORMANCE_TIMERS; +select * from performance_schema.SETUP_CONSUMERS; +select * from performance_schema.SETUP_INSTRUMENTS; +select * from performance_schema.SETUP_TIMERS; + +Post-test queries +----------------- + +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; + +Configuration PERFSCHEMA-ENABLED-BIGBANG-CYCLE +============================================== + +Description +----------- + +Server built with the performance schema. +The performance schema is enabled at startup. +All instruments are enabled and timed, in CYCLE. +All possible consumers are enabled. + +Compiling options +----------------- + +./configure --with-perfschema + +Server start options +-------------------- + +./mysqld --enable-performance-schema + +Configuration +------------- + +UPDATE performance_schema.SETUP_INSTRUMENTS + set enabled='YES', timed='YES'; + +UPDATE performance_schema.SETUP_TIMERS + set timer_name='CYCLE'; + +UPDATE performance_schema.SETUP_CONSUMERS + set enabled='YES'; + +Pre-test queries +---------------- + +select version(); +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; +select * from performance_schema.PERFORMANCE_TIMERS; +select * from performance_schema.SETUP_CONSUMERS; +select * from performance_schema.SETUP_INSTRUMENTS; +select * from performance_schema.SETUP_TIMERS; + +Post-test queries +----------------- + +show engine performance_schema status; +show variables like "performance%"; +show status like "performance%"; + diff --git a/storage/perfschema/unittest/pfs-t.cc b/storage/perfschema/unittest/pfs-t.cc new file mode 100644 index 00000000..981792f9 --- /dev/null +++ b/storage/perfschema/unittest/pfs-t.cc @@ -0,0 +1,1909 @@ +/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_server.h> +#include <pfs_instr_class.h> +#include <pfs_instr.h> +#include <pfs_global.h> +#include <pfs_buffer_container.h> +#include <tap.h> + +#include <string.h> +#include <memory.h> + +#include "stub_print_error.h" +#include "stub_pfs_defaults.h" +#include "stub_global_status_var.h" + +void unload_performance_schema(); + +/* test helpers, to simulate the setup */ + +void setup_thread(PSI_thread *t, bool enabled) +{ + PFS_thread *t2= (PFS_thread*) t; + t2->m_enabled= enabled; +} + +/* test helpers, to inspect data */ + +PFS_file* lookup_file_by_name(const char* name) +{ + PFS_file *pfs; + size_t len= strlen(name); + size_t dirlen; + const char *filename; + size_t filename_length; + + PFS_file_iterator it= global_file_container.iterate(); + pfs= it.scan_next(); + + while (pfs != NULL) + { + /* + When a file "foo" is instrumented, the name is normalized + to "/path/to/current/directory/foo", so we remove the + directory name here to find it back. + */ + dirlen= dirname_length(pfs->m_filename); + filename= pfs->m_filename + dirlen; + filename_length= pfs->m_filename_length - dirlen; + if ((len == filename_length) && + (strncmp(name, filename, filename_length) == 0)) + return pfs; + + pfs= it.scan_next(); + } + + return NULL; +} + +/* tests */ + +void test_bootstrap() +{ + void *psi; + void *psi_2; + PSI_bootstrap *boot; + PFS_global_param param; + + diag("test_bootstrap"); + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 0; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 0; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_host_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; + param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 0; + param.m_metadata_lock_sizing= 0; + param.m_max_digest_length= 0; + param.m_max_sql_text_length= 0; + + param.m_hints.m_table_definition_cache = 100; + param.m_hints.m_table_open_cache = 100; + param.m_hints.m_max_connections = 100; + param.m_hints.m_open_files_limit = 100; + param.m_hints.m_max_prepared_stmt_count= 100; + + pre_initialize_performance_schema(); + boot= initialize_performance_schema(& param); + ok(boot != NULL, "boot"); + ok(boot->get_interface != NULL, "boot->get_interface"); + + psi= boot->get_interface(0); + ok(psi == NULL, "no version 0"); + + psi= boot->get_interface(PSI_VERSION_1); + ok(psi != NULL, "version 1"); + + psi_2= boot->get_interface(PSI_VERSION_2); + ok(psi_2 == NULL, "version 2"); + + unload_performance_schema(); +} + +/* + Not a test, helper for testing pfs.cc +*/ +PSI * load_perfschema() +{ + PSI *psi; + PSI_bootstrap *boot; + PFS_global_param param; + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 10; + param.m_rwlock_class_sizing= 10; + param.m_cond_class_sizing= 10; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 10; + param.m_file_class_sizing= 10; + param.m_socket_class_sizing= 10; + param.m_mutex_sizing= 10; + param.m_rwlock_sizing= 10; + param.m_cond_sizing= 10; + param.m_thread_sizing= 10; + param.m_table_sizing= 10; + param.m_file_sizing= 10; + param.m_file_handle_sizing= 50; + param.m_socket_sizing= 10; + param.m_events_waits_history_sizing= 10; + param.m_events_waits_history_long_sizing= 10; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_host_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; + param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_statement_stack_sizing= 10; + param.m_memory_class_sizing= 10; + param.m_metadata_lock_sizing= 10; + param.m_max_digest_length= 0; + param.m_max_sql_text_length= 1000; + + param.m_hints.m_table_definition_cache = 100; + param.m_hints.m_table_open_cache = 100; + param.m_hints.m_max_connections = 100; + param.m_hints.m_open_files_limit = 100; + param.m_hints.m_max_prepared_stmt_count= 100; + + pre_initialize_performance_schema(); + /* test_bootstrap() covered this, assuming it just works */ + boot= initialize_performance_schema(& param); + psi= (PSI *)boot->get_interface(PSI_VERSION_1); + + /* Reset every consumer to a known state */ + flag_global_instrumentation= true; + flag_thread_instrumentation= true; + + return (PSI*) psi; +} + +void unload_performance_schema() +{ + cleanup_table_share(); + cleanup_instruments(); + cleanup_sync_class(); + cleanup_thread_class(); + cleanup_table_share(); + cleanup_file_class(); + cleanup_stage_class(); + cleanup_statement_class(); + cleanup_socket_class(); + cleanup_events_waits_history_long(); + cleanup_events_stages_history_long(); + cleanup_events_statements_history_long(); + cleanup_table_share_hash(); + cleanup_file_hash(); + cleanup_digest(); + + shutdown_performance_schema(); +} + +void test_bad_registration() +{ + PSI *psi; + + diag("test_bad_registration"); + + psi= load_perfschema(); + + /* + Test that length('wait/synch/mutex/' (17) + category + '/' (1)) < 32 + --> category can be up to 13 chars for a mutex. + */ + + PSI_mutex_key dummy_mutex_key= 9999; + PSI_mutex_info bad_mutex_1[]= + { + { & dummy_mutex_key, "X", 0} + }; + + psi->register_mutex("/", bad_mutex_1, 1); + ok(dummy_mutex_key == 0, "zero key"); + dummy_mutex_key= 9999; + psi->register_mutex("a/", bad_mutex_1, 1); + ok(dummy_mutex_key == 0, "zero key"); + dummy_mutex_key= 9999; + psi->register_mutex("/b", bad_mutex_1, 1); + ok(dummy_mutex_key == 0, "zero key"); + dummy_mutex_key= 9999; + psi->register_mutex("a/b", bad_mutex_1, 1); + ok(dummy_mutex_key == 0, "zero key"); + dummy_mutex_key= 9999; + psi->register_mutex("12345678901234", bad_mutex_1, 1); + ok(dummy_mutex_key == 0, "zero key"); + dummy_mutex_key= 9999; + psi->register_mutex("1234567890123", bad_mutex_1, 1); + ok(dummy_mutex_key == 1, "assigned key"); + + /* + Test that length('wait/synch/mutex/' (17) + category + '/' (1) + name) <= 128 + --> category + name can be up to 110 chars for a mutex. + */ + + dummy_mutex_key= 9999; + PSI_mutex_info bad_mutex_2[]= + { + { & dummy_mutex_key, + /* 110 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "1234567890", + 0} + }; + + psi->register_mutex("X", bad_mutex_2, 1); + ok(dummy_mutex_key == 0, "zero key"); + + dummy_mutex_key= 9999; + PSI_mutex_info bad_mutex_3[]= + { + { & dummy_mutex_key, + /* 109 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "123456789", + 0} + }; + + psi->register_mutex("XX", bad_mutex_3, 1); + ok(dummy_mutex_key == 0, "zero key"); + + psi->register_mutex("X", bad_mutex_3, 1); + ok(dummy_mutex_key == 2, "assigned key"); + + /* + Test that length('wait/synch/rwlock/' (18) + category + '/' (1)) < 32 + --> category can be up to 12 chars for a rwlock. + */ + + PSI_rwlock_key dummy_rwlock_key= 9999; + PSI_rwlock_info bad_rwlock_1[]= + { + { & dummy_rwlock_key, "X", 0} + }; + + psi->register_rwlock("/", bad_rwlock_1, 1); + ok(dummy_rwlock_key == 0, "zero key"); + dummy_rwlock_key= 9999; + psi->register_rwlock("a/", bad_rwlock_1, 1); + ok(dummy_rwlock_key == 0, "zero key"); + dummy_rwlock_key= 9999; + psi->register_rwlock("/b", bad_rwlock_1, 1); + ok(dummy_rwlock_key == 0, "zero key"); + dummy_rwlock_key= 9999; + psi->register_rwlock("a/b", bad_rwlock_1, 1); + ok(dummy_rwlock_key == 0, "zero key"); + dummy_rwlock_key= 9999; + psi->register_rwlock("1234567890123", bad_rwlock_1, 1); + ok(dummy_rwlock_key == 0, "zero key"); + dummy_rwlock_key= 9999; + psi->register_rwlock("123456789012", bad_rwlock_1, 1); + ok(dummy_rwlock_key == 1, "assigned key"); + + /* + Test that length('wait/synch/rwlock/' (18) + category + '/' (1) + name) <= 128 + --> category + name can be up to 109 chars for a rwlock. + */ + + dummy_rwlock_key= 9999; + PSI_rwlock_info bad_rwlock_2[]= + { + { & dummy_rwlock_key, + /* 109 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "123456789", + 0} + }; + + psi->register_rwlock("X", bad_rwlock_2, 1); + ok(dummy_rwlock_key == 0, "zero key"); + + dummy_rwlock_key= 9999; + PSI_rwlock_info bad_rwlock_2_sx[]= + { + { & dummy_rwlock_key, + /* 109 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "123456789", + PSI_RWLOCK_FLAG_SX} + }; + + psi->register_rwlock("Y", bad_rwlock_2_sx, 1); + ok(dummy_rwlock_key == 0, "zero key SX"); + + dummy_rwlock_key= 9999; + PSI_rwlock_info bad_rwlock_3[]= + { + { & dummy_rwlock_key, + /* 108 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678", + 0} + }; + + psi->register_rwlock("XX", bad_rwlock_3, 1); + ok(dummy_rwlock_key == 0, "zero key"); + + psi->register_rwlock("X", bad_rwlock_3, 1); + ok(dummy_rwlock_key == 2, "assigned key"); + + dummy_rwlock_key= 9999; + PSI_rwlock_info bad_rwlock_3_sx[]= + { + { & dummy_rwlock_key, + /* 108 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678", + PSI_RWLOCK_FLAG_SX} + }; + + psi->register_rwlock("YY", bad_rwlock_3_sx, 1); + ok(dummy_rwlock_key == 0, "zero key SX"); + + psi->register_rwlock("Y", bad_rwlock_3_sx, 1); + ok(dummy_rwlock_key == 3, "assigned key SX"); + + /* + Test that length('wait/synch/cond/' (16) + category + '/' (1)) < 32 + --> category can be up to 14 chars for a cond. + */ + + PSI_cond_key dummy_cond_key= 9999; + PSI_cond_info bad_cond_1[]= + { + { & dummy_cond_key, "X", 0} + }; + + psi->register_cond("/", bad_cond_1, 1); + ok(dummy_cond_key == 0, "zero key"); + dummy_cond_key= 9999; + psi->register_cond("a/", bad_cond_1, 1); + ok(dummy_cond_key == 0, "zero key"); + dummy_cond_key= 9999; + psi->register_cond("/b", bad_cond_1, 1); + ok(dummy_cond_key == 0, "zero key"); + dummy_cond_key= 9999; + psi->register_cond("a/b", bad_cond_1, 1); + ok(dummy_cond_key == 0, "zero key"); + dummy_cond_key= 9999; + psi->register_cond("123456789012345", bad_cond_1, 1); + ok(dummy_cond_key == 0, "zero key"); + dummy_cond_key= 9999; + psi->register_cond("12345678901234", bad_cond_1, 1); + ok(dummy_cond_key == 1, "assigned key"); + + /* + Test that length('wait/synch/cond/' (16) + category + '/' (1) + name) <= 128 + --> category + name can be up to 111 chars for a cond. + */ + + dummy_cond_key= 9999; + PSI_cond_info bad_cond_2[]= + { + { & dummy_cond_key, + /* 111 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678901", + 0} + }; + + psi->register_cond("X", bad_cond_2, 1); + ok(dummy_cond_key == 0, "zero key"); + + dummy_cond_key= 9999; + PSI_cond_info bad_cond_3[]= + { + { & dummy_cond_key, + /* 110 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "1234567890", + 0} + }; + + psi->register_cond("XX", bad_cond_3, 1); + ok(dummy_cond_key == 0, "zero key"); + + psi->register_cond("X", bad_cond_3, 1); + ok(dummy_cond_key == 2, "assigned key"); + + /* + Test that length('thread/' (7) + category + '/' (1)) < 32 + --> category can be up to 23 chars for a thread. + */ + + PSI_thread_key dummy_thread_key= 9999; + PSI_thread_info bad_thread_1[]= + { + { & dummy_thread_key, "X", 0} + }; + + psi->register_thread("/", bad_thread_1, 1); + ok(dummy_thread_key == 0, "zero key"); + dummy_thread_key= 9999; + psi->register_thread("a/", bad_thread_1, 1); + ok(dummy_thread_key == 0, "zero key"); + dummy_thread_key= 9999; + psi->register_thread("/b", bad_thread_1, 1); + ok(dummy_thread_key == 0, "zero key"); + dummy_thread_key= 9999; + psi->register_thread("a/b", bad_thread_1, 1); + ok(dummy_thread_key == 0, "zero key"); + dummy_thread_key= 9999; + psi->register_thread("123456789012345678901234", bad_thread_1, 1); + ok(dummy_thread_key == 0, "zero key"); + dummy_thread_key= 9999; + psi->register_thread("12345678901234567890123", bad_thread_1, 1); + ok(dummy_thread_key == 1, "assigned key"); + + /* + Test that length('thread/' (7) + category + '/' (1) + name) <= 128 + --> category + name can be up to 120 chars for a thread. + */ + + dummy_thread_key= 9999; + PSI_thread_info bad_thread_2[]= + { + { & dummy_thread_key, + /* 120 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678901234567890", + 0} + }; + + psi->register_thread("X", bad_thread_2, 1); + ok(dummy_thread_key == 0, "zero key"); + + dummy_thread_key= 9999; + PSI_thread_info bad_thread_3[]= + { + { & dummy_thread_key, + /* 119 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "1234567890123456789", + 0} + }; + + psi->register_thread("XX", bad_thread_3, 1); + ok(dummy_thread_key == 0, "zero key"); + + psi->register_thread("X", bad_thread_3, 1); + ok(dummy_thread_key == 2, "assigned key"); + + /* + Test that length('wait/io/file/' (13) + category + '/' (1)) < 32 + --> category can be up to 17 chars for a file. + */ + + PSI_file_key dummy_file_key= 9999; + PSI_file_info bad_file_1[]= + { + { & dummy_file_key, "X", 0} + }; + + psi->register_file("/", bad_file_1, 1); + ok(dummy_file_key == 0, "zero key"); + dummy_file_key= 9999; + psi->register_file("a/", bad_file_1, 1); + ok(dummy_file_key == 0, "zero key"); + dummy_file_key= 9999; + psi->register_file("/b", bad_file_1, 1); + ok(dummy_file_key == 0, "zero key"); + dummy_file_key= 9999; + psi->register_file("a/b", bad_file_1, 1); + ok(dummy_file_key == 0, "zero key"); + dummy_file_key= 9999; + psi->register_file("123456789012345678", bad_file_1, 1); + ok(dummy_file_key == 0, "zero key"); + dummy_file_key= 9999; + psi->register_file("12345678901234567", bad_file_1, 1); + ok(dummy_file_key == 1, "assigned key"); + + /* + Test that length('wait/io/file/' (13) + category + '/' (1) + name) <= 128 + --> category + name can be up to 114 chars for a file. + */ + + dummy_file_key= 9999; + PSI_file_info bad_file_2[]= + { + { & dummy_file_key, + /* 114 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678901234", + 0} + }; + + psi->register_file("X", bad_file_2, 1); + ok(dummy_file_key == 0, "zero key"); + + dummy_file_key= 9999; + PSI_file_info bad_file_3[]= + { + { & dummy_file_key, + /* 113 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "1234567890123", + 0} + }; + + psi->register_file("XX", bad_file_3, 1); + ok(dummy_file_key == 0, "zero key"); + + psi->register_file("X", bad_file_3, 1); + ok(dummy_file_key == 2, "assigned key"); + + /* + Test that length('wait/io/socket/' (15) + category + '/' (1)) < 32 + --> category can be up to 15 chars for a socket. + */ + + PSI_socket_key dummy_socket_key= 9999; + PSI_socket_info bad_socket_1[]= + { + { & dummy_socket_key, "X", 0} + }; + + psi->register_socket("/", bad_socket_1, 1); + ok(dummy_socket_key == 0, "zero key"); + dummy_socket_key= 9999; + psi->register_socket("a/", bad_socket_1, 1); + ok(dummy_socket_key == 0, "zero key"); + dummy_socket_key= 9999; + psi->register_socket("/b", bad_socket_1, 1); + ok(dummy_socket_key == 0, "zero key"); + dummy_socket_key= 9999; + psi->register_socket("a/b", bad_socket_1, 1); + ok(dummy_socket_key == 0, "zero key"); + dummy_socket_key= 9999; + psi->register_socket("1234567890123456", bad_socket_1, 1); + ok(dummy_socket_key == 0, "zero key"); + dummy_socket_key= 9999; + psi->register_socket("123456789012345", bad_socket_1, 1); + ok(dummy_socket_key == 1, "assigned key"); + + /* + Test that length('wait/io/socket/' (15) + category + '/' (1) + name) <= 128 + --> category + name can be up to 112 chars for a socket. + */ + + dummy_socket_key= 9999; + PSI_socket_info bad_socket_2[]= + { + { & dummy_socket_key, + /* 112 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "123456789012", + 0} + }; + + psi->register_socket("X", bad_socket_2, 1); + ok(dummy_socket_key == 0, "zero key"); + + dummy_socket_key= 9999; + PSI_socket_info bad_socket_3[]= + { + { & dummy_socket_key, + /* 111 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678901", + 0} + }; + + psi->register_socket("XX", bad_socket_3, 1); + ok(dummy_socket_key == 0, "zero key"); + + psi->register_socket("X", bad_socket_3, 1); + ok(dummy_socket_key == 2, "assigned key"); + + unload_performance_schema(); +} + +void test_init_disabled() +{ + PSI *psi; + + diag("test_init_disabled"); + + psi= load_perfschema(); + + PSI_mutex_key mutex_key_A; + PSI_mutex_info all_mutex[]= + { + { & mutex_key_A, "M-A", 0} + }; + + PSI_rwlock_key rwlock_key_A; + PSI_rwlock_info all_rwlock[]= + { + { & rwlock_key_A, "RW-A", 0} + }; + + PSI_cond_key cond_key_A; + PSI_cond_info all_cond[]= + { + { & cond_key_A, "C-A", 0} + }; + + PSI_file_key file_key_A; + PSI_file_info all_file[]= + { + { & file_key_A, "F-A", 0} + }; + + PSI_socket_key socket_key_A; + PSI_socket_info all_socket[]= + { + { & socket_key_A, "S-A", 0} + }; + + PSI_thread_key thread_key_1; + PSI_thread_info all_thread[]= + { + { & thread_key_1, "T-1", 0} + }; + + psi->register_mutex("test", all_mutex, 1); + psi->register_rwlock("test", all_rwlock, 1); + psi->register_cond("test", all_cond, 1); + psi->register_file("test", all_file, 1); + psi->register_socket("test", all_socket, 1); + psi->register_thread("test", all_thread, 1); + + PFS_mutex_class *mutex_class_A; + PFS_rwlock_class *rwlock_class_A; + PFS_cond_class *cond_class_A; + PFS_file_class *file_class_A; + PFS_socket_class *socket_class_A; + PSI_mutex *mutex_A1; + PSI_rwlock *rwlock_A1; + PSI_cond *cond_A1; + PFS_file *file_A1; + PSI_socket *socket_A1; + PSI_thread *thread_1; + + /* Preparation */ + + thread_1= psi->new_thread(thread_key_1, NULL, 0); + ok(thread_1 != NULL, "T-1"); + psi->set_thread_id(thread_1, 1); + + mutex_class_A= find_mutex_class(mutex_key_A); + ok(mutex_class_A != NULL, "mutex class A"); + + rwlock_class_A= find_rwlock_class(rwlock_key_A); + ok(rwlock_class_A != NULL, "rwlock class A"); + + cond_class_A= find_cond_class(cond_key_A); + ok(cond_class_A != NULL, "cond class A"); + + file_class_A= find_file_class(file_key_A); + ok(file_class_A != NULL, "file class A"); + + socket_class_A= find_socket_class(socket_key_A); + ok(socket_class_A != NULL, "socket class A"); + + /* + Pretend thread T-1 is running, and disabled, with thread_instrumentation. + Disabled instruments are still created so they can be enabled later. + */ + + /* ------------------------------------------------------------------------ */ + + psi->set_thread(thread_1); + setup_thread(thread_1, false); + + /* disabled M-A + disabled T-1: instrumentation */ + + mutex_class_A->m_enabled= false; + mutex_A1= psi->init_mutex(mutex_key_A, NULL); + ok(mutex_A1 != NULL, "mutex_A1 disabled, instrumented"); + + /* enabled M-A + disabled T-1: instrumentation (for later) */ + + mutex_class_A->m_enabled= true; + mutex_A1= psi->init_mutex(mutex_key_A, NULL); + ok(mutex_A1 != NULL, "mutex_A1 enabled, instrumented"); + + /* broken key + disabled T-1: no instrumentation */ + + mutex_class_A->m_enabled= true; + mutex_A1= psi->init_mutex(0, NULL); + ok(mutex_A1 == NULL, "mutex key 0 not instrumented"); + mutex_A1= psi->init_mutex(99, NULL); + ok(mutex_A1 == NULL, "broken mutex key not instrumented"); + + /* disabled RW-A + disabled T-1: no instrumentation */ + + rwlock_class_A->m_enabled= false; + rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); + ok(rwlock_A1 != NULL, "rwlock_A1 disabled, instrumented"); + + /* enabled RW-A + disabled T-1: instrumentation (for later) */ + + rwlock_class_A->m_enabled= true; + rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); + ok(rwlock_A1 != NULL, "rwlock_A1 enabled, instrumented"); + + /* broken key + disabled T-1: no instrumentation */ + + rwlock_class_A->m_enabled= true; + rwlock_A1= psi->init_rwlock(0, NULL); + ok(rwlock_A1 == NULL, "rwlock key 0 not instrumented"); + rwlock_A1= psi->init_rwlock(99, NULL); + ok(rwlock_A1 == NULL, "broken rwlock key not instrumented"); + + /* disabled C-A + disabled T-1: no instrumentation */ + + cond_class_A->m_enabled= false; + cond_A1= psi->init_cond(cond_key_A, NULL); + ok(cond_A1 != NULL, "cond_A1 disabled, instrumented"); + + /* enabled C-A + disabled T-1: instrumentation (for later) */ + + cond_class_A->m_enabled= true; + cond_A1= psi->init_cond(cond_key_A, NULL); + ok(cond_A1 != NULL, "cond_A1 enabled, instrumented"); + + /* broken key + disabled T-1: no instrumentation */ + + cond_class_A->m_enabled= true; + cond_A1= psi->init_cond(0, NULL); + ok(cond_A1 == NULL, "cond key 0 not instrumented"); + cond_A1= psi->init_cond(99, NULL); + ok(cond_A1 == NULL, "broken cond key not instrumented"); + + /* disabled F-A + disabled T-1: no instrumentation */ + + file_class_A->m_enabled= false; + psi->create_file(file_key_A, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "not instrumented"); + + /* enabled F-A + disabled T-1: no instrumentation */ + + file_class_A->m_enabled= true; + psi->create_file(file_key_A, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "not instrumented"); + + /* broken key + disabled T-1: no instrumentation */ + + file_class_A->m_enabled= true; + psi->create_file(0, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "file_A1 not instrumented"); + psi->create_file(99, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "file_A1 not instrumented"); + + /* disabled S-A + disabled T-1: no instrumentation */ + + socket_class_A->m_enabled= false; + socket_A1= psi->init_socket(socket_key_A, NULL, NULL, 0); + ok(socket_A1 != NULL, "socket_A1 disabled, instrumented"); + + /* enabled S-A + disabled T-1: instrumentation (for later) */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(socket_key_A, NULL, NULL, 0); + ok(socket_A1 != NULL, "socket_A1 enabled, instrumented"); + + /* broken key + disabled T-1: no instrumentation */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(0, NULL, NULL, 0); + ok(socket_A1 == NULL, "socket key 0 not instrumented"); + socket_A1= psi->init_socket(99, NULL, NULL, 0); + ok(socket_A1 == NULL, "broken socket key not instrumented"); + + /* Pretend thread T-1 is enabled */ + /* ----------------------------- */ + + setup_thread(thread_1, true); + + /* disabled M-A + enabled T-1: no instrumentation */ + + mutex_class_A->m_enabled= false; + mutex_A1= psi->init_mutex(mutex_key_A, NULL); + ok(mutex_A1 != NULL, "mutex_A1 disabled, instrumented"); + + /* enabled M-A + enabled T-1: instrumentation */ + + mutex_class_A->m_enabled= true; + mutex_A1= psi->init_mutex(mutex_key_A, NULL); + ok(mutex_A1 != NULL, "mutex_A1 enabled, instrumented"); + psi->destroy_mutex(mutex_A1); + + /* broken key + enabled T-1: no instrumentation */ + + mutex_class_A->m_enabled= true; + mutex_A1= psi->init_mutex(0, NULL); + ok(mutex_A1 == NULL, "mutex_A1 not instrumented"); + mutex_A1= psi->init_mutex(99, NULL); + ok(mutex_A1 == NULL, "mutex_A1 not instrumented"); + + /* disabled RW-A + enabled T-1: no instrumentation */ + + rwlock_class_A->m_enabled= false; + rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); + ok(rwlock_A1 != NULL, "rwlock_A1 disabled, instrumented"); + + /* enabled RW-A + enabled T-1: instrumentation */ + + rwlock_class_A->m_enabled= true; + rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); + ok(rwlock_A1 != NULL, "rwlock_A1 enabled, instrumented"); + psi->destroy_rwlock(rwlock_A1); + + /* broken key + enabled T-1: no instrumentation */ + + rwlock_class_A->m_enabled= true; + rwlock_A1= psi->init_rwlock(0, NULL); + ok(rwlock_A1 == NULL, "rwlock_A1 not instrumented"); + rwlock_A1= psi->init_rwlock(99, NULL); + ok(rwlock_A1 == NULL, "rwlock_A1 not instrumented"); + + /* disabled C-A + enabled T-1: no instrumentation */ + + cond_class_A->m_enabled= false; + cond_A1= psi->init_cond(cond_key_A, NULL); + ok(cond_A1 != NULL, "cond_A1 disabled, instrumented"); + + /* enabled C-A + enabled T-1: instrumentation */ + + cond_class_A->m_enabled= true; + cond_A1= psi->init_cond(cond_key_A, NULL); + ok(cond_A1 != NULL, "cond_A1 enabled, instrumented"); + psi->destroy_cond(cond_A1); + + /* broken key + enabled T-1: no instrumentation */ + + cond_class_A->m_enabled= true; + cond_A1= psi->init_cond(0, NULL); + ok(cond_A1 == NULL, "cond_A1 not instrumented"); + cond_A1= psi->init_cond(99, NULL); + ok(cond_A1 == NULL, "cond_A1 not instrumented"); + + /* disabled F-A + enabled T-1: no instrumentation */ + + file_class_A->m_enabled= false; + psi->create_file(file_key_A, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "file_A1 not instrumented"); + + /* enabled F-A + open failed + enabled T-1: no instrumentation */ + + file_class_A->m_enabled= true; + psi->create_file(file_key_A, "foo", (File) -1); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "file_A1 not instrumented"); + + /* enabled F-A + out-of-descriptors + enabled T-1: no instrumentation */ + + file_class_A->m_enabled= true; + psi->create_file(file_key_A, "foo", (File) 65000); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "file_A1 not instrumented"); + ok(file_handle_lost == 1, "lost a file handle"); + file_handle_lost= 0; + + /* enabled F-A + enabled T-1: instrumentation */ + + file_class_A->m_enabled= true; + psi->create_file(file_key_A, "foo-instrumented", (File) 12); + file_A1= lookup_file_by_name("foo-instrumented"); + ok(file_A1 != NULL, "file_A1 instrumented"); + destroy_file(reinterpret_cast<PFS_thread*>(psi->get_thread()), file_A1); + + /* broken key + enabled T-1: no instrumentation */ + + file_class_A->m_enabled= true; + psi->create_file(0, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "file key 0 not instrumented"); + psi->create_file(99, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "broken file key not instrumented"); + + /* disabled S-A + enabled T-1: no instrumentation */ + + socket_class_A->m_enabled= false; + ok(socket_A1 == NULL, "socket_A1 not instrumented"); + + /* enabled S-A + enabled T-1: instrumentation */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(socket_key_A, NULL, NULL, 0); + ok(socket_A1 != NULL, "socket_A1 instrumented"); + psi->destroy_socket(socket_A1); + + /* broken key + enabled T-1: no instrumentation */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(0, NULL, NULL, 0); + ok(socket_A1 == NULL, "socket_A1 not instrumented"); + socket_A1= psi->init_socket(99, NULL, NULL, 0); + ok(socket_A1 == NULL, "socket_A1 not instrumented"); + + /* Pretend the running thread is not instrumented */ + /* ---------------------------------------------- */ + + psi->delete_current_thread(); + + /* disabled M-A + unknown thread: no instrumentation */ + + mutex_class_A->m_enabled= false; + mutex_A1= psi->init_mutex(mutex_key_A, NULL); + ok(mutex_A1 != NULL, "mutex_A1 disabled, instrumented"); + + /* enabled M-A + unknown thread: instrumentation (for later) */ + + mutex_class_A->m_enabled= true; + mutex_A1= psi->init_mutex(mutex_key_A, NULL); + ok(mutex_A1 != NULL, "mutex_A1 enabled, instrumented"); + + /* broken key + unknown thread: no instrumentation */ + + mutex_class_A->m_enabled= true; + mutex_A1= psi->init_mutex(0, NULL); + ok(mutex_A1 == NULL, "mutex key 0 not instrumented"); + mutex_A1= psi->init_mutex(99, NULL); + ok(mutex_A1 == NULL, "broken mutex key not instrumented"); + + /* disabled RW-A + unknown thread: no instrumentation */ + + rwlock_class_A->m_enabled= false; + rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); + ok(rwlock_A1 != NULL, "rwlock_A1 disabled, instrumented"); + + /* enabled RW-A + unknown thread: instrumentation (for later) */ + + rwlock_class_A->m_enabled= true; + rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); + ok(rwlock_A1 != NULL, "rwlock_A1 enabled, instrumented"); + + /* broken key + unknown thread: no instrumentation */ + + rwlock_class_A->m_enabled= true; + rwlock_A1= psi->init_rwlock(0, NULL); + ok(rwlock_A1 == NULL, "rwlock key 0 not instrumented"); + rwlock_A1= psi->init_rwlock(99, NULL); + ok(rwlock_A1 == NULL, "broken rwlock key not instrumented"); + + /* disabled C-A + unknown thread: no instrumentation */ + + cond_class_A->m_enabled= false; + cond_A1= psi->init_cond(cond_key_A, NULL); + ok(cond_A1 != NULL, "cond_A1 disabled, instrumented"); + + /* enabled C-A + unknown thread: instrumentation (for later) */ + + cond_class_A->m_enabled= true; + cond_A1= psi->init_cond(cond_key_A, NULL); + ok(cond_A1 != NULL, "cond_A1 enabled, instrumented"); + + /* broken key + unknown thread: no instrumentation */ + + cond_class_A->m_enabled= true; + cond_A1= psi->init_cond(0, NULL); + ok(cond_A1 == NULL, "cond key 0 not instrumented"); + cond_A1= psi->init_cond(99, NULL); + ok(cond_A1 == NULL, "broken cond key not instrumented"); + + /* disabled F-A + unknown thread: no instrumentation */ + + file_class_A->m_enabled= false; + psi->create_file(file_key_A, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "file_A1 not instrumented"); + + /* enabled F-A + unknown thread: no instrumentation */ + + file_class_A->m_enabled= true; + psi->create_file(file_key_A, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "file_A1 not instrumented"); + + /* broken key + unknown thread: no instrumentation */ + + file_class_A->m_enabled= true; + psi->create_file(0, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "not instrumented"); + psi->create_file(99, "foo", (File) 12); + file_A1= lookup_file_by_name("foo"); + ok(file_A1 == NULL, "not instrumented"); + + /* disabled S-A + unknown thread: no instrumentation */ + + socket_class_A->m_enabled= false; + socket_A1= psi->init_socket(socket_key_A, NULL, NULL, 0); + ok(socket_A1 != NULL, "socket_A1 disabled, instrumented"); + + /* enabled S-A + unknown thread: instrumentation (for later) */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(socket_key_A, NULL, NULL, 0); + ok(socket_A1 != NULL, "socket_A1 enabled, instrumented"); + + /* broken key + unknown thread: no instrumentation */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(0, NULL, NULL, 0); + ok(socket_A1 == NULL, "socket key 0 not instrumented"); + socket_A1= psi->init_socket(99, NULL, NULL, 0); + ok(socket_A1 == NULL, "broken socket key not instrumented"); + + unload_performance_schema(); +} + +void test_locker_disabled() +{ + PSI *psi; + + diag("test_locker_disabled"); + + psi= load_perfschema(); + + PSI_mutex_key mutex_key_A; + PSI_mutex_info all_mutex[]= + { + { & mutex_key_A, "M-A", 0} + }; + + PSI_rwlock_key rwlock_key_A; + PSI_rwlock_info all_rwlock[]= + { + { & rwlock_key_A, "RW-A", 0} + }; + + PSI_cond_key cond_key_A; + PSI_cond_info all_cond[]= + { + { & cond_key_A, "C-A", 0} + }; + + PSI_file_key file_key_A; + PSI_file_info all_file[]= + { + { & file_key_A, "F-A", 0} + }; + + PSI_socket_key socket_key_A; + PSI_socket_info all_socket[]= + { + { & socket_key_A, "S-A", 0} + }; + + PSI_thread_key thread_key_1; + PSI_thread_info all_thread[]= + { + { & thread_key_1, "T-1", 0} + }; + + psi->register_mutex("test", all_mutex, 1); + psi->register_rwlock("test", all_rwlock, 1); + psi->register_cond("test", all_cond, 1); + psi->register_file("test", all_file, 1); + psi->register_socket("test", all_socket, 1); + psi->register_thread("test", all_thread, 1); + + PFS_mutex_class *mutex_class_A; + PFS_rwlock_class *rwlock_class_A; + PFS_cond_class *cond_class_A; + PFS_file_class *file_class_A; + PFS_socket_class *socket_class_A; + PSI_mutex *mutex_A1; + PSI_rwlock *rwlock_A1; + PSI_cond *cond_A1; + PSI_file *file_A1; + PSI_socket *socket_A1; + PSI_thread *thread_1; + + /* Preparation */ + + thread_1= psi->new_thread(thread_key_1, NULL, 0); + ok(thread_1 != NULL, "T-1"); + psi->set_thread_id(thread_1, 1); + + mutex_class_A= find_mutex_class(mutex_key_A); + ok(mutex_class_A != NULL, "mutex info A"); + + rwlock_class_A= find_rwlock_class(rwlock_key_A); + ok(rwlock_class_A != NULL, "rwlock info A"); + + cond_class_A= find_cond_class(cond_key_A); + ok(cond_class_A != NULL, "cond info A"); + + file_class_A= find_file_class(file_key_A); + ok(file_class_A != NULL, "file info A"); + + socket_class_A= find_socket_class(socket_key_A); + ok(socket_class_A != NULL, "socket info A"); + + /* Pretend thread T-1 is running, and enabled */ + /* ------------------------------------------ */ + + psi->set_thread(thread_1); + setup_thread(thread_1, true); + + /* Enable all instruments, instantiate objects */ + + mutex_class_A->m_enabled= true; + mutex_A1= psi->init_mutex(mutex_key_A, NULL); + ok(mutex_A1 != NULL, "instrumented"); + + rwlock_class_A->m_enabled= true; + rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); + ok(rwlock_A1 != NULL, "instrumented"); + + cond_class_A->m_enabled= true; + cond_A1= psi->init_cond(cond_key_A, NULL); + ok(cond_A1 != NULL, "instrumented"); + + file_class_A->m_enabled= true; + psi->create_file(file_key_A, "foo", (File) 12); + file_A1= (PSI_file*) lookup_file_by_name("foo"); + ok(file_A1 != NULL, "instrumented"); + destroy_file(reinterpret_cast<PFS_thread*>(psi->get_thread()), + reinterpret_cast<PFS_file*>(file_A1)); + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(socket_key_A, NULL, NULL, 0); + ok(socket_A1 != NULL, "instrumented"); + + /* Socket lockers require a thread owner */ + psi->set_socket_thread_owner(socket_A1); + + PSI_mutex_locker *mutex_locker; + PSI_mutex_locker_state mutex_state; + PSI_rwlock_locker *rwlock_locker; + PSI_rwlock_locker_state rwlock_state; + PSI_cond_locker *cond_locker; + PSI_cond_locker_state cond_state; + PSI_file_locker *file_locker; + PSI_file_locker_state file_state; + PSI_socket_locker *socket_locker; + PSI_socket_locker_state socket_state; + + /* Pretend thread T-1 is disabled */ + /* ------------------------------ */ + + setup_thread(thread_1, false); + flag_events_waits_current= true; + mutex_class_A->m_enabled= true; + rwlock_class_A->m_enabled= true; + cond_class_A->m_enabled= true; + file_class_A->m_enabled= true; + socket_class_A->m_enabled= true; + + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12); + ok(mutex_locker == NULL, "no locker (T-1 disabled)"); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12); + ok(rwlock_locker == NULL, "no locker (T-1 disabled)"); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12); + ok(cond_locker == NULL, "no locker (T-1 disabled)"); + file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); + ok(file_locker == NULL, "no locker (T-1 disabled)"); + file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ); + ok(file_locker == NULL, "no locker (T-1 disabled)"); + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); + ok(file_locker == NULL, "no locker (T-1 disabled)"); + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker == NULL, "no locker (T-1 disabled)"); + + /* Pretend the global consumer is disabled */ + /* --------------------------------------- */ + + setup_thread(thread_1, true); + flag_global_instrumentation= false; + mutex_class_A->m_enabled= true; + rwlock_class_A->m_enabled= true; + cond_class_A->m_enabled= true; + file_class_A->m_enabled= true; + socket_class_A->m_enabled= true; + update_instruments_derived_flags(); + + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12); + ok(mutex_locker == NULL, "no locker (global disabled)"); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12); + ok(rwlock_locker == NULL, "no locker (global disabled)"); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12); + ok(cond_locker == NULL, "no locker (global disabled)"); + file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); + ok(file_locker == NULL, "no locker (global disabled)"); + file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ); + ok(file_locker == NULL, "no locker (global disabled)"); + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); + ok(file_locker == NULL, "no locker (global disabled)"); + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker == NULL, "no locker (global disabled)"); + + /* Pretend the mode is global, counted only */ + /* ---------------------------------------- */ + + setup_thread(thread_1, true); + flag_global_instrumentation= true; + flag_thread_instrumentation= false; + mutex_class_A->m_enabled= true; + mutex_class_A->m_timed= false; + rwlock_class_A->m_enabled= true; + rwlock_class_A->m_timed= false; + cond_class_A->m_enabled= true; + cond_class_A->m_timed= false; + file_class_A->m_enabled= true; + file_class_A->m_timed= false; + socket_class_A->m_enabled= true; + socket_class_A->m_timed= false; + update_instruments_derived_flags(); + + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12); + ok(mutex_locker == NULL, "no locker (global counted)"); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12); + ok(rwlock_locker == NULL, "no locker (global counted)"); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12); + ok(cond_locker == NULL, "no locker (global counted)"); + file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); + ok(file_locker != NULL, "locker (global counted)"); + psi->start_file_wait(file_locker, 10, __FILE__, __LINE__); + psi->end_file_wait(file_locker, 10); + file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ); + ok(file_locker != NULL, "locker (global counted)"); + psi->start_file_wait(file_locker, 10, __FILE__, __LINE__); + psi->end_file_wait(file_locker, 10); + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); + ok(file_locker != NULL, "locker (global counted)"); + psi->start_file_wait(file_locker, 10, __FILE__, __LINE__); + psi->end_file_wait(file_locker, 10); + /* The null locker shortcut applies only to socket ops with no byte count */ + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_BIND, 0, "foo.cc", 12); + ok(socket_locker == NULL, "no locker (global counted)"); + + /* TODO */ + + /* Pretend the instrument is disabled */ + /* ---------------------------------- */ + + setup_thread(thread_1, true); + flag_global_instrumentation= true; + flag_events_waits_current= true; + mutex_class_A->m_enabled= false; + rwlock_class_A->m_enabled= false; + cond_class_A->m_enabled= false; + file_class_A->m_enabled= false; + socket_class_A->m_enabled= false; + update_instruments_derived_flags(); + + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12); + ok(mutex_locker == NULL, "no locker"); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12); + ok(rwlock_locker == NULL, "no locker"); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12); + ok(cond_locker == NULL, "no locker"); + file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); + ok(file_locker == NULL, "no locker"); + file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ); + ok(file_locker == NULL, "no locker"); + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); + ok(file_locker == NULL, "no locker"); + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker == NULL, "no locker"); + + /* Pretend everything is enabled and timed */ + /* --------------------------------------- */ + + setup_thread(thread_1, true); + flag_global_instrumentation= true; + flag_thread_instrumentation= true; + flag_events_waits_current= true; + mutex_class_A->m_enabled= true; + mutex_class_A->m_timed= true; + rwlock_class_A->m_enabled= true; + rwlock_class_A->m_timed= true; + cond_class_A->m_enabled= true; + cond_class_A->m_timed= true; + file_class_A->m_enabled= true; + file_class_A->m_timed= true; + socket_class_A->m_enabled= true; + socket_class_A->m_timed= true; + update_instruments_derived_flags(); + + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, __FILE__, __LINE__); + ok(mutex_locker != NULL, "locker"); + psi->end_mutex_wait(mutex_locker, 0); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, __FILE__, __LINE__); + ok(rwlock_locker != NULL, "locker"); + psi->end_rwlock_rdwait(rwlock_locker, 0); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, __FILE__, __LINE__); + ok(cond_locker != NULL, "locker"); + psi->end_cond_wait(cond_locker, 0); + file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_STREAM_OPEN, "xxx", NULL); + ok(file_locker != NULL, "locker"); + psi->start_file_open_wait(file_locker, __FILE__, __LINE__); + psi->end_file_open_wait(file_locker, NULL); + file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ); + ok(file_locker != NULL, "locker"); + psi->start_file_wait(file_locker, 10, __FILE__, __LINE__); + psi->end_file_wait(file_locker, 10); + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); + ok(file_locker != NULL, "locker"); + psi->start_file_wait(file_locker, 10, __FILE__, __LINE__); + psi->end_file_wait(file_locker, 10); + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker != NULL, "locker"); + psi->end_socket_wait(socket_locker, 10); + + /* Pretend the socket does not have a thread owner */ + /* ---------------------------------------------- */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(socket_key_A, NULL, NULL, 0); + ok(socket_A1 != NULL, "instrumented"); + /* Socket thread owner has not been set */ + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker != NULL, "locker (owner not used)"); + psi->end_socket_wait(socket_locker, 10); + + /* Pretend the running thread is not instrumented */ + /* ---------------------------------------------- */ + + psi->delete_current_thread(); + flag_events_waits_current= true; + mutex_class_A->m_enabled= true; + rwlock_class_A->m_enabled= true; + cond_class_A->m_enabled= true; + file_class_A->m_enabled= true; + socket_class_A->m_enabled= true; + update_instruments_derived_flags(); + + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12); + ok(mutex_locker == NULL, "no locker"); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12); + ok(rwlock_locker == NULL, "no locker"); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12); + ok(cond_locker == NULL, "no locker"); + file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); + ok(file_locker == NULL, "no locker"); + file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ); + ok(file_locker == NULL, "no locker"); + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); + ok(file_locker == NULL, "no locker"); + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker == NULL, "no locker"); + + unload_performance_schema(); +} + +void test_file_instrumentation_leak() +{ + PSI *psi; + + diag("test_file_instrumentation_leak"); + + psi= load_perfschema(); + + PSI_file_key file_key_A; + PSI_file_key file_key_B; + PSI_file_info all_file[]= + { + { & file_key_A, "F-A", 0}, + { & file_key_B, "F-B", 0} + }; + + PSI_thread_key thread_key_1; + PSI_thread_info all_thread[]= + { + { & thread_key_1, "T-1", 0} + }; + + psi->register_file("test", all_file, 2); + psi->register_thread("test", all_thread, 1); + + PFS_file_class *file_class_A; + PFS_file_class *file_class_B; + PSI_file_locker_state file_state; + PSI_thread *thread_1; + + /* Preparation */ + + thread_1= psi->new_thread(thread_key_1, NULL, 0); + ok(thread_1 != NULL, "T-1"); + psi->set_thread_id(thread_1, 1); + + file_class_A= find_file_class(file_key_A); + ok(file_class_A != NULL, "file info A"); + + file_class_B= find_file_class(file_key_B); + ok(file_class_B != NULL, "file info B"); + + psi->set_thread(thread_1); + + /* Pretend everything is enabled */ + /* ----------------------------- */ + + setup_thread(thread_1, true); + flag_events_waits_current= true; + file_class_A->m_enabled= true; + file_class_B->m_enabled= true; + + PSI_file_locker *file_locker; + + /* Simulate OPEN + READ of 100 bytes + CLOSE on descriptor 12 */ + + file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "AAA", NULL); + ok(file_locker != NULL, "locker"); + psi->start_file_open_wait(file_locker, __FILE__, __LINE__); + psi->end_file_open_wait_and_bind_to_descriptor(file_locker, 12); + + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); + ok(file_locker != NULL, "locker"); + psi->start_file_wait(file_locker, 100, __FILE__, __LINE__); + psi->end_file_wait(file_locker, 100); + + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_CLOSE); + ok(file_locker != NULL, "locker"); + psi->start_file_wait(file_locker, 0, __FILE__, __LINE__); + psi->end_file_wait(file_locker, 0); + + /* Simulate uninstrumented-OPEN + WRITE on descriptor 24 */ + + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 24, PSI_FILE_WRITE); + ok(file_locker == NULL, "no locker, since the open was not instrumented"); + + /* + Simulate uninstrumented-OPEN + WRITE on descriptor 12 : + the instrumentation should not leak (don't charge the file io on unknown B to "AAA") + */ + + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_WRITE); + ok(file_locker == NULL, "no locker, no leak"); + + unload_performance_schema(); +} + +void test_enabled() +{ +#ifdef LATER + PSI *psi; + + diag("test_enabled"); + + psi= load_perfschema(); + + PSI_mutex_key mutex_key_A; + PSI_mutex_key mutex_key_B; + PSI_mutex_info all_mutex[]= + { + { & mutex_key_A, "M-A", 0}, + { & mutex_key_B, "M-B", 0} + }; + + PSI_rwlock_key rwlock_key_A; + PSI_rwlock_key rwlock_key_B; + PSI_rwlock_info all_rwlock[]= + { + { & rwlock_key_A, "RW-A", 0}, + { & rwlock_key_B, "RW-B", 0} + }; + + PSI_cond_key cond_key_A; + PSI_cond_key cond_key_B; + PSI_cond_info all_cond[]= + { + { & cond_key_A, "C-A", 0}, + { & cond_key_B, "C-B", 0} + }; + + unload_performance_schema(); +#endif +} + +void test_event_name_index() +{ + PSI *psi; + PSI_bootstrap *boot; + PFS_global_param param; + + diag("test_event_name_index"); + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + + /* NOTE: Need to add 4 to each index: table io, table lock, idle, metadata lock */ + + /* Per mutex info waits should be at [0..9] */ + param.m_mutex_class_sizing= 10; + /* Per rwlock info waits should be at [10..29] */ + param.m_rwlock_class_sizing= 20; + /* Per cond info waits should be at [30..69] */ + param.m_cond_class_sizing= 40; + /* Per file info waits should be at [70..149] */ + param.m_file_class_sizing= 80; + /* Per socket info waits should be at [150..309] */ + param.m_socket_class_sizing= 160; + /* Per table info waits should be at [310] */ + param.m_table_share_sizing= 320; + + param.m_thread_class_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_host_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; + param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_statement_stack_sizing= 10; + param.m_memory_class_sizing= 12; + param.m_metadata_lock_sizing= 10; + param.m_max_digest_length= 0; + param.m_max_sql_text_length= 1000; + + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 0; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + + param.m_hints.m_table_definition_cache = 100; + param.m_hints.m_table_open_cache = 100; + param.m_hints.m_max_connections = 100; + param.m_hints.m_open_files_limit = 100; + param.m_hints.m_max_prepared_stmt_count= 100; + + pre_initialize_performance_schema(); + boot= initialize_performance_schema(& param); + ok(boot != NULL, "bootstrap"); + psi= (PSI*) boot->get_interface(PSI_VERSION_1); + ok(psi != NULL, "psi"); + + PFS_mutex_class *mutex_class; + PSI_mutex_key dummy_mutex_key_1; + PSI_mutex_key dummy_mutex_key_2; + PSI_mutex_info dummy_mutexes[]= + { + { & dummy_mutex_key_1, "M-1", 0}, + { & dummy_mutex_key_2, "M-2", 0} + }; + + psi->register_mutex("X", dummy_mutexes, 2); + mutex_class= find_mutex_class(dummy_mutex_key_1); + ok(mutex_class != NULL, "mutex class 1"); + ok(mutex_class->m_event_name_index == 4, "index 4"); + mutex_class= find_mutex_class(dummy_mutex_key_2); + ok(mutex_class != NULL, "mutex class 2"); + ok(mutex_class->m_event_name_index == 5, "index 5"); + + PFS_rwlock_class *rwlock_class; + PSI_rwlock_key dummy_rwlock_key_1; + PSI_rwlock_key dummy_rwlock_key_2; + PSI_rwlock_info dummy_rwlocks[]= + { + { & dummy_rwlock_key_1, "RW-1", 0}, + { & dummy_rwlock_key_2, "RW-2", 0} + }; + + psi->register_rwlock("X", dummy_rwlocks, 2); + rwlock_class= find_rwlock_class(dummy_rwlock_key_1); + ok(rwlock_class != NULL, "rwlock class 1"); + ok(rwlock_class->m_event_name_index == 14, "index 14"); + rwlock_class= find_rwlock_class(dummy_rwlock_key_2); + ok(rwlock_class != NULL, "rwlock class 2"); + ok(rwlock_class->m_event_name_index == 15, "index 15"); + + PFS_cond_class *cond_class; + PSI_cond_key dummy_cond_key_1; + PSI_cond_key dummy_cond_key_2; + PSI_cond_info dummy_conds[]= + { + { & dummy_cond_key_1, "C-1", 0}, + { & dummy_cond_key_2, "C-2", 0} + }; + + psi->register_cond("X", dummy_conds, 2); + cond_class= find_cond_class(dummy_cond_key_1); + ok(cond_class != NULL, "cond class 1"); + ok(cond_class->m_event_name_index == 34, "index 34"); + cond_class= find_cond_class(dummy_cond_key_2); + ok(cond_class != NULL, "cond class 2"); + ok(cond_class->m_event_name_index == 35, "index 35"); + + PFS_file_class *file_class; + PSI_file_key dummy_file_key_1; + PSI_file_key dummy_file_key_2; + PSI_file_info dummy_files[]= + { + { & dummy_file_key_1, "F-1", 0}, + { & dummy_file_key_2, "F-2", 0} + }; + + psi->register_file("X", dummy_files, 2); + file_class= find_file_class(dummy_file_key_1); + ok(file_class != NULL, "file class 1"); + ok(file_class->m_event_name_index == 74, "index 74"); + file_class= find_file_class(dummy_file_key_2); + ok(file_class != NULL, "file class 2"); + ok(file_class->m_event_name_index == 75, "index 75"); + + PFS_socket_class *socket_class; + PSI_socket_key dummy_socket_key_1; + PSI_socket_key dummy_socket_key_2; + PSI_socket_info dummy_sockets[]= + { + { & dummy_socket_key_1, "S-1", 0}, + { & dummy_socket_key_2, "S-2", 0} + }; + + psi->register_socket("X", dummy_sockets, 2); + socket_class= find_socket_class(dummy_socket_key_1); + ok(socket_class != NULL, "socket class 1"); + ok(socket_class->m_event_name_index == 154, "index 154"); + socket_class= find_socket_class(dummy_socket_key_2); + ok(socket_class != NULL, "socket class 2"); + ok(socket_class->m_event_name_index == 155, "index 155"); + + ok(global_table_io_class.m_event_name_index == 0, "index 0"); + ok(global_table_lock_class.m_event_name_index == 1, "index 1"); + ok(wait_class_max= 314, "314 event names"); // 4 global classes + + shutdown_performance_schema(); +} + +void test_memory_instruments() +{ + PSI *psi; + PSI_thread *owner; + + diag("test_memory_instruments"); + + psi= load_perfschema(); + + PSI_memory_key memory_key_A; + PSI_memory_info all_memory[]= + { + { & memory_key_A, "M-A", 0} + }; + + PSI_thread_key thread_key_1; + PSI_thread_info all_thread[]= + { + { & thread_key_1, "T-1", 0} + }; + + psi->register_memory("test", all_memory, 1); + psi->register_thread("test", all_thread, 1); + + PFS_memory_class *memory_class_A; + PSI_thread *thread_1; + PSI_memory_key key; + + /* Preparation */ + + thread_1= psi->new_thread(thread_key_1, NULL, 0); + ok(thread_1 != NULL, "T-1"); + psi->set_thread_id(thread_1, 1); + + memory_class_A= find_memory_class(memory_key_A); + ok(memory_class_A != NULL, "memory info A"); + + /* Pretend thread T-1 is running, and enabled */ + /* ------------------------------------------ */ + + psi->set_thread(thread_1); + setup_thread(thread_1, true); + + /* Enable all instruments */ + + memory_class_A->m_enabled= true; + + /* for coverage, need to print stats collected. */ + + key= psi->memory_alloc(memory_key_A, 100, & owner); + ok(key == memory_key_A, "alloc memory info A"); + key= psi->memory_realloc(memory_key_A, 100, 200, & owner); + ok(key == memory_key_A, "realloc memory info A"); + key= psi->memory_realloc(memory_key_A, 200, 300, & owner); + ok(key == memory_key_A, "realloc up memory info A"); + key= psi->memory_realloc(memory_key_A, 300, 50, & owner); + ok(key == memory_key_A, "realloc down memory info A"); + psi->memory_free(memory_key_A, 50, owner); + + /* Use global instrumentation only */ + /* ------------------------------- */ + + flag_thread_instrumentation= false; + + key= psi->memory_alloc(memory_key_A, 100, & owner); + ok(key == memory_key_A, "alloc memory info A"); + key= psi->memory_realloc(memory_key_A, 100, 200, & owner); + ok(key == memory_key_A, "realloc memory info A"); + key= psi->memory_realloc(memory_key_A, 200, 300, & owner); + ok(key == memory_key_A, "realloc up memory info A"); + key= psi->memory_realloc(memory_key_A, 300, 50, & owner); + ok(key == memory_key_A, "realloc down memory info A"); + psi->memory_free(memory_key_A, 50, owner); + + /* Garbage, for robustness */ + /* ----------------------- */ + + key= psi->memory_alloc(9999, 100, & owner); + ok(key == PSI_NOT_INSTRUMENTED, "alloc with unknown key"); + key= psi->memory_realloc(PSI_NOT_INSTRUMENTED, 100, 200, & owner); + ok(key == PSI_NOT_INSTRUMENTED, "realloc with unknown key"); + psi->memory_free(PSI_NOT_INSTRUMENTED, 200, owner); + + shutdown_performance_schema(); +} + +void test_leaks() +{ + PSI_bootstrap *boot; + PFS_global_param param; + + /* Allocate everything, to make sure cleanup does not forget anything. */ + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 10; + param.m_rwlock_class_sizing= 10; + param.m_cond_class_sizing= 10; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 10; + param.m_file_class_sizing= 10; + param.m_socket_class_sizing= 10; + param.m_mutex_sizing= 1000; + param.m_rwlock_sizing= 1000; + param.m_cond_sizing= 1000; + param.m_thread_sizing= 1000; + param.m_table_sizing= 1000; + param.m_file_sizing= 1000; + param.m_file_handle_sizing= 1000; + param.m_socket_sizing= 1000; + param.m_events_waits_history_sizing= 10; + param.m_events_waits_history_long_sizing= 1000; + param.m_setup_actor_sizing= 1000; + param.m_setup_object_sizing= 1000; + param.m_host_sizing= 1000; + param.m_user_sizing= 1000; + param.m_account_sizing= 1000; + param.m_stage_class_sizing= 10; + param.m_events_stages_history_sizing= 10; + param.m_events_stages_history_long_sizing= 1000; + param.m_statement_class_sizing= 10; + param.m_events_statements_history_sizing= 10; + param.m_events_statements_history_long_sizing= 1000; + param.m_session_connect_attrs_sizing= 1000; + param.m_memory_class_sizing= 10; + param.m_metadata_lock_sizing= 1000; + param.m_digest_sizing= 1000; + param.m_program_sizing= 1000; + param.m_statement_stack_sizing= 10; + param.m_max_digest_length= 1000; + param.m_max_sql_text_length= 1000; + + param.m_hints.m_table_definition_cache = 100; + param.m_hints.m_table_open_cache = 100; + param.m_hints.m_max_connections = 100; + param.m_hints.m_open_files_limit = 100; + param.m_hints.m_max_prepared_stmt_count= 100; + + pre_initialize_performance_schema(); + boot= initialize_performance_schema(& param); + ok(boot != NULL, "bootstrap"); + shutdown_performance_schema(); + + /* Leaks will be reported with valgrind */ +} + +void do_all_tests() +{ + /* Using initialize_performance_schema(), no partial init needed. */ + + test_bootstrap(); + test_bad_registration(); + test_init_disabled(); + test_locker_disabled(); + test_file_instrumentation_leak(); + test_event_name_index(); + test_memory_instruments(); + test_leaks(); +} + +int main(int argc, char **argv) +{ + plan(232); + MY_INIT(argv[0]); + do_all_tests(); + my_end(0); + return (exit_status()); +} diff --git a/storage/perfschema/unittest/pfs_account-oom-t.cc b/storage/perfschema/unittest/pfs_account-oom-t.cc new file mode 100644 index 00000000..97aea4c5 --- /dev/null +++ b/storage/perfschema/unittest/pfs_account-oom-t.cc @@ -0,0 +1,174 @@ +/* Copyright (c) 2011, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_instr.h> +#include <pfs_stat.h> +#include <pfs_global.h> +#include <pfs_defaults.h> +#include <pfs_user.h> +#include <pfs_host.h> +#include <pfs_account.h> +#include <pfs_buffer_container.h> +#include <tap.h> + +#include "stub_pfs_global.h" +#include "stub_global_status_var.h" + +#include <string.h> /* memset */ + +PFS_thread pfs_thread; + +void initialize_performance_schema_helper(PFS_global_param *param) +{ + stub_alloc_always_fails= false; + stub_alloc_fails_after_count= 1000; + + param->m_enabled= true; + param->m_thread_class_sizing= 10; + param->m_thread_sizing= 1000; + param->m_account_sizing= 1000; + transaction_class_max= 0; + + pfs_thread.m_account_hash_pins= NULL; + + init_event_name_sizing(param); + init_sync_class(param->m_mutex_class_sizing, param->m_rwlock_class_sizing, param->m_cond_class_sizing); + init_thread_class(param->m_thread_class_sizing); + init_table_share(param->m_table_share_sizing); + init_table_share_lock_stat(param->m_table_lock_stat_sizing); + init_table_share_index_stat(param->m_index_stat_sizing); + init_file_class(param->m_file_class_sizing); + init_stage_class(param->m_stage_class_sizing); + init_statement_class(param->m_statement_class_sizing); + init_socket_class(param->m_socket_class_sizing); + init_memory_class(param->m_memory_class_sizing); + init_instruments(param); + init_events_waits_history_long(param->m_events_waits_history_long_sizing); + init_events_stages_history_long(param->m_events_stages_history_long_sizing); + init_events_statements_history_long(param->m_events_statements_history_long_sizing); + init_events_transactions_history_long(param->m_events_transactions_history_long_sizing); + init_file_hash(param); + init_table_share_hash(param); + init_setup_actor(param); + init_setup_actor_hash(param); + init_setup_object(param); + init_setup_object_hash(param); + init_host(param); + init_host_hash(param); + init_user(param); + init_user_hash(param); + init_account(param); + init_account_hash(param); + init_digest(param); + init_digest_hash(param); + init_program(param); + init_program_hash(param); + init_prepared_stmt(param); + pfs_initialized= true; +} + +void test_oom() +{ + PFS_global_param param; + PFS_account *pfs_account; + const char *username= "username"; + const char *hostname= "hostname"; + + uint user_len= (uint)strlen(username); + uint host_len= (uint)strlen(hostname); + + /* Account. */ + memset(¶m, 0, sizeof(param)); + initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 1; + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account)"); + ok(global_account_container.m_lost == 1, "lost (account)"); + shutdown_performance_schema(); + + /* Account waits. */ + memset(¶m, 0, sizeof(param)); + param.m_mutex_class_sizing= 10; + initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 2; + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account waits)"); + ok(global_account_container.m_lost == 1, "lost (account waits)"); + shutdown_performance_schema(); + + + /* Account stages. */ + memset(¶m, 0, sizeof(param)); + param.m_stage_class_sizing= 10; + initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account stages)"); + ok(global_account_container.m_lost == 1, "lost (account stages)"); + shutdown_performance_schema(); + + /* Account statements. */ + memset(¶m, 0, sizeof(param)); + param.m_statement_class_sizing= 10; + initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account statements)"); + ok(global_account_container.m_lost == 1, "lost (account statements)"); + shutdown_performance_schema(); + + /* Account transactions. */ + memset(¶m, 0, sizeof(param)); + initialize_performance_schema_helper(¶m); + transaction_class_max= 1; + stub_alloc_fails_after_count= 3; + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account transactions)"); + ok(global_account_container.m_lost == 1, "lost (account transactions)"); + shutdown_performance_schema(); + + /* Account memory. */ + memset(¶m, 0, sizeof(param)); + param.m_memory_class_sizing= 10; + initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account memory)"); + ok(global_account_container.m_lost == 1, "lost (account memory)"); + shutdown_performance_schema(); +} + +void do_all_tests() +{ + test_oom(); +} + +int main(int, char **) +{ + plan(12); + MY_INIT("pfs_account-oom-t"); + do_all_tests(); + my_end(0); + return (exit_status()); +} diff --git a/storage/perfschema/unittest/pfs_connect_attr-t.cc b/storage/perfschema/unittest/pfs_connect_attr-t.cc new file mode 100644 index 00000000..dee56ebc --- /dev/null +++ b/storage/perfschema/unittest/pfs_connect_attr-t.cc @@ -0,0 +1,352 @@ +/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_server.h> +#include <pfs_instr_class.h> +#include <pfs_instr.h> +#include <pfs_global.h> +#include <tap.h> + + +#include <string.h> +#include <memory.h> + +/* test helpers, to inspect data */ +bool read_nth_attr(const char *connect_attrs, uint connect_attrs_length, + const CHARSET_INFO *connect_attrs_cs, + uint ordinal, + char *attr_name, uint max_attr_name, + uint *attr_name_length, + char *attr_value, uint max_attr_value, + uint *attr_value_length); + +void test_blob_parser() +{ + char name[100], value[4096]; + unsigned char packet[10000], *ptr; + uint name_len, value_len, idx, packet_length; + bool result; + const CHARSET_INFO *cs= &my_charset_utf8mb3_bin; + + diag("test_blob_parser"); + + result= read_nth_attr("", 0, cs, 0, + name, 32, &name_len, value, 1024, &value_len); + ok(result == false, "zero length blob"); + + + result= read_nth_attr("\x1", 1, cs, 0, + name, 32, &name_len, value, 1024, &value_len); + ok(result == false, "invalid key length"); + + + result= read_nth_attr("\x2k1\x1", 4, cs, 0, + name, 32, &name_len, value, 1024, &value_len); + ok(result == false, "invalid value length"); + + + result= read_nth_attr("\x2k1\x2v1", 6, cs, 0, + name, 32, &name_len, value, 1024, &value_len); + ok(result == true, "one pair return"); + ok(name_len == 2, "one pair attr name length"); + ok(!strncmp(name, "k1", name_len), "one pair attr name"); + ok(value_len == 2, "one pair value length"); + ok(!strncmp(value, "v1", value_len), "one pair value"); + + result= read_nth_attr("\x2k1\x2v1", 6, cs, 1, + name, 32, &name_len, value, 1024, &value_len); + ok(result == false, "no second arg"); + + result= read_nth_attr("\x2k1\x2v1\x2k2\x2v2", 12, cs, 1, + name, 32, &name_len, value, 1024, &value_len); + ok(result == true, "two pairs return"); + ok(name_len == 2, "two pairs attr name length"); + ok(!strncmp(name, "k2", name_len), "two pairs attr name"); + ok(value_len == 2, "two pairs value length"); + ok(!strncmp(value, "v2", value_len), "two pairs value"); + + result= read_nth_attr("\x2k1\xff\x2k2\x2v2", 12, cs, 1, + name, 32, &name_len, value, 1024, &value_len); + ok(result == false, "two pairs first value bad return"); + + result= read_nth_attr("\x2k1\x2v1\x2k2\x2v2", 10, cs, 1, + name, 32, &name_len, value, 1024, &value_len); + ok(result == false, "two pairs wrong global length"); + + result= read_nth_attr("\x21z123456789z123456789z123456789z12\x2v1", 37, cs, 0, + name, 32, &name_len, value, 1024, &value_len); + ok(result == true, "attr name overflow"); + ok(name_len == 32, "attr name overflow length"); + ok(!strncmp(name, "z123456789z123456789z123456789z1", name_len), + "attr name overflow name"); + ok(value_len == 2, "attr name overflow value length"); + ok(!strncmp(value, "v1", value_len), "attr name overflow value"); + + packet[0]= 2; + packet[1]= 'k'; + packet[2]= '1'; + ptr= net_store_length(packet + 3, 1025); + for (idx= 0; idx < 1025; idx++) + *ptr++= '0' + (idx % 10); + packet_length= (uint) (ptr - packet); + result= read_nth_attr((char *) packet, packet_length, cs, 0, + name, 32, &name_len, value, 1024, &value_len); + ok(result == true, "attr value overflow"); + ok(name_len == 2, "attr value overflow length"); + ok(!strncmp(name, "k1", name_len), "attr value overflow name"); + ok(value_len == 1024, "attr value overflow value length"); + for (idx= 0; idx < 1024; idx++) + { + if (value[idx] != (char) ('0' + (idx % 10))) + break; + } + ok (idx == 1024, "attr value overflow value"); + + result= read_nth_attr("\x21z123456789z123456789z123456789z12\x2v1\x2k2\x2v2", + 43, cs, 1, + name, 32, &name_len, value, 1024, &value_len); + ok(result == true, "prev attr name overflow"); + ok(name_len == 2, "prev attr name overflow length"); + ok(!strncmp(name, "k2", name_len), + "prev attr name overflow name"); + ok(value_len == 2, "prev attr name overflow value length"); + ok(!strncmp(value, "v2", value_len), "prev attr name overflow value"); + + + packet[1]= 'k'; + packet[2]= '1'; + packet[3]= 2; + packet[4]= 'v'; + packet[5]= '1'; + + for(idx= 251; idx < 256; idx++) + { + packet[0]= idx; + result= read_nth_attr((char *) packet, 6, cs, 0, + name, 32, &name_len, value, 1024, &value_len); + ok(result == false, "invalid string length %d", idx); + } + + memset(packet, 0, sizeof(packet)); + for (idx=0; idx < 1660 /* *6 = 9960 */; idx++) + memcpy(packet + idx * 6, "\x2k1\x2v1", 6); + result= read_nth_attr((char *) packet, 8192, cs, 1364, + name, 32, &name_len, value, 1024, &value_len); + ok(result == true, "last valid attribute %d", 1364); + result= read_nth_attr((char *) packet, 8192, cs, 1365, + name, 32, &name_len, value, 1024, &value_len); + ok(result == false, "first attribute that's cut %d", 1365); +} + +void test_multibyte_lengths() +{ + char name[100], value[4096]; + uint name_len, value_len; + bool result; + const CHARSET_INFO *cs= &my_charset_utf8mb3_bin; + + unsigned char var_len_packet[] = { + 252, 2, 0, 'k', '1', + 253, 2, 0, 0, 'v', '1', + 254, 2, 0, 0, 0, 0, 0, 0, 0, 'k', '2', + 254, 2, 0, 0, 0, 0, 0, 0, 0, 'v', '2' + }; + + result= read_nth_attr((char *) var_len_packet, sizeof(var_len_packet), cs, 0, + name, 32, &name_len, value, 1024, &value_len); + ok(result == true, "multibyte lengths return"); + ok(name_len == 2, "multibyte lengths name length"); + ok(!strncmp(name, "k1", name_len), "multibyte lengths attr name"); + ok(value_len == 2, "multibyte lengths value length"); + ok(!strncmp(value, "v1", value_len), "multibyte lengths value"); + + result= read_nth_attr((char *) var_len_packet, sizeof(var_len_packet), cs, 1, + name, 32, &name_len, value, 1024, &value_len); + ok(result == true, "multibyte lengths second attr return"); + ok(name_len == 2, "multibyte lengths second attr name length"); + ok(!strncmp(name, "k2", name_len), "multibyte lengths second attr attr name"); + ok(value_len == 2, "multibyte lengths value length"); + ok(!strncmp(value, "v2", value_len), "multibyte lengths second attr value"); +} + + +void test_utf8_parser() +{ + /* utf8 max byte length per character is 6 */ + char name[33 * 6], value[1024 * 6], packet[1500 * 6], *ptr; + uint name_len, value_len; + bool result; + const CHARSET_INFO *cs= &my_charset_utf8mb3_bin; + + /* note : this is encoded in utf-8 */ + const char *attr1= "Георги"; + const char *val1= "Кодинов"; + const char *attr2= "Пловдив"; + const char *val2= "България"; + + ptr= packet; + *ptr++= strlen(attr1); + memcpy(ptr, attr1, strlen(attr1)); + ptr+= strlen(attr1); + *ptr++= strlen(val1); + memcpy(ptr, val1, strlen(val1)); + ptr+= strlen(val1); + + *ptr++= strlen(attr2); + memcpy(ptr, attr2, strlen(attr2)); + ptr+= strlen(attr2); + *ptr++= strlen(val2); + memcpy(ptr, val2, strlen(val2)); + ptr+= strlen(val2); + + diag("test_utf8_parser attr pair #1"); + + result= read_nth_attr((char *) packet, ptr - packet, cs, 0, + name, sizeof(name), &name_len, + value, sizeof(value), &value_len); + ok(result == true, "return"); + ok(name_len == strlen(attr1), "name length"); + ok(!strncmp(name, attr1, name_len), "attr name"); + ok(value_len == strlen(val1), "value length"); + ok(!strncmp(value, val1, value_len), "value"); + + diag("test_utf8_parser attr pair #2"); + result= read_nth_attr((char *) packet, ptr - packet, cs, 1, + name, sizeof(name), &name_len, + value, sizeof(value), &value_len); + ok(result == true, "return"); + ok(name_len == strlen(attr2), "name length"); + ok(!strncmp(name, attr2, name_len), "attr name"); + ok(value_len == strlen(val2), "value length"); + ok(!strncmp(value, val2, value_len), "value"); +} + + +void test_utf8_parser_bad_encoding() +{ + /* utf8 max byte length per character is 3*/ + char name[33 * 3], value[1024 * 3], packet[1500 * 3], *ptr; + uint name_len, value_len; + bool result; + const CHARSET_INFO *cs= &my_charset_utf8mb3_bin; + + /* note : this is encoded in utf-8 */ + const char *attr= "Георги"; + const char *val= "Кодинов"; + + ptr= packet; + *ptr++= strlen(attr); + memcpy(ptr, attr, strlen(attr)); + ptr[0]= (char)0xFA; // invalid UTF-8 char + ptr+= strlen(attr); + *ptr++= strlen(val); + memcpy(ptr, val, strlen(val)); + ptr+= strlen(val); + + diag("test_utf8_parser_bad_encoding"); + + result= read_nth_attr((char *) packet, ptr - packet, cs, 0, + name, sizeof(name), &name_len, + value, sizeof(value), &value_len); + ok(result == false, "return"); +} + +const CHARSET_INFO *cs_cp1251; + +void test_cp1251_parser() +{ + /* utf8 max byte length per character is 3*/ + char name[33 * 3], value[1024 * 3], packet[1500 * 3], *ptr; + uint name_len, value_len; + bool result; + + /* note : this is Георги in windows-1251 */ + const char *attr1= "\xc3\xe5\xee\xf0\xe3\xe8"; + /* note : this is Кодинов in windows-1251 */ + const char *val1= "\xca\xee\xe4\xe8\xed\xee\xe2"; + /* note : this is Пловдив in windows-1251 */ + const char *attr2= "\xcf\xeb\xee\xe2\xe4\xe8\xe2"; + /* note : this is България in windows-1251 */ + const char *val2= "\xc1\xfa\xeb\xe3\xe0\xf0\xe8\xff"; + + ptr= packet; + *ptr++= strlen(attr1); + memcpy(ptr, attr1, strlen(attr1)); + ptr+= strlen(attr1); + *ptr++= strlen(val1); + memcpy(ptr, val1, strlen(val1)); + ptr+= strlen(val1); + + *ptr++= strlen(attr2); + memcpy(ptr, attr2, strlen(attr2)); + ptr+= strlen(attr2); + *ptr++= strlen(val2); + memcpy(ptr, val2, strlen(val2)); + ptr+= strlen(val2); + + diag("test_cp1251_parser attr pair #1"); + + result= read_nth_attr((char *) packet, ptr - packet, cs_cp1251, 0, + name, sizeof(name), &name_len, + value, sizeof(value), &value_len); + ok(result == true, "return"); + /* need to compare to the UTF-8 equivalents */ + ok(name_len == strlen("Георги"), "name length"); + ok(!strncmp(name, "Георги", name_len), "attr name"); + ok(value_len == strlen("Кодинов"), "value length"); + ok(!strncmp(value, "Кодинов", value_len), "value"); + + diag("test_cp1251_parser attr pair #2"); + result= read_nth_attr((char *) packet, ptr - packet, cs_cp1251, 1, + name, sizeof(name), &name_len, + value, sizeof(value), &value_len); + ok(result == true, "return"); + /* need to compare to the UTF-8 equivalents */ + ok(name_len == strlen("Пловдив"), "name length"); + ok(!strncmp(name, "Пловдив", name_len), "attr name"); + ok(value_len == strlen("България"), "value length"); + ok(!strncmp(value, "България", value_len), "value"); +} + + +void do_all_tests() +{ + test_blob_parser(); + test_multibyte_lengths(); + test_utf8_parser(); + test_utf8_parser_bad_encoding(); + test_cp1251_parser(); +} + +int main(int, char **) +{ + MY_INIT("pfs_connect_attr-t"); + + cs_cp1251= get_charset_by_csname("cp1251", MY_CS_PRIMARY, MYF(0)); + if (!cs_cp1251) + diag("skipping the cp1251 tests : missing character set"); + plan(59 + (cs_cp1251 ? 10 : 0)); + do_all_tests(); + return (exit_status()); +} diff --git a/storage/perfschema/unittest/pfs_host-oom-t.cc b/storage/perfschema/unittest/pfs_host-oom-t.cc new file mode 100644 index 00000000..f903561d --- /dev/null +++ b/storage/perfschema/unittest/pfs_host-oom-t.cc @@ -0,0 +1,148 @@ +/* Copyright (c) 2011, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_instr.h> +#include <pfs_stat.h> +#include <pfs_global.h> +#include <pfs_host.h> +#include <pfs_buffer_container.h> +#include <tap.h> + +#include "stub_pfs_global.h" +#include "stub_global_status_var.h" + +#include <string.h> /* memset */ + +extern struct PSI_bootstrap PFS_bootstrap; + +void test_oom() +{ + PSI *psi; + PFS_global_param param; + PSI_bootstrap *boot; + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 1000; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; + param.m_events_waits_history_sizing= 10; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_user_sizing= 0; + param.m_host_sizing= 1000; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 50; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 50; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; + param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 10; + param.m_metadata_lock_sizing= 0; + param.m_max_digest_length= 0; + param.m_max_sql_text_length= 0; + + /* Setup */ + + stub_alloc_always_fails= false; + stub_alloc_fails_after_count= 1000; + + pre_initialize_performance_schema(); + boot= initialize_performance_schema(¶m); + psi= (PSI *)boot->get_interface(PSI_VERSION_1); + + PSI_thread_key thread_key_1; + PSI_thread_info all_thread[]= + { + {&thread_key_1, "T-1", 0} + }; + psi->register_thread("test", all_thread, 1); + + PSI_thread *thread_1= psi->new_thread(thread_key_1, NULL, 0); + psi->set_thread(thread_1); + + /* Tests */ + + int first_fail= 1; + stub_alloc_fails_after_count= first_fail; + psi->set_thread_account("", 0, "host1", 5); + ok(global_host_container.m_lost == 1, "oom (host)"); + + stub_alloc_fails_after_count= first_fail + 1; + psi->set_thread_account("", 0, "host2", 5); + ok(global_host_container.m_lost == 2, "oom (host waits)"); + + stub_alloc_fails_after_count= first_fail + 2; + psi->set_thread_account("", 0, "host3", 5); + ok(global_host_container.m_lost == 3, "oom (host stages)"); + + stub_alloc_fails_after_count= first_fail + 3; + psi->set_thread_account("", 0, "host4", 5); + ok(global_host_container.m_lost == 4, "oom (host statements)"); + + stub_alloc_fails_after_count= first_fail + 4; + psi->set_thread_account("", 0, "host5", 5); + ok(global_host_container.m_lost == 5, "oom (host transactions)"); + + stub_alloc_fails_after_count= first_fail + 5; + psi->set_thread_account("", 0, "host6", 5); + ok(global_host_container.m_lost == 6, "oom (host memory)"); + + shutdown_performance_schema(); +} + +void do_all_tests() +{ + test_oom(); +} + +int main(int, char **) +{ + plan(6); + MY_INIT("pfs_host-oom-t"); + do_all_tests(); + my_end(0); + return (exit_status()); +} + diff --git a/storage/perfschema/unittest/pfs_instr-oom-t.cc b/storage/perfschema/unittest/pfs_instr-oom-t.cc new file mode 100644 index 00000000..579aec6c --- /dev/null +++ b/storage/perfschema/unittest/pfs_instr-oom-t.cc @@ -0,0 +1,459 @@ +/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_instr.h> +#include <pfs_stat.h> +#include <pfs_global.h> +#include <pfs_user.h> +#include <pfs_host.h> +#include <pfs_account.h> +#include <pfs_instr_class.h> +#include <pfs_buffer_container.h> +#include <tap.h> + +#include "stub_pfs_global.h" +#include "stub_global_status_var.h" + +#include <string.h> /* memset */ + +extern struct PSI_bootstrap PFS_bootstrap; + +PSI_thread_key thread_key_1; +PSI_thread_info all_thread[]= +{ + {&thread_key_1, "T-1", 0} +}; + +/** Simulate initialize_performance_schema(). */ + +PSI * initialize_performance_schema_helper(PFS_global_param *param) +{ + PSI *psi; + + stub_alloc_always_fails= false; + stub_alloc_fails_after_count= 1000; + + param->m_enabled= true; + param->m_thread_class_sizing= 10; + param->m_thread_sizing= 1000; + + pre_initialize_performance_schema(); + + init_event_name_sizing(param); + init_sync_class(param->m_mutex_class_sizing, param->m_rwlock_class_sizing, param->m_cond_class_sizing); + init_thread_class(param->m_thread_class_sizing); + init_table_share(param->m_table_share_sizing); + init_table_share_lock_stat(param->m_table_lock_stat_sizing); + init_table_share_index_stat(param->m_index_stat_sizing); + init_file_class(param->m_file_class_sizing); + init_stage_class(param->m_stage_class_sizing); + init_statement_class(param->m_statement_class_sizing); + init_socket_class(param->m_socket_class_sizing); + init_memory_class(param->m_memory_class_sizing); + init_instruments(param); + init_events_waits_history_long(param->m_events_waits_history_long_sizing); + init_events_stages_history_long(param->m_events_stages_history_long_sizing); + init_events_statements_history_long(param->m_events_statements_history_long_sizing); + init_events_transactions_history_long(param->m_events_transactions_history_long_sizing); + init_file_hash(param); + init_table_share_hash(param); + init_setup_actor(param); + init_setup_actor_hash(param); + init_setup_object(param); + init_setup_object_hash(param); + init_host(param); + init_host_hash(param); + init_user(param); + init_user_hash(param); + init_account(param); + init_account_hash(param); + init_digest(param); + init_digest_hash(param); + init_program(param); + init_program_hash(param); + init_prepared_stmt(param); + pfs_initialized= true; + + PSI_bootstrap *boot= &PFS_bootstrap; + psi= (PSI *)boot->get_interface(PSI_VERSION_1); + psi->register_thread("test", all_thread, 1); + return (psi); +} + +void test_oom() +{ + int rc; + PSI *psi; + PFS_global_param param; + + stub_alloc_always_fails= false; + stub_alloc_fails_after_count= 1000; + + PFS_mutex_class dummy_mutex_class; + PFS_rwlock_class dummy_rwlock_class; + PFS_cond_class dummy_cond_class; + PFS_thread_class dummy_thread_class; + PFS_file_class dummy_file_class; + PFS_socket_class dummy_socket_class; + PFS_table_share dummy_table_share; + PFS_mutex *mutex_1; + PFS_mutex *mutex_2; + PFS_rwlock *rwlock_1; + PFS_rwlock *rwlock_2; + PFS_cond *cond_1; + PFS_cond *cond_2; + PFS_thread *thread_1; + PFS_thread *thread_2; + PFS_file *file_1; + PFS_file *file_2; + PFS_socket *socket_1; + PFS_socket *socket_2; + PFS_table *table_1; + PFS_table *table_2; + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 1; + param.m_rwlock_class_sizing= 1; + param.m_cond_class_sizing= 1; + param.m_thread_class_sizing= 1; + param.m_table_share_sizing= 1; + param.m_file_class_sizing= 1; + param.m_socket_class_sizing= 1; + param.m_mutex_sizing= 1; + param.m_rwlock_sizing= 1; + param.m_cond_sizing= 1; + param.m_thread_sizing= 1; + param.m_table_sizing= 1; + param.m_file_sizing= 1; + param.m_file_handle_sizing= 100; + param.m_socket_sizing= 2; + param.m_events_waits_history_sizing= 10; + param.m_events_waits_history_long_sizing= 10000; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; + param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_prepared_stmt_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 1; + param.m_metadata_lock_sizing= 0; + param.m_max_digest_length= 0; + param.m_max_sql_text_length= 0; + + init_event_name_sizing(¶m); + rc= init_instruments(¶m); + ok(rc == 0, "instances init"); + + dummy_mutex_class.m_event_name_index= 0; + dummy_mutex_class.m_flags= 0; + dummy_mutex_class.m_enabled= true; + dummy_mutex_class.m_volatility= PSI_VOLATILITY_UNKNOWN; + dummy_rwlock_class.m_event_name_index= 1; + dummy_rwlock_class.m_flags= 0; + dummy_rwlock_class.m_enabled= true; + dummy_rwlock_class.m_volatility= PSI_VOLATILITY_UNKNOWN; + dummy_cond_class.m_event_name_index= 2; + dummy_cond_class.m_flags= 0; + dummy_cond_class.m_enabled= true; + dummy_cond_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_file_class.m_event_name_index= 3; + dummy_file_class.m_flags= 0; + dummy_file_class.m_enabled= true; + dummy_file_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_socket_class.m_event_name_index= 4; + dummy_socket_class.m_flags= 0; + dummy_socket_class.m_enabled= true; + dummy_socket_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_table_share.m_enabled= true; + dummy_table_share.m_timed= true; + + /* Create mutex. */ + stub_alloc_always_fails= false; + mutex_1= create_mutex(&dummy_mutex_class, NULL); + ok(mutex_1 != NULL, "create mutex"); + destroy_mutex(mutex_1); + cleanup_instruments(); + + stub_alloc_always_fails= true; + mutex_2= create_mutex(&dummy_mutex_class, NULL); + ok(mutex_2 == NULL, "oom (create mutex)"); + + /* Create rwlock. */ + stub_alloc_always_fails = false; + rc = init_instruments(¶m); + ok(rc == 0, "instances init"); + rwlock_1= create_rwlock(&dummy_rwlock_class, NULL); + ok(rwlock_1 != NULL, "create rwlock"); + destroy_rwlock(rwlock_1); + cleanup_instruments(); + + stub_alloc_always_fails= true; + rwlock_2= create_rwlock(&dummy_rwlock_class, NULL); + ok(rwlock_2 == NULL, "oom (create rwlock)"); + + /* Create cond. */ + stub_alloc_always_fails = false; + rc = init_instruments(¶m); + ok(rc == 0, "instances init"); + cond_1= create_cond(&dummy_cond_class, NULL); + ok(cond_1 != NULL, "create cond"); + destroy_cond(cond_1); + cleanup_instruments(); + + stub_alloc_always_fails= true; + cond_2= create_cond(&dummy_cond_class, NULL); + ok(cond_2 == NULL, "oom (create cond)"); + + /* Create file. */ + PFS_thread fake_thread; + rc = init_instruments(¶m); + fake_thread.m_filename_hash_pins= NULL; + init_file_hash(¶m); + + stub_alloc_always_fails = true; + file_2 = find_or_create_file(&fake_thread, &dummy_file_class, "dummy", 5, true); + ok(file_2 == NULL, "oom (create file)"); + + stub_alloc_always_fails= false; + file_1= find_or_create_file(&fake_thread, &dummy_file_class, "dummy", 5, true); + ok(file_1 != NULL, "create file"); + release_file(file_1); + cleanup_instruments(); + + /* Create socket. */ + stub_alloc_always_fails = false; + rc = init_instruments(¶m); + ok(rc == 0, "instances init"); + socket_1= create_socket(&dummy_socket_class, NULL, NULL, 0); + ok(socket_1 != NULL, "create socket"); + destroy_socket(socket_1); + cleanup_instruments(); + + stub_alloc_always_fails= true; + socket_2= create_socket(&dummy_socket_class, NULL, NULL, 0); + ok(socket_2 == NULL, "oom (create socket)"); + + /* Create table. */ + stub_alloc_always_fails= false; + rc = init_instruments(¶m); + table_1= create_table(&dummy_table_share, &fake_thread, NULL); + ok(table_1 != NULL, "create table"); + destroy_table(table_1); + cleanup_instruments(); + + stub_alloc_always_fails= true; + table_2= create_table(&dummy_table_share, &fake_thread, NULL); + ok(table_2 == NULL, "oom (create table)"); + + /* Create thread. */ + stub_alloc_always_fails= false; + rc = init_instruments(¶m); + thread_1= create_thread(&dummy_thread_class, NULL, 0); + ok(thread_1 != NULL, "create thread"); + destroy_thread(thread_1); + cleanup_instruments(); + + stub_alloc_always_fails= true; + thread_2= create_thread(&dummy_thread_class, NULL, 0); + ok(thread_2 == NULL, "oom (create thread)"); + + PSI_thread *thread; + + /* Per thread wait. */ + memset(¶m, 0, sizeof(param)); + param.m_mutex_class_sizing= 50; + param.m_rwlock_class_sizing= 50; + param.m_cond_class_sizing= 50; + param.m_file_class_sizing= 50; + param.m_socket_class_sizing= 0; + psi= initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 2; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (per thread wait)"); + + cleanup_sync_class(); + cleanup_thread_class(); + cleanup_file_class(); + cleanup_instruments(); + + /* Thread waits history sizing. */ + memset(¶m, 0, sizeof(param)); + param.m_enabled= true; + param.m_events_waits_history_sizing= 10; + psi= initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (thread waits history sizing)"); + + cleanup_thread_class(); + cleanup_instruments(); + + /* Per thread stages. */ + memset(¶m, 0, sizeof(param)); + param.m_stage_class_sizing= 50; + psi= initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (per thread stages)"); + + cleanup_stage_class(); + cleanup_thread_class(); + cleanup_instruments(); + cleanup_stage_class(); + + /* Thread stages history sizing. */ + memset(¶m, 0, sizeof(param)); + param.m_events_stages_history_sizing= 10; + psi= initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (thread stages history sizing)"); + + cleanup_instruments(); + cleanup_thread_class(); + + /* Per thread statements. */ + memset(¶m, 0, sizeof(param)); + param.m_stage_class_sizing= 50; + psi= initialize_performance_schema_helper(¶m); + init_statement_class(param.m_statement_class_sizing); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (per thread statements)"); + + cleanup_stage_class(); + cleanup_statement_class(); + cleanup_thread_class(); + cleanup_instruments(); + + /* Thread statements history sizing. */ + memset(¶m, 0, sizeof(param)); + param.m_events_statements_history_sizing= 10; + psi= initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (thread statements history sizing)"); + + cleanup_thread_class(); + cleanup_instruments(); + + /* Per thread transactions. */ + memset(¶m, 0, sizeof(param)); + psi= initialize_performance_schema_helper(¶m); + transaction_class_max= 1; // set by register_global_classes(); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (per thread transactions)"); + transaction_class_max= 0; + + cleanup_thread_class(); + cleanup_instruments(); + + /* Thread transactions history sizing. */ + memset(¶m, 0, sizeof(param)); + param.m_events_transactions_history_sizing= 10; + psi= initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (thread transactions history sizing)"); + + cleanup_thread_class(); + cleanup_instruments(); + + /* Global stages. */ + memset(¶m, 0, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 10; + param.m_stage_class_sizing= 20; + + stub_alloc_fails_after_count= 2; + init_event_name_sizing(¶m); + rc= init_stage_class(param.m_stage_class_sizing); + ok(rc == 0, "init stage class"); + rc= init_instruments(& param); + ok(rc == 1, "oom (global stages)"); + + cleanup_stage_class(); + cleanup_instruments(); + + /* Global statements. */ + memset(¶m, 0, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 10; + param.m_statement_class_sizing= 20; + + stub_alloc_fails_after_count= 2; + init_event_name_sizing(¶m); + rc= init_statement_class(param.m_statement_class_sizing); + ok(rc == 0, "init statement class"); + rc= init_instruments(¶m); + ok(rc == 1, "oom (global statements)"); + + cleanup_statement_class(); + cleanup_instruments(); + + /* Global memory. */ + memset(¶m, 0, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 10; + param.m_memory_class_sizing= 20; + + stub_alloc_fails_after_count= 2; + init_event_name_sizing(¶m); + rc= init_memory_class(param.m_memory_class_sizing); + ok(rc == 0, "init memory class"); + rc= init_instruments(& param); + ok(rc == 1, "oom (global memory)"); + + cleanup_memory_class(); + cleanup_instruments(); +} + +void do_all_tests() +{ + test_oom(); +} + +int main(int argc, char **argv) +{ + plan(32); + MY_INIT(argv[0]); + do_all_tests(); + my_end(0); + return exit_status(); +} + diff --git a/storage/perfschema/unittest/pfs_instr-t.cc b/storage/perfschema/unittest/pfs_instr-t.cc new file mode 100644 index 00000000..9667d7ff --- /dev/null +++ b/storage/perfschema/unittest/pfs_instr-t.cc @@ -0,0 +1,488 @@ +/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_instr.h> +#include <pfs_stat.h> +#include <pfs_global.h> +#include <pfs_instr_class.h> +#include <pfs_buffer_container.h> +#include <tap.h> + +#include "stub_global_status_var.h" + +#include <memory.h> + +PFS_global_param param; + +void test_no_instruments() +{ + int rc; + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 0; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 0; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; + param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_prepared_stmt_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 0; + param.m_metadata_lock_sizing= 0; + + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 0, "zero init"); + + cleanup_instruments(); +} + +void test_no_instances() +{ + int rc; + PFS_mutex_class dummy_mutex_class; + PFS_rwlock_class dummy_rwlock_class; + PFS_cond_class dummy_cond_class; + PFS_thread_class dummy_thread_class; + PFS_file_class dummy_file_class; + PFS_table_share dummy_table_share; + PFS_socket_class dummy_socket_class; + PFS_mutex *mutex; + PFS_rwlock *rwlock; + PFS_cond *cond; + PFS_thread *thread; + PFS_file *file; + PFS_socket *socket; + PFS_table *table; + + dummy_mutex_class.m_event_name_index = 0; + dummy_mutex_class.m_flags = 0; + dummy_mutex_class.m_enabled = true; + dummy_mutex_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_rwlock_class.m_event_name_index = 1; + dummy_rwlock_class.m_flags = 0; + dummy_rwlock_class.m_enabled = true; + dummy_rwlock_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_cond_class.m_event_name_index = 2; + dummy_cond_class.m_flags = 0; + dummy_cond_class.m_enabled = true; + dummy_cond_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_file_class.m_event_name_index = 3; + dummy_file_class.m_flags = 0; + dummy_file_class.m_enabled = true; + dummy_file_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_socket_class.m_event_name_index = 4; + dummy_socket_class.m_flags = 0; + dummy_socket_class.m_enabled = true; + dummy_socket_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 1; + param.m_rwlock_class_sizing= 1; + param.m_cond_class_sizing= 1; + param.m_thread_class_sizing= 1; + param.m_table_share_sizing= 1; + param.m_file_class_sizing= 1; + param.m_socket_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 0; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; + param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_prepared_stmt_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 1; + param.m_metadata_lock_sizing= 0; + + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 0, "no instances init"); + + mutex= create_mutex(& dummy_mutex_class, NULL); + ok(mutex == NULL, "no mutex"); + ok(global_mutex_container.get_lost_counter() == 1, "lost 1"); + mutex= create_mutex(& dummy_mutex_class, NULL); + ok(mutex == NULL, "no mutex"); + ok(global_mutex_container.get_lost_counter() == 2, "lost 2"); + + rwlock= create_rwlock(& dummy_rwlock_class, NULL); + ok(rwlock == NULL, "no rwlock"); + ok(global_rwlock_container.m_lost == 1, "lost 1"); + rwlock= create_rwlock(& dummy_rwlock_class, NULL); + ok(rwlock == NULL, "no rwlock"); + ok(global_rwlock_container.m_lost == 2, "lost 2"); + + cond= create_cond(& dummy_cond_class, NULL); + ok(cond == NULL, "no cond"); + ok(global_cond_container.m_lost == 1, "lost 1"); + cond= create_cond(& dummy_cond_class, NULL); + ok(cond == NULL, "no cond"); + ok(global_cond_container.m_lost == 2, "lost 2"); + + thread= create_thread(& dummy_thread_class, NULL, 0); + ok(thread == NULL, "no thread"); + ok(global_thread_container.m_lost == 1, "lost 1"); + thread= create_thread(& dummy_thread_class, NULL, 0); + ok(thread == NULL, "no thread"); + ok(global_thread_container.m_lost == 2, "lost 2"); + + PFS_thread fake_thread; + fake_thread.m_filename_hash_pins= NULL; + + file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); + ok(file == NULL, "no file"); + ok(global_file_container.m_lost == 1, "lost 1"); + file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); + ok(file == NULL, "no file"); + ok(global_file_container.m_lost == 2, "lost 2"); + + init_file_hash(& param); + + file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); + ok(file == NULL, "no file"); + ok(global_file_container.m_lost == 3, "lost 3"); + file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); + ok(file == NULL, "no file"); + ok(global_file_container.m_lost == 4, "lost 4"); + + char long_file_name[10000]; + int size= sizeof(long_file_name); + memset(long_file_name, 'X', size); + + file= find_or_create_file(& fake_thread, & dummy_file_class, long_file_name, size, true); + ok(file == NULL, "no file"); + ok(global_file_container.m_lost == 5, "lost 5"); + + table= create_table(& dummy_table_share, & fake_thread, NULL); + ok(table == NULL, "no table"); + ok(global_table_container.m_lost == 1, "lost 1"); + table= create_table(& dummy_table_share, & fake_thread, NULL); + ok(table == NULL, "no table"); + ok(global_table_container.m_lost == 2, "lost 2"); + + socket= create_socket(& dummy_socket_class, NULL, NULL, 0); + ok(socket == NULL, "no socket"); + ok(global_socket_container.m_lost == 1, "lost 1"); + socket= create_socket(& dummy_socket_class, NULL, NULL, 0); + ok(socket == NULL, "no socket"); + ok(global_socket_container.m_lost == 2, "lost 2"); + + /* No result to test, just make sure it does not crash */ + reset_events_waits_by_instance(); + reset_events_waits_by_thread(); + + cleanup_file_hash(); + cleanup_instruments(); +} + +void test_with_instances() +{ + int rc; + PFS_mutex_class dummy_mutex_class; + PFS_rwlock_class dummy_rwlock_class; + PFS_cond_class dummy_cond_class; + PFS_thread_class dummy_thread_class; + PFS_file_class dummy_file_class; + PFS_socket_class dummy_socket_class; + PFS_table_share dummy_table_share; + PFS_mutex *mutex_1; + PFS_mutex *mutex_2; + PFS_rwlock *rwlock_1; + PFS_rwlock *rwlock_2; + PFS_cond *cond_1; + PFS_cond *cond_2; + PFS_thread *thread_1; + PFS_thread *thread_2; + PFS_file *file_1; + PFS_file *file_2; + PFS_socket *socket_1; + PFS_socket *socket_2; + PFS_table *table_1; + PFS_table *table_2; + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 1; + param.m_rwlock_class_sizing= 1; + param.m_cond_class_sizing= 1; + param.m_thread_class_sizing= 1; + param.m_table_share_sizing= 1; + param.m_file_class_sizing= 1; + param.m_socket_class_sizing= 1; + param.m_mutex_sizing= 2; + param.m_rwlock_sizing= 2; + param.m_cond_sizing= 2; + param.m_thread_sizing= 2; + param.m_table_sizing= 2; + param.m_file_sizing= 2; + param.m_file_handle_sizing= 100; + param.m_socket_sizing= 2; + param.m_events_waits_history_sizing= 10; + param.m_events_waits_history_long_sizing= 10000; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; + param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_prepared_stmt_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 1; + param.m_metadata_lock_sizing= 0; + + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 0, "instances init"); + + dummy_mutex_class.m_event_name_index= 0; + dummy_mutex_class.m_flags= 0; + dummy_mutex_class.m_enabled= true; + dummy_mutex_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_rwlock_class.m_event_name_index= 1; + dummy_rwlock_class.m_flags= 0; + dummy_rwlock_class.m_enabled= true; + dummy_rwlock_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_cond_class.m_event_name_index= 2; + dummy_cond_class.m_flags= 0; + dummy_cond_class.m_enabled= true; + dummy_cond_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_file_class.m_event_name_index= 3; + dummy_file_class.m_flags= 0; + dummy_file_class.m_enabled= true; + dummy_file_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_socket_class.m_event_name_index= 4; + dummy_socket_class.m_flags= 0; + dummy_socket_class.m_enabled= true; + dummy_socket_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + + dummy_table_share.m_enabled= true; + dummy_table_share.m_timed= true; + + mutex_1= create_mutex(& dummy_mutex_class, NULL); + ok(mutex_1 != NULL, "mutex"); + ok(global_mutex_container.get_lost_counter() == 0, "not lost"); + mutex_2= create_mutex(& dummy_mutex_class, NULL); + ok(mutex_2 != NULL, "mutex"); + ok(global_mutex_container.get_lost_counter() == 0, "not lost"); + mutex_2= create_mutex(& dummy_mutex_class, NULL); + ok(mutex_2 == NULL, "no mutex"); + ok(global_mutex_container.get_lost_counter() == 1, "lost 1"); + destroy_mutex(mutex_1); + mutex_2= create_mutex(& dummy_mutex_class, NULL); + ok(mutex_2 != NULL, "mutex"); + ok(global_mutex_container.get_lost_counter() == 1, "no new loss"); + + rwlock_1= create_rwlock(& dummy_rwlock_class, NULL); + ok(rwlock_1 != NULL, "rwlock"); + ok(global_rwlock_container.m_lost == 0, "not lost"); + rwlock_2= create_rwlock(& dummy_rwlock_class, NULL); + ok(rwlock_2 != NULL, "rwlock"); + ok(global_rwlock_container.m_lost == 0, "not lost"); + rwlock_2= create_rwlock(& dummy_rwlock_class, NULL); + ok(rwlock_2 == NULL, "no rwlock"); + ok(global_rwlock_container.m_lost == 1, "lost 1"); + destroy_rwlock(rwlock_1); + rwlock_2= create_rwlock(& dummy_rwlock_class, NULL); + ok(rwlock_2 != NULL, "rwlock"); + ok(global_rwlock_container.m_lost == 1, "no new loss"); + + cond_1= create_cond(& dummy_cond_class, NULL); + ok(cond_1 != NULL, "cond"); + ok(global_cond_container.m_lost == 0, "not lost"); + cond_2= create_cond(& dummy_cond_class, NULL); + ok(cond_2 != NULL, "cond"); + ok(global_cond_container.m_lost == 0, "not lost"); + cond_2= create_cond(& dummy_cond_class, NULL); + ok(cond_2 == NULL, "no cond"); + ok(global_cond_container.m_lost == 1, "lost 1"); + destroy_cond(cond_1); + cond_2= create_cond(& dummy_cond_class, NULL); + ok(cond_2 != NULL, "cond"); + ok(global_cond_container.m_lost == 1, "no new loss"); + + thread_1= create_thread(& dummy_thread_class, NULL, 0); + ok(thread_1 != NULL, "thread"); + ok(global_thread_container.m_lost == 0, "not lost"); + thread_2= create_thread(& dummy_thread_class, NULL, 0); + ok(thread_2 != NULL, "thread"); + ok(global_thread_container.m_lost == 0, "not lost"); + thread_2= create_thread(& dummy_thread_class, NULL, 0); + ok(thread_2 == NULL, "no thread"); + ok(global_thread_container.m_lost == 1, "lost 1"); + destroy_thread(thread_1); + thread_2= create_thread(& dummy_thread_class, NULL, 0); + ok(thread_2 != NULL, "thread"); + ok(global_thread_container.m_lost == 1, "no new loss"); + + PFS_thread fake_thread; + fake_thread.m_filename_hash_pins= NULL; + + file_1= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); + ok(file_1 == NULL, "no file"); + ok(global_file_container.m_lost == 1, "lost 1"); + file_1= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); + ok(file_1 == NULL, "no file"); + ok(global_file_container.m_lost == 2, "lost 2"); + + init_file_hash(& param); + global_file_container.m_lost= 0; + + file_1= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_A", 7, true); + ok(file_1 != NULL, "file"); + ok(file_1->m_file_stat.m_open_count == 1, "open count 1"); + ok(global_file_container.m_lost == 0, "not lost"); + file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_A", 7, true); + ok(file_1 == file_2, "same file"); + ok(file_1->m_file_stat.m_open_count == 2, "open count 2"); + ok(global_file_container.m_lost == 0, "not lost"); + release_file(file_2); + ok(file_1->m_file_stat.m_open_count == 1, "open count 1"); + file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_B", 7, true); + ok(file_2 != NULL, "file"); + ok(global_file_container.m_lost == 0, "not lost"); + file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_C", 7, true); + ok(file_2 == NULL, "no file"); + ok(global_file_container.m_lost == 1, "lost"); + release_file(file_1); + /* the file still exists, not destroyed */ + ok(file_1->m_file_stat.m_open_count == 0, "open count 0"); + file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_D", 7, true); + ok(file_2 == NULL, "no file"); + ok(global_file_container.m_lost == 2, "lost"); + + socket_1= create_socket(& dummy_socket_class, NULL, NULL, 0); + ok(socket_1 != NULL, "socket"); + ok(global_socket_container.m_lost == 0, "not lost"); + socket_2= create_socket(& dummy_socket_class, NULL, NULL, 0); + ok(socket_2 != NULL, "socket"); + ok(global_socket_container.m_lost == 0, "not lost"); + socket_2= create_socket(& dummy_socket_class, NULL, NULL, 0); + ok(socket_2 == NULL, "no socket"); + ok(global_socket_container.m_lost == 1, "lost 1"); + destroy_socket(socket_1); + socket_2= create_socket(& dummy_socket_class, NULL, NULL, 0); + ok(socket_2 != NULL, "socket"); + ok(global_socket_container.m_lost == 1, "no new loss"); + + table_1= create_table(& dummy_table_share, & fake_thread, NULL); + ok(table_1 != NULL, "table"); + ok(global_table_container.m_lost == 0, "not lost"); + table_2= create_table(& dummy_table_share, & fake_thread, NULL); + ok(table_2 != NULL, "table"); + ok(global_table_container.m_lost == 0, "not lost"); + table_2= create_table(& dummy_table_share, & fake_thread, NULL); + ok(table_2 == NULL, "no table"); + ok(global_table_container.m_lost == 1, "lost 1"); + destroy_table(table_1); + table_2= create_table(& dummy_table_share, & fake_thread, NULL); + ok(table_2 != NULL, "table"); + ok(global_table_container.m_lost == 1, "no new loss"); + + //TODO: test that cleanup works + reset_events_waits_by_instance(); + reset_events_waits_by_thread(); + + cleanup_file_hash(); + cleanup_instruments(); +} + +void do_all_tests() +{ + flag_global_instrumentation= true; + flag_thread_instrumentation= true; + + test_no_instruments(); + test_no_instances(); + test_with_instances(); +} + +int main(int argc, char **argv) +{ + plan(103); + MY_INIT(argv[0]); + do_all_tests(); + my_end(0); + return (exit_status()); +} + diff --git a/storage/perfschema/unittest/pfs_instr_class-oom-t.cc b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc new file mode 100644 index 00000000..b7c17d06 --- /dev/null +++ b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc @@ -0,0 +1,114 @@ +/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_instr_class.h> +#include <pfs_instr.h> +#include <pfs_global.h> +#include <tap.h> +#include <sql_class.h> +#include <pfs_buffer_container.h> + +#include "stub_pfs_global.h" +#include "stub_global_status_var.h" + +void test_oom() +{ + int rc; + PFS_global_param param; + TABLE_SHARE table_share; + PFS_thread pfs_thread; + PFS_table_share *pfs_table_share; + + rc= init_sync_class(1000, 0, 0); + ok(rc == 1, "oom (mutex)"); + rc= init_sync_class(0, 1000, 0); + ok(rc == 1, "oom (rwlock)"); + rc= init_sync_class(0, 0, 1000); + ok(rc == 1, "oom (cond)"); + rc= init_thread_class(1000); + ok(rc == 1, "oom (thread)"); + rc= init_file_class(1000); + ok(rc == 1, "oom (file)"); + rc= init_socket_class(1000); + ok(rc == 1, "oom (socket)"); + rc= init_stage_class(1000); + ok(rc == 1, "oom (stage)"); + rc= init_statement_class(1000); + ok(rc == 1, "oom (statement)"); + rc= init_memory_class(1000); + ok(rc == 1, "oom (memory)"); + + cleanup_sync_class(); + cleanup_thread_class(); + cleanup_file_class(); + cleanup_table_share(); + cleanup_socket_class(); + cleanup_stage_class(); + cleanup_statement_class(); + cleanup_memory_class(); + + /* Table share classes. */ + memset(¶m, 0, sizeof(param)); + param.m_enabled= true; + param.m_table_share_sizing= 100; + param.m_setup_object_sizing= 100; + + pfs_thread.m_table_share_hash_pins= NULL; + pfs_thread.m_setup_object_hash_pins= NULL; + + char db_name[]= "schema 1"; + char table_name[]= "table 1"; + table_share.db.str= db_name; + table_share.db.length= strlen(db_name); + table_share.table_name.str= table_name; + table_share.table_name.length= strlen(table_name); + + init_table_share(param.m_table_share_sizing); + init_table_share_hash(¶m); + init_setup_object_hash(¶m); + + stub_alloc_always_fails= false; + pfs_table_share= find_or_create_table_share(&pfs_thread, false, &table_share); + ok(pfs_table_share == NULL, "oom (pfs table share)"); + ok(global_table_share_container.m_lost == 1, "oom (table share)"); + + cleanup_table_share(); + cleanup_table_share_hash(); + cleanup_setup_object_hash(); +} + +void do_all_tests() +{ + test_oom(); +} + +int main(int argc, char **argv) +{ + plan(11); + MY_INIT(argv[0]); + do_all_tests(); + my_end(0); + return (exit_status()); +} + diff --git a/storage/perfschema/unittest/pfs_instr_class-t.cc b/storage/perfschema/unittest/pfs_instr_class-t.cc new file mode 100644 index 00000000..7651898d --- /dev/null +++ b/storage/perfschema/unittest/pfs_instr_class-t.cc @@ -0,0 +1,750 @@ +/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <string.h> // strncpy +#include <pfs_instr_class.h> +#include <pfs_instr.h> +#include <pfs_global.h> +#include <tap.h> + +#include "stub_global_status_var.h" + +void test_no_registration() +{ + int rc; + PFS_sync_key key; + PFS_thread_key thread_key; + PFS_file_key file_key; + PFS_socket_key socket_key; + PFS_memory_key memory_key; + PFS_mutex_class *mutex; + PFS_rwlock_class *rwlock; + PFS_cond_class *cond; + PFS_thread_class *thread; + PFS_file_class *file; + PFS_socket_class *socket; + PFS_memory_class *memory; + /* PFS_table_share *table; */ + + rc= init_sync_class(0, 0, 0); + ok(rc == 0, "zero init (sync)"); + rc= init_thread_class(0); + ok(rc == 0, "zero init (thread)"); + rc= init_file_class(0); + ok(rc == 0, "zero init (file)"); + rc= init_socket_class(0); + ok(rc == 0, "zero init (socket)"); + rc= init_table_share(0); + ok(rc == 0, "zero init (table)"); + rc= init_memory_class(0); + ok(rc == 0, "zero init (memory)"); + + key= register_mutex_class("FOO", 3, 0); + ok(key == 0, "no mutex registered"); + key= register_mutex_class("BAR", 3, 0); + ok(key == 0, "no mutex registered"); + key= register_mutex_class("FOO", 3, 0); + ok(key == 0, "no mutex registered"); + + key= register_rwlock_class("FOO", 3, 0); + ok(key == 0, "no rwlock registered"); + key= register_rwlock_class("BAR", 3, 0); + ok(key == 0, "no rwlock registered"); + key= register_rwlock_class("FOO", 3, 0); + ok(key == 0, "no rwlock registered"); + + key= register_cond_class("FOO", 3, 0); + ok(key == 0, "no cond registered"); + key= register_cond_class("BAR", 3, 0); + ok(key == 0, "no cond registered"); + key= register_cond_class("FOO", 3, 0); + ok(key == 0, "no cond registered"); + + thread_key= register_thread_class("FOO", 3, 0); + ok(thread_key == 0, "no thread registered"); + thread_key= register_thread_class("BAR", 3, 0); + ok(thread_key == 0, "no thread registered"); + thread_key= register_thread_class("FOO", 3, 0); + ok(thread_key == 0, "no thread registered"); + + file_key= register_file_class("FOO", 3, 0); + ok(file_key == 0, "no file registered"); + file_key= register_file_class("BAR", 3, 0); + ok(file_key == 0, "no file registered"); + file_key= register_file_class("FOO", 3, 0); + ok(file_key == 0, "no file registered"); + + socket_key= register_socket_class("FOO", 3, 0); + ok(socket_key == 0, "no socket registered"); + socket_key= register_socket_class("BAR", 3, 0); + ok(socket_key == 0, "no socket registered"); + socket_key= register_socket_class("FOO", 3, 0); + ok(socket_key == 0, "no socket registered"); + + memory_key= register_memory_class("FOO", 3, 0); + ok(memory_key == 0, "no memory registered"); + memory_key= register_memory_class("BAR", 3, 0); + ok(memory_key == 0, "no memory registered"); + memory_key= register_memory_class("FOO", 3, 0); + ok(memory_key == 0, "no memory registered"); + +#ifdef LATER + PFS_thread fake_thread; + fake_thread.m_table_share_hash_pins= NULL; + + table= find_or_create_table_share(& fake_thread, false, "foo_db", 6, "foo_table", 9); + ok(table == NULL, "not created"); + table= find_or_create_table_share(& fake_thread, false, "bar_db", 6, "bar_table", 9); + ok(table == NULL, "not created"); + table= find_or_create_table_share(& fake_thread, false, "foo_db", 6, "foo_table", 9); + ok(table == NULL, "not created"); +#endif + + mutex= find_mutex_class(0); + ok(mutex == NULL, "no mutex key 0"); + mutex= find_mutex_class(1); + ok(mutex == NULL, "no mutex key 1"); + mutex= find_mutex_class(9999); + ok(mutex == NULL, "no mutex key 9999"); + + rwlock= find_rwlock_class(0); + ok(rwlock == NULL, "no rwlock key 0"); + rwlock= find_rwlock_class(1); + ok(rwlock == NULL, "no rwlock key 1"); + rwlock= find_rwlock_class(9999); + ok(rwlock == NULL, "no rwlock key 9999"); + + cond= find_cond_class(0); + ok(cond == NULL, "no cond key 0"); + cond= find_cond_class(1); + ok(cond == NULL, "no cond key 1"); + cond= find_cond_class(9999); + ok(cond == NULL, "no cond key 9999"); + + thread= find_thread_class(0); + ok(thread == NULL, "no thread key 0"); + thread= find_thread_class(1); + ok(thread == NULL, "no thread key 1"); + thread= find_thread_class(9999); + ok(thread == NULL, "no thread key 9999"); + + file= find_file_class(0); + ok(file == NULL, "no file key 0"); + file= find_file_class(1); + ok(file == NULL, "no file key 1"); + file= find_file_class(9999); + ok(file == NULL, "no file key 9999"); + + socket= find_socket_class(0); + ok(socket == NULL, "no socket key 0"); + socket= find_socket_class(1); + ok(socket == NULL, "no socket key 1"); + socket= find_socket_class(9999); + ok(socket == NULL, "no socket key 9999"); + + memory= find_memory_class(0); + ok(memory == NULL, "no memory key 0"); + memory= find_memory_class(1); + ok(memory == NULL, "no memory key 1"); + memory= find_memory_class(9999); + ok(memory == NULL, "no memory key 9999"); + + cleanup_sync_class(); + cleanup_thread_class(); + cleanup_file_class(); + cleanup_socket_class(); + cleanup_table_share(); + cleanup_memory_class(); +} + +void test_mutex_registration() +{ + int rc; + PFS_sync_key key; + PFS_mutex_class *mutex; + + rc= init_sync_class(5, 0, 0); + ok(rc == 0, "room for 5 mutex"); + + key= register_mutex_class("FOO", 3, 0); + ok(key == 1, "foo registered"); + key= register_mutex_class("BAR", 3, 0); + ok(key == 2, "bar registered"); + key= register_mutex_class("FOO", 3, 0); + ok(key == 1, "foo re registered"); + key= register_mutex_class("M-3", 3, 0); + ok(key == 3, "M-3 registered"); + key= register_mutex_class("M-4", 3, 0); + ok(key == 4, "M-4 registered"); + key= register_mutex_class("M-5", 3, 0); + ok(key == 5, "M-5 registered"); + ok(mutex_class_lost == 0, "lost nothing"); + key= register_mutex_class("M-6", 3, 0); + ok(key == 0, "M-6 not registered"); + ok(mutex_class_lost == 1, "lost 1 mutex"); + key= register_mutex_class("M-7", 3, 0); + ok(key == 0, "M-7 not registered"); + ok(mutex_class_lost == 2, "lost 2 mutex"); + key= register_mutex_class("M-3", 3, 0); + ok(key == 3, "M-3 re registered"); + ok(mutex_class_lost == 2, "lost 2 mutex"); + key= register_mutex_class("M-5", 3, 0); + ok(key == 5, "M-5 re registered"); + ok(mutex_class_lost == 2, "lost 2 mutex"); + + mutex= find_mutex_class(0); + ok(mutex == NULL, "no key 0"); + mutex= find_mutex_class(3); + ok(mutex != NULL, "found key 3"); + ok(strncmp(mutex->m_name, "M-3", 3) == 0, "key 3 is M-3"); + ok(mutex->m_name_length == 3, "name length 3"); + mutex= find_mutex_class(9999); + ok(mutex == NULL, "no key 9999"); + + cleanup_sync_class(); +} + +void test_rwlock_registration() +{ + int rc; + PFS_sync_key key; + PFS_rwlock_class *rwlock; + + rc= init_sync_class(0, 5, 0); + ok(rc == 0, "room for 5 rwlock"); + + key= register_rwlock_class("FOO", 3, 0); + ok(key == 1, "foo registered"); + key= register_rwlock_class("BAR", 3, 0); + ok(key == 2, "bar registered"); + key= register_rwlock_class("FOO", 3, 0); + ok(key == 1, "foo re registered"); + key= register_rwlock_class("RW-3", 4, 0); + ok(key == 3, "RW-3 registered"); + key= register_rwlock_class("RW-4", 4, 0); + ok(key == 4, "RW-4 registered"); + key= register_rwlock_class("RW-5", 4, 0); + ok(key == 5, "RW-5 registered"); + key= register_rwlock_class("RW-6", 4, 0); + ok(key == 0, "RW-6 not registered"); + key= register_rwlock_class("RW-7", 4, 0); + ok(key == 0, "RW-7 not registered"); + key= register_rwlock_class("RW-3", 4, 0); + ok(key == 3, "RW-3 re registered"); + key= register_rwlock_class("RW-5", 4, 0); + ok(key == 5, "RW-5 re registered"); + + rwlock= find_rwlock_class(0); + ok(rwlock == NULL, "no key 0"); + rwlock= find_rwlock_class(3); + ok(rwlock != NULL, "found key 3"); + ok(strncmp(rwlock->m_name, "RW-3", 4) == 0, "key 3 is RW-3"); + ok(rwlock->m_name_length == 4, "name length 4"); + rwlock= find_rwlock_class(9999); + ok(rwlock == NULL, "no key 9999"); + + cleanup_sync_class(); +} + +void test_cond_registration() +{ + int rc; + PFS_sync_key key; + PFS_cond_class *cond; + + rc= init_sync_class(0, 0, 5); + ok(rc == 0, "room for 5 cond"); + + key= register_cond_class("FOO", 3, 0); + ok(key == 1, "foo registered"); + key= register_cond_class("BAR", 3, 0); + ok(key == 2, "bar registered"); + key= register_cond_class("FOO", 3, 0); + ok(key == 1, "foo re registered"); + key= register_cond_class("C-3", 3, 0); + ok(key == 3, "C-3 registered"); + key= register_cond_class("C-4", 3, 0); + ok(key == 4, "C-4 registered"); + key= register_cond_class("C-5", 3, 0); + ok(key == 5, "C-5 registered"); + key= register_cond_class("C-6", 3, 0); + ok(key == 0, "C-6 not registered"); + key= register_cond_class("C-7", 3, 0); + ok(key == 0, "C-7 not registered"); + key= register_cond_class("C-3", 3, 0); + ok(key == 3, "C-3 re registered"); + key= register_cond_class("C-5", 3, 0); + ok(key == 5, "C-5 re registered"); + + cond= find_cond_class(0); + ok(cond == NULL, "no key 0"); + cond= find_cond_class(3); + ok(cond != NULL, "found key 3"); + ok(strncmp(cond->m_name, "C-3", 3) == 0, "key 3 is C-3"); + ok(cond->m_name_length == 3, "name length 3"); + cond= find_cond_class(9999); + ok(cond == NULL, "no key 9999"); + + cleanup_sync_class(); +} + +void test_thread_registration() +{ + int rc; + PFS_thread_key key; + PFS_thread_class *thread; + + rc= init_thread_class(5); + ok(rc == 0, "room for 5 thread"); + + key= register_thread_class("FOO", 3, 0); + ok(key == 1, "foo registered"); + key= register_thread_class("BAR", 3, 0); + ok(key == 2, "bar registered"); + key= register_thread_class("FOO", 3, 0); + ok(key == 1, "foo re registered"); + key= register_thread_class("Thread-3", 8, 0); + ok(key == 3, "Thread-3 registered"); + key= register_thread_class("Thread-4", 8, 0); + ok(key == 4, "Thread-4 registered"); + key= register_thread_class("Thread-5", 8, 0); + ok(key == 5, "Thread-5 registered"); + key= register_thread_class("Thread-6", 8, 0); + ok(key == 0, "Thread-6 not registered"); + key= register_thread_class("Thread-7", 8, 0); + ok(key == 0, "Thread-7 not registered"); + key= register_thread_class("Thread-3", 8, 0); + ok(key == 3, "Thread-3 re registered"); + key= register_thread_class("Thread-5", 8, 0); + ok(key == 5, "Thread-5 re registered"); + + thread= find_thread_class(0); + ok(thread == NULL, "no key 0"); + thread= find_thread_class(3); + ok(thread != NULL, "found key 3"); + ok(strncmp(thread->m_name, "Thread-3", 8) == 0, "key 3 is Thread-3"); + ok(thread->m_name_length == 8, "name length 8"); + thread= find_thread_class(9999); + ok(thread == NULL, "no key 9999"); + + cleanup_thread_class(); +} + +void test_file_registration() +{ + int rc; + PFS_file_key key; + PFS_file_class *file; + + rc= init_file_class(5); + ok(rc == 0, "room for 5 file"); + + key= register_file_class("FOO", 3, 0); + ok(key == 1, "foo registered"); + key= register_file_class("BAR", 3, 0); + ok(key == 2, "bar registered"); + key= register_file_class("FOO", 3, 0); + ok(key == 1, "foo re registered"); + key= register_file_class("File-3", 6, 0); + ok(key == 3, "File-3 registered"); + key= register_file_class("File-4", 6, 0); + ok(key == 4, "File-4 registered"); + key= register_file_class("File-5", 6, 0); + ok(key == 5, "File-5 registered"); + key= register_file_class("File-6", 6, 0); + ok(key == 0, "File-6 not registered"); + key= register_file_class("File-7", 6, 0); + ok(key == 0, "File-7 not registered"); + key= register_file_class("File-3", 6, 0); + ok(key == 3, "File-3 re registered"); + key= register_file_class("File-5", 6, 0); + ok(key == 5, "File-5 re registered"); + + file= find_file_class(0); + ok(file == NULL, "no key 0"); + file= find_file_class(3); + ok(file != NULL, "found key 3"); + ok(strncmp(file->m_name, "File-3", 6) == 0, "key 3 is File-3"); + ok(file->m_name_length == 6, "name length 6"); + file= find_file_class(9999); + ok(file == NULL, "no key 9999"); + + cleanup_file_class(); +} + +void test_socket_registration() +{ + int rc; + PFS_socket_key key; + PFS_socket_class *socket; + + rc= init_socket_class(5); + ok(rc == 0, "room for 5 socket"); + + key= register_socket_class("FOO", 3, 0); + ok(key == 1, "foo registered"); + key= register_socket_class("BAR", 3, 0); + ok(key == 2, "bar registered"); + key= register_socket_class("FOO", 3, 0); + ok(key == 1, "foo re registered"); + key= register_socket_class("Socket-3", 8, 0); + ok(key == 3, "Socket-3 registered"); + key= register_socket_class("Socket-4", 8, 0); + ok(key == 4, "Socket-4 registered"); + key= register_socket_class("Socket-5", 8, 0); + ok(key == 5, "Socket-5 registered"); + ok(socket_class_lost == 0, "lost nothing"); + key= register_socket_class("Socket-6", 8, 0); + ok(key == 0, "Socket-6 not registered"); + ok(socket_class_lost == 1, "lost 1 socket"); + key= register_socket_class("Socket-7", 8, 0); + ok(key == 0, "Socket-7 not registered"); + ok(socket_class_lost == 2, "lost 2 socket"); + key= register_socket_class("Socket-3", 8, 0); + ok(key == 3, "Socket-3 re registered"); + ok(socket_class_lost == 2, "lost 2 socket"); + key= register_socket_class("Socket-5", 8, 0); + ok(key == 5, "Socket-5 re registered"); + ok(socket_class_lost == 2, "lost 2 socket"); + + socket= find_socket_class(0); + ok(socket == NULL, "no key 0"); + socket= find_socket_class(3); + ok(socket != NULL, "found key 3"); + ok(strncmp(socket->m_name, "Socket-3", 8) == 0, "key 3 is Socket-3"); + ok(socket->m_name_length == 8, "name length 3"); + socket= find_socket_class(9999); + ok(socket == NULL, "no key 9999"); + + cleanup_socket_class(); +} + +void test_table_registration() +{ +#ifdef LATER + PFS_table_share *table_share; + PFS_table_share *table_share_2; + + PFS_thread fake_thread; + fake_thread.m_table_share_hash_pins= NULL; + + table_share_lost= 0; + table_share= find_or_create_table_share(& fake_thread, false, "db1", 3, "t1", 2); + ok(table_share == NULL, "not created"); + ok(table_share_lost == 1, "lost the table"); + + table_share_lost= 0; + init_table_share(5); + init_table_share_hash(); + + table_share= find_or_create_table_share(& fake_thread, false, "db1", 3, "t1", 2); + ok(table_share != NULL, "created db1.t1"); + ok(table_share_lost == 0, "not lost"); + + table_share_2= find_or_create_table_share(& fake_thread, false, "db1", 3, "t1", 2); + ok(table_share_2 != NULL, "found db1.t1"); + ok(table_share_lost == 0, "not lost"); + ok(table_share == table_share_2, "same table"); + + table_share_2= find_or_create_table_share(& fake_thread, false, "db1", 3, "t2", 2); + ok(table_share_2 != NULL, "created db1.t2"); + ok(table_share_lost == 0, "not lost"); + + table_share_2= find_or_create_table_share(& fake_thread, false, "db2", 3, "t1", 2); + ok(table_share_2 != NULL, "created db2.t1"); + ok(table_share_lost == 0, "not lost"); + + table_share_2= find_or_create_table_share(& fake_thread, false, "db2", 3, "t2", 2); + ok(table_share_2 != NULL, "created db2.t2"); + ok(table_share_lost == 0, "not lost"); + + table_share_2= find_or_create_table_share(& fake_thread, false, "db3", 3, "t3", 2); + ok(table_share_2 != NULL, "created db3.t3"); + ok(table_share_lost == 0, "not lost"); + + table_share_2= find_or_create_table_share(& fake_thread, false, "db4", 3, "t4", 2); + ok(table_share_2 == NULL, "lost db4.t4"); + ok(table_share_lost == 1, "lost"); + + table_share_lost= 0; + table_share_2= find_or_create_table_share(& fake_thread, false, "db1", 3, "t2", 2); + ok(table_share_2 != NULL, "found db1.t2"); + ok(table_share_lost == 0, "not lost"); + ok(strncmp(table_share_2->m_schema_name, "db1", 3) == 0 , "schema db1"); + ok(table_share_2->m_schema_name_length == 3, "length 3"); + ok(strncmp(table_share_2->m_table_name, "t2", 2) == 0 , "table t2"); + ok(table_share_2->m_table_name_length == 2, "length 2"); + + cleanup_table_share_hash(); + cleanup_table_share(); +#endif +} + +void test_memory_registration() +{ + int rc; + PFS_memory_key key; + PFS_memory_class *memory; + + rc= init_memory_class(5); + ok(rc == 0, "room for 5 memory"); + + key= register_memory_class("FOO", 3, 0); + ok(key == 1, "foo registered"); + key= register_memory_class("BAR", 3, 0); + ok(key == 2, "bar registered"); + key= register_memory_class("FOO", 3, 0); + ok(key == 1, "foo re registered"); + key= register_memory_class("Memory-3", 8, 0); + ok(key == 3, "Memory-3 registered"); + key= register_memory_class("Memory-4", 8, 0); + ok(key == 4, "Memory-4 registered"); + key= register_memory_class("Memory-5", 8, 0); + ok(key == 5, "Memory-5 registered"); + ok(memory_class_lost == 0, "lost nothing"); + key= register_memory_class("Memory-6", 8, 0); + ok(key == 0, "Memory-6 not registered"); + ok(memory_class_lost == 1, "lost 1 memory"); + key= register_memory_class("Memory-7", 8, 0); + ok(key == 0, "Memory-7 not registered"); + ok(memory_class_lost == 2, "lost 2 memory"); + key= register_memory_class("Memory-3", 8, 0); + ok(key == 3, "Memory-3 re registered"); + ok(memory_class_lost == 2, "lost 2 memory"); + key= register_memory_class("Memory-5", 8, 0); + ok(key == 5, "Memory-5 re registered"); + ok(memory_class_lost == 2, "lost 2 memory"); + + memory= find_memory_class(0); + ok(memory == NULL, "no key 0"); + memory= find_memory_class(3); + ok(memory != NULL, "found key 3"); + ok(strncmp(memory->m_name, "Memory-3", 8) == 0, "key 3 is Memory-3"); + ok(memory->m_name_length == 8, "name length 3"); + memory= find_memory_class(9999); + ok(memory == NULL, "no key 9999"); + + cleanup_memory_class(); +} + +#ifdef LATER +void set_wait_stat(PFS_instr_class *klass) +{ + PFS_single_stat *stat; + stat= & global_instr_class_waits_array[klass->m_event_name_index]; + + stat->m_count= 12; + stat->m_min= 5; + stat->m_max= 120; + stat->m_sum= 999; +} + +bool is_empty_stat(PFS_instr_class *klass) +{ + PFS_single_stat *stat; + stat= & global_instr_class_waits_array[klass->m_event_name_index]; + + if (stat->m_count != 0) + return false; + if (stat->m_min != (ulonglong) -1) + return false; + if (stat->m_max != 0) + return false; + if (stat->m_sum != 0) + return false; + return true; +} +#endif + +void test_instruments_reset() +{ + int rc; + PFS_sync_key key; + PFS_file_key file_key; + PFS_socket_key socket_key; + PFS_mutex_class *mutex_1; + PFS_mutex_class *mutex_2; + PFS_mutex_class *mutex_3; + PFS_rwlock_class *rwlock_1; + PFS_rwlock_class *rwlock_2; + PFS_rwlock_class *rwlock_3; + PFS_cond_class *cond_1; + PFS_cond_class *cond_2; + PFS_cond_class *cond_3; + PFS_file_class *file_1; + PFS_file_class *file_2; + PFS_file_class *file_3; + PFS_socket_class *socket_1; + PFS_socket_class *socket_2; + PFS_socket_class *socket_3; + + rc= init_sync_class(3, 3, 3); + ok(rc == 0, "init (sync)"); + rc= init_thread_class(3); + ok(rc == 0, "init (thread)"); + rc= init_file_class(3); + ok(rc == 0, "init (file)"); + rc= init_socket_class(3); + ok(rc == 0, "init (socket)"); + + key= register_mutex_class("M-1", 3, 0); + ok(key == 1, "mutex registered"); + key= register_mutex_class("M-2", 3, 0); + ok(key == 2, "mutex registered"); + key= register_mutex_class("M-3", 3, 0); + ok(key == 3, "mutex registered"); + + key= register_rwlock_class("RW-1", 4, 0); + ok(key == 1, "rwlock registered"); + key= register_rwlock_class("RW-2", 4, 0); + ok(key == 2, "rwlock registered"); + key= register_rwlock_class("RW-3", 4, 0); + ok(key == 3, "rwlock registered"); + + key= register_cond_class("C-1", 3, 0); + ok(key == 1, "cond registered"); + key= register_cond_class("C-2", 3, 0); + ok(key == 2, "cond registered"); + key= register_cond_class("C-3", 3, 0); + ok(key == 3, "cond registered"); + + file_key= register_file_class("F-1", 3, 0); + ok(file_key == 1, "file registered"); + file_key= register_file_class("F-2", 3, 0); + ok(file_key == 2, "file registered"); + file_key= register_file_class("F-3", 3, 0); + ok(file_key == 3, "file registered"); + + socket_key= register_socket_class("S-1", 3, 0); + ok(socket_key == 1, "socket registered"); + socket_key= register_socket_class("S-2", 3, 0); + ok(socket_key == 2, "socket registered"); + socket_key= register_socket_class("S-3", 3, 0); + ok(socket_key == 3, "socket registered"); + + mutex_1= find_mutex_class(1); + ok(mutex_1 != NULL, "mutex key 1"); + mutex_2= find_mutex_class(2); + ok(mutex_2 != NULL, "mutex key 2"); + mutex_3= find_mutex_class(3); + ok(mutex_3 != NULL, "mutex key 3"); + + rwlock_1= find_rwlock_class(1); + ok(rwlock_1 != NULL, "rwlock key 1"); + rwlock_2= find_rwlock_class(2); + ok(rwlock_2 != NULL, "rwlock key 2"); + rwlock_3= find_rwlock_class(3); + ok(rwlock_3 != NULL, "rwlock key 3"); + + cond_1= find_cond_class(1); + ok(cond_1 != NULL, "cond key 1"); + cond_2= find_cond_class(2); + ok(cond_2 != NULL, "cond key 2"); + cond_3= find_cond_class(3); + ok(cond_3 != NULL, "cond key 3"); + + file_1= find_file_class(1); + ok(file_1 != NULL, "file key 1"); + file_2= find_file_class(2); + ok(file_2 != NULL, "file key 2"); + file_3= find_file_class(3); + ok(file_3 != NULL, "file key 3"); + + socket_1= find_socket_class(1); + ok(socket_1 != NULL, "socket key 1"); + socket_2= find_socket_class(2); + ok(socket_2 != NULL, "socket key 2"); + socket_3= find_socket_class(3); + ok(socket_3 != NULL, "socket key 3"); + +#ifdef LATER + set_wait_stat(mutex_1); + set_wait_stat(mutex_2); + set_wait_stat(mutex_3); + set_wait_stat(rwlock_1); + set_wait_stat(rwlock_2); + set_wait_stat(rwlock_3); + set_wait_stat(cond_1); + set_wait_stat(cond_2); + set_wait_stat(cond_3); + set_wait_stat(file_1); + set_wait_stat(file_2); + set_wait_stat(file_3); + + ok(! is_empty_stat(mutex_1), "mutex_1 stat is populated"); + ok(! is_empty_stat(mutex_2), "mutex_2 stat is populated"); + ok(! is_empty_stat(mutex_3), "mutex_3 stat is populated"); + ok(! is_empty_stat(rwlock_1), "rwlock_1 stat is populated"); + ok(! is_empty_stat(rwlock_2), "rwlock_2 stat is populated"); + ok(! is_empty_stat(rwlock_3), "rwlock_3 stat is populated"); + ok(! is_empty_stat(cond_1), "cond_1 stat is populated"); + ok(! is_empty_stat(cond_2), "cond_2 stat is populated"); + ok(! is_empty_stat(cond_3), "cond_3 stat is populated"); + ok(! is_empty_stat(file_1), "file_1 stat is populated"); + ok(! is_empty_stat(file_2), "file_2 stat is populated"); + ok(! is_empty_stat(file_3), "file_3 stat is populated"); + + reset_global_wait_stat(); + + ok(is_empty_stat(mutex_1), "mutex_1 stat is cleared"); + ok(is_empty_stat(mutex_2), "mutex_2 stat is cleared"); + ok(is_empty_stat(mutex_3), "mutex_3 stat is cleared"); + ok(is_empty_stat(rwlock_1), "rwlock_1 stat is cleared"); + ok(is_empty_stat(rwlock_2), "rwlock_2 stat is cleared"); + ok(is_empty_stat(rwlock_3), "rwlock_3 stat is cleared"); + ok(is_empty_stat(cond_1), "cond_1 stat is cleared"); + ok(is_empty_stat(cond_2), "cond_2 stat is cleared"); + ok(is_empty_stat(cond_3), "cond_3 stat is cleared"); + ok(is_empty_stat(file_1), "file_1 stat is cleared"); + ok(is_empty_stat(file_2), "file_2 stat is cleared"); + ok(is_empty_stat(file_3), "file_3 stat is cleared"); +#endif + + cleanup_sync_class(); + cleanup_file_class(); + cleanup_socket_class(); +} + +void do_all_tests() +{ + test_no_registration(); + test_mutex_registration(); + test_rwlock_registration(); + test_cond_registration(); + test_thread_registration(); + test_file_registration(); + test_socket_registration(); + test_table_registration(); + test_memory_registration(); + test_instruments_reset(); +} + +int main(int argc, char **argv) +{ + plan(209); + MY_INIT(argv[0]); + do_all_tests(); + my_end(0); + return (exit_status()); +} diff --git a/storage/perfschema/unittest/pfs_misc-t.cc b/storage/perfschema/unittest/pfs_misc-t.cc new file mode 100644 index 00000000..f5964348 --- /dev/null +++ b/storage/perfschema/unittest/pfs_misc-t.cc @@ -0,0 +1,95 @@ +/* Copyright (c) 2015, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_instr.h> +#include <pfs_stat.h> +#include <pfs_global.h> +#include <pfs_instr_class.h> +#include <pfs_buffer_container.h> +#include <tap.h> + +#include "stub_global_status_var.h" + +#include <memory.h> + +void test_digest_length_overflow() +{ + if (sizeof(size_t) != 4) + { + skip(3, "digest length overflow requires a 32-bit environment"); + return; + } + + PFS_global_param param; + memset(¶m, 0, sizeof(param)); + param.m_enabled= true; + /* + Force 32-bit arithmetic overflow using the digest memory allocation + parameters. The Performance Schema should detect the overflow, free + allocated memory and abort initialization with a warning. + */ + + /* Max digest length, events_statements_history_long. */ + param.m_events_statements_history_long_sizing= 10000; + param.m_digest_sizing= 1000; + param.m_max_digest_length= (1024 * 1024); + param.m_max_sql_text_length= 0; + pfs_max_digest_length= param.m_max_digest_length; + pfs_max_sqltext= param.m_max_sql_text_length; + + int rc = init_events_statements_history_long(param.m_events_statements_history_long_sizing); + ok(rc == 1, "digest length overflow (init_events_statements_history_long"); + + /* Max sql text length, events_statements_history_long. */ + param.m_max_sql_text_length= (1024 * 1024); + param.m_max_digest_length= 0; + pfs_max_digest_length= param.m_max_digest_length; + pfs_max_sqltext= param.m_max_sql_text_length; + + rc = init_events_statements_history_long(param.m_events_statements_history_long_sizing); + ok(rc == 1, "sql text length overflow (init_events_statements_history_long"); + + /* Max digest length, events_statements_summary_by_digest. */ + param.m_max_digest_length= (1024 * 1024); + param.m_digest_sizing= 10000; + pfs_max_digest_length= param.m_max_digest_length; + pfs_max_sqltext= param.m_max_sql_text_length; + + rc = init_digest(¶m); + ok(rc == 1, "digest length overflow (init_digest)"); +} + +void do_all_tests() +{ + test_digest_length_overflow(); +} + +int main(int, char **) +{ + plan(3); + MY_INIT("pfs_misc-t"); + do_all_tests(); + my_end(0); + return (exit_status()); +} diff --git a/storage/perfschema/unittest/pfs_noop-t.cc b/storage/perfschema/unittest/pfs_noop-t.cc new file mode 100644 index 00000000..57e8cfd8 --- /dev/null +++ b/storage/perfschema/unittest/pfs_noop-t.cc @@ -0,0 +1,245 @@ +/* Copyright (c) 2013, 2023, Oracle and/or its affiliates. + Copyright (c) 2022, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_server.h> +#include <pfs_instr_class.h> +#include <pfs_instr.h> +#include <pfs_global.h> +#include <tap.h> + +#include <string.h> +#include <memory.h> + +#include "stub_print_error.h" +#include "stub_pfs_defaults.h" + +void test_noop() +{ + PSI_mutex *mutex; + PSI_rwlock *rwlock; + PSI_cond *cond; + PSI_socket *socket; + PSI_table_share *table_share; + PSI_table *table; + PSI_file *file; + PSI_thread *thread; + PSI_file_locker *file_locker; + PSI_idle_locker *idle_locker; + PSI_mutex_locker *mutex_locker; + PSI_rwlock_locker *rwlock_locker; + PSI_cond_locker *cond_locker; + PSI_table_locker *table_locker; + PSI_statement_locker *statement_locker; + PSI_transaction_locker *transaction_locker; + PSI_socket_locker *socket_locker; + PSI_digest_locker *digest_locker; + PSI_sp_locker *sp_locker; + PSI_sp_share *sp_share; + PSI_memory_key memory_key; + PSI_metadata_lock *metadata_lock; + PSI_metadata_locker *metadata_locker; + PSI_thread *owner; + + diag("test_noop"); + + PSI_server->register_mutex(NULL, NULL, 0); + PSI_server->register_rwlock(NULL, NULL, 0); + PSI_server->register_cond(NULL, NULL, 0); + PSI_server->register_thread(NULL, NULL, 0); + PSI_server->register_file(NULL, NULL, 0); + PSI_server->register_stage(NULL, NULL, 0); + PSI_server->register_statement(NULL, NULL, 0); + PSI_server->register_socket(NULL, NULL, 0); + + ok(true, "register"); + mutex= PSI_server->init_mutex(1, NULL); + ok(mutex == NULL, "no mutex"); + PSI_server->destroy_mutex(NULL); + rwlock= PSI_server->init_rwlock(1, NULL); + ok(rwlock == NULL, "no rwlock"); + PSI_server->destroy_rwlock(NULL); + cond= PSI_server->init_cond(1, NULL); + ok(cond == NULL, "no cond"); + PSI_server->destroy_cond(NULL); + socket= PSI_server->init_socket(1, NULL, NULL, 0); + ok(socket == NULL, "no socket"); + PSI_server->destroy_socket(NULL); + table_share= PSI_server->get_table_share(false, NULL); + ok(table_share == NULL, "no table_share"); + PSI_server->release_table_share(NULL); + PSI_server->drop_table_share(false, NULL, 0, NULL, 0); + table= PSI_server->open_table(NULL, NULL); + ok(table == NULL, "no table"); + PSI_server->unbind_table(NULL); + table= PSI_server->rebind_table(NULL, NULL, NULL); + ok(table == NULL, "no table"); + PSI_server->close_table(NULL, NULL); + PSI_server->create_file(1, NULL, 2); + /* TODO: spawn thread */ + thread= PSI_server->new_thread(1, NULL, 2); + ok(thread == NULL, "no thread"); + PSI_server->set_thread_id(NULL, 1); + thread= PSI_server->get_thread(); + ok(thread == NULL, "no thread"); + PSI_server->set_thread_user(NULL, 0); + PSI_server->set_thread_account(NULL, 0, NULL, 0); + PSI_server->set_thread_db(NULL, 0); + PSI_server->set_thread_command(1); + PSI_server->set_thread_start_time(1); + PSI_server->set_thread_state(NULL); + PSI_server->set_thread_info(NULL, 0); + PSI_server->set_thread(NULL); + PSI_server->delete_current_thread(); + PSI_server->delete_thread(NULL); + file_locker= PSI_server->get_thread_file_name_locker(NULL, 1, PSI_FILE_OPEN, NULL, NULL); + ok(file_locker == NULL, "no file_locker"); + file_locker= PSI_server->get_thread_file_stream_locker(NULL, NULL, PSI_FILE_OPEN); + ok(file_locker == NULL, "no file_locker"); + file_locker= PSI_server->get_thread_file_descriptor_locker(NULL, 0, PSI_FILE_OPEN); + ok(file_locker == NULL, "no file_locker"); + PSI_server->unlock_mutex(NULL); + PSI_server->unlock_rwlock(NULL); + PSI_server->signal_cond(NULL); + PSI_server->broadcast_cond(NULL); + idle_locker= PSI_server->start_idle_wait(NULL, NULL, 0); + ok(idle_locker == NULL, "no idle_locker"); + PSI_server->end_idle_wait(NULL); + mutex_locker= PSI_server->start_mutex_wait(NULL, NULL, PSI_MUTEX_LOCK, NULL, 0); + ok(mutex_locker == NULL, "no mutex_locker"); + PSI_server->end_mutex_wait(NULL, 0); + rwlock_locker= PSI_server->start_rwlock_rdwait(NULL, NULL, PSI_RWLOCK_READLOCK, NULL, 0); + ok(rwlock_locker == NULL, "no rwlock_locker"); + PSI_server->end_rwlock_rdwait(NULL, 0); + rwlock_locker= PSI_server->start_rwlock_wrwait(NULL, NULL, PSI_RWLOCK_WRITELOCK, NULL, 0); + ok(rwlock_locker == NULL, "no rwlock_locker"); + PSI_server->end_rwlock_wrwait(NULL, 0); + cond_locker= PSI_server->start_cond_wait(NULL, NULL, NULL, PSI_COND_WAIT, NULL, 0); + ok(cond_locker == NULL, "no cond_locker"); + PSI_server->end_cond_wait(NULL, 0); + table_locker= PSI_server->start_table_io_wait(NULL, NULL, PSI_TABLE_FETCH_ROW, 0, NULL, 0); + ok(table_locker == NULL, "no table_locker"); + PSI_server->end_table_io_wait(NULL, 0); + table_locker= PSI_server->start_table_lock_wait(NULL, NULL, PSI_TABLE_LOCK, 0, NULL, 0); + ok(table_locker == NULL, "no table_locker"); + PSI_server->end_table_lock_wait(NULL); + PSI_server->start_file_open_wait(NULL, NULL, 0); + file= PSI_server->end_file_open_wait(NULL, NULL); + ok(file == NULL, "no file"); + PSI_server->end_file_open_wait_and_bind_to_descriptor(NULL, 0); + PSI_server->start_file_wait(NULL, 0, NULL, 0); + PSI_server->end_file_wait(NULL, 0); + PSI_server->start_file_close_wait(NULL, NULL, 0); + PSI_server->end_file_close_wait(NULL, 0); + PSI_server->end_file_rename_wait(NULL, NULL, NULL, 0); + PSI_server->start_stage(1, NULL, 0); + + PSI_stage_progress *progress; + progress= PSI_server->get_current_stage_progress(); + ok(progress == NULL, "no progress"); + + PSI_server->end_stage(); + statement_locker= PSI_server->get_thread_statement_locker(NULL, 1, NULL, NULL); + ok(statement_locker == NULL, "no statement_locker"); + statement_locker= PSI_server->refine_statement(NULL, 1); + ok(statement_locker == NULL, "no statement_locker"); + PSI_server->start_statement(NULL, NULL, 0, NULL, 0); + PSI_server->set_statement_text(NULL, NULL, 0); + PSI_server->set_statement_lock_time(NULL, 0); + PSI_server->set_statement_rows_sent(NULL, 0); + PSI_server->set_statement_rows_examined(NULL, 0); + PSI_server->inc_statement_created_tmp_disk_tables(NULL, 0); + PSI_server->inc_statement_created_tmp_tables(NULL, 0); + PSI_server->inc_statement_select_full_join(NULL, 0); + PSI_server->inc_statement_select_full_range_join(NULL, 0); + PSI_server->inc_statement_select_range(NULL, 0); + PSI_server->inc_statement_select_range_check(NULL, 0); + PSI_server->inc_statement_select_scan(NULL, 0); + PSI_server->inc_statement_sort_merge_passes(NULL, 0); + PSI_server->inc_statement_sort_range(NULL, 0); + PSI_server->inc_statement_sort_rows(NULL, 0); + PSI_server->inc_statement_sort_scan(NULL, 0); + PSI_server->set_statement_no_index_used(NULL); + PSI_server->set_statement_no_good_index_used(NULL); + PSI_server->end_statement(NULL, NULL); + socket_locker= PSI_server->start_socket_wait(NULL, NULL, PSI_SOCKET_SEND, 1, NULL, 0); + ok(socket_locker == NULL, "no socket_locker"); + PSI_server->end_socket_wait(NULL, 0); + PSI_server->set_socket_state(NULL, PSI_SOCKET_STATE_IDLE); + PSI_server->set_socket_info(NULL, NULL, NULL, 0); + PSI_server->set_socket_thread_owner(NULL); + digest_locker= PSI_server->digest_start(NULL); + ok(digest_locker == NULL, "no digest_locker"); + PSI_server->digest_end(NULL, NULL); + sp_locker= PSI_server->start_sp(NULL, NULL); + ok(sp_locker == NULL, "no sp_locker"); + PSI_server->end_sp(NULL); + PSI_server->drop_sp(0, NULL, 0, NULL, 0); + sp_share= PSI_server->get_sp_share(0, NULL, 0, NULL, 0); + ok(sp_share == NULL, "no sp_share"); + PSI_server->release_sp_share(NULL); + PSI_server->register_memory(NULL, NULL, 0); + memory_key= PSI_server->memory_alloc(0, 0, & owner); + ok(memory_key == PSI_NOT_INSTRUMENTED, "no memory_key"); + memory_key= PSI_server->memory_realloc(0, 0, 0, & owner); + ok(memory_key == PSI_NOT_INSTRUMENTED, "no memory_key"); + PSI_server->memory_free(0, 0, NULL); + PSI_server->unlock_table(NULL); + metadata_lock= PSI_server->create_metadata_lock(NULL, NULL, 1, 2, 3, NULL, 0); + ok(metadata_lock == NULL, "no metadata_lock"); + PSI_server->set_metadata_lock_status(NULL, 0); + PSI_server->destroy_metadata_lock(NULL); + metadata_locker= PSI_server->start_metadata_wait(NULL, NULL, NULL, 0); + ok(metadata_locker == NULL, "no metadata_locker"); + PSI_server->end_metadata_wait(NULL, 0); + + transaction_locker= PSI_server->get_thread_transaction_locker(NULL, NULL, 0, 1, false, 1); + ok(transaction_locker == NULL, "no transaction_locker"); + PSI_server->start_transaction(NULL, NULL, 0); + PSI_server->end_transaction(NULL, true); + + PSI_server->set_transaction_gtid(NULL, NULL, NULL); + PSI_server->set_transaction_trxid(NULL, NULL); + PSI_server->set_transaction_xa_state(NULL, 1); + PSI_server->set_transaction_xid(NULL, NULL, 1); + PSI_server->inc_transaction_release_savepoint(NULL, 1); + PSI_server->inc_transaction_rollback_to_savepoint(NULL, 1); + PSI_server->inc_transaction_savepoints(NULL, 1); + + PSI_server->set_thread_THD(NULL, NULL); + + PSI_server->set_thread_peer_port(NULL, 0); + + ok(true, "all noop api called"); +} + +int main(int, char **) +{ + plan(34); + + MY_INIT("pfs_noop-t"); + test_noop(); + return (exit_status()); +} + diff --git a/storage/perfschema/unittest/pfs_server_stubs.cc b/storage/perfschema/unittest/pfs_server_stubs.cc new file mode 100644 index 00000000..1ec84c25 --- /dev/null +++ b/storage/perfschema/unittest/pfs_server_stubs.cc @@ -0,0 +1,63 @@ +/* Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights + reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +/* + Minimal code to be able to link a unit test. +*/ + +#include "my_global.h" +#include "m_ctype.h" +#include "sql_class.h" +#include "sql_show.h" + +struct system_status_var global_status_var; +struct sql_digest_storage; + +uint lower_case_table_names= 0; +CHARSET_INFO *files_charset_info= NULL; +CHARSET_INFO *system_charset_info= NULL; + +void compute_digest_md5(const sql_digest_storage *, unsigned char *) +{ +} + +void reset_status_vars() +{ +} + +void sql_print_warning(const char *format, ...) +{ + /* Do not pollute the unit test output with annoying messages. */ +} + +class sys_var { public: enum where { AUTO }; }; +void set_sys_var_value_origin(void *, enum sys_var::where, const char *) +{ +} + +enum sys_var::where get_sys_var_value_origin(void *ptr) +{ + return sys_var::AUTO; +} + +MY_TIMER_INFO sys_timer_info; diff --git a/storage/perfschema/unittest/pfs_timer-t.cc b/storage/perfschema/unittest/pfs_timer-t.cc new file mode 100644 index 00000000..20a5cb97 --- /dev/null +++ b/storage/perfschema/unittest/pfs_timer-t.cc @@ -0,0 +1,128 @@ +/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_pthread.h> +#include <pfs_timer.h> +#include "my_sys.h" +#include <tap.h> + +void test_timers() +{ + ulonglong t1_a; + ulonglong t2_a; + ulonglong t3_a; + ulonglong t4_a; + ulonglong t5_a; + ulonglong t1_b; + ulonglong t2_b; + ulonglong t3_b; + ulonglong t4_b; + ulonglong t5_b; + + my_timer_init(&sys_timer_info); + + init_timers(); + + t1_a= get_timer_pico_value(TIMER_NAME_CYCLE); + /* Wait 5 seconds */ + my_sleep(5000000); + t1_b= get_timer_pico_value(TIMER_NAME_CYCLE); + + t2_a= get_timer_pico_value(TIMER_NAME_NANOSEC); + my_sleep(5000000); + t2_b= get_timer_pico_value(TIMER_NAME_NANOSEC); + + t3_a= get_timer_pico_value(TIMER_NAME_MICROSEC); + my_sleep(5000000); + t3_b= get_timer_pico_value(TIMER_NAME_MICROSEC); + + t4_a= get_timer_pico_value(TIMER_NAME_MILLISEC); + my_sleep(5000000); + t4_b= get_timer_pico_value(TIMER_NAME_MILLISEC); + + t5_a= get_timer_pico_value(TIMER_NAME_TICK); + my_sleep(5000000); + t5_b= get_timer_pico_value(TIMER_NAME_TICK); + + /* + Print the timer values, for manual inspection by a human. + Tests involving low level timers can not be automated. + */ + diag("cycle a: %13llu", t1_a); + diag("nano a: %13llu", t2_a); + diag("micro a: %13llu", t3_a); + diag("milli a: %13llu", t4_a); + diag("tick a: %13llu", t5_a); + + diag("cycle b: %13llu", t1_b); + diag("nano b: %13llu", t2_b); + diag("micro b: %13llu", t3_b); + diag("milli b: %13llu", t4_b); + diag("tick b: %13llu", t5_b); + + diag("cycle b-a: %13llu", t1_b-t1_a); + diag("nano b-a: %13llu", t2_b-t2_a); + diag("micro b-a: %13llu", t3_b-t3_a); + diag("milli b-a: %13llu", t4_b-t4_a); + diag("tick b-a: %13llu", t5_b-t5_a); + + if ((t1_a == 0) && (t1_b == 0)) + skip(1, "cycle timer not implemented"); + else + ok(t1_b > t1_a, "cycle timer ascending"); + + if ((t2_a == 0) && (t2_b == 0)) + skip(1, "nano timer not implemented"); + else + ok(t2_b > t2_a, "nano timer ascending"); + + if ((t3_a == 0) && (t3_b == 0)) + skip(1, "micro timer not implemented"); + else + ok(t3_b > t3_a, "micro timer ascending"); + + if ((t4_a == 0) && (t4_b == 0)) + skip(1, "milli timer not implemented"); + else + ok(t4_b > t4_a, "milli timer ascending"); + + if ((t5_a == 0) && (t5_b == 0)) + skip(1, "tick timer not implemented"); + else + ok(t5_b > t5_a, "tick timer ascending"); +} + +void do_all_tests() +{ + test_timers(); +} + +int main(int, char **) +{ + plan(5); + MY_INIT("pfs_timer-t"); + do_all_tests(); + my_end(0); + return (exit_status()); +} + diff --git a/storage/perfschema/unittest/pfs_user-oom-t.cc b/storage/perfschema/unittest/pfs_user-oom-t.cc new file mode 100644 index 00000000..acc3d8c6 --- /dev/null +++ b/storage/perfschema/unittest/pfs_user-oom-t.cc @@ -0,0 +1,146 @@ +/* Copyright (c) 2011, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_instr.h> +#include <pfs_stat.h> +#include <pfs_global.h> +#include <pfs_user.h> +#include <pfs_buffer_container.h> +#include <tap.h> + +#include "stub_pfs_global.h" +#include "stub_global_status_var.h" + +#include <string.h> /* memset */ + +void test_oom() +{ + PSI *psi; + PFS_global_param param; + PSI_bootstrap *boot; + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 1000; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; + param.m_events_waits_history_sizing= 10; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 1000; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 50; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 50; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; + param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 10; + param.m_metadata_lock_sizing= 0; + param.m_max_digest_length= 0; + param.m_max_sql_text_length= 0; + + /* Setup */ + + stub_alloc_always_fails= false; + stub_alloc_fails_after_count= 1000; + + pre_initialize_performance_schema(); + boot= initialize_performance_schema(¶m); + psi= (PSI *)boot->get_interface(PSI_VERSION_1); + + PSI_thread_key thread_key_1; + PSI_thread_info all_thread[]= + { + {&thread_key_1, "T-1", 0} + }; + psi->register_thread("test", all_thread, 1); + + PSI_thread *thread_1= psi->new_thread(thread_key_1, NULL, 0); + psi->set_thread(thread_1); + + /* Tests */ + + int first_fail= 1; + stub_alloc_fails_after_count= first_fail; + psi->set_thread_account("user1", 5, "", 0); + ok(global_user_container.m_lost == 1, "oom (user)"); + + stub_alloc_fails_after_count= first_fail + 1; + psi->set_thread_account("user2", 5, "", 0); + ok(global_user_container.m_lost == 2, "oom (user waits)"); + + stub_alloc_fails_after_count= first_fail + 2; + psi->set_thread_account("user3", 5, "", 0); + ok(global_user_container.m_lost == 3, "oom (user stages)"); + + stub_alloc_fails_after_count= first_fail + 3; + psi->set_thread_account("user4", 5, "", 0); + ok(global_user_container.m_lost == 4, "oom (user statements)"); + + stub_alloc_fails_after_count= first_fail + 4; + psi->set_thread_account("user5", 5, "", 0); + ok(global_user_container.m_lost == 5, "oom (user transactions)"); + + stub_alloc_fails_after_count= first_fail + 5; + psi->set_thread_account("user6", 5, "", 0); + ok(global_user_container.m_lost == 6, "oom (user memory)"); + + shutdown_performance_schema(); +} + +void do_all_tests() +{ + test_oom(); +} + +int main(int, char **) +{ + plan(6); + MY_INIT("pfs_user-oom-t"); + do_all_tests(); + my_end(0); + return (exit_status()); +} + diff --git a/storage/perfschema/unittest/stub_global_status_var.h b/storage/perfschema/unittest/stub_global_status_var.h new file mode 100644 index 00000000..70644981 --- /dev/null +++ b/storage/perfschema/unittest/stub_global_status_var.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2015, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_sys.h> +#include <pfs_global.h> +#include <string.h> + + +void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var) +{ +} diff --git a/storage/perfschema/unittest/stub_pfs_defaults.h b/storage/perfschema/unittest/stub_pfs_defaults.h new file mode 100644 index 00000000..4b064b57 --- /dev/null +++ b/storage/perfschema/unittest/stub_pfs_defaults.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2010, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <pfs.h> +#include <pfs_defaults.h> + +void install_default_setup(PSI_bootstrap *) +{ +} + diff --git a/storage/perfschema/unittest/stub_pfs_global.h b/storage/perfschema/unittest/stub_pfs_global.h new file mode 100644 index 00000000..4b792f9b --- /dev/null +++ b/storage/perfschema/unittest/stub_pfs_global.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. + Copyright (c) 2022, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_sys.h> +#include <pfs_global.h> +#include <string.h> +#include "aligned.h" +#include "assume_aligned.h" + +bool pfs_initialized= false; +size_t pfs_allocated_memory_size= 0; +size_t pfs_allocated_memory_count= 0; + +bool stub_alloc_always_fails= true; +int stub_alloc_fails_after_count= 0; + +void *pfs_malloc(PFS_builtin_memory_class *klass, size_t size, myf) +{ + /* + Catch non initialized sizing parameter in the unit tests. + */ + assert(size <= 100*1024*1024); + + if (stub_alloc_always_fails) + return NULL; + + if (--stub_alloc_fails_after_count <= 0) + return NULL; + + size= MY_ALIGN(size, CPU_LEVEL1_DCACHE_LINESIZE); + void *ptr= aligned_malloc(size, CPU_LEVEL1_DCACHE_LINESIZE); + if (ptr != NULL) + memset_aligned<CPU_LEVEL1_DCACHE_LINESIZE>(ptr, 0, size); + return ptr; +} + +void pfs_free(PFS_builtin_memory_class *, size_t, void *ptr) +{ + if (ptr != NULL) + free(ptr); +} + +void *pfs_malloc_array(PFS_builtin_memory_class *klass, size_t n, size_t size, myf flags) +{ + size_t array_size= n * size; + /* Check for overflow before allocating. */ + if (is_overflow(array_size, n, size)) + return NULL; + return pfs_malloc(klass, array_size, flags); +} + +void pfs_free_array(PFS_builtin_memory_class *klass, size_t n, size_t size, void *ptr) +{ + if (ptr == NULL) + return; + size_t array_size= n * size; + return pfs_free(klass, array_size, ptr); +} + +bool is_overflow(size_t product, size_t n1, size_t n2) +{ + if (n1 != 0 && (product / n1 != n2)) + return true; + else + return false; +} + +void pfs_print_error(const char *format, ...) +{ +} + + diff --git a/storage/perfschema/unittest/stub_print_error.h b/storage/perfschema/unittest/stub_print_error.h new file mode 100644 index 00000000..a02e2478 --- /dev/null +++ b/storage/perfschema/unittest/stub_print_error.h @@ -0,0 +1,72 @@ +/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_sys.h> +#include <pfs_global.h> + +bool pfs_initialized= false; + +void *pfs_malloc(PFS_builtin_memory_class *klass, size_t size, myf flags) +{ + void *ptr= malloc(size); + if (ptr && (flags & MY_ZEROFILL)) + memset(ptr, 0, size); + return ptr; +} + +void pfs_free(PFS_builtin_memory_class *, size_t, void *ptr) +{ + if (ptr != NULL) + free(ptr); +} + +void *pfs_malloc_array(PFS_builtin_memory_class *klass, size_t n, size_t size, myf flags) +{ + size_t array_size= n * size; + /* Check for overflow before allocating. */ + if (is_overflow(array_size, n, size)) + return NULL; + return pfs_malloc(klass, array_size, flags); +} + +void pfs_free_array(PFS_builtin_memory_class *klass, size_t n, size_t size, void *ptr) +{ + if (ptr == NULL) + return; + size_t array_size= n * size; + return pfs_free(klass, array_size, ptr); +} + +bool is_overflow(size_t product, size_t n1, size_t n2) +{ + if (n1 != 0 && (product / n1 != n2)) + return true; + else + return false; +} + +void pfs_print_error(const char *format, ...) +{ + /* Do not pollute the unit test output with annoying messages. */ +} + |