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
019/**
020 * Used to keep track of how much of something is being used so that a
021 * productive working set usage can be controlled. Main use case is manage
022 * memory usage.
023 * 
024 * @org.apache.xbean.XBean
025 * 
026 */
027public class MemoryUsage extends Usage<MemoryUsage> {
028
029    private long usage;
030
031    public MemoryUsage() {
032        this(null, null);
033    }
034
035    /**
036     * Create the memory manager linked to a parent. When the memory manager is
037     * linked to a parent then when usage increased or decreased, the parent's
038     * usage is also increased or decreased.
039     * 
040     * @param parent
041     */
042    public MemoryUsage(MemoryUsage parent) {
043        this(parent, "default");
044    }
045
046    public MemoryUsage(String name) {
047        this(null, name);
048    }
049
050    public MemoryUsage(MemoryUsage parent, String name) {
051        this(parent, name, 1.0f);
052    }
053
054    public MemoryUsage(MemoryUsage parent, String name, float portion) {
055        super(parent, name, portion);
056    }
057
058    /**
059     * @throws InterruptedException
060     */
061    public void waitForSpace() throws InterruptedException {
062        if (parent != null) {
063            parent.waitForSpace();
064        }
065        synchronized (usageMutex) {
066            for (int i = 0; percentUsage >= 100; i++) {
067                usageMutex.wait();
068            }
069        }
070    }
071
072    /**
073     * @param timeout
074     * @throws InterruptedException
075     * @return true if space
076     */
077    public boolean waitForSpace(long timeout) throws InterruptedException {
078        if (parent != null) {
079            if (!parent.waitForSpace(timeout)) {
080                return false;
081            }
082        }
083        synchronized (usageMutex) {
084            if (percentUsage >= 100) {
085                usageMutex.wait(timeout);
086            }
087            return percentUsage < 100;
088        }
089    }
090
091    public boolean isFull() {
092        if (parent != null && parent.isFull()) {
093            return true;
094        }
095        synchronized (usageMutex) {
096            return percentUsage >= 100;
097        }
098    }
099
100    /**
101     * Tries to increase the usage by value amount but blocks if this object is
102     * currently full.
103     * 
104     * @param value
105     * @throws InterruptedException
106     */
107    public void enqueueUsage(long value) throws InterruptedException {
108        waitForSpace();
109        increaseUsage(value);
110    }
111
112    /**
113     * Increases the usage by the value amount.
114     * 
115     * @param value
116     */
117    public void increaseUsage(long value) {
118        if (value == 0) {
119            return;
120        }
121        int percentUsage;
122        synchronized (usageMutex) {
123            usage += value;
124            percentUsage = caclPercentUsage();
125        }
126        setPercentUsage(percentUsage);
127        if (parent != null) {
128            ((MemoryUsage)parent).increaseUsage(value);
129        }
130    }
131
132    /**
133     * Decreases the usage by the value amount.
134     * 
135     * @param value
136     */
137    public void decreaseUsage(long value) {
138        if (value == 0) {
139            return;
140        }
141        int percentUsage;
142        synchronized (usageMutex) {
143            usage -= value;
144            percentUsage = caclPercentUsage();
145        }
146        setPercentUsage(percentUsage);
147        if (parent != null) {
148            parent.decreaseUsage(value);
149        }
150    }
151
152    protected long retrieveUsage() {
153        return usage;
154    }
155
156    public long getUsage() {
157        return usage;
158    }
159
160    public void setUsage(long usage) {
161        this.usage = usage;
162    }
163}