diff options
Diffstat (limited to 'storage/perfschema/unittest/pfs-t.cc')
-rw-r--r-- | storage/perfschema/unittest/pfs-t.cc | 1909 |
1 files changed, 1909 insertions, 0 deletions
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()); +} |