001 /* 002 // $Id: //open/mondrian/src/main/mondrian/util/MemoryMonitor.java#5 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2007-2007 Julian Hyde and others 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.util; 011 012 /** 013 * API for Mondrian's memory monitors. 014 * 015 * <p>For Java4, the available monitors 016 * do nothing since there is no reliable way of detecting that 017 * memory is running low using such a JVM (you are welcome to 018 * try to create one, but I believe you will fail - some such candidates 019 * only make it more likely that an OutOfMemory condition will occur). 020 * 021 * <p>For Java5 one 022 * can optionally enable a monitor which is based upon the Java5 023 * memory classes locate in java.lang.management. 024 * 025 * <p>A client must implement the <code>MemoryMonitor.Listener</code> interface 026 * and register with the <code>MemoryMonitor</code>. 027 * 028 * <p>The <code>MemoryMonitor</code> supports having multiple 029 * <code>Listener</code> clients. The clients can have the same 030 * threshold percentage or different values. The threshold percentage value 031 * is used by the <code>MemoryMonitor</code> to determine when to 032 * notify a client. It is the percentage of the total memory: 033 * <blockquote> 034 * <code> 035 * 100 * free-memory / total-memory (0 ≤ free-memory ≤ total-memory). 036 * </code> 037 * </blockquote> 038 * 039 * @author Richard M. Emberson 040 * @since Feb 01 2007 041 * @version $Id: //open/mondrian/src/main/mondrian/util/MemoryMonitor.java#5 $ 042 */ 043 public interface MemoryMonitor { 044 045 /** 046 * Adds a <code>Listener</code> to the <code>MemoryMonitor</code> with 047 * a given threshold percentage. 048 * 049 * <p>If the threshold is below the Java5 memory managment system's 050 * threshold, then the Listener is notified from within this 051 * method. 052 * 053 * @param listener the <code>Listener</code> to be added. 054 * @param thresholdPercentage the threshold percentage for this 055 * <code>Listener</code>. 056 * @return <code>true</code> if the <code>Listener</code> was 057 * added and <code>false</code> otherwise. 058 */ 059 boolean addListener(Listener listener, int thresholdPercentage); 060 061 /** 062 * Adds a <code>Listener</code> using the default threshold percentage. 063 * 064 * <p>If the threshold is below the Java5 memory managment system's 065 * threshold, then the Listener is notified from within this 066 * method. 067 * 068 * @param listener the <code>Listener</code> to be added. 069 * @return <code>true</code> if the <code>Listener</code> was 070 * added and <code>false</code> otherwise. 071 */ 072 boolean addListener(final Listener listener); 073 074 /** 075 * Changes the threshold percentage of a given <code>Listener</code>. 076 * 077 * <p>If the new value is below the system's current value, then the 078 * <code>Listener</code> will have its notification callback called 079 * while in this method - so a client should always check if its 080 * notification method was called immediately after calling this 081 * method. 082 * 083 * <p>This method can be used if, for example, an algorithm has 084 * different approaches that result in different memory 085 * usage profiles; one, large memory but fast and 086 * a second which is low-memory but slow. The algorithm starts 087 * with the large memory approach, receives a low memory 088 * notification, switches to the low memory approach and changes 089 * when it should be notified for this new approach. The first 090 * approach need to be notified at a lower percentage because it 091 * uses lots of memory, possibly quickly; while the second 092 * approach, possibly a file based algorithm, has smaller memory 093 * requirements and uses memory less quickly thus one can 094 * live with a higher notification threshold percentage. 095 * 096 * @param listener the <code>Listener</code> being updated. 097 * @param percentage new percentage threshold. 098 */ 099 void updateListenerThreshold(Listener listener, int percentage); 100 101 /** 102 * Removes a <code>Listener</code> from the <code>MemoryMonitor</code>. 103 * Returns <code>true</code> if listener was removed and 104 * <code>false</code> otherwise. 105 * 106 * @param listener the listener to be removed 107 * @return <code>true</code> if listener was removed. 108 */ 109 boolean removeListener(Listener listener); 110 111 /** 112 * Clear out all <code>Listener</code>s and turnoff JVM 113 * memory notification. 114 */ 115 void removeAllListener(); 116 117 /** 118 * Returns the maximum memory usage. 119 * 120 * @return the maximum memory usage. 121 */ 122 long getMaxMemory(); 123 124 /** 125 * Returns the current memory used. 126 * 127 * @return the current memory used. 128 */ 129 long getUsedMemory(); 130 131 132 /** 133 * A <code>MemoryMonitor</code> client implements the <code>Listener</code> 134 * interface and registers with the <code>MemoryMonitor</code>. 135 * When the <code>MemoryMonitor</code> detects that free memory is 136 * low, it notifies the client by calling the client's 137 * <code>memoryUsageNotification</code> method. It is important 138 * that the client quickly return from this call, that the 139 * <code>memoryUsageNotification</code> method does not do a lot of 140 * work. It is best if it simply sets a flag. The flag should be 141 * polled by an application thread and when it detects that the 142 * flag was set, it should take immediate memory relinquishing operations. 143 * In the case of Mondrian, the present query is aborted. 144 */ 145 interface Listener { 146 147 /** 148 * When the <code>MemoryMonitor</code> determines that the 149 * <code>Listener</code>'s threshold is equal to or less than 150 * the current available memory (post garbage collection), 151 * then this method is called with the current memory usage, 152 * <code>usedMemory</code>, and the maximum memory (which 153 * is a constant per JVM invocation). 154 * <p> 155 * This method is called (in the case of Java5) by a system 156 * thread associated with the garbage collection activity. 157 * When this method is called, the client should quickly do what 158 * it needs to to communicate with an application thread and 159 * then return. Generally, quickly de-referencing some big objects 160 * and setting a flag is the most that should be done by 161 * implementations of this method. If the implementor chooses to 162 * de-reference some objects, then the application code must 163 * be written so that if will not throw a NullPointerException 164 * when such de-referenced objects are accessed. If a flag 165 * is set, then the application must be written to check the 166 * flag periodically. 167 * 168 * @param usedMemory the current memory used. 169 * @param maxMemory the maximum available memory. 170 */ 171 void memoryUsageNotification(long usedMemory, long maxMemory); 172 } 173 174 /** 175 * This is an interface that a <code>MemoryMonitor</code> may optionally 176 * implement. These methods give the tester access to some of the 177 * internal, white-box data. 178 * <p> 179 * During testing Mondrian has a default 180 * <code>MemoryMonitor</code> which might be replaced with a test 181 * <code>MemoryMonitor</code>s using the <code>ThreadLocal</code> 182 * mechanism. After the test using the test 183 * <code>MemoryMonitor</code> finishes, a call to the 184 * <code>resetFromTest</code> method allows 185 * the default <code>MemoryMonitor</code> reset itself. 186 * This is hook that should only be called as part of testing. 187 */ 188 interface Test { 189 190 /** 191 * This should only be called when one is switching from a 192 * test <code>MemoryMonitor</code> back to the default system 193 * <code>MemoryMonitor</code>. In particular, look at 194 * the <code>MemoryMonitorFactory</code>'s 195 * <code>clearThreadLocalClassName()</code> method for its 196 * usage. 197 */ 198 void resetFromTest(); 199 } 200 } 201 202 // End MemoryMonitor.java