summaryrefslogtreecommitdiffstats
path: root/storage/perfschema/unittest
diff options
context:
space:
mode:
Diffstat (limited to 'storage/perfschema/unittest')
-rw-r--r--storage/perfschema/unittest/CMakeLists.txt40
-rw-r--r--storage/perfschema/unittest/conf.txt427
-rw-r--r--storage/perfschema/unittest/pfs-t.cc1909
-rw-r--r--storage/perfschema/unittest/pfs_account-oom-t.cc174
-rw-r--r--storage/perfschema/unittest/pfs_connect_attr-t.cc352
-rw-r--r--storage/perfschema/unittest/pfs_host-oom-t.cc148
-rw-r--r--storage/perfschema/unittest/pfs_instr-oom-t.cc459
-rw-r--r--storage/perfschema/unittest/pfs_instr-t.cc488
-rw-r--r--storage/perfschema/unittest/pfs_instr_class-oom-t.cc114
-rw-r--r--storage/perfschema/unittest/pfs_instr_class-t.cc750
-rw-r--r--storage/perfschema/unittest/pfs_misc-t.cc95
-rw-r--r--storage/perfschema/unittest/pfs_noop-t.cc245
-rw-r--r--storage/perfschema/unittest/pfs_server_stubs.cc63
-rw-r--r--storage/perfschema/unittest/pfs_timer-t.cc128
-rw-r--r--storage/perfschema/unittest/pfs_user-oom-t.cc146
-rw-r--r--storage/perfschema/unittest/stub_global_status_var.h31
-rw-r--r--storage/perfschema/unittest/stub_pfs_defaults.h30
-rw-r--r--storage/perfschema/unittest/stub_pfs_global.h93
-rw-r--r--storage/perfschema/unittest/stub_print_error.h72
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(&param, 0, sizeof(param));
+ initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ param.m_mutex_class_sizing= 10;
+ initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ param.m_stage_class_sizing= 10;
+ initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ param.m_statement_class_sizing= 10;
+ initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ param.m_memory_class_sizing= 10;
+ initialize_performance_schema_helper(&param);
+ 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(&param);
+ 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(&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;
+
+ /* 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(&param);
+ 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(&param);
+ 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(&param);
+ fake_thread.m_filename_hash_pins= NULL;
+ init_file_hash(&param);
+
+ 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(&param);
+ 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(&param);
+ 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(&param);
+ 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(&param, 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(&param);
+ 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(&param, 0, sizeof(param));
+ param.m_enabled= true;
+ param.m_events_waits_history_sizing= 10;
+ psi= initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ param.m_stage_class_sizing= 50;
+ psi= initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ param.m_events_stages_history_sizing= 10;
+ psi= initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ param.m_stage_class_sizing= 50;
+ psi= initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ param.m_events_statements_history_sizing= 10;
+ psi= initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ psi= initialize_performance_schema_helper(&param);
+ 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(&param, 0, sizeof(param));
+ param.m_events_transactions_history_sizing= 10;
+ psi= initialize_performance_schema_helper(&param);
+ 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(&param, 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(&param);
+ 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(&param, 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(&param);
+ rc= init_statement_class(param.m_statement_class_sizing);
+ ok(rc == 0, "init statement class");
+ rc= init_instruments(&param);
+ ok(rc == 1, "oom (global statements)");
+
+ cleanup_statement_class();
+ cleanup_instruments();
+
+ /* Global memory. */
+ memset(&param, 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(&param);
+ 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(&param, 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(&param);
+ init_setup_object_hash(&param);
+
+ 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(&param, 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(&param);
+ 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(&param);
+ 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. */
+}
+