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 &le; free-memory &le; 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