KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > web > ara > rules > HeapMemoryRule


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.web.ara.rules;
25
26 import com.sun.enterprise.web.ara.IsolationRulesExecutor;
27 import com.sun.enterprise.web.connector.grizzly.Pipeline;
28 import com.sun.enterprise.web.connector.grizzly.LinkedListPipeline;
29 import com.sun.enterprise.web.connector.grizzly.ReadTask;
30 import com.sun.enterprise.web.connector.grizzly.SelectorThread;
31 import com.sun.enterprise.web.connector.grizzly.Task;
32 import com.sun.enterprise.web.connector.grizzly.TaskEvent;
33 import com.sun.enterprise.web.connector.grizzly.TaskListener;
34 import com.sun.enterprise.web.connector.grizzly.WorkerThread;
35 import java.util.Iterator JavaDoc;
36 import java.util.concurrent.ConcurrentHashMap JavaDoc;
37 import java.util.logging.Level JavaDoc;
38
39 /**
40  * Based on the application context-root, configure the <code>ReadTask</code>
41  * <code>Pipeline</code> based on the policy metric defined in domain.xml.
42  *
43  * @author Jeanfrancois Arcand
44  */

45 public class HeapMemoryRule extends ThreadRatioRule implements TaskListener{
46
47     /**
48      * The memory allocated per application.
49      */

50     protected static ConcurrentHashMap JavaDoc<String JavaDoc,Long JavaDoc>
51             memoryAllowed = new ConcurrentHashMap JavaDoc<String JavaDoc,Long JavaDoc>();
52
53                        
54     /**
55      * The memory available at startup.
56      */

57     private static long availableMemory = -1L;
58     
59     
60     /**
61      * Cache application memory usage approximation.
62      */

63     protected static ConcurrentHashMap JavaDoc<String JavaDoc,Long JavaDoc>
64             appMemoryUsage = new ConcurrentHashMap JavaDoc<String JavaDoc,Long JavaDoc>();
65     
66     
67     /**
68      * Cache the context-root assocated with a <code>ReadTask</code>
69      */

70     protected static ConcurrentHashMap JavaDoc<ReadTask,String JavaDoc>
71             contextRootyCache = new ConcurrentHashMap JavaDoc<ReadTask,String JavaDoc>();
72          
73     
74     /**
75      * A customized <code>Pipeline</code> used to measure the memory used
76      * by an application.
77      */

78     private static HeapMemoryRulePipeline hmrPipeline;
79
80      
81     /**
82      * The default <code>Pipeline</code> used by application that are
83      * allowed to execute.
84      */

85     private static Pipeline defaultPipeline;
86     
87     
88     /**
89      * The consolidated amount of memory an application is using.
90      */

91     private static ConcurrentHashMap JavaDoc<String JavaDoc,Long JavaDoc>
92             consolidatedMemoryUsed = new ConcurrentHashMap JavaDoc<String JavaDoc,Long JavaDoc>();
93     // ------------------------------------------------ Pipeline ------------//
94

95     public Integer JavaDoc call() throws Exception JavaDoc {
96         if (availableMemory == -1L){
97             availableMemory = usedMemory();
98         }
99               
100         if ( hmrPipeline == null ) {
101             hmrPipeline = new HeapMemoryRulePipeline();
102             hmrPipeline.initPipeline();
103             hmrPipeline.startPipeline();
104         }
105         
106         String JavaDoc token = getContextRoot();
107         Long JavaDoc memoryAllowedSize = memoryAllowed.get(token);
108         Double JavaDoc allowedRatio = privilegedTokens.get(token);
109         
110         Pipeline pipeline = pipelines.get(token);
111         if ( pipeline == null ){
112             if ( defaultPipeline == null) {
113                 defaultPipeline = newPipeline(readTask.getPipeline()
114                     .getMaxThreads(),readTask.getPipeline());
115             }
116             pipelines.put(token,defaultPipeline);
117             readTask.setPipeline(defaultPipeline);
118         } else {
119             readTask.setPipeline(pipeline);
120         }
121         
122         // If no policy metry has been defined for this token and there
123
// is free memory, allow execution.
124
if ( memoryAllowedSize == null && allowedRatio == null){
125             if ( countReservedMemory() <= availableMemory) {
126                 return IsolationRulesExecutor.RULE_OK_NOCACHE;
127             }
128             
129             if ( allocationPolicy.equals(RESERVE) )
130                 return IsolationRulesExecutor.RULE_BLOCKED;
131             else if ( allocationPolicy.equals(CEILING) )
132                 return IsolationRulesExecutor.RULE_DELAY;
133         }
134         
135         boolean isAllowed =
136                 isAllowedToExecute(token,memoryAllowedSize,allowedRatio);
137         
138         pipeline = pipelines.get(token);
139         if ( pipeline != null)
140             readTask.setPipeline(pipeline);
141         
142         if ( !isAllowed ) {
143             if ( allocationPolicy.equals(RESERVE) )
144                 return IsolationRulesExecutor.RULE_BLOCKED;
145             else if ( allocationPolicy.equals(CEILING) )
146                 return IsolationRulesExecutor.RULE_DELAY;
147         }
148         return IsolationRulesExecutor.RULE_OK_NOCACHE;
149     }
150
151     
152     /**
153      * Determine if an application can execute based on its policy metric and
154      * method.
155      */

156     protected boolean isAllowedToExecute(String JavaDoc token, Long JavaDoc memoryAllowedSize,
157             Double JavaDoc allowedRatio) throws Exception JavaDoc{
158         
159         long currentMemory = usedMemory();
160        
161         // First request, needs to calculate the ratio.
162
if ( memoryAllowedSize == null ){
163             memoryAllowedSize =
164                     (availableMemory * allowedRatio.longValue())/100;
165             // We must find the allowed size based on the ratio.
166
memoryAllowed.put(token,memoryAllowedSize);
167         }
168         
169         if ( memoryAllowedSize > currentMemory) {
170             return false;
171         }
172
173         // Do we know how much memory is used?
174
Long JavaDoc usage = appMemoryUsage.get(token);
175         contextRootyCache.put(readTask,token);
176         
177         // If null, we must execute the task to find how much memory
178
// the app consume.
179
if ( usage == null) {
180             pipelines.put(token,hmrPipeline);
181             return true;
182         }
183         
184         // Make sure we can get all memory consumed by the application
185
Long JavaDoc currentAppUsage = consolidatedMemoryUsed.get(token);
186         if ( currentAppUsage == null ) {
187             currentAppUsage = 0L;
188         }
189         
190         usage = currentAppUsage + usage;
191         
192         if ( usage > currentMemory ) return false;
193         
194         if ( usage > memoryAllowedSize ) return false;
195             
196         consolidatedMemoryUsed.put(token,usage);
197         readTask.addTaskListener(this);
198         return true;
199     }
200    
201     
202     /**
203      * Return the total memory required by application which has a policy
204      * metric defined.
205      */

206     private long countReservedMemory(){
207         Iterator JavaDoc<Long JavaDoc> iterator = memoryAllowed.values().iterator();
208         long count = 0L;
209         while (iterator.hasNext()){
210             count += iterator.next();
211         }
212         return count;
213     }
214     
215     
216     /**
217      * Predict the current memory
218      */

219     private static long usedMemory(){
220         Runtime.getRuntime().gc();
221         return Runtime.getRuntime().totalMemory ()
222             - Runtime.getRuntime().freeMemory ();
223     }
224
225     
226     /**
227      * Reduce the memory usage count when an application complete its execution.
228      */

229     public void taskEvent(TaskEvent event) {
230         if ( event.getStatus() == TaskEvent.COMPLETED){
231         
232             String JavaDoc token = contextRootyCache.remove(event.attachement());
233             if ( token != null ) {
234                Long JavaDoc count = consolidatedMemoryUsed.get(token);
235                count -= appMemoryUsage.get(token);
236                consolidatedMemoryUsed.put(token,count);
237             }
238         }
239     }
240
241     
242     /**
243      * Customized <code>Pipeline</code> used to approximate the memory used
244      * by an application.
245      */

246     private static class HeapMemoryRulePipeline extends LinkedListPipeline{
247                 
248         public void initPipeline(){
249             workerThreads = new WorkerThread[1];
250             WorkerThread workerThread = new WorkerThread(this,
251                     "HeapMemoryRuleThread"){
252                 
253                 public void run(){
254                     while (true) {
255                         try{
256                             ReadTask t =
257                                 (ReadTask)HeapMemoryRulePipeline.this.getTask();
258                             if ( t != null){
259                                 long current = usedMemory();
260                                 t.run();
261                                 long usage = usedMemory() - current;
262                                 if ( usage > 0){
263                                     String JavaDoc token =
264                                        contextRootyCache.get(t);
265                                     appMemoryUsage.put(token,usage);
266                                     pipelines.remove(token);
267                                 }
268                             }
269                         } catch (Throwable JavaDoc t) {
270                             SelectorThread.logger().log(Level.SEVERE,
271                                     "workerThread.httpException",t);
272                         }
273                     }
274                 }
275             };
276             workerThread.setPriority(priority);
277             workerThreads[0] = workerThread;
278             threadCount++;
279         }
280         
281         
282         /**
283          * Start the <code>Pipeline</code> and all associated
284          * <code>WorkerThread</code>
285          */

286         public void startPipeline(){
287             if (!isStarted) {
288                 workerThreads[0].start();
289                 isStarted = true;
290             }
291         }
292
293
294         /**
295          * Stop the <code>Pipeline</code> and all associated
296          * <code>WorkerThread</code>
297          */

298         public void stopPipeline(){
299             if (isStarted) {
300                 workerThreads[0].terminate();
301                 isStarted = false;
302             }
303         }
304         
305         
306         /**
307          * Add an object to this pipeline
308          */

309         public synchronized void addTask(Task task) {
310             addLast(task);
311             notify();
312         }
313     }
314 }
Popular Tags