/* * 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() {} }