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(final 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 final long deadline = timeout > 0 ? System.currentTimeMillis() + timeout : Long.MAX_VALUE; 110 long timeleft = deadline; 111 while (percentUsage >= 100 && timeleft > 0) { 112 waitForSpaceCondition.await(Math.min(getPollingTime(), timeleft), TimeUnit.MILLISECONDS); 113 timeleft = deadline - System.currentTimeMillis(); 114 } 115 } finally { 116 usageLock.writeLock().unlock(); 117 usageLock.readLock().lock(); 118 } 119 } 120 121 return percentUsage < 100; 122 } finally { 123 usageLock.readLock().unlock(); 124 } 125 } 126 127 @Override 128 public boolean isFull() { 129 if (parent != null && parent.isFull()) { 130 return true; 131 } 132 usageLock.readLock().lock(); 133 try { 134 return percentUsage >= 100; 135 } finally { 136 usageLock.readLock().unlock(); 137 } 138 } 139 140 /** 141 * Tries to increase the usage by value amount but blocks if this object is 142 * currently full. 143 * 144 * @param value 145 * @throws InterruptedException 146 */ 147 public void enqueueUsage(long value) throws InterruptedException { 148 waitForSpace(); 149 increaseUsage(value); 150 } 151 152 /** 153 * Increases the usage by the value amount. 154 * 155 * @param value 156 */ 157 public void increaseUsage(long value) { 158 if (value == 0) { 159 return; 160 } 161 162 usageLock.writeLock().lock(); 163 try { 164 usage += value; 165 setPercentUsage(caclPercentUsage()); 166 } finally { 167 usageLock.writeLock().unlock(); 168 } 169 170 if (parent != null) { 171 parent.increaseUsage(value); 172 } 173 } 174 175 /** 176 * Decreases the usage by the value amount. 177 * 178 * @param value 179 */ 180 public void decreaseUsage(long value) { 181 if (value == 0) { 182 return; 183 } 184 185 usageLock.writeLock().lock(); 186 try { 187 usage -= value; 188 setPercentUsage(caclPercentUsage()); 189 } finally { 190 usageLock.writeLock().unlock(); 191 } 192 193 if (parent != null) { 194 parent.decreaseUsage(value); 195 } 196 } 197 198 @Override 199 protected long retrieveUsage() { 200 return usage; 201 } 202 203 @Override 204 public long getUsage() { 205 return usage; 206 } 207 208 public void setUsage(long usage) { 209 this.usage = usage; 210 } 211 212 public void setPercentOfJvmHeap(int percentOfJvmHeap) { 213 if (percentOfJvmHeap > 0) { 214 setLimit(Math.round(Runtime.getRuntime().maxMemory() * percentOfJvmHeap / 100.0)); 215 } 216 } 217}