/*
* 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.indeed.util.varexport.Export;
import com.indeed.util.varexport.VarExporter;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author jsgroth
*/
/**
* a class for managing large memory allocations to help prevent an ImhotepDaemon from slamming into OutOfMemoryError
* primary allocation candidates for being managed:
* - allocating a new ImhotepLocalSession (specifically the docIdToGroupId array)
* - loading a new metric (most of these involve caching an int field of an inverted index)
*/
public final class ImhotepMemoryPool extends MemoryReserver {
private final long capacityInBytes;
private final AtomicLong sizeInBytes = new AtomicLong(0);
public ImhotepMemoryPool(long capacityInBytes) {
this.capacityInBytes = capacityInBytes;
VarExporter.forNamespace(getClass().getSimpleName()).includeInGlobal().export(this, "");
}
@Export(name = "used-memory", doc = "claimed memory in bytes")
public final long usedMemory() {
return sizeInBytes.get();
}
@Export(name = "total-memory", doc = "total memory in bytes")
public final long totalMemory() {
return capacityInBytes;
}
public final boolean claimMemory(long numBytes) {
if (numBytes < 0) return false;
final long used = sizeInBytes.addAndGet(numBytes);
if (used > capacityInBytes || used < 0) {
sizeInBytes.addAndGet(-numBytes);
return false;
}
return true;
}
public final void releaseMemory(long numBytes) {
final long used = sizeInBytes.addAndGet(-numBytes);
if (used < 0) {
sizeInBytes.addAndGet(numBytes);
throw new IllegalArgumentException("trying to free too many bytes: " + numBytes + ", current size: " + (used+numBytes));
}
}
@Override
public void close() {}
}