/*
* Copyright (C) 2014 Indeed Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.indeed.imhotep;
import com.google.common.base.Throwables;
/**
* @author jsadun
*/
public final class MemoryReservationContext extends MemoryReserver {
private final MemoryReserver memoryReserver;
private long reservationSize = 0;
private boolean closed = false;
public MemoryReservationContext(MemoryReserver memoryReserver) {
this.memoryReserver = memoryReserver;
}
public long usedMemory() {
return reservationSize;
}
public long totalMemory() {
return memoryReserver.totalMemory();
}
public synchronized boolean claimMemory(long numBytes) {
if (closed) throw new IllegalStateException("cannot allocate memory after reservation context has been closed");
if (memoryReserver.claimMemory(numBytes)) {
reservationSize += numBytes;
return true;
}
return false;
}
public synchronized void releaseMemory(long numBytes) {
if (closed) throw new IllegalStateException("cannot free memory after reservation context has been closed");
if (numBytes > reservationSize) {
throw new IllegalArgumentException("trying to free too many bytes: " + numBytes + ", current size: " + (reservationSize));
}
reservationSize -= numBytes;
try {
memoryReserver.releaseMemory(numBytes);
} catch (Exception e) {
reservationSize += numBytes;
throw Throwables.propagate(e);
}
}
public synchronized void hoist(long numBytes) {
if (closed) throw new IllegalStateException("cannot hoist memory after reservation context has been closed");
if (numBytes > reservationSize) {
throw new IllegalArgumentException("trying to hoist too many bytes: " + numBytes + ", current size: " + reservationSize);
}
reservationSize -= numBytes;
}
public synchronized void dehoist(long numBytes) {
if (closed) throw new IllegalStateException("cannot dehoist memory after reservation context has been closed");
reservationSize += numBytes;
}
@Override
public synchronized void close() {
if (reservationSize > 0) {
memoryReserver.releaseMemory(reservationSize);
reservationSize = 0;
}
closed = true;
}
}