001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.usage; 018 019import java.util.concurrent.TimeUnit; 020 021/** 022 * Used to keep track of how much of something is being used so that a 023 * productive working set usage can be controlled. Main use case is manage 024 * memory usage. 025 * 026 * @org.apache.xbean.XBean 027 * 028 */ 029public class MemoryUsage extends Usage<MemoryUsage> { 030 031 private long usage; 032 033 public MemoryUsage() { 034 this(null, null); 035 } 036 037 /** 038 * Create the memory manager linked to a parent. When the memory manager is 039 * linked to a parent then when usage increased or decreased, the parent's 040 * usage is also increased or decreased. 041 * 042 * @param parent 043 */ 044 public MemoryUsage(MemoryUsage parent) { 045 this(parent, "default"); 046 } 047 048 public MemoryUsage(String name) { 049 this(null, name); 050 } 051 052 public MemoryUsage(MemoryUsage parent, String name) { 053 this(parent, name, 1.0f); 054 } 055 056 public MemoryUsage(MemoryUsage parent, String name, float portion) { 057 super(parent, name, portion); 058 } 059 060 /** 061 * @throws InterruptedException 062 */ 063 @Override 064 public void waitForSpace() throws InterruptedException { 065 if (parent != null) { 066 parent.waitForSpace(); 067 } 068 usageLock.readLock().lock(); 069 try { 070 if (percentUsage >= 100 && isStarted()) { 071 usageLock.readLock().unlock(); 072 usageLock.writeLock().lock(); 073 try { 074 while (percentUsage >= 100 && isStarted()) { 075 waitForSpaceCondition.await(); 076 } 077 usageLock.readLock().lock(); 078 } finally { 079 usageLock.writeLock().unlock(); 080 } 081 } 082 083 if (percentUsage >= 100 && !isStarted()) { 084 throw new InterruptedException("waitForSpace stopped during wait."); 085 } 086 } finally { 087 usageLock.readLock().unlock(); 088 } 089 } 090 091 /** 092 * @param timeout 093 * @throws InterruptedException 094 * @return true if space 095 */ 096 @Override 097 public boolean waitForSpace(long timeout) throws InterruptedException { 098 if (parent != null) { 099 if (!parent.waitForSpace(timeout)) { 100 return false; 101 } 102 } 103 usageLock.readLock().lock(); 104 try { 105 if (percentUsage >= 100) { 106 usageLock.readLock().unlock(); 107 usageLock.writeLock().lock(); 108 try { 109 while (percentUsage >= 100 ) { 110 waitForSpaceCondition.await(timeout, TimeUnit.MILLISECONDS); 111 } 112 usageLock.readLock().lock(); 113 } finally { 114 usageLock.writeLock().unlock(); 115 } 116 } 117 118 return percentUsage < 100; 119 } finally { 120 usageLock.readLock().unlock(); 121 } 122 } 123 124 @Override 125 public boolean isFull() { 126 if (parent != null && parent.isFull()) { 127 return true; 128 } 129 usageLock.readLock().lock(); 130 try { 131 return percentUsage >= 100; 132 } finally { 133 usageLock.readLock().unlock(); 134 } 135 } 136 137 /** 138 * Tries to increase the usage by value amount but blocks if this object is 139 * currently full. 140 * 141 * @param value 142 * @throws InterruptedException 143 */ 144 public void enqueueUsage(long value) throws InterruptedException { 145 waitForSpace(); 146 increaseUsage(value); 147 } 148 149 /** 150 * Increases the usage by the value amount. 151 * 152 * @param value 153 */ 154 public void increaseUsage(long value) { 155 if (value == 0) { 156 return; 157 } 158 159 usageLock.writeLock().lock(); 160 try { 161 usage += value; 162 setPercentUsage(caclPercentUsage()); 163 } finally { 164 usageLock.writeLock().unlock(); 165 } 166 167 if (parent != null) { 168 parent.increaseUsage(value); 169 } 170 } 171 172 /** 173 * Decreases the usage by the value amount. 174 * 175 * @param value 176 */ 177 public void decreaseUsage(long value) { 178 if (value == 0) { 179 return; 180 } 181 182 usageLock.writeLock().lock(); 183 try { 184 usage -= value; 185 setPercentUsage(caclPercentUsage()); 186 } finally { 187 usageLock.writeLock().unlock(); 188 } 189 190 if (parent != null) { 191 parent.decreaseUsage(value); 192 } 193 } 194 195 @Override 196 protected long retrieveUsage() { 197 return usage; 198 } 199 200 @Override 201 public long getUsage() { 202 return usage; 203 } 204 205 public void setUsage(long usage) { 206 this.usage = usage; 207 } 208 209 public void setPercentOfJvmHeap(int percentOfJvmHeap) { 210 if (percentOfJvmHeap > 0) { 211 setLimit(Math.round(Runtime.getRuntime().maxMemory() * percentOfJvmHeap / 100.0)); 212 } 213 } 214}