package org.dcache.pool.repository;
/**
* Encapsulation of space accounting information for a
* repository.
*
* Used as a synchronisation point between several repository
* components. The object is thread safe and external synchronisations
* are allowed. Any modification of the object triggers a call to
* notifyAll on the object.
*/
public class Account
{
private long _total;
private long _used;
private long _precious;
private long _removable;
private long _requested;
private long _timeOfLastFree;
public synchronized long getTotal()
{
return _total;
}
public synchronized long getUsed()
{
return _used;
}
public synchronized long getFree()
{
return _total - _used;
}
public synchronized long getRemovable()
{
return _removable;
}
public synchronized long getPrecious()
{
return _precious;
}
public synchronized long getRequested()
{
return _requested;
}
public synchronized long getTimeOfLastFree()
{
return _timeOfLastFree;
}
public synchronized void setTotal(long total)
{
if (total < _used) {
throw new IllegalArgumentException("Cannot set repository size below amount of used space.");
}
_total = total;
notifyAll();
}
/**
* Moves <code>space</code> bytes from used to free space.
*/
public synchronized void free(long space)
{
if (space < 0) {
throw new IllegalArgumentException("Cannot free negative space.");
}
if (_used < space) {
throw new IllegalArgumentException("Cannot set used space to a negative value.");
}
notifyAll();
_used -= space;
_timeOfLastFree = System.currentTimeMillis();
}
/**
* Allocates up to <code>request</code> bytes. If less space is
* free, then nothing is allocated.
*
* @return true if and only if the request was served
*/
public synchronized boolean allocateNow(long request)
throws InterruptedException
{
if (request < 0) {
throw new IllegalArgumentException("Cannot allocate negative space.");
}
_requested += request;
try {
while (request > getFree() && request <= getFree() + getRemovable()) {
notifyAll();
wait();
}
if (request > getFree()) {
return false;
}
_used += request;
notifyAll();
} finally {
_requested -= request;
}
return true;
}
/**
* Allocates <code>request</code> bytes. If less space is
* available, the request is added to the request pool and the
* call blocks. Space is not allocated until the complete request
* can be served. For this reason, large requests can starve.
*/
public synchronized void allocate(long request)
throws InterruptedException
{
if (request < 0) {
throw new IllegalArgumentException("Cannot allocate negative space.");
}
_requested += request;
try {
while (request > getFree()) {
notifyAll();
wait();
}
_used += request;
notifyAll();
} finally {
_requested -= request;
}
}
public synchronized void growTotalAndUsed(long delta)
{
if (delta < 0) {
throw new IllegalArgumentException("Argument must be non-negative.");
}
long used = _used + delta;
long total = _total + delta;
if (used < 0) {
throw new IllegalArgumentException("Negative used space is not allowed.");
}
if (total < 0) {
throw new IllegalArgumentException("Negative total space is not allowed.");
}
if (_removable > total) {
throw new IllegalArgumentException("Removable space would exceed repository size.");
}
if (_precious > total) {
throw new IllegalArgumentException("Precious space would exceed repository size.");
}
_total = total;
_used = used;
notifyAll();
}
public synchronized void adjustRemovable(long delta)
{
long removable = _removable + delta;
if (removable < 0) {
throw new IllegalArgumentException("Negative removable space is not allowed.");
}
if (removable > _total) {
throw new IllegalArgumentException("Removable space would exceed repository size.");
}
_removable = removable;
notifyAll();
}
public synchronized void adjustPrecious(long delta)
{
long precious = _precious + delta;
if (precious < 0) {
throw new IllegalArgumentException("Negative precious space is not allowed.");
}
if (precious > _total) {
throw new IllegalArgumentException("Precious space would exceed repository size.");
}
_precious = precious;
notifyAll();
}
public synchronized SpaceRecord getSpaceRecord()
{
return new SpaceRecord(_total, getFree(), _precious, _removable, 0);
}
}