/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.runner.internal; import org.eclipse.che.api.runner.RunnerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import java.util.concurrent.Semaphore; /** * Allocator for resources. * Usage (memory allocation as example): * <pre> * int mem = ... * ResourceAllocator memAllocator = ResourceAllocators.getInstance().newMemoryAllocator(mem).allocate(); * try { * // do something * } finally { * memAllocator.release(); * } * </pre> * * @author andrew00x */ @Singleton public class ResourceAllocators { /** @deprecated use {@link Constants#TOTAL_APPS_MEM_SIZE}. */ public static final String TOTAL_APPS_MEM_SIZE = Constants.TOTAL_APPS_MEM_SIZE; private static final Logger LOG = LoggerFactory.getLogger(ResourceAllocators.class); private final int memSize; private final Semaphore memSemaphore; @Inject public ResourceAllocators(@Named(Constants.TOTAL_APPS_MEM_SIZE) int memSize) { if (memSize <= 0) { throw new IllegalArgumentException(String.format("Invalid mem size %d", memSize)); } this.memSize = memSize; memSemaphore = new Semaphore(memSize); } /** * Create new memory allocator. Returned instance doesn't manage memory directly or indirectly it just remembers size of requested * memory and prevents getting more amount of memory than it is set in configuration. To 'allocate' memory caller must call method * {@link ResourceAllocator#allocate()}. It is important to call method {@link * ResourceAllocator#release()} to release allocated memory. Typically this should be done after stopping of * application. * * @param size * memory size in megabytes * @return memory allocator * @see #freeMemory() * @see #totalMemory() * @see Constants#TOTAL_APPS_MEM_SIZE */ public ResourceAllocator newMemoryAllocator(int size) { return new MemoryAllocator(size); } /** * Returns amount of 'free' memory in megabytes. The returned value is not related to amount of free memory in the Java virtual * machine or free physical memory. It shows how much memory is available for <b>all</b> Runners for starting new applications. * * @return amount of 'free' memory in megabytes * @see #totalMemory() * @see Constants#TOTAL_APPS_MEM_SIZE */ public int freeMemory() { return memSemaphore.availablePermits(); } /** * Returns 'total' amount of memory in megabytes. The returned value is not related to amount of memory in the Java virtual machine or * total physical memory. It shows how much memory is defined for <b>all</b> Runners for starting applications. * * @return amount of 'total' memory in megabytes * @see #freeMemory() * @see Constants#TOTAL_APPS_MEM_SIZE */ public int totalMemory() { return memSize; } /* ===== INTERNAL STUFF ===== */ /** Manages memory available for running applications. */ private class MemoryAllocator implements ResourceAllocator { final int size; MemoryAllocator(int size) { this.size = size; } @Override public MemoryAllocator allocate() throws RunnerException { if (!memSemaphore.tryAcquire(size)) { throw new RunnerException(String.format("Couldn't allocate %dM for starting application", size)); } LOG.debug("allocate memory: {}M, available: {}M", size, memSemaphore.availablePermits()); return this; } @Override public void release() { memSemaphore.release(size); LOG.debug("release memory: {}M, available: {}M", size, memSemaphore.availablePermits()); } } }