/* Copyright (c) 2008, 2010, 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 as published by the Free Software Foundation; version 2 of the License. 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 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 */ #ifndef PFS_INSTR_H #define PFS_INSTR_H /** @file storage/perfschema/pfs_instr.h Performance schema instruments (declarations). */ #include "pfs_lock.h" #include "pfs_instr_class.h" #include "pfs_events_waits.h" #include "pfs_server.h" #include "lf.h" /** @addtogroup Performance_schema_buffers @{ */ struct PFS_thread; struct PFS_instr { /** Internal lock. */ pfs_lock m_lock; /** Instrument wait statistics chain. */ PFS_single_stat_chain m_wait_stat; }; /** Instrumented mutex implementation. @see PSI_mutex. */ struct PFS_mutex : public PFS_instr { /** Mutex identity, typically a pthread_mutex_t. */ const void *m_identity; /** Mutex class. */ PFS_mutex_class *m_class; /** Mutex lock usage statistics chain. This statistic is not exposed in user visible tables yet. */ PFS_single_stat_chain m_lock_stat; /** Current owner. */ PFS_thread *m_owner; /** Timestamp of the last lock. This statistic is not exposed in user visible tables yet. */ ulonglong m_last_locked; }; /** Instrumented rwlock implementation. @see PSI_rwlock. */ struct PFS_rwlock : public PFS_instr { /** RWLock identity, typically a pthread_rwlock_t. */ const void *m_identity; /** RWLock class. */ PFS_rwlock_class *m_class; /** RWLock read lock usage statistics chain. This statistic is not exposed in user visible tables yet. */ PFS_single_stat_chain m_read_lock_stat; /** RWLock write lock usage statistics chain. This statistic is not exposed in user visible tables yet. */ PFS_single_stat_chain m_write_lock_stat; /** Current writer thread. */ PFS_thread *m_writer; /** Current count of readers. */ uint m_readers; /** Timestamp of the last write. This statistic is not exposed in user visible tables yet. */ ulonglong m_last_written; /** Timestamp of the last read. This statistic is not exposed in user visible tables yet. */ ulonglong m_last_read; }; /** Instrumented cond implementation. @see PSI_cond. */ struct PFS_cond : public PFS_instr { /** Condition identity, typically a pthread_cond_t. */ const void *m_identity; /** Condition class. */ PFS_cond_class *m_class; /** Condition instance usage statistics. */ PFS_cond_stat m_cond_stat; }; /** Instrumented File and FILE implementation. @see PSI_file. */ struct PFS_file : public PFS_instr { /** File name. */ char m_filename[FN_REFLEN]; /** File name length in bytes. */ uint m_filename_length; /** File class. */ PFS_file_class *m_class; /** File usage statistics. */ PFS_file_stat m_file_stat; }; /** Instrumented table implementation. @see PSI_table. */ struct PFS_table : public PFS_instr { /** Table share. */ PFS_table_share *m_share; /** Table identity, typically a handler. */ const void *m_identity; }; /** @def LOCKER_STACK_SIZE Maximum number of nested waits. */ #define LOCKER_STACK_SIZE 3 /** @def PFS_MAX_ALLOC_RETRY Maximum number of times the code attempts to allocate an item from internal buffers, before giving up. */ #define PFS_MAX_ALLOC_RETRY 1000 #define PFS_MAX_SCAN_PASS 2 /** Helper to scan circular buffers. Given a buffer of size [0, max_size - 1], and a random starting point in the buffer, this helper returns up to two [first, last -1] intervals that: - fit into the [0, max_size - 1] range, - have a maximum combined length of at most PFS_MAX_ALLOC_RETRY. */ struct PFS_scan { public: void init(uint random, uint max_size); bool has_pass() const { return (m_pass < m_pass_max); } void next_pass() { m_pass++; } uint first() const { return m_first[m_pass]; } uint last() const { return m_last[m_pass]; } private: uint m_pass; uint m_pass_max; uint m_first[PFS_MAX_SCAN_PASS]; uint m_last[PFS_MAX_SCAN_PASS]; }; /** Instrumented thread implementation. @see PSI_thread. */ struct PFS_thread { /** Internal lock. */ pfs_lock m_lock; /** Pins for filename_hash. */ LF_PINS *m_filename_hash_pins; /** Pins for table_share_hash. */ LF_PINS *m_table_share_hash_pins; /** Event ID counter */ ulonglong m_event_id; /** Thread instrumentation flag. */ bool m_enabled; /** Internal thread identifier, unique. */ ulong m_thread_internal_id; /** External (SHOW PROCESSLIST) thread identifier, not unique. */ ulong m_thread_id; /** Thread class. */ PFS_thread_class *m_class; /** Size of @c m_wait_locker_stack. */ uint m_wait_locker_count; /** Stack of wait lockers. This member holds the data for the table PERFORMANCE_SCHEMA.EVENTS_WAITS_CURRENT. For most locks, only 1 wait locker is used at a given time. For composite locks, several records are needed: - 1 for a 'logical' wait (for example on the GLOBAL READ LOCK state) - 1 for a 'physical' wait (for example on COND_refresh) */ PFS_wait_locker m_wait_locker_stack[LOCKER_STACK_SIZE]; /** True if the circular buffer @c m_waits_history is full. */ bool m_waits_history_full; /** Current index in the circular buffer @c m_waits_history. */ uint m_waits_history_index; /** Waits history circular buffer. This member holds the data for the table PERFORMANCE_SCHEMA.EVENTS_WAITS_HISTORY. */ PFS_events_waits *m_waits_history; /** Per thread waits aggregated statistics. This member holds the data for the table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. */ PFS_single_stat_chain *m_instr_class_wait_stats; }; PFS_thread *sanitize_thread(PFS_thread *unsafe); PFS_single_stat_chain* find_per_thread_mutex_class_wait_stat(PFS_thread *thread, PFS_mutex_class *klass); PFS_single_stat_chain* find_per_thread_rwlock_class_wait_stat(PFS_thread *thread, PFS_rwlock_class *klass); PFS_single_stat_chain* find_per_thread_cond_class_wait_stat(PFS_thread *thread, PFS_cond_class *klass); PFS_single_stat_chain* find_per_thread_file_class_wait_stat(PFS_thread *thread, PFS_file_class *klass); int init_instruments(const PFS_global_param *param); void cleanup_instruments(); int init_file_hash(); void cleanup_file_hash(); PFS_mutex* create_mutex(PFS_mutex_class *mutex_class, const void *identity); void destroy_mutex(PFS_mutex *pfs); PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity); void destroy_rwlock(PFS_rwlock *pfs); PFS_cond* create_cond(PFS_cond_class *klass, const void *identity); void destroy_cond(PFS_cond *pfs); PFS_thread* create_thread(PFS_thread_class *klass, const void *identity, ulong thread_id); void destroy_thread(PFS_thread *pfs); PFS_file* find_or_create_file(PFS_thread *thread, PFS_file_class *klass, const char *filename, uint len); void release_file(PFS_file *pfs); void destroy_file(PFS_thread *thread, PFS_file *pfs); PFS_table* create_table(PFS_table_share *share, const void *identity); void destroy_table(PFS_table *pfs); /* For iterators and show status. */ extern ulong mutex_max; extern ulong mutex_lost; extern ulong rwlock_max; extern ulong rwlock_lost; extern ulong cond_max; extern ulong cond_lost; extern ulong thread_max; extern ulong thread_lost; extern ulong file_max; extern ulong file_lost; extern long file_handle_max; extern ulong file_handle_lost; extern ulong table_max; extern ulong table_lost; extern ulong events_waits_history_per_thread; extern ulong instr_class_per_thread; extern ulong locker_lost; /* Exposing the data directly, for iterators. */ extern PFS_mutex *mutex_array; extern PFS_rwlock *rwlock_array; extern PFS_cond *cond_array; extern PFS_thread *thread_array; extern PFS_file *file_array; extern PFS_file **file_handle_array; extern PFS_table *table_array; void reset_events_waits_by_instance(); void reset_per_thread_wait_stat(); void reset_file_instance_io(); /** @} */ #endif