/* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.resourcemonitor; import java.util.ArrayList; import java.util.StringTokenizer; import netscape.ldap.LDAPAttribute; import netscape.ldap.LDAPConnection; import netscape.ldap.LDAPEntry; import netscape.ldap.LDAPException; import netscape.ldap.LDAPSearchResults; import com.slamd.common.Constants; import com.slamd.common.SLAMDException; import com.slamd.stat.IntegerValueTracker; import com.slamd.stat.StatTracker; /** * This class defines a SLAMD resource monitor that has the ability to * communicate with an instance of the Sun ONE Directory Server and periodically * capture monitor information from it. In particular, it will retrieve the * "cn=monitor" entry and parse its contents, and it may also parse the * "cn=monitor,cn={dbname},cn=ldbm database,cn=plugins,cn=config" entries to * retrieve database-specific information. * * * @author Neil A. Wilson */ public class SunONEDirectoryServerResourceMonitor extends ResourceMonitor { /** * The display name for the stat tracker that monitors the number of * connections currently established to the directory server. */ public static final String STAT_TRACKER_CURRENT_CONNECTIONS = "Current Connections"; /** * The name of the configuration property that indicates whether to capture * information about the number of connections currently established to the * directory server. */ public static final String PROPERTY_CAPTURE_CURRENT_CONNECTIONS = "capture_current_connections"; /** * The flag that indicates whether the number of current connections will be * captured by default. */ public static final boolean DEFAULT_CAPTURE_CURRENT_CONNECTIONS = true; /** * The display name for the stat tracker that monitors the number of requests * requests that have been received but not yet completed. */ public static final String STAT_TRACKER_REQUESTS_IN_PROGRESS = "Requests In Progress"; /** * The name of the configuration property that indicates whether to capture * information about the number of requests in progress. */ public static final String PROPERTY_CAPTURE_REQUESTS_IN_PROGRESS = "capture_requests_in_progress"; /** * The flag that indicates whether the number of requests in progress will be * captured by default. */ public static final boolean DEFAULT_CAPTURE_REQUESTS_IN_PROGRESS = true; /** * The display name for the stat tracker that monitors the total number of * requests that have been fully processed by the server. */ public static final String STAT_TRACKER_REQUESTS_COMPLETED = "Requests Completed"; /** * The name of the configuration property that indicates whether to capture * information about the number of requests that have been completed. */ public static final String PROPERTY_CAPTURE_REQUESTS_COMPLETED = "capture_requests_completed"; /** * The flag that indicates whether the number of completed requests will be * captured by default. */ public static final boolean DEFAULT_CAPTURE_REQUESTS_COMPLETED = true; /** * The display name for the stat tracker that monitors the number of * records in the backend database. */ public static final String STAT_TRACKER_DB_ENTRY_COUNT = "Total Database Records"; /** * The name of the configuration property that indicates whether to capture * information about the number of records in the backend database. */ public static final String PROPERTY_CAPTURE_DB_ENTRY_COUNT = "capture_db_entry_count"; /** * The flag that indicates whether the number of records in the database will * be captured by default. */ public static final boolean DEFAULT_CAPTURE_DB_ENTRY_COUNT = true; /** * The display name for the stat tracker that monitors the number of * entries in the backend database. */ public static final String STAT_TRACKER_LDAP_ENTRY_COUNT = "Total LDAP Entries"; /** * The name of the configuration property that indicates whether to capture * information about the number of entries in the backend database. */ public static final String PROPERTY_CAPTURE_LDAP_ENTRY_COUNT = "capture_ldap_entry_count"; /** * The flag that indicates whether the number of entries in the database will * be captured by default. */ public static final boolean DEFAULT_CAPTURE_LDAP_ENTRY_COUNT = true; /** * The display name for the stat tracker that monitors the current entry cache * size. */ public static final String STAT_TRACKER_ENTRY_CACHE_SIZE = "Entry Cache Size (MB)"; /** * The name of the configuration property that indicates whether to capture * information about the size of the entry cache. */ public static final String PROPERTY_CAPTURE_ENTRY_CACHE_SIZE = "capture_entry_cache_size"; /** * The flag that indicates whether the entry cache size will be captured by * default. */ public static final boolean DEFAULT_CAPTURE_ENTRY_CACHE_SIZE = true; /** * The display name for the stat tracker that monitors the number of entries * currently in the entry cache. */ public static final String STAT_TRACKER_ENTRY_CACHE_COUNT = "Entry Cache Count"; /** * The name of the configuration property that indicates whether to capture * information about the number of entries in the entry cache. */ public static final String PROPERTY_CAPTURE_ENTRY_CACHE_COUNT = "capture_entry_cache_count"; /** * The flag that indicates whether the number of entries in the entry cache * will be captured by default. */ public static final boolean DEFAULT_CAPTURE_ENTRY_CACHE_COUNT = true; /** * The display name for the stat tracker that monitors the percent full for * the entry cache. */ public static final String STAT_TRACKER_ENTRY_CACHE_PCT_FULL = "Entry Cache Percent Full"; /** * The name of the configuration property that indicates whether to capture * information about the entry cache percent full. */ public static final String PROPERTY_CAPTURE_ENTRY_CACHE_PCT_FULL = "capture_entry_cache_percent_full"; /** * The flag that indicates whether the entry cache percent full will be * captured by default. */ public static final boolean DEFAULT_CAPTURE_ENTRY_CACHE_PCT_FULL = true; /** * The display name for the stat tracker that monitors the percent of the * total entries that are cached. */ public static final String STAT_TRACKER_ENTRY_CACHE_PCT_CACHED = "Percent of Entries Cached"; /** * The name of the configuration property that indicates whether to capture * information about the entry cache percent of entries cached. */ public static final String PROPERTY_CAPTURE_ENTRY_CACHE_PCT_CACHED = "capture_entry_cache_percent_entries_cached"; /** * The flag that indicates whether the entry cache percent of entries cached * will be captured by default. */ public static final boolean DEFAULT_CAPTURE_ENTRY_CACHE_PCT_CACHED = true; /** * The display name for the stat tracker that monitors the current entry cache * hit ratio. */ public static final String STAT_TRACKER_ENTRY_CACHE_HIT_RATIO = "Entry Cache Hit Ratio"; /** * The name of the configuration property that indicates whether to capture * information about the entry cache hit ratio. */ public static final String PROPERTY_CAPTURE_ENTRY_CACHE_HIT_RATIO = "capture_entry_cache_hit_ratio"; /** * The flag that indicates whether the entry cache hit ratio will be captured * by default. */ public static final boolean DEFAULT_CAPTURE_ENTRY_CACHE_HIT_RATIO = true; /** * The name of the configuration parameter that specifies which backend(s) to * monitor for statistics. */ public static final String PROPERTY_MONITOR_DBS = "monitor_dbs"; /** * The name of the configuration property that specifies the address of the * directory server. */ public static final String PROPERTY_DS_HOST = "ds_address"; /** * The default address to use for the directory server. */ public static final String DEFAULT_DS_HOST = "127.0.0.1"; /** * The name of the configuration property that specifies the port of the * directory server. */ public static final String PROPERTY_DS_PORT = "ds_port"; /** * The default port to use for the directory server. */ public static final int DEFAULT_DS_PORT = 389; /** * The name of the configuration property that specifies the DN to use when * binding to the server. */ public static final String PROPERTY_DS_BIND_DN = "ds_bind_dn"; /** * The default DN to use when binding to the directory server. */ public static final String DEFAULT_DS_BIND_DN = ""; /** * The name of the configuration property that specifies the password to use * when binding to the server. */ public static final String PROPERTY_DS_BIND_PW = "ds_bind_pw"; /** * The default password to use when binding to the directory server. */ public static final String DEFAULT_DS_BIND_PW = ""; /** * The name of the LDAP attribute that specifies the total number of * connections currently established to the server. */ public static final String ATTR_CURRENT_CONNECTIONS = "currentConnections"; /** * The name of the LDAP attribute that specifies the total number of * operations that have been requested of the server. */ public static final String ATTR_OPS_INITIATED = "opsInitiated"; /** * The name of the LDAP attribute that specifies the total number of * operations that have been processed by the server. */ public static final String ATTR_OPS_COMPLETED = "opsCompleted"; /** * The name of the LDAP attribute that specifies the DNs of the entries * serving as monitors for the backend databases. */ public static final String ATTR_BACKEND_MONITOR_DN = "backendMonitorDN"; /** * The name of the LDAP attribute that specifies the total number of keys * in the backend database. */ public static final String ATTR_DB_ENTRY_COUNT = "dbEntryCount"; /** * The name of the LDAP attribute that specifies the number of entries in the * backend database. */ public static final String ATTR_LDAP_ENTRY_COUNT = "ldapEntryCount"; /** * The name of the LDAP attribute that specifies the current size of the entry * cache in bytes. */ public static final String ATTR_CURRENT_EC_SIZE = "currentEntryCacheSize"; /** * The name of the LDAP attribute that specifies the total number of entries * currently in the entry cache. */ public static final String ATTR_CURRENT_EC_ENTRIES = "currentEntryCacheCount"; /** * The name of the LDAP attribute that specifies the maximum entry cache size * in bytes. */ public static final String ATTR_MAX_EC_SIZE = "maxEntryCacheSize"; /** * The name of the LDAP attribute that specifies the entry cache hit ratio. */ public static final String ATTR_EC_HIT_RATIO = "entryCacheHitRatio"; /** * The names of the attributes that should be retrieved when reading the * primary monitor entry. */ public static final String[] MONITOR_ATTRS = { ATTR_CURRENT_CONNECTIONS, ATTR_OPS_INITIATED, ATTR_OPS_COMPLETED, ATTR_BACKEND_MONITOR_DN }; /** * The names of the attributes that should be retrieved when reading a * database monitor entry. */ public static final String[] DB_MONITOR_ATTRS = { ATTR_DB_ENTRY_COUNT, ATTR_LDAP_ENTRY_COUNT, ATTR_CURRENT_EC_SIZE, ATTR_MAX_EC_SIZE, ATTR_CURRENT_EC_ENTRIES, ATTR_EC_HIT_RATIO }; // The data collected by this resource monitor. private ArrayList<Integer> connList; private ArrayList<Integer> opsCompletedList; private ArrayList<Integer> opsInitiatedList; private ArrayList<Integer>[] dbCountList; private ArrayList<Integer>[] entryCountList; private ArrayList<Integer>[] cacheEntriesList; private ArrayList<Integer>[] cachePercentFullList; private ArrayList<Integer>[] cachePercentEntriesList; private ArrayList<Integer>[] cacheHitRatioList; private ArrayList<Long>[] cacheSizeList; // The arrays of the DNs of backend monitors and their database names. private String[] backendMonitorDNs; private String[] backendDBNames; // The maximum entry cache size for each database. private long[] maxEntryCacheSizes; // The information to use to connect to the directory server. private int dsPort; private String dsHost; private String bindDN; private String bindPW; // The information we will use to create the stat trackers later. private int collectionInterval; private String clientID; private String threadID; // Information about which statistics we want to capture. private boolean captureBackendStats; private boolean captureCurrentConnections; private boolean captureRequestsInProgress; private boolean captureRequestsCompleted; private boolean captureDBEntryCount; private boolean captureLDAPEntryCount; private boolean captureEntryCacheSize; private boolean captureEntryCacheCount; private boolean captureEntryCachePercentFull; private boolean captureEntryCachePercentEntries; private boolean captureEntryCacheHitRatio; // A flag that indicates whether the monitor information was retrieved during // initialization, and a variable used to hold the reason for the failure if // it was not successful. private boolean monitorRetrievedInInit; private String failureReason; /** * Performs any initialization specific to this resource monitor. * * @throws SLAMDException If a problem occurs while performing the * initialization. */ @Override() public void initializeMonitor() throws SLAMDException { captureCurrentConnections = getProperty(PROPERTY_CAPTURE_CURRENT_CONNECTIONS, DEFAULT_CAPTURE_CURRENT_CONNECTIONS); captureRequestsInProgress = getProperty(PROPERTY_CAPTURE_REQUESTS_IN_PROGRESS, DEFAULT_CAPTURE_REQUESTS_IN_PROGRESS); captureRequestsCompleted = getProperty(PROPERTY_CAPTURE_REQUESTS_COMPLETED, DEFAULT_CAPTURE_REQUESTS_COMPLETED); captureDBEntryCount = getProperty(PROPERTY_CAPTURE_DB_ENTRY_COUNT, DEFAULT_CAPTURE_DB_ENTRY_COUNT); captureLDAPEntryCount = getProperty(PROPERTY_CAPTURE_LDAP_ENTRY_COUNT, DEFAULT_CAPTURE_LDAP_ENTRY_COUNT); captureEntryCacheSize = getProperty(PROPERTY_CAPTURE_ENTRY_CACHE_SIZE, DEFAULT_CAPTURE_ENTRY_CACHE_SIZE); captureEntryCacheCount = getProperty(PROPERTY_CAPTURE_ENTRY_CACHE_COUNT, DEFAULT_CAPTURE_ENTRY_CACHE_COUNT); captureEntryCachePercentFull = getProperty(PROPERTY_CAPTURE_ENTRY_CACHE_PCT_FULL, DEFAULT_CAPTURE_ENTRY_CACHE_PCT_FULL); captureEntryCachePercentEntries = getProperty(PROPERTY_CAPTURE_ENTRY_CACHE_PCT_CACHED, DEFAULT_CAPTURE_ENTRY_CACHE_PCT_CACHED); captureEntryCacheHitRatio = getProperty(PROPERTY_CAPTURE_ENTRY_CACHE_HIT_RATIO, DEFAULT_CAPTURE_ENTRY_CACHE_HIT_RATIO); String monitorDBStr = getProperty(PROPERTY_MONITOR_DBS); if ((monitorDBStr == null) || (monitorDBStr.length() == 0)) { backendMonitorDNs = null; backendDBNames = null; maxEntryCacheSizes = null; } else { ArrayList<String> nameList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(monitorDBStr, ","); while (tokenizer.hasMoreTokens()) { nameList.add(tokenizer.nextToken().trim()); } backendDBNames = new String[nameList.size()]; nameList.toArray(backendDBNames); backendMonitorDNs = new String[backendDBNames.length]; maxEntryCacheSizes = new long[backendDBNames.length]; } dsHost = getProperty(PROPERTY_DS_HOST, DEFAULT_DS_HOST); dsPort = getProperty(PROPERTY_DS_PORT, DEFAULT_DS_PORT); bindDN = getProperty(PROPERTY_DS_BIND_DN, DEFAULT_DS_BIND_DN); bindPW = getProperty(PROPERTY_DS_BIND_PW, DEFAULT_DS_BIND_PW); // Make sure that we can actually read the cn=monitor entry boolean connFailure = false; failureReason = null; monitorRetrievedInInit = false; LDAPConnection conn = new LDAPConnection(); try { conn.connect(3, dsHost, dsPort, bindDN, bindPW); } catch (LDAPException le) { connFailure = true; failureReason = "Unable to establish an LDAP connection to " + dsHost + ':' + dsPort + " -- " + le.getLDAPResultCode() + " (" + le.getLDAPErrorMessage() + ')'; } if (! connFailure) { LDAPSearchResults results = null; try { results = conn.search("cn=monitor", LDAPConnection.SCOPE_BASE, "(objectClass=*)", MONITOR_ATTRS, false); } catch (LDAPException le) { try { conn.disconnect(); } catch (Exception e) {} connFailure = true; failureReason = "Unable to search the directory " + dsHost + ':' + dsPort + " for the cn=monitor entry: " + le.getLDAPResultCode() + '(' + le.getLDAPErrorMessage() + ')'; } LDAPEntry monitorEntry = null; while ((! connFailure) && results.hasMoreElements()) { Object element = results.nextElement(); if (element instanceof LDAPEntry) { monitorEntry = (LDAPEntry) element; } } if ((! connFailure) && (monitorEntry == null)) { connFailure = true; failureReason = "Could not read cn=monitor entry from " + dsHost + ':' + dsPort + " -- no entries returned from search"; } // If a set of DB names was specified, then make sure we can read the // monitor entries for each. If no names were specified, then use the // values of the backendMonitorDN attribute. if ((! connFailure) && ((backendDBNames == null) || (backendDBNames.length == 0))) { ArrayList<String> dnList = new ArrayList<String>(); ArrayList<String> nameList = new ArrayList<String>(); ArrayList<Long> maxSizeList = new ArrayList<Long>(); LDAPAttribute attr = monitorEntry.getAttribute(ATTR_BACKEND_MONITOR_DN); String[] values = null; if ((attr == null) || ((values = attr.getStringValueArray()) == null) || (values.length == 0)) { writeVerbose("No backends found -- will not monitor backend " + "information"); captureDBEntryCount = false; captureLDAPEntryCount = false; captureEntryCacheHitRatio = false; captureEntryCacheCount = false; captureEntryCacheSize = false; captureEntryCachePercentFull = false; captureEntryCachePercentEntries = false; } else { for (int i=0; i < values.length; i++) { String dn = values[i]; try { results = conn.search(dn, LDAPConnection.SCOPE_BASE, "(objectClass=*)", DB_MONITOR_ATTRS, false); LDAPEntry dbEntry = null; while (results.hasMoreElements()) { Object element = results.nextElement(); if (element instanceof LDAPEntry) { dbEntry = (LDAPEntry) element; } } if (dbEntry == null) { writeVerbose("Unable to read backend monitor " + dn); continue; } LDAPAttribute maxSizeAttr = dbEntry.getAttribute(ATTR_MAX_EC_SIZE); String[] sizeValues = null; if ((maxSizeAttr != null) && ((sizeValues = maxSizeAttr.getStringValueArray()) != null) && (sizeValues.length > 0)) { maxSizeList.add(new Long(sizeValues[0])); } } catch (Exception e) { writeVerbose("Exception reading backend monitor " + dn + " -- " + e); continue; } dnList.add(dn); int commaPos = dn.indexOf(','); int equalPos = dn.indexOf('=', commaPos+1); commaPos = dn.indexOf(',', equalPos+1); nameList.add(dn.substring(equalPos+1, commaPos)); } } backendDBNames = new String[nameList.size()]; backendMonitorDNs = new String[dnList.size()]; nameList.toArray(backendDBNames); dnList.toArray(backendMonitorDNs); maxEntryCacheSizes = new long[maxSizeList.size()]; for (int i=0; i < maxEntryCacheSizes.length; i++) { maxEntryCacheSizes[i] = maxSizeList.get(i); } } else if (! connFailure) { for (int i=0; i < backendDBNames.length; i++) { String dn = "cn=monitor,cn=" + backendDBNames[i] + ",cn=ldbm database,cn=plugins,cn=config"; try { results = conn.search(dn, LDAPConnection.SCOPE_BASE, "(objectClass=*)", DB_MONITOR_ATTRS, false); LDAPEntry backendMonitorEntry = null; while (results.hasMoreElements()) { Object element = results.nextElement(); if (element instanceof LDAPEntry) { backendMonitorEntry = (LDAPEntry) element; } } if (backendMonitorEntry == null) { connFailure = true; failureReason = "Unable to read monitor entry " + dn + " from " + dsHost + ':' + dsPort + " -- no entries returned from search."; } if (! connFailure) { LDAPAttribute maxSizeAttr = backendMonitorEntry.getAttribute(ATTR_MAX_EC_SIZE); String[] values = null; if ((maxSizeAttr == null) || ((values = maxSizeAttr.getStringValueArray()) == null) || (values.length == 0)) { connFailure = true; failureReason = "Unable to read data from backend monitor " + "entry " + dn + " from " + dsHost + ':' + dsPort; } if (! connFailure) { maxEntryCacheSizes[i] = Long.parseLong(values[0]); backendMonitorDNs[i] = dn; } } } catch (LDAPException le) { connFailure = true; failureReason = "Unable to search the directory " + dsHost + ':' + dsPort + " for the " + dn + " entry: " + le.getLDAPResultCode() + '(' + le.getLDAPErrorMessage() + ')'; } } } try { conn.disconnect(); } catch (Exception e) {} } if (! connFailure) { captureBackendStats = (((! connFailure) && (backendMonitorDNs.length > 0)) && (captureDBEntryCount || captureLDAPEntryCount || captureEntryCacheCount || captureEntryCacheHitRatio || captureEntryCachePercentFull || captureEntryCachePercentEntries || captureEntryCacheSize)); monitorRetrievedInInit = (! connFailure); opsCompletedList = new ArrayList<Integer>(); connList = new ArrayList<Integer>(); opsInitiatedList = new ArrayList<Integer>(); initializeListArrays(); } } /** * Initializses arrays of lists. Suppress warnings since an array cannot be * created with a type. */ @SuppressWarnings("unchecked") private void initializeListArrays() { dbCountList = new ArrayList[backendMonitorDNs.length]; entryCountList = new ArrayList[backendMonitorDNs.length]; cacheSizeList = new ArrayList[backendMonitorDNs.length]; cacheEntriesList = new ArrayList[backendMonitorDNs.length]; cachePercentFullList = new ArrayList[backendMonitorDNs.length]; cachePercentEntriesList = new ArrayList[backendMonitorDNs.length]; cacheHitRatioList = new ArrayList[backendMonitorDNs.length]; for (int i=0; i < backendMonitorDNs.length; i++) { dbCountList[i] = new ArrayList<Integer>(); entryCountList[i] = new ArrayList<Integer>(); cacheSizeList[i] = new ArrayList<Long>(); cacheEntriesList[i] = new ArrayList<Integer>(); cachePercentFullList[i] = new ArrayList<Integer>(); cachePercentEntriesList[i] = new ArrayList<Integer>(); cacheHitRatioList[i] = new ArrayList<Integer>(); } } /** * Indicates whether the current client system is supported for this resource * monitor. * * @return <CODE>true</CODE> if the current client system is supported for * this resource monitor, or <CODE>false</CODE> if not. */ @Override() public boolean clientSupported() { return true; } /** * Creates a new instance of this resource monitor thread. Note that the * <CODE>initialize()</CODE> method should have been called on the new * instance before it is returned. * * @return A new instance of this resource monitor thread. * * @throws SLAMDException If a problem occurs while creating or initializing * the resource monitor. */ @Override() public ResourceMonitor newInstance() throws SLAMDException { SunONEDirectoryServerResourceMonitor monitor = new SunONEDirectoryServerResourceMonitor(); monitor.initialize(getMonitorClient(), getMonitorProperties()); return monitor; } /** * Initializes the stat trackers maintained by this resource monitor. * * @param clientID The client ID to use for the stubs. * @param threadID The thread ID to use for the stubs. * @param collectionInterval The collection interval to use for the stubs. */ @Override() public void initializeStatistics(String clientID, String threadID, int collectionInterval) { // Capture the information now so that we can use it later. this.clientID = clientID; this.threadID = threadID; this.collectionInterval = collectionInterval; } /** * Retrieves the name to use for this resource monitor. * * @return The name to use for this resource monitor. */ @Override() public String getMonitorName() { return "Sun ONE Directory Monitor"; } /** * Retrieves the statistical data collected by this resource monitor. * * @return The statistical data collected by this resource monitor. */ @Override() public StatTracker[] getResourceStatistics() { if (! monitorRetrievedInInit) { return new StatTracker[0]; } ArrayList<StatTracker> trackerList = new ArrayList<StatTracker>(); String prefix = "ldap://" + dsHost + ':' + dsPort + "/ "; if (captureCurrentConnections) { int[] connArray = new int[connList.size()]; int[] countArray = new int[connList.size()]; for (int i=0; i < connArray.length; i++) { connArray[i] = connList.get(i); countArray[i] = 1; } IntegerValueTracker tracker = new IntegerValueTracker(clientID, threadID, prefix + STAT_TRACKER_CURRENT_CONNECTIONS, collectionInterval); tracker.setIntervalData(connArray, countArray); trackerList.add(tracker); } if (captureRequestsInProgress || captureRequestsCompleted) { int[] inProgressArray = new int[opsInitiatedList.size()]; int[] opsCompletedArray = new int[opsCompletedList.size()]; int[] countArray = new int[opsInitiatedList.size()]; for (int i=0; i < inProgressArray.length; i++) { int opsInitiated = opsInitiatedList.get(i); int opsCompleted = opsCompletedList.get(i); opsCompletedArray[i] = opsCompleted; inProgressArray[i] = opsInitiated - opsCompleted; countArray[i] = 1; } if (captureRequestsInProgress) { IntegerValueTracker tracker = new IntegerValueTracker(clientID, threadID, prefix + STAT_TRACKER_REQUESTS_IN_PROGRESS, collectionInterval); tracker.setIntervalData(inProgressArray, countArray); trackerList.add(tracker); } if (captureRequestsCompleted) { IntegerValueTracker tracker = new IntegerValueTracker(clientID, threadID, prefix + STAT_TRACKER_REQUESTS_COMPLETED, collectionInterval); tracker.setIntervalData(opsCompletedArray, countArray); trackerList.add(tracker); } } if (captureBackendStats) { for (int i=0; i < backendDBNames.length; i++) { prefix = "ldap://" + dsHost + ':' + dsPort + "/ " + backendDBNames[i] + ' '; if (captureDBEntryCount) { int[] dbCountArray = new int[dbCountList[i].size()]; int[] countArray = new int[dbCountList[i].size()]; for (int j=0; j < dbCountArray.length; j++) { dbCountArray[j] = dbCountList[i].get(j); countArray[j] = 1; } IntegerValueTracker tracker = new IntegerValueTracker(clientID, threadID, prefix + STAT_TRACKER_DB_ENTRY_COUNT, collectionInterval); tracker.setIntervalData(dbCountArray, countArray); trackerList.add(tracker); } if (captureLDAPEntryCount) { int[] entryCountArray = new int[entryCountList[i].size()]; int[] countArray = new int[entryCountList[i].size()]; for (int j=0; j < entryCountArray.length; j++) { entryCountArray[j] = entryCountList[i].get(j); countArray[j] = 1; } IntegerValueTracker tracker = new IntegerValueTracker(clientID, threadID, prefix + STAT_TRACKER_LDAP_ENTRY_COUNT, collectionInterval); tracker.setIntervalData(entryCountArray, countArray); trackerList.add(tracker); } if (captureEntryCacheCount) { int[] cacheCountArray = new int[cacheEntriesList[i].size()]; int[] countArray = new int[cacheEntriesList[i].size()]; for (int j=0; j < cacheCountArray.length; j++) { cacheCountArray[j] = cacheEntriesList[i].get(j); countArray[j] = 1; } IntegerValueTracker tracker = new IntegerValueTracker(clientID, threadID, prefix + STAT_TRACKER_ENTRY_CACHE_COUNT, collectionInterval); tracker.setIntervalData(cacheCountArray, countArray); trackerList.add(tracker); } if (captureEntryCachePercentEntries) { int[] cachePctArray = new int[entryCountList[i].size()]; int[] countArray = new int[entryCountList[i].size()]; for (int j=0; j < cachePctArray.length; j++) { int entryCount = entryCountList[i].get(j); int cacheCount = cacheEntriesList[i].get(j); cachePctArray[j] = (int) Math.round(1.0 * cacheCount * 100 / entryCount); countArray[j] = 1; } IntegerValueTracker tracker = new IntegerValueTracker(clientID, threadID, prefix + STAT_TRACKER_ENTRY_CACHE_PCT_CACHED, collectionInterval); tracker.setIntervalData(cachePctArray, countArray); trackerList.add(tracker); } if (captureEntryCacheSize || captureEntryCachePercentFull) { int[] sizeArray = new int[cacheSizeList[i].size()]; int[] pctFullArray = new int[cacheSizeList[i].size()]; int[] countArray = new int[cacheSizeList[i].size()]; for (int j=0; j < sizeArray.length; j++) { long size = cacheSizeList[i].get(j); sizeArray[j] = (int) Math.round(1.0 * size / 1024 / 1024); pctFullArray[j] = (int) Math.round(1.0 * size * 100 / maxEntryCacheSizes[i]); countArray[j] = 1; } if (captureEntryCacheSize) { IntegerValueTracker tracker = new IntegerValueTracker(clientID, threadID, prefix + STAT_TRACKER_ENTRY_CACHE_SIZE, collectionInterval); tracker.setIntervalData(sizeArray, countArray); trackerList.add(tracker); } if (captureEntryCachePercentFull) { IntegerValueTracker tracker = new IntegerValueTracker(clientID, threadID, prefix + STAT_TRACKER_ENTRY_CACHE_PCT_FULL, collectionInterval); tracker.setIntervalData(pctFullArray, countArray); trackerList.add(tracker); } } if (captureEntryCacheHitRatio) { int[] hitRatioArray = new int[cacheHitRatioList[i].size()]; int[] countArray = new int[cacheHitRatioList[i].size()]; for (int j=0; j < hitRatioArray.length; j++) { hitRatioArray[j] = cacheHitRatioList[i].get(j); countArray[j] = 1; } IntegerValueTracker tracker = new IntegerValueTracker(clientID, threadID, prefix + STAT_TRACKER_ENTRY_CACHE_HIT_RATIO, collectionInterval); tracker.setIntervalData(hitRatioArray, countArray); trackerList.add(tracker); } } } StatTracker[] returnTrackers = new StatTracker[trackerList.size()]; trackerList.toArray(returnTrackers); return returnTrackers; } /** * Performs the work of actually collecting resource statistics. This method * should periodically call the <CODE>shouldStop()</CODE> method to determine * whether to stop collecting statistics. * * @return A value that indicates the status of the monitor when it * completed. */ @Override() public int runMonitor() { if (! monitorRetrievedInInit) { if (failureReason == null) { logMessage("Unable to retrieve directory server monitor information " + "during initialization"); } else { logMessage("Unable to retrieve directory server monitor information " + "during initialization: " + failureReason); } return Constants.JOB_STATE_STOPPED_DUE_TO_ERROR; } LDAPConnection conn = new LDAPConnection(); try { conn.connect(3, dsHost, dsPort, bindDN, bindPW); } catch (LDAPException le) { logMessage("Unable to connect to directory server " + dsHost + ':' + dsPort + " -- " + le.getLDAPResultCode() + " (" + le.getLDAPErrorMessage() + ')'); return Constants.JOB_STATE_STOPPED_DUE_TO_ERROR; } while (! shouldStop()) { long nextStartTime = System.currentTimeMillis() + (1000 * collectionInterval); try { captureData(conn); } catch (LDAPException le) { try { conn.disconnect(); } catch (Exception e) {} logMessage("Exception encountered while trying to process monitor " + "data: " + le.getLDAPResultCode() + " (" + le.getLDAPErrorMessage() + ')'); return Constants.JOB_STATE_STOPPED_DUE_TO_ERROR; } long sleepTime = nextStartTime - System.currentTimeMillis(); if (sleepTime > 0) { try { Thread.sleep(sleepTime); } catch (InterruptedException ie) {} } } try { conn.disconnect(); } catch (Exception e) {} return Constants.JOB_STATE_COMPLETED_SUCCESSFULLY; } /** * Retrieves the monitor information and processes it as necessary. * * @param conn The connection to the directory server to use when reading * the information. * * @throws LDAPException If a problem occurs while interacting with the * directory server. */ private void captureData(LDAPConnection conn) throws LDAPException { LDAPEntry entry = conn.read("cn=monitor", MONITOR_ATTRS); if (entry == null) { throw new LDAPException("Unable to read monitor entry", LDAPException.NO_RESULTS_RETURNED, "Unable to read monitor entry"); } LDAPAttribute attr = null; String[] values = null; if (captureCurrentConnections) { attr = entry.getAttribute(ATTR_CURRENT_CONNECTIONS); if ((attr == null) || ((values = attr.getStringValueArray()) == null) || (values.length == 0)) { throw new LDAPException("Unable to read current connection count", LDAPException.NO_RESULTS_RETURNED, "Unable to read current connection count"); } try { connList.add(new Integer(values[0])); } catch (NumberFormatException nfe) { throw new LDAPException("Unable to parse current connection count", LDAPException.NO_RESULTS_RETURNED, "Unable to parse current connection count"); } } if (captureRequestsInProgress || captureRequestsCompleted) { Integer opsInitiated; attr = entry.getAttribute(ATTR_OPS_INITIATED); if ((attr == null) || ((values = attr.getStringValueArray()) == null) || (values.length == 0)) { throw new LDAPException("Unable to read opsInitiated", LDAPException.NO_RESULTS_RETURNED, "Unable to read opsInitiated"); } try { opsInitiated = new Integer(values[0]); } catch (NumberFormatException nfe) { throw new LDAPException("Unable to parse opsInitiated", LDAPException.NO_RESULTS_RETURNED, "Unable to parse opsInitiated"); } Integer opsCompleted; attr = entry.getAttribute(ATTR_OPS_COMPLETED); if ((attr == null) || ((values = attr.getStringValueArray()) == null) || (values.length == 0)) { throw new LDAPException("Unable to read opsCompleted", LDAPException.NO_RESULTS_RETURNED, "Unable to read opsCompleted"); } try { opsCompleted = new Integer(values[0]); } catch (NumberFormatException nfe) { throw new LDAPException("Unable to parse opsCompleted", LDAPException.NO_RESULTS_RETURNED, "Unable to parse opsCompleted"); } opsInitiatedList.add(opsInitiated); opsCompletedList.add(opsCompleted); } if (captureBackendStats) { for (int i=0; i < backendMonitorDNs.length; i++) { entry = conn.read(backendMonitorDNs[i], DB_MONITOR_ATTRS); if (entry == null) { throw new LDAPException("Unable to read backend monitor entry " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to read monitor entry " + backendMonitorDNs[i]); } if (captureDBEntryCount) { attr = entry.getAttribute(ATTR_DB_ENTRY_COUNT); if ((attr == null) || ((values = attr.getStringValueArray()) == null) || (values.length == 0)) { throw new LDAPException("Unable to read dbEntryCount from " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to read dbEntryCount from " + backendMonitorDNs[i]); } try { dbCountList[i].add(new Integer(values[0])); } catch (NumberFormatException nfe) { throw new LDAPException("Unable to parse dbEntryCount from " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to parse dbEntryCount from " + backendMonitorDNs[i]); } } if (captureLDAPEntryCount || captureEntryCachePercentEntries) { attr = entry.getAttribute(ATTR_LDAP_ENTRY_COUNT); if ((attr == null) || ((values = attr.getStringValueArray()) == null) || (values.length == 0)) { throw new LDAPException("Unable to read ldapEntryCount from " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to read ldapEntryCount from " + backendMonitorDNs[i]); } try { entryCountList[i].add(new Integer(values[0])); } catch (NumberFormatException nfe) { throw new LDAPException("Unable to parse ldapEntryCount from " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to parse ldapEntryCount from " + backendMonitorDNs[i]); } } if (captureEntryCacheCount || captureEntryCachePercentEntries) { attr = entry.getAttribute(ATTR_CURRENT_EC_ENTRIES); if ((attr == null) || ((values = attr.getStringValueArray()) == null) || (values.length == 0)) { throw new LDAPException("Unable to read currentEntryCacheCount " + "from " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to read currentEntryCacheCount " + "from " + backendMonitorDNs[i]); } try { cacheEntriesList[i].add(new Integer(values[0])); } catch (NumberFormatException nfe) { throw new LDAPException("Unable to parse currentEntryCacheCount " + "from " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to parse currentEntryCacheCount " + "from " + backendMonitorDNs[i]); } } if (captureEntryCacheSize || captureEntryCachePercentFull) { attr = entry.getAttribute(ATTR_CURRENT_EC_SIZE); if ((attr == null) || ((values = attr.getStringValueArray()) == null) || (values.length == 0)) { throw new LDAPException("Unable to read currentEntryCacheSize " + "from " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to read currentEntryCacheSize " + "from " + backendMonitorDNs[i]); } try { cacheSizeList[i].add(new Long(values[0])); } catch (NumberFormatException nfe) { throw new LDAPException("Unable to parse currentEntryCacheSize " + "from " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to parse currentEntryCacheSize " + "from " + backendMonitorDNs[i]); } } if (captureEntryCacheHitRatio) { attr = entry.getAttribute(ATTR_EC_HIT_RATIO); if ((attr == null) || ((values = attr.getStringValueArray()) == null) || (values.length == 0)) { throw new LDAPException("Unable to read entryCacheHitRatio " + "from " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to read entryCacheHitRatio " + "from " + backendMonitorDNs[i]); } try { cacheHitRatioList[i].add(new Integer(values[0])); } catch (NumberFormatException nfe) { throw new LDAPException("Unable to parse entryCacheHitRatio " + "from " + backendMonitorDNs[i], LDAPException.NO_RESULTS_RETURNED, "Unable to parse entryCacheHitRatio " + "from " + backendMonitorDNs[i]); } } } } } }