001/*
002 * Copyright 2008-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2008-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2008-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk.unboundidds.monitors;
037
038
039
040import java.util.ArrayList;
041import java.util.Collections;
042import java.util.LinkedHashMap;
043import java.util.List;
044import java.util.Map;
045import java.util.TreeMap;
046import java.util.TreeSet;
047
048import com.unboundid.ldap.sdk.Attribute;
049import com.unboundid.ldap.sdk.Entry;
050import com.unboundid.util.Debug;
051import com.unboundid.util.NotMutable;
052import com.unboundid.util.NotNull;
053import com.unboundid.util.Nullable;
054import com.unboundid.util.StaticUtils;
055import com.unboundid.util.ThreadSafety;
056import com.unboundid.util.ThreadSafetyLevel;
057
058import static com.unboundid.ldap.sdk.unboundidds.monitors.MonitorMessages.*;
059
060
061
062/**
063 * This class defines a monitor entry that provides information about the memory
064 * usage for the JVM in which the Directory Server is running.  In particular,
065 * it reports information about the memory pools and garbage collectors defined
066 * in the JVM.
067 * <BR>
068 * <BLOCKQUOTE>
069 *   <B>NOTE:</B>  This class, and other classes within the
070 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
071 *   supported for use against Ping Identity, UnboundID, and
072 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
073 *   for proprietary functionality or for external specifications that are not
074 *   considered stable or mature enough to be guaranteed to work in an
075 *   interoperable way with other types of LDAP servers.
076 * </BLOCKQUOTE>
077 * <BR>
078 * The information that may be available in the memory usage monitor entry
079 * includes:
080 * <UL>
081 *   <LI>The names of the memory pools that are in use within the JVM.</LI>
082 *   <LI>The number of bytes currently used within each memory pool.</LI>
083 *   <LI>The number of bytes used within each memory pool after the last
084 *       garbage collection.</LI>
085 *   <LI>The names of the garbage collectors that are in use within the
086 *       JVM.</LI>
087 *   <LI>The number of garbage collections performed by each collector.</LI>
088 *   <LI>The total duration of all garbage collections performed by each
089 *       collector.</LI>
090 *   <LI>The average duration of garbage collections performed by each
091 *       collector.</LI>
092 *   <LI>The duration of the most recent garbage collection performed by each
093 *       collector.</LI>
094 *   <LI>The amount of non-heap memory consumed by the JVM.</LI>
095 *   <LI>The number of detected pauses of various durations detected by the
096 *       server.</LI>
097 *   <LI>The duration of the longest pause detected by the server.</LI>
098 * </UL>
099 * The server should present at most one memory usage monitor entry.  It can be
100 * retrieved using the {@link MonitorManager#getMemoryUsageMonitorEntry} method.
101 * This entry provides specific methods for accessing information about JVM
102 * memory usage (e.g., the {@link MemoryUsageMonitorEntry#getMemoryPoolNames}
103 * method can be used to retrieve the names of the memory pool).  Alternately,
104 * this information may be accessed using the generic API.  See the
105 * {@link MonitorManager} class documentation for an example that demonstrates
106 * the use of the generic API for accessing monitor data.
107 */
108@NotMutable()
109@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
110public final class MemoryUsageMonitorEntry
111       extends MonitorEntry
112{
113  /**
114   * The structural object class used in memory usage monitor entries.
115   */
116  @NotNull static final String MEMORY_USAGE_MONITOR_OC =
117       "ds-memory-usage-monitor-entry";
118
119
120
121  /**
122   * The name of the attribute that holds the duration of the longest detected
123   * pause.
124   */
125  @NotNull private static final String ATTR_LONGEST_PAUSE_TIME =
126       "max-detected-pause-time-millis";
127
128
129
130  /**
131   * The name of the attribute that holds the amount of non-heap memory used
132   * by the JVM.
133   */
134  @NotNull private static final String ATTR_NON_HEAP_USED =
135       "non-heap-memory-bytes-used";
136
137
138
139  /**
140   * The name of the attribute that holds the total amount of memory used by
141   * memory consumers.
142   */
143  @NotNull private static final String ATTR_TOTAL_CONSUMER_MEMORY =
144       "total-bytes-used-by-memory-consumers";
145
146
147
148  /**
149   * The name of the attribute that holds the percentage of committed tenured
150   * memory held by memory consumers.
151   */
152  @NotNull private static final String
153       ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_COMMITTED =
154            "memory-consumers-total-as-percent-of-committed-tenured-memory";
155
156
157
158  /**
159   * The name of the attribute that holds the percentage of maximum allowed
160   * tenured memory held by memory consumers.
161   */
162  @NotNull private static final String
163       ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_MAX =
164            "memory-consumers-total-as-percent-of-maximum-tenured-memory";
165
166
167
168  /**
169   * The prefix that will be used for pauses detected by the server.
170   */
171  @NotNull private static final String ATTR_PREFIX_DETECTED_PAUSE =
172       "detected-pauses-over-";
173
174
175
176  /**
177   * The suffix that will be used for attributes providing the total collection
178   * count for a garbage collector.
179   */
180  @NotNull private static final String ATTR_SUFFIX_TOTAL_COLLECTION_COUNT =
181       "-total-collection-count";
182
183
184
185  /**
186   * The suffix that will be used for attributes providing the total collection
187   * duration for a garbage collector.
188   */
189  @NotNull private static final String ATTR_SUFFIX_TOTAL_COLLECTION_DURATION =
190       "-total-collection-duration";
191
192
193
194  /**
195   * The suffix that will be used for attributes providing the average
196   * collection duration for a garbage collector.
197   */
198  @NotNull private static final String ATTR_SUFFIX_AVERAGE_COLLECTION_DURATION =
199       "-average-collection-duration";
200
201
202
203  /**
204   * The suffix that will be used for attributes providing the recent collection
205   * duration for a garbage collector.
206   */
207  @NotNull private static final String ATTR_SUFFIX_RECENT_COLLECTION_DURATION =
208       "-recent-collection-duration";
209
210
211
212  /**
213   * The suffix that will be used for attributes providing the current bytes
214   * used in a memory pool.
215   */
216  @NotNull private static final String ATTR_SUFFIX_CURRENT_BYTES_USED =
217       "-current-bytes-used";
218
219
220
221  /**
222   * The suffix that will be used for attributes providing the bytes used after
223   * the last collection in a memory pool.
224   */
225  @NotNull private static final String
226       ATTR_SUFFIX_BYTES_USED_AFTER_LAST_COLLECTION =
227            "-bytes-used-after-last-collection";
228
229
230
231  /**
232   * The name of the property used to provide the numbers of pauses of various
233   * durations detected.
234   */
235  @NotNull private static final String PROPERTY_DETECTED_PAUSE_COUNTS =
236       "detected-pause-counts";
237
238
239
240  /**
241   * The name of the attribute that holds the maximum amount of memory that may
242   * be used by the JVM, in megabytes.
243   */
244  @NotNull private static final String ATTR_MAX_RESERVABLE_MEMORY_MB =
245       "maxReservableMemoryMB";
246
247
248
249  /**
250   * The name of the attribute that holds the amount of memory currently
251   * allocated for use by the JVM, in megabytes.
252   */
253  @NotNull private static final String ATTR_CURRENT_RESERVED_MEMORY_MB =
254       "currentReservedMemoryMB";
255
256
257
258  /**
259   * The name of the attribute that holds the amount of allocated JVM memory
260   * which is actually in use.
261   */
262  @NotNull private static final String ATTR_USED_MEMORY_MB =
263       "usedReservedMemoryMB";
264
265
266
267  /**
268   * The name of the attribute that holds the amount of allocated JVM memory
269   * that is not currently in use.
270   */
271  @NotNull private static final String ATTR_FREE_MEMORY_MB =
272       "freeReservedMemoryMB";
273
274
275
276  /**
277   * The name of the attribute that holds the percentage of the maximum JVM
278   * memory that is actually in use.
279   */
280  @NotNull private static final String ATTR_RESERVED_MEMORY_PERCENT_FULL =
281       "reservedMemoryPercentFull";
282
283
284
285  /**
286   * The serial version UID for this serializable class.
287   */
288  private static final long serialVersionUID = 1924052253885937441L;
289
290
291
292  // The list of garbage collectors for which information is available.
293  @NotNull private final List<String> garbageCollectors;
294
295  // The list of memory pools for which information is available.
296  @NotNull private final List<String> memoryPools;
297
298  // The amount of memory that has currently been allocated by the JVM, in
299  // megabytes.
300  @Nullable private final Long currentReservedMemoryMB;
301
302  // The amount of allocated JVM memory that is not currently in use, in
303  // megabytes.
304  @Nullable private final Long freeReservedMemoryMB;
305
306  // The maximum pause time detected by the JVM.
307  @Nullable private final Long maxDetectedPauseTime;
308
309  // The maximum amount of memory that may be used by the JVM, in megabytes.
310  @Nullable private final Long maxReservableMemoryMB;
311
312  // The amount of non-heap memory consumed by the JVM.
313  @Nullable private final Long nonHeapMemoryUsed;
314
315  // The percentage of committed tenured memory held by consumers.
316  @Nullable private final Long percentOfCommittedTenuredMemory;
317
318  // The percentage of maximum tenured memory held by consumers.
319  @Nullable private final Long percentOfMaxTenuredMemory;
320
321  // The percentage of the maximum JVM memory that is currently in use.
322  @Nullable private final Long reservedMemoryPercentFull;
323
324  // The total amount of memory held by memory consumers.
325  @Nullable private final Long totalBytesHeldByConsumers;
326
327  // The amount of allocated JVM memory that is currently in use, in megabytes.
328  @Nullable private final Long usedReservedMemoryMB;
329
330  // The number of pauses exceeding specified thresholds.
331  @NotNull private final Map<Long,Long> detectedPauses;
332
333  // The list of bytes used after the last collection per memory pool.
334  @NotNull private final Map<String,Long> bytesUsedAfterLastCollectionPerMP;
335
336  // The list of current bytes used per memory pool.
337  @NotNull private final Map<String,Long> currentBytesUsedPerMP;
338
339  // The list of average collection durations per garbage collector.
340  @NotNull private final Map<String,Long> averageCollectionDurationPerGC;
341
342  // The list of recent collection durations per garbage collector.
343  @NotNull private final Map<String,Long> recentCollectionDurationPerGC;
344
345  // The list of total collection counts per garbage collector.
346  @NotNull private final Map<String,Long> totalCollectionCountPerGC;
347
348  // The list of total collection durations per garbage collector.
349  @NotNull private final Map<String,Long> totalCollectionDurationPerGC;
350
351
352
353  /**
354   * Creates a new memory usage monitor entry from the provided entry.
355   *
356   * @param  entry  The entry to be parsed as a memory usage monitor entry.  It
357   *                must not be {@code null}.
358   */
359  public MemoryUsageMonitorEntry(@NotNull final Entry entry)
360  {
361    super(entry);
362
363    maxDetectedPauseTime            = getLong(ATTR_LONGEST_PAUSE_TIME);
364    nonHeapMemoryUsed               = getLong(ATTR_NON_HEAP_USED);
365    totalBytesHeldByConsumers       = getLong(ATTR_TOTAL_CONSUMER_MEMORY);
366    percentOfCommittedTenuredMemory =
367         getLong(ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_COMMITTED);
368    percentOfMaxTenuredMemory =
369         getLong(ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_MAX);
370
371    maxReservableMemoryMB     = getLong(ATTR_MAX_RESERVABLE_MEMORY_MB);
372    currentReservedMemoryMB   = getLong(ATTR_CURRENT_RESERVED_MEMORY_MB);
373    usedReservedMemoryMB      = getLong(ATTR_USED_MEMORY_MB);
374    freeReservedMemoryMB      = getLong(ATTR_FREE_MEMORY_MB);
375    reservedMemoryPercentFull = getLong(ATTR_RESERVED_MEMORY_PERCENT_FULL);
376
377
378    final TreeMap<Long,Long> pauses = new TreeMap<>();
379
380    final TreeSet<String> mpNames = new TreeSet<>();
381    final TreeSet<String> gcNames = new TreeSet<>();
382
383    final TreeMap<String,Long> averageDurations = new TreeMap<>();
384    final TreeMap<String,Long> currentBytesUsed = new TreeMap<>();
385    final TreeMap<String,Long> lastBytesUsed    = new TreeMap<>();
386    final TreeMap<String,Long> recentDurations  = new TreeMap<>();
387    final TreeMap<String,Long> totalCounts      = new TreeMap<>();
388    final TreeMap<String,Long> totalDurations   = new TreeMap<>();
389
390    for (final Attribute a : entry.getAttributes())
391    {
392      final String name      = a.getName();
393      final String lowerName = StaticUtils.toLowerCase(name);
394
395      if (lowerName.startsWith(ATTR_PREFIX_DETECTED_PAUSE))
396      {
397        final Long l = getLong(name);
398
399        final String timeStr =
400             lowerName.substring(ATTR_PREFIX_DETECTED_PAUSE.length());
401        if (timeStr.endsWith("ms"))
402        {
403          try
404          {
405            final long millis =
406                 Long.parseLong(timeStr.substring(0, timeStr.length()-2));
407            pauses.put(millis, l);
408          }
409          catch (final Exception e)
410          {
411            Debug.debugException(e);
412          }
413        }
414        else if (timeStr.endsWith("s"))
415        {
416          try
417          {
418            final long millis = 1000 *
419                 Long.parseLong(timeStr.substring(0, timeStr.length()-1));
420            pauses.put(millis, l);
421          }
422          catch (final Exception e)
423          {
424            Debug.debugException(e);
425          }
426        }
427      }
428
429      int pos = lowerName.indexOf(ATTR_SUFFIX_AVERAGE_COLLECTION_DURATION);
430      if (pos > 0)
431      {
432        final String gcName = name.substring(0, pos);
433        gcNames.add(gcName);
434
435        final Long l = getLong(name);
436        if (l != null)
437        {
438          averageDurations.put(StaticUtils.toLowerCase(gcName), l);
439        }
440
441        continue;
442      }
443
444      pos = lowerName.indexOf(ATTR_SUFFIX_BYTES_USED_AFTER_LAST_COLLECTION);
445      if (pos > 0)
446      {
447        final String mpName = name.substring(0, pos);
448        mpNames.add(mpName);
449
450        final Long l = getLong(name);
451        if (l != null)
452        {
453          lastBytesUsed.put(StaticUtils.toLowerCase(mpName), l);
454        }
455
456        continue;
457      }
458
459      pos = lowerName.indexOf(ATTR_SUFFIX_CURRENT_BYTES_USED);
460      if (pos > 0)
461      {
462        final String mpName = name.substring(0, pos);
463        mpNames.add(mpName);
464
465        final Long l = getLong(name);
466        if (l != null)
467        {
468          currentBytesUsed.put(StaticUtils.toLowerCase(mpName), l);
469        }
470
471        continue;
472      }
473
474      pos = lowerName.indexOf(ATTR_SUFFIX_RECENT_COLLECTION_DURATION);
475      if (pos > 0)
476      {
477        final String gcName = name.substring(0, pos);
478        gcNames.add(gcName);
479
480        final Long l = getLong(name);
481        if (l != null)
482        {
483          recentDurations.put(StaticUtils.toLowerCase(gcName), l);
484        }
485
486        continue;
487      }
488
489      pos = lowerName.indexOf(ATTR_SUFFIX_TOTAL_COLLECTION_COUNT);
490      if ((pos > 0) && (! lowerName.startsWith("mem-pool-")))
491      {
492        final String gcName = name.substring(0, pos);
493        gcNames.add(gcName);
494
495        final Long l = getLong(name);
496        if (l != null)
497        {
498          totalCounts.put(StaticUtils.toLowerCase(gcName), l);
499        }
500
501        continue;
502      }
503
504      pos = lowerName.indexOf(ATTR_SUFFIX_TOTAL_COLLECTION_DURATION);
505      if (pos > 0)
506      {
507        final String gcName = name.substring(0, pos);
508        gcNames.add(gcName);
509
510        final Long l = getLong(name);
511        if (l != null)
512        {
513          totalDurations.put(StaticUtils.toLowerCase(gcName), l);
514        }
515
516        continue;
517      }
518    }
519
520
521    garbageCollectors =
522         Collections.unmodifiableList(new ArrayList<>(gcNames));
523
524    memoryPools = Collections.unmodifiableList(new ArrayList<>(mpNames));
525
526    totalCollectionCountPerGC = Collections.unmodifiableMap(totalCounts);
527
528    totalCollectionDurationPerGC = Collections.unmodifiableMap(totalDurations);
529
530    averageCollectionDurationPerGC =
531         Collections.unmodifiableMap(averageDurations);
532
533    recentCollectionDurationPerGC =
534         Collections.unmodifiableMap(recentDurations);
535
536    bytesUsedAfterLastCollectionPerMP =
537         Collections.unmodifiableMap(lastBytesUsed);
538
539    currentBytesUsedPerMP = Collections.unmodifiableMap(currentBytesUsed);
540
541    detectedPauses = Collections.unmodifiableMap(pauses);
542  }
543
544
545
546  /**
547   * Retrieves the maximum amount of memory (in megabytes) that may be allocated
548   * and used by the JVM.
549   *
550   * @return  The maximum amount of memory (in megabytes) that may be allocated
551   *          and used by the JVM, or {@code null} if this was not included in
552   *          the monitor entry.
553   */
554  @Nullable()
555  public Long getMaxReservableMemoryMB()
556  {
557    return maxReservableMemoryMB;
558  }
559
560
561
562  /**
563   * Retrieves the amount of memory (in megabytes) that is currently allocated
564   * for use by the JVM.
565   *
566   * @return  The amount of memory (in megabytes) that is currently allocated
567   *          for use by the JVM, or {@code null} if this was not included in
568   *          the monitor entry.
569   */
570  @Nullable()
571  public Long getCurrentReservedMemoryMB()
572  {
573    return currentReservedMemoryMB;
574  }
575
576
577
578  /**
579   * Retrieves the amount of memory (in megabytes) allocated for use by the JVM
580   * that is currently in use for holding Java objects.
581   *
582   * @return  The amount of memory (in megabytes) allocated for use by the JVM
583   *          that is currently in use for holding Java objects, or {@code null}
584   *          if this was not included in the monitor entry.
585   */
586  @Nullable()
587  public Long getUsedReservedMemoryMB()
588  {
589    return usedReservedMemoryMB;
590  }
591
592
593
594  /**
595   * Retrieves the amount of memory (in megabytes) allocated for use by the JVM
596   * that is not currently in use for holding Java objects.
597   *
598   * @return  The amount of memory (in megabytes) allocated for use by the JVM
599   *          that is not currently in use for holding Java objects, or
600   *          {@code null} if this was not included in the monitor entry.
601   */
602  @Nullable()
603  public Long getFreeReservedMemoryMB()
604  {
605    return freeReservedMemoryMB;
606  }
607
608
609
610  /**
611   * Retrieves the percent of the currently-reserved memory that is actually in
612   * use by the JVM for storing Java objects.
613   *
614   * @return  The percent of the currently-reserved memory that is actually in
615   *          use by the JVM for storing Java objects.
616   */
617  @Nullable()
618  public Long getReservedMemoryPercentFull()
619  {
620    return reservedMemoryPercentFull;
621  }
622
623
624
625  /**
626   * Retrieves the names of the garbage collectors for which information is
627   * available.
628   *
629   * @return  The names of the garbage collectors for which information is
630   *          available.
631   */
632  @NotNull()
633  public List<String> getGarbageCollectorNames()
634  {
635    return garbageCollectors;
636  }
637
638
639
640  /**
641   * Retrieves the names of the memory pools for which information is available.
642   *
643   * @return  The names of the memory pools for which information is available.
644   */
645  @NotNull()
646  public List<String> getMemoryPoolNames()
647  {
648    return memoryPools;
649  }
650
651
652
653  /**
654   * Retrieves a map containing the total number of garbage collections
655   * performed per collector.
656   *
657   * @return  A map containing the total number of garbage collections performed
658   *          per collector.
659   */
660  @NotNull()
661  public Map<String,Long> getTotalCollectionCounts()
662  {
663    return totalCollectionCountPerGC;
664  }
665
666
667
668  /**
669   * Retrieves the total number of garbage collections performed by the
670   * specified collector.
671   *
672   * @param  collectorName  The name of the garbage collector for which to
673   *                        retrieve the information.
674   *
675   * @return  The total number of garbage collections performed by the specified
676   *          collector, or {@code null} if that information is not available.
677   */
678  @Nullable()
679  public Long getTotalCollectionCount(@NotNull final String collectorName)
680  {
681    return totalCollectionCountPerGC.get(
682         StaticUtils.toLowerCase(collectorName));
683  }
684
685
686
687  /**
688   * Retrieves a map containing the total length of time (in milliseconds) spent
689   * performing garbage collection per collector.
690   *
691   * @return  A map containing the total length of time (in milliseconds) spent
692   *          performing garbage collection per collector.
693   */
694  @NotNull()
695  public Map<String,Long> getTotalCollectionDurations()
696  {
697    return totalCollectionDurationPerGC;
698  }
699
700
701
702  /**
703   * Retrieves the total length of time (in milliseconds) spent performing
704   * garbage collection for the specified collector.
705   *
706   * @param  collectorName  The name of the garbage collector for which to
707   *                        retrieve the information.
708   *
709   * @return  The total length of time (in milliseconds) spent performing
710   *          garbage collection for the specified collector, or {@code null} if
711   *          that information is not available.
712   */
713  @Nullable()
714  public Long getTotalCollectionDuration(@NotNull final String collectorName)
715  {
716    return totalCollectionDurationPerGC.get(
717         StaticUtils.toLowerCase(collectorName));
718  }
719
720
721
722  /**
723   * Retrieves a map containing the average garbage collection duration (in
724   * milliseconds) per garbage collector.
725   *
726   * @return  A map containing the average garbage collection duration (in
727   *          milliseconds) per garbage collector.
728   */
729  @NotNull()
730  public Map<String,Long> getAverageCollectionDurations()
731  {
732    return averageCollectionDurationPerGC;
733  }
734
735
736
737  /**
738   * Retrieves the average garbage collection duration (in milliseconds) for the
739   * specified collector.
740   *
741   * @param  collectorName  The name of the garbage collector for which to
742   *                        retrieve the information.
743   *
744   * @return  The average garbage collection duration (in milliseconds) for the
745   *          specified collector, or {@code null} if that information is not
746   *          available.
747   */
748  @Nullable()
749  public Long getAverageCollectionDuration(@NotNull final String collectorName)
750  {
751    return averageCollectionDurationPerGC.get(
752         StaticUtils.toLowerCase(collectorName));
753  }
754
755
756
757  /**
758   * Retrieves a map containing the most recent garbage collection duration (in
759   * milliseconds) per garbage collector.
760   *
761   * @return  A map containing the duration of the most recent garbage
762   *          collection duration (in milliseconds) per garbage collector.
763   */
764  @NotNull()
765  public Map<String,Long> getRecentCollectionDurations()
766  {
767    return recentCollectionDurationPerGC;
768  }
769
770
771
772  /**
773   * Retrieves the duration (in milliseconds) of the most recent garbage
774   * collection for the specified collector.
775   *
776   * @param  collectorName  The name of the garbage collector for which to
777   *                        retrieve the information.
778   *
779   * @return  The duration (in milliseconds) of the most recent garbage
780   *          collection for the specified collector, or {@code null} if that
781   *          information is not available.
782   */
783  @Nullable()
784  public Long getRecentCollectionDuration(@NotNull final String collectorName)
785  {
786    return recentCollectionDurationPerGC.get(
787         StaticUtils.toLowerCase(collectorName));
788  }
789
790
791
792  /**
793   * Retrieves a map containing the current number of bytes used per memory
794   * pool.
795   *
796   * @return  A map containing the current number of bytes used per memory pool.
797   */
798  @NotNull()
799  public Map<String,Long> getCurrentBytesUsed()
800  {
801    return currentBytesUsedPerMP;
802  }
803
804
805
806  /**
807   * Retrieves the current number of bytes used for the specified memory pool.
808   *
809   * @param  poolName  The name of the memory pool for which to retrieve the
810   *                   information.
811   *
812   * @return  The current number of bytes used for the specified memory pool, or
813   *          {@code null} if that information is not available.
814   */
815  @Nullable()
816  public Long getCurrentBytesUsed(@NotNull final String poolName)
817  {
818    return currentBytesUsedPerMP.get(StaticUtils.toLowerCase(poolName));
819  }
820
821
822
823  /**
824   * Retrieves a map containing the number of bytes used after the last garbage
825   * collection per memory pool.
826   *
827   * @return  A map containing the number of bytes used after the last garbage
828   *          collection per memory pool.
829   */
830  @NotNull()
831  public Map<String,Long> getBytesUsedAfterLastCollection()
832  {
833    return bytesUsedAfterLastCollectionPerMP;
834  }
835
836
837
838  /**
839   * Retrieves the number of bytes used after the last garbage collection for
840   * the specified memory pool.
841   *
842   * @param  poolName  The name of the memory pool for which to retrieve the
843   *                   information.
844   *
845   * @return  The number of bytes used after the last garbage collection for the
846   *          specified memory pool, or {@code null} if that information is not
847   *          available.
848   */
849  @Nullable()
850  public Long getBytesUsedAfterLastCollection(@NotNull final String poolName)
851  {
852    return bytesUsedAfterLastCollectionPerMP.get(
853         StaticUtils.toLowerCase(poolName));
854  }
855
856
857
858  /**
859   * Retrieves the amount of non-heap memory consumed by the JVM.
860   *
861   * @return  The amount of non-heap memory consumed by the JVM, or {@code null}
862   *          if that information is not available.
863   */
864  @Nullable()
865  public Long getNonHeapMemoryBytesUsed()
866  {
867    return nonHeapMemoryUsed;
868  }
869
870
871
872  /**
873   * Retrieves the total amount of memory in bytes held by memory consumers.
874   *
875   * @return  The total amount of memory in bytes held by memory consumers, or
876   *          {@code null} if that information is not available.
877   */
878  @Nullable()
879  public Long getTotalBytesUsedByMemoryConsumers()
880  {
881    return totalBytesHeldByConsumers;
882  }
883
884
885
886  /**
887   * Retrieves the percentage of the maximum allowed amount of tenured memory
888   * that is used by memory consumers (assuming that all memory used by memory
889   * consumers is contained in the tenured generation).
890   *
891   * @return  The percentage of the maximum allowed amount of tenured memory
892   *          that is used by memory consumers, or {@code null} if that
893   *          information is not available.
894   */
895  @Nullable()
896  public Long getPercentageOfMaximumTenuredMemoryUsedByMemoryConsumers()
897  {
898    return percentOfMaxTenuredMemory;
899  }
900
901
902
903  /**
904   * Retrieves the percentage of the committed amount of tenured memory that is
905   * used by memory consumers (assuming that all memory used by memory consumers
906   * is contained in the tenured generation).
907   *
908   * @return  The percentage of the committed amount of tenured memory that is
909   *          used by memory consumers, or {@code null} if that information is
910   *          not available.
911   */
912  @Nullable()
913  public Long getPercentageOfCommittedTenuredMemoryUsedByMemoryConsumers()
914  {
915    return percentOfCommittedTenuredMemory;
916  }
917
918
919
920  /**
921   * Retrieves the number of pauses of various durations detected by the server.
922   * The value returned will contain a map between the minimum duration in
923   * milliseconds for the associated bucket and the number of pauses detected of
924   * at least that duration.
925   *
926   * @return  The number of pauses of various durations detected by the server.
927   */
928  @NotNull()
929  public Map<Long,Long> getDetectedPauseCounts()
930  {
931    return detectedPauses;
932  }
933
934
935
936  /**
937   * Retrieves the duration of the longest pause detected by the server.
938   *
939   * @return  The duration of the longest pause detected by the server, or
940   *          {@code null} if that information is not available.
941   */
942  @Nullable()
943  public Long getMaxDetectedPauseTimeMillis()
944  {
945    return maxDetectedPauseTime;
946  }
947
948
949
950  /**
951   * {@inheritDoc}
952   */
953  @Override()
954  @NotNull()
955  public String getMonitorDisplayName()
956  {
957    return INFO_MEMORY_USAGE_MONITOR_DISPNAME.get();
958  }
959
960
961
962  /**
963   * {@inheritDoc}
964   */
965  @Override()
966  @NotNull()
967  public String getMonitorDescription()
968  {
969    return INFO_MEMORY_USAGE_MONITOR_DESC.get();
970  }
971
972
973
974  /**
975   * {@inheritDoc}
976   */
977  @Override()
978  @NotNull()
979  public Map<String,MonitorAttribute> getMonitorAttributes()
980  {
981    final LinkedHashMap<String,MonitorAttribute> attrs =
982         new LinkedHashMap<>(StaticUtils.computeMapCapacity(50));
983
984    if (maxReservableMemoryMB != null)
985    {
986      addMonitorAttribute(attrs,
987           ATTR_MAX_RESERVABLE_MEMORY_MB,
988           INFO_MEMORY_USAGE_DISPNAME_MAX_MEM.get(),
989           INFO_MEMORY_USAGE_DESC_MAX_MEM.get(),
990           maxReservableMemoryMB);
991    }
992
993    if (currentReservedMemoryMB != null)
994    {
995      addMonitorAttribute(attrs,
996           ATTR_CURRENT_RESERVED_MEMORY_MB,
997           INFO_MEMORY_USAGE_DISPNAME_CURRENT_MEM.get(),
998           INFO_MEMORY_USAGE_DESC_CURRENT_MEM.get(),
999           currentReservedMemoryMB);
1000    }
1001
1002    if (usedReservedMemoryMB != null)
1003    {
1004      addMonitorAttribute(attrs,
1005           ATTR_USED_MEMORY_MB,
1006           INFO_MEMORY_USAGE_DISPNAME_USED_MEM.get(),
1007           INFO_MEMORY_USAGE_DESC_USED_MEM.get(),
1008           usedReservedMemoryMB);
1009    }
1010
1011    if (freeReservedMemoryMB != null)
1012    {
1013      addMonitorAttribute(attrs,
1014           ATTR_FREE_MEMORY_MB,
1015           INFO_MEMORY_USAGE_DISPNAME_FREE_MEM.get(),
1016           INFO_MEMORY_USAGE_DESC_FREE_MEM.get(),
1017           freeReservedMemoryMB);
1018    }
1019
1020    if (reservedMemoryPercentFull != null)
1021    {
1022      addMonitorAttribute(attrs,
1023           ATTR_RESERVED_MEMORY_PERCENT_FULL,
1024           INFO_MEMORY_USAGE_DISPNAME_RESERVED_PCT.get(),
1025           INFO_MEMORY_USAGE_DESC_RESERVED_PCT.get(),
1026           reservedMemoryPercentFull);
1027    }
1028
1029    if (! garbageCollectors.isEmpty())
1030    {
1031      addMonitorAttribute(attrs,
1032           "gcNames",
1033           INFO_MEMORY_USAGE_DISPNAME_GC_NAMES.get(),
1034           INFO_MEMORY_USAGE_DESC_GC_NAMES.get(),
1035           garbageCollectors);
1036    }
1037
1038    if (! totalCollectionCountPerGC.isEmpty())
1039    {
1040      for (final String name : totalCollectionCountPerGC.keySet())
1041      {
1042        addMonitorAttribute(attrs,
1043            "totalCollectionCount-" + name,
1044            INFO_MEMORY_USAGE_DISPNAME_TOTAL_COLLECTION_COUNT.get(name),
1045            INFO_MEMORY_USAGE_DESC_TOTAL_COLLECTION_COUNT.get(name),
1046            totalCollectionCountPerGC.get(name));
1047      }
1048    }
1049
1050    if (! totalCollectionDurationPerGC.isEmpty())
1051    {
1052      for (final String name : totalCollectionDurationPerGC.keySet())
1053      {
1054        addMonitorAttribute(attrs,
1055            "totalCollectionDuration-" + name,
1056            INFO_MEMORY_USAGE_DISPNAME_TOTAL_COLLECTION_DURATION.get(name),
1057            INFO_MEMORY_USAGE_DESC_TOTAL_COLLECTION_DURATION.get(name),
1058            totalCollectionDurationPerGC.get(name));
1059      }
1060    }
1061
1062    if (! averageCollectionDurationPerGC.isEmpty())
1063    {
1064      for (final String name : averageCollectionDurationPerGC.keySet())
1065      {
1066        addMonitorAttribute(attrs,
1067            "averageCollectionDuration-" + name,
1068            INFO_MEMORY_USAGE_DISPNAME_AVERAGE_COLLECTION_DURATION.get(name),
1069            INFO_MEMORY_USAGE_DESC_AVERAGE_COLLECTION_DURATION.get(name),
1070            averageCollectionDurationPerGC.get(name));
1071      }
1072    }
1073
1074    if (! recentCollectionDurationPerGC.isEmpty())
1075    {
1076      for (final String name : recentCollectionDurationPerGC.keySet())
1077      {
1078        addMonitorAttribute(attrs,
1079            "recentCollectionDuration-" + name,
1080            INFO_MEMORY_USAGE_DISPNAME_RECENT_COLLECTION_DURATION.get(name),
1081            INFO_MEMORY_USAGE_DESC_RECENT_COLLECTION_DURATION.get(name),
1082            recentCollectionDurationPerGC.get(name));
1083      }
1084    }
1085
1086    if (! memoryPools.isEmpty())
1087    {
1088      addMonitorAttribute(attrs,
1089           "memoryPools",
1090           INFO_MEMORY_USAGE_DISPNAME_MEMORY_POOLS.get(),
1091           INFO_MEMORY_USAGE_DESC_MEMORY_POOLS.get(),
1092           memoryPools);
1093    }
1094
1095    if (! currentBytesUsedPerMP.isEmpty())
1096    {
1097      for (final String name : currentBytesUsedPerMP.keySet())
1098      {
1099        addMonitorAttribute(attrs,
1100            "currentBytesUsed-" + name,
1101            INFO_MEMORY_USAGE_DISPNAME_CURRENT_BYTES_USED.get(name),
1102            INFO_MEMORY_USAGE_DESC_CURRENT_BYTES_USED.get(name),
1103            currentBytesUsedPerMP.get(name));
1104      }
1105    }
1106
1107    if (! bytesUsedAfterLastCollectionPerMP.isEmpty())
1108    {
1109      for (final String name : bytesUsedAfterLastCollectionPerMP.keySet())
1110      {
1111        addMonitorAttribute(attrs,
1112            "bytesUsedAfterLastCollection-" + name,
1113            INFO_MEMORY_USAGE_DISPNAME_BYTES_USED_AFTER_COLLECTION.get(name),
1114            INFO_MEMORY_USAGE_DESC_BYTES_USED_AFTER_COLLECTION.get(name),
1115            bytesUsedAfterLastCollectionPerMP.get(name));
1116      }
1117    }
1118
1119    if (nonHeapMemoryUsed != null)
1120    {
1121      addMonitorAttribute(attrs,
1122           ATTR_NON_HEAP_USED,
1123           INFO_MEMORY_USAGE_DISPNAME_NON_HEAP_MEMORY.get(),
1124           INFO_MEMORY_USAGE_DESC_NON_HEAP_MEMORY.get(),
1125           nonHeapMemoryUsed);
1126    }
1127
1128    if (totalBytesHeldByConsumers != null)
1129    {
1130      addMonitorAttribute(attrs,
1131           ATTR_TOTAL_CONSUMER_MEMORY,
1132           INFO_MEMORY_USAGE_DISPNAME_TOTAL_CONSUMER_MEMORY.get(),
1133           INFO_MEMORY_USAGE_DESC_TOTAL_CONSUMER_MEMORY.get(),
1134           totalBytesHeldByConsumers);
1135    }
1136
1137    if (percentOfMaxTenuredMemory != null)
1138    {
1139      addMonitorAttribute(attrs,
1140           ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_MAX,
1141           INFO_MEMORY_USAGE_DISPNAME_CONSUMERS_AS_PCT_OF_MAX.get(),
1142           INFO_MEMORY_USAGE_DESC_CONSUMERS_AS_PCT_OF_MAX.get(),
1143           percentOfMaxTenuredMemory);
1144    }
1145
1146    if (percentOfCommittedTenuredMemory != null)
1147    {
1148      addMonitorAttribute(attrs,
1149           ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_COMMITTED,
1150           INFO_MEMORY_USAGE_DISPNAME_CONSUMERS_AS_PCT_OF_COMMITTED.get(),
1151           INFO_MEMORY_USAGE_DESC_CONSUMERS_AS_PCT_OF_COMMITTED.get(),
1152           percentOfCommittedTenuredMemory);
1153    }
1154
1155    if (! detectedPauses.isEmpty())
1156    {
1157      final ArrayList<String> values =
1158           new ArrayList<>(detectedPauses.size());
1159      for (final Map.Entry<Long,Long> e : detectedPauses.entrySet())
1160      {
1161        values.add(e.getKey() + "ms=" + e.getValue());
1162      }
1163
1164      addMonitorAttribute(attrs,
1165           PROPERTY_DETECTED_PAUSE_COUNTS,
1166           INFO_MEMORY_USAGE_DISPNAME_DETECTED_PAUSES.get(),
1167           INFO_MEMORY_USAGE_DESC_DETECTED_PAUSES.get(),
1168           values);
1169    }
1170
1171    if (maxDetectedPauseTime != null)
1172    {
1173      addMonitorAttribute(attrs,
1174           ATTR_LONGEST_PAUSE_TIME,
1175           INFO_MEMORY_USAGE_DISPNAME_MAX_PAUSE_TIME.get(),
1176           INFO_MEMORY_USAGE_DESC_MAX_PAUSE_TIME.get(),
1177           maxDetectedPauseTime);
1178    }
1179
1180    return Collections.unmodifiableMap(attrs);
1181  }
1182}