/* * eXist Open Source Native XML Database * Copyright (C) 2001-2016 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.exist.storage; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.collections.CollectionCache; import org.exist.storage.cache.Cache; import org.exist.util.Configuration; import org.exist.util.DatabaseConfigurationException; import org.exist.management.AgentFactory; import org.exist.management.Agent; import java.util.Optional; public class CollectionCacheManager implements CacheManager, BrokerPoolService { private static final Logger LOG = LogManager.getLogger(CollectionCacheManager.class); private static final int DEFAULT_CACHE_SIZE_BYTES = 64 * 1024 * 1024; // 64 MB public static final String CACHE_SIZE_ATTRIBUTE = "collectionCache"; public static final String PROPERTY_CACHE_SIZE_BYTES = "db-connection.collection-cache-mem"; private final String brokerPoolId; private CollectionCache collectionCache; private int maxCacheSize; public CollectionCacheManager(final BrokerPool pool, final CollectionCache cache) { this.brokerPoolId = pool.getId(); this.collectionCache = cache; this.collectionCache.setCacheManager(this); } @Override public void configure(final Configuration configuration) throws BrokerPoolServiceException { final int cacheSize = Optional.of(configuration.getInteger(PROPERTY_CACHE_SIZE_BYTES)).filter(size -> size > 0) .orElse(DEFAULT_CACHE_SIZE_BYTES); this.maxCacheSize = cacheSize; if(LOG.isDebugEnabled()){ LOG.debug("collection collectionCache will be using " + this.maxCacheSize + " bytes max."); } //TODO(AR) move to some start method... registerMBean(brokerPoolId); } @Override public void registerCache(final Cache cache) { } @Override public void deregisterCache(final Cache cache) { this.collectionCache = null; } @Override public int requestMem(final Cache cache) { final int realSize = collectionCache.getRealSize(); if (realSize < maxCacheSize) { synchronized (this) { final int newCacheSize = (int)(collectionCache.getBuffers() * collectionCache.getGrowthFactor()); if (LOG.isDebugEnabled()) { LOG.debug("Growing cache {} (a {}) from {} to {} bytes. Current memory usage = {}", collectionCache.getName(), collectionCache.getClass().getName(), collectionCache.getBuffers(), newCacheSize, realSize); } collectionCache.resize(newCacheSize); return newCacheSize; } } if(LOG.isDebugEnabled()) { LOG.debug("Cache has reached max. size: " + realSize); } return -1; } @Override public void checkCaches() { } @Override public void checkDistribution() { } /** * @return Maximum size of all Caches in bytes */ @Override public long getMaxTotal() { return maxCacheSize; } /** * @return Maximum size of a single Cache in bytes */ @Override public long getMaxSingle() { return maxCacheSize; } /** * @return Current size of all Caches in bytes */ @Override public long getCurrentSize() { return collectionCache.getRealSize(); } @Override public int getDefaultInitialSize() { return DEFAULT_CACHE_SIZE_BYTES; } private void registerMBean(final String instanceName) { final Agent agent = AgentFactory.getInstance(); try { agent.addMBean(instanceName, "org.exist.management." + instanceName + ":type=CollectionCacheManager", new org.exist.management.CacheManager(this)); } catch (final DatabaseConfigurationException e) { LOG.warn("Exception while registering cache mbean.", e); } } }