Class SlowQueryReportJmx
- All Implemented Interfaces:
InvocationHandler, NotificationBroadcaster, NotificationEmitter, SlowQueryReportJmxMBean
The MBean and the notification broadcaster are published for the pool name: the first interceptor instance to borrow a connection registers them, and every other instance sharing the name - the other connections of that pool, the second interceptor of the recommended two-thresholds configuration, or a second pool configured with the same name - reports through them. They stay published until the last live pool registered under the name closes; closing one of several same-named pools leaves the registration with the survivors. A pool that starts under the name after that last close has decided its release - racing it - adopts the registration still published under the name, and the pending release notices the takeover and leaves the registration with the new pool.
A JMX client's listener subscription belongs to the registration it was added through. JMX cannot carry a subscription across an unregistration, so after the last pool of a name has closed, a client must attach its listeners again to receive notifications from a pool started under that name anew.
-
Nested Class Summary
Nested classes/interfaces inherited from class SlowQueryReport
SlowQueryReport.PoolStatistics, SlowQueryReport.QueryStats, SlowQueryReport.QueryStatsComparatorModifier and TypeClassDescriptionprotected static classThe query statistics published under one pool name, together with the live pools registered for that name.static classHolds timing and invocation statistics for a single SQL query.static classCompares QueryStats by their lastInvocation value.Nested classes/interfaces inherited from class AbstractQueryReport
AbstractQueryReport.StatementProxyModifier and TypeClassDescriptionprotected classClass to measure query execute time -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringNotification type for failed query events.protected static final ConcurrentHashMap<String, SlowQueryReportJmxMBean> Registry of JMX MBeans for each connection pool.protected NotificationBroadcasterSupportNotification broadcaster used before the pool name is known; once the pool name is known,getNotifier()returns the broadcaster shared by all interceptor instances of that pool.protected static final ConcurrentHashMap<String, NotificationBroadcasterSupport> Notification broadcasters for each connection pool.protected booleanWhether to send notifications to the pool.protected static final AtomicLongAtomic sequence counter for notifications.static final StringProperty key for overriding the JMX object name.protected ConnectionPoolThe connection pool reference.protected StringThe name of the connection pool.protected ObjectNameThe ObjectName this instance published itself under.protected static final ConcurrentHashMap<String, ObjectName> Registry of the first registration failure seen for each pool name, holding the ObjectName that failed.static final StringNotification type for slow query events.protected static CompositeTypeComposite type used for JMX query statistics data.Fields inherited from class SlowQueryReport
lastPoolOfNameClosed, logFailed, logSlow, maxQueries, perPoolStats, queries, queryStatsComparatorModifier and TypeFieldDescriptionprotected booleanWhether theSlowQueryReport.poolClosed(ConnectionPool)delivered to this instance deregistered the closing pool as the last live pool under its name, meaning everything else registered for that name - the interceptor's MBean and broadcaster, for instance - can and must now be released with it.protected booleanFlag to enable disable logging of failed queriesprotected booleanFlag to enable disable logging of slow queriesprotected intMaximum number of queries we will be storing statistics for.protected static final ConcurrentHashMap<String, SlowQueryReport.PoolStatistics> we will be keeping track of query stats on a per pool basis, keyed by pool name; pools registered under one name share the statisticsprotected ConcurrentHashMap<String, SlowQueryReport.QueryStats> the queries that are used for this interceptor.protected final Comparator<SlowQueryReport.QueryStats> Sort QueryStats by last invocation timeFields inherited from class AbstractQueryReport
thresholdFields inherited from class AbstractCreateStatementInterceptor
constructors, CREATE_STATEMENT, CREATE_STATEMENT_IDX, EXECUTE, EXECUTE_BATCH, EXECUTE_LARGE_BATCH, EXECUTE_LARGE_UPDATE, EXECUTE_QUERY, EXECUTE_TYPES, EXECUTE_UPDATE, GET_GENERATED_KEYS, GET_RESULTSET, GET_STATEMENT, PREPARE_CALL, PREPARE_CALL_IDX, PREPARE_STATEMENT, PREPARE_STATEMENT_IDX, RESULTSET_IDX, STATEMENT_TYPE_COUNT, STATEMENT_TYPESModifier and TypeFieldDescriptionprotected static final Constructor<?>[]the constructors that are used to create statement proxies.protected static final Stringprotected static final intprotected static final Stringprotected static final Stringprotected static final Stringprotected static final StringStatement.executeLargeUpdate(String)and its overloads, andPreparedStatement.executeLargeUpdate()protected static final Stringprotected static final String[]Array of execute type method namesprotected static final Stringprotected static final Stringprotected static final Stringprotected static final Stringprotected static final Stringprotected static final intprotected static final Stringprotected static final intprotected static final intprotected static final intCount of statement types inAbstractCreateStatementInterceptor.STATEMENT_TYPESprotected static final String[]Array of statement type method namesFields inherited from class JdbcInterceptor
ABORT_VAL, CLOSE_VAL, EQUALS_VAL, GETCONNECTION_VAL, HASHCODE_VAL, ISCLOSED_VAL, ISVALID_VAL, ISWRAPPERFOR_VAL, properties, TOSTRING_VAL, UNWRAP_VALModifier and TypeFieldDescriptionstatic final StringConnection.abort(java.util.concurrent.Executor)method namestatic final StringConnection.close()method namestatic final Stringstatic final StringPooledConnection.getConnection()method namestatic final Stringstatic final StringConnection.isClosed()method namestatic final StringConnection.isValid(int)method namestatic final StringWrapper.isWrapperFor(Class)method nameprotected Map<String, PoolProperties.InterceptorProperty> Properties for this interceptor.static final StringObject.toString()method namestatic final StringWrapper.unwrap(Class)method name -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidaddNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) Adds a notification listener.protected voidReleases the MBean registration and the shared broadcaster held for the current pool name - even when the pool name is still owned by live pools.protected static CompositeTypeReturns the composite type used for JMX query statistics.Returns information about the notifications this MBean can send.protected ObjectReturns the source this MBean's notifications are sent with.protected NotificationBroadcasterSupportReturns the notification broadcaster that all interceptor instances of the current pool share, so that notifications raised on any connection reach the listeners registered with the pool's MBean.getObjectName(Class<?> clazz, String poolName) Returns the JMX ObjectName for the given class and pool name.JMX operation - return the name of the poolString[]JMX operation - return the names of all the poolsJMX operation - returns all the queries we have collected.booleanReturns whether notifications are sent to the pool.protected voidSends a JMX notification for the given query and notification type.voidpoolClosed(ConnectionPool pool) Called when the connection pool is closed; releases the JMX registration of the pool's name - the MBean and the broadcaster its clients' listeners are attached to - only once that pool was the last live pool registered under the name.voidpoolStarted(ConnectionPool pool) Called when the connection pool is started.protected voidRegisters this interceptor with JMX.protected ObjectNameregistrationObjectName(SlowQueryReportJmxMBean registered) Returns the ObjectName the given registry registration published itself under, as the registry owner recorded it whenregisterJmx()took the slot.protected voidreleaseJmxRegistration(ConnectionPool releasedPool) Completes the release of the current pool name whose statistics the given pool has just freed: drops the MBean registration with the name's broadcaster and registration-failure marker throughderegisterJmx()- unless a live pool is registered under the name again that does not include the releasing one.voidRemoves a notification listener.voidremoveNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) Removes a notification listener with the given filter and handback.protected StringreportFailedQuery(String query, Object[] args, String name, long start, long delta, Throwable t) Reports a failed query and sends a JMX notification if logging is enabled.protected StringreportSlowQuery(String query, Object[] args, String name, long start, long delta) Reports a slow query and sends a JMX notification if logging is enabled.voidreset(ConnectionPool parent, PooledConnection con) Resets this interceptor for a new connection, registering JMX if applicable.voidJMX operation - remove all stats for this connection pool.voidsetNotifyPool(boolean notifyPool) Sets whether notifications are sent to the pool.voidsetProperties(Map<String, PoolProperties.InterceptorProperty> properties) Sets the interceptor properties, including the notifyPool flag.Methods inherited from class SlowQueryReport
closeInvoked, getPoolStats, getQueryStats, isLogFailed, isLogSlow, prepareCall, prepareStatement, releaseStatistics, removeOldest, reportQuery, setLogFailed, setLogSlow, setMaxQueriesModifier and TypeMethodDescriptionvoidinvoked when the connection receives the close request Not used for now.getPoolStats(String poolname) Returns the query stats for a given poolprotected SlowQueryReport.QueryStatsgetQueryStats(String sql) Retrieves or creates a QueryStats entry for the given SQL string.booleanReturns whether failed query logging is enabled.booleanReturns whether slow query logging is enabled.voidprepareCall(String sql, long time) Tracks the preparation time for a callable statement.voidprepareStatement(String sql, long time) Tracks the preparation time for a prepared statement.protected static booleanDeregisters a closed pool from the live pools that the per-name statistics are held for, and releases the statistics once no live pool is registered under the name any more.protected voidEvicts the least recently invoked query statistics until the map is back withinmaxQueriesentries.protected StringreportQuery(String query, Object[] args, String name, long start, long delta) Invoked when a query execution, a call to an execute method as recognised byAbstractCreateStatementInterceptor.isExecute(Method, boolean), succeeded and was within the timing thresholdvoidsetLogFailed(boolean logFailed) Enables or disables failed query logging.voidsetLogSlow(boolean logSlow) Enables or disables slow query logging.voidsetMaxQueries(int maxQueries) Sets the maximum number of queries to track statistics for.Methods inherited from class AbstractQueryReport
createStatement, getThreshold, setThresholdModifier and TypeMethodDescriptioncreateStatement(Object proxy, Method method, Object[] args, Object statement, long time) Creates a statement interceptor to monitor query response timeslongreturns the query measure threshold.voidsetThreshold(long threshold) Sets the query measurement threshold.Methods inherited from class AbstractCreateStatementInterceptor
getConstructor, invoke, isExecute, isStatement, processModifier and TypeMethodDescriptionprotected Constructor<?> getConstructor(int idx, Class<?> clazz) Creates a constructor for a proxy class, if one doesn't already exist.Gets invoked each time an operation onConnectionis invoked.protected booleanReturns true if the method that is being invoked matches one of the execute types.protected booleanisStatement(Method method, boolean process) Returns true if the method that is being invoked matches one of the statement types.protected booleanReturns true if the method that is being invoked matches one of the method names passed inMethods inherited from class JdbcInterceptor
compare, compare, disconnected, getNext, getProperties, isUseEquals, setNext, setUseEqualsModifier and TypeMethodDescriptionbooleanCompares a method name (String) to a method (Method)JdbcInterceptor.compare(String,String)Uses reference comparison unless the useEquals property is set to truebooleanPerforms a string comparison, using references unless the useEquals property is set to true.voiddisconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) Called whenConnection.close()is called on the underlying connection.getNext()Returns the next interceptor in the chainReturns the properties configured for this interceptorbooleanTrue if the compare method uses the Object.equals(Object) method, false if comparison is done on a reference level.voidsetNext(JdbcInterceptor next) configures the next interceptor in the chainvoidsetUseEquals(boolean useEquals) Set to true if string comparisons (for theJdbcInterceptor.compare(String, Method)andJdbcInterceptor.compare(String, String)methods) should use the Object.equals(Object) method The default is false
-
Field Details
-
SLOW_QUERY_NOTIFICATION
Notification type for slow query events.- See Also:
-
FAILED_QUERY_NOTIFICATION
Notification type for failed query events.- See Also:
-
objectNameAttribute
Property key for overriding the JMX object name.- See Also:
-
SLOW_QUERY_TYPE
Composite type used for JMX query statistics data. -
mbeans
Registry of JMX MBeans for each connection pool. -
notifiers
Notification broadcasters for each connection pool. Interceptor instances are created per pooled connection, but JMX clients attach their listeners to the single MBean registered per pool, so notifications raised by any instance of a pool must reach the broadcaster of the pool rather than a broadcaster private to the instance. -
registrationFailuresLogged
Registry of the first registration failure seen for each pool name, holding the ObjectName that failed. Registration is retried by every borrow of such a pool, but only the first failure of a name is logged with its exception, so a persistent refusal - a foreign MBean holding the name, a security restriction - is not reported with a stack trace once per borrow. The marker is dropped when a registration under the name succeeds and when the name's release runs throughderegisterJmx(), so a later failure cycle is reported loudly once again. -
registeredUnder
The ObjectName this instance published itself under.registerJmx()records it on the instance that took the registry slot, before the publish, and clears it again when the MBeanServer refused the MBean. The release inderegisterJmx()unregisters exactly the name recorded on the registration the registry held, whatever class andobjectNameproperty the releasing instance carries - a closing pool delivers a freshly instantiated interceptor whose definitions need not match those of the pool that registered. -
notifier
Notification broadcaster used before the pool name is known; once the pool name is known,getNotifier()returns the broadcaster shared by all interceptor instances of that pool. -
poolName
The name of the connection pool. -
notifySequence
Atomic sequence counter for notifications. -
notifyPool
protected boolean notifyPoolWhether to send notifications to the pool. -
pool
The connection pool reference.
-
-
Constructor Details
-
SlowQueryReportJmx
public SlowQueryReportJmx()Creates a new SlowQueryReportJmx instance.
-
-
Method Details
-
getNotifier
Returns the notification broadcaster that all interceptor instances of the current pool share, so that notifications raised on any connection reach the listeners registered with the pool's MBean.- Returns:
- the shared broadcaster for this interceptor's pool
-
addNotificationListener
public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException Adds a notification listener.- Specified by:
addNotificationListenerin interfaceNotificationBroadcaster- Parameters:
listener- the listener to addfilter- the notification filterhandback- the handback object- Throws:
IllegalArgumentException- if the listener is null
-
getNotificationInfo
Returns information about the notifications this MBean can send.- Specified by:
getNotificationInfoin interfaceNotificationBroadcaster- Returns:
- an array of MBeanNotificationInfo objects
-
removeNotificationListener
public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException Removes a notification listener.- Specified by:
removeNotificationListenerin interfaceNotificationBroadcaster- Parameters:
listener- the listener to remove- Throws:
ListenerNotFoundException- if the listener was not previously added
-
removeNotificationListener
public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException Removes a notification listener with the given filter and handback.- Specified by:
removeNotificationListenerin interfaceNotificationEmitter- Parameters:
listener- the listener to removefilter- the notification filterhandback- the handback object- Throws:
ListenerNotFoundException- if the listener was not previously added
-
getCompositeType
Returns the composite type used for JMX query statistics.- Returns:
- the composite type, or
nullif initialization failed
-
reset
Resets this interceptor for a new connection, registering JMX if applicable.- Overrides:
resetin classSlowQueryReport- Parameters:
parent- the connection poolcon- the pooled connection
-
poolClosed
Called when the connection pool is closed; releases the JMX registration of the pool's name - the MBean and the broadcaster its clients' listeners are attached to - only once that pool was the last live pool registered under the name. Both belong to the name and are shared by every live pool of that name, so taking them down while a survivor is still running would orphan the survivor's monitoring; releasing them on every close but a decided last one would unregister a shared registration that other closing or live pools still rely on. Whether this close is the last one is decided atomically bySlowQueryReport.releaseStatistics(ConnectionPool)on the way throughsuper.poolClosed, so concurrent closes of same-named pools cannot all see a survivor and leave the name registered for ever.The decision and the release are separate steps, and a pool that starts under the name between them has taken the name - and the registration still published under it - back;
releaseJmxRegistration(ConnectionPool)therefore re-verifies the name before anything is taken down.- Overrides:
poolClosedin classSlowQueryReport- Parameters:
pool- the connection pool being closed
-
releaseJmxRegistration
Completes the release of the current pool name whose statistics the given pool has just freed: drops the MBean registration with the name's broadcaster and registration-failure marker throughderegisterJmx()- unless a live pool is registered under the name again that does not include the releasing one. A pool that started under the name after the release was decided has taken the name over, adopting the registration still published under it, and it - not this close - owns the name's JMX state from then on; the last live pool of the name is the one to release it.The statistics are read the plain way here, without a lock, deliberately: a check computed inside a
ConcurrentHashMap.computeon the name would be atomic against a start but would also make that start wait behind the release, and a release must never block a pool that is coming up. Without the lock the check cannot see a start that begins after it has read - thederegisterJmx()that follows then still takes down only the registration the registry held at its own read, never a fresher one, and only the name's broadcaster and failure marker can be hit early by a start landing inside that window; seederegisterJmx(). The one case the value guard does not spare is a start whose fresh registration lands in the slot between the read here and the read inderegisterJmx(): that release takes down the value it read, leaving the newcomer to republish on its next borrow - a window narrower than the one that existed before this guard, measured in the gap between two map reads. The guard likewise proceeds when the statistics still hold the very pool that is closing, which only happens when the same pool instance is restarted while this close is still in flight; the restarted generation then republishes its registration on its first borrow, like any pool whose registration was released.- Parameters:
releasedPool- the pool whose statistics release decided this release of the name
-
poolStarted
Called when the connection pool is started.- Overrides:
poolStartedin classSlowQueryReport- Parameters:
pool- the connection pool being started
-
reportFailedQuery
protected String reportFailedQuery(String query, Object[] args, String name, long start, long delta, Throwable t) Reports a failed query and sends a JMX notification if logging is enabled.- Overrides:
reportFailedQueryin classSlowQueryReport- Parameters:
query- the SQL queryargs- the query argumentsname- the name of the method used to executestart- the wall clock time the query execution starteddelta- the time the execution took before it failed, measured with the monotonic clockt- the throwable that caused the failure- Returns:
- the formatted query string
-
notifyJmx
-
getNotificationSource
Returns the source this MBean's notifications are sent with.Notificationmarshals its source, so a listener outside this JVM - one reached through a JMX connector, or one that hands the notification on to another process - only receives the notification at all if the source is serializable. This MBean is not, and neither is the pool it reports on, so the source is theObjectNamethe MBean is registered under, which names the pool and is serializable. Interceptor instances are created per pooled connection and only one of them is the registered MBean's resource, so an instance cannot name itself: every instance of a pool name sends the very name its registration was published under. An instance whose name cannot be formed - a malformedobjectNameproperty or a pool name that cannot be quoted into an ObjectName - was never registered at all, so no listener reached through a connector can exist for it; the source is then a string of the default name's shape, which still names the pool for the local listeners the broadcaster serves.- Returns:
- the ObjectName the registration of this interceptor's pool name is published under, or, when that name cannot be formed, a string of the default name's shape
-
reportSlowQuery
Reports a slow query and sends a JMX notification if logging is enabled.- Overrides:
reportSlowQueryin classSlowQueryReport- Parameters:
query- the SQL queryargs- the query argumentsname- the connection pool namestart- the start time in millisecondsdelta- the elapsed time in milliseconds- Returns:
- the formatted query string
-
getPoolNames
JMX operation - return the names of all the pools- Specified by:
getPoolNamesin interfaceSlowQueryReportJmxMBean- Returns:
- - all the names of pools that we have stored data for, which is a view of the JVM-wide statistics registry rather than of this pool alone
-
getPoolName
JMX operation - return the name of the pool- Specified by:
getPoolNamein interfaceSlowQueryReportJmxMBean- Returns:
- the name of the pool, unique within the JVM, or
nullbefore this instance is bound to a pool
-
isNotifyPool
public boolean isNotifyPool()Returns whether notifications are sent to the pool.- Returns:
- true if notifications are sent to the pool
-
setNotifyPool
public void setNotifyPool(boolean notifyPool) Sets whether notifications are sent to the pool. Configuration entry point only, applied to every interceptor instance of a pool bysetPropertieswhile its connection chain is built: it is not part of the JMX management interface, because writing it through the registered MBean would reach only the one instance that owns the registration and leave the pool's other connections routing as before. SeeSlowQueryReportJmxMBean.- Parameters:
notifyPool- true if notifications should be sent to the pool
-
resetStats
public void resetStats()JMX operation - remove all stats for this connection pool. The statistics are keyed by pool name and shared by every live pool configured with that name, so clearing them through one pool's MBean clears them for all of those pools. Only the recorded content goes: the statistics map stays registered with the name - every live instance holds that very map and keeps accumulating into it.- Specified by:
resetStatsin interfaceSlowQueryReportJmxMBean
-
getSlowQueriesCD
JMX operation - returns all the queries we have collected.- Specified by:
getSlowQueriesCDin interfaceSlowQueryReportJmxMBean- Returns:
- - the slow query report as composite data; an empty array when the pool name holds no statistics map - none was ever registered under it, or the last live pool of the name has closed and freed it
- Throws:
OpenDataException- if the composite data cannot be created; a JMX client gets it wrapped in anMBeanException
-
deregisterJmx
protected void deregisterJmx()Releases the MBean registration and the shared broadcaster held for the current pool name - even when the pool name is still owned by live pools. Normal pool shutdown releases throughsuper.poolClosedplusSlowQueryReport.lastPoolOfNameClosedinpoolClosed(ConnectionPool), which keeps the registration for any surviving same-named pool and skips the release when a new pool has taken the name back (releaseJmxRegistration(ConnectionPool)).The registry slot is dropped only while it still holds the registration the registry was read at: a registration a pool installing itself behind this release puts into the slot belongs to that pool and keeps its MBean published. The unregistration uses the ObjectName that registration recorded when it was published, so it never depends on the class or the
objectNameproperty of the instance running this release - which a closing pool delivers freshly, and which need not share either with the registration it releases.The broadcaster and the registration-failure marker belong to the name as much as the MBean does, so the release drops them even when this pool never held the registry slot: a pool whose every registration attempt was refused still reported through the broadcaster, and its throttle marker must not outlive the name and hush the first failure of a later failure cycle under the name. Both entries are created lazily - by
getNotifier()and by listeners a client adds through interceptor handles it still holds - so a client subscribing to the released name concurrently with this release can have its late subscription re-insert an entry nothing registered under the name uses any more; a fresh registration under the name re-uses or replaces it. -
registrationObjectName
protected ObjectName registrationObjectName(SlowQueryReportJmxMBean registered) throws MalformedObjectNameException Returns the ObjectName the given registry registration published itself under, as the registry owner recorded it whenregisterJmx()took the slot. Unregistering this - rather than a name recomputed from the class and properties of the instance running the release - is what keeps the unregistration on the name the MBean actually occupies: two pools configured with one name may carry interceptor definitions that compute different ObjectNames, and the release run by one of them must not give up on the name the other one's registration was published under and leave it registered for ever.- Parameters:
registered- the registry value this release took out of the registry- Returns:
- the ObjectName to unregister
- Throws:
MalformedObjectNameException- if a fallback ObjectName cannot be formed
-
getObjectName
public ObjectName getObjectName(Class<?> clazz, String poolName) throws MalformedObjectNameException Returns the JMX ObjectName for the given class and pool name.- Parameters:
clazz- the interceptor classpoolName- the name of the connection pool- Returns:
- the JMX ObjectName
- Throws:
MalformedObjectNameException- if the object name is malformed
-
registerJmx
protected void registerJmx()Registers this interceptor with JMX.The registration is attempted under the protection of the per-name registry slot: the slot is taken with
putIfAbsentso only one instance per pool name registers, and it is released again when the MBeanServer refuses the MBean. A failed publish must not keep the slot, because the slot is the only registration gate: every later borrow would find it occupied and skip the registration, so the pool would claim an MBean for its whole life that was never published - and would not re-register even after whatever made the MBeanServer refuse it is gone. Releasing the slot lets a later borrow retry;JmxUtil.registerJmxcannot be used for the attempt because it swallows every exception and returns a name whatever happened, so the failure of its own call is unobservable to the caller. Only the first refusal of a name is logged with its exception, so a persistent refusal is not reported once per borrow. -
setProperties
Sets the interceptor properties, including the notifyPool flag.- Overrides:
setPropertiesin classSlowQueryReport- Parameters:
properties- the interceptor properties
-