/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.blur.store.blockcache_v2; import java.util.Map.Entry; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.blur.log.Log; import org.apache.blur.log.LogFactory; import org.apache.blur.store.blockcache_v2.BaseCache.STORE; import org.apache.blur.store.blockcache_v2.cachevalue.ByteArrayCacheValue; import org.apache.blur.store.blockcache_v2.cachevalue.UnsafeAllocateCacheValue; public class SimpleCacheValueBufferPool extends BaseCacheValueBufferPool { private static final Log LOG = LogFactory.getLog(SimpleCacheValueBufferPool.class); private final ConcurrentMap<Integer, BlockingQueue<CacheValue>> _cacheValuePool = new ConcurrentHashMap<Integer, BlockingQueue<CacheValue>>(); private final int _queueDepth; public SimpleCacheValueBufferPool(STORE store, int queueDepth) { super(store); _queueDepth = queueDepth; } public CacheValue getCacheValue(int cacheBlockSize) { BlockingQueue<CacheValue> blockingQueue = getPool(cacheBlockSize); CacheValue cacheValue = blockingQueue.poll(); if (cacheValue == null) { _created.mark(); return createCacheValue(cacheBlockSize); } _reused.mark(); return cacheValue; } private BlockingQueue<CacheValue> getPool(int cacheBlockSize) { BlockingQueue<CacheValue> blockingQueue = _cacheValuePool.get(cacheBlockSize); if (blockingQueue == null) { blockingQueue = buildNewBlockQueue(cacheBlockSize); } return blockingQueue; } private BlockingQueue<CacheValue> buildNewBlockQueue(int cacheBlockSize) { LOG.info("Allocating new ArrayBlockingQueue with capacity [{0}]", _queueDepth); BlockingQueue<CacheValue> value = new ArrayBlockingQueue<CacheValue>(_queueDepth); _cacheValuePool.putIfAbsent(cacheBlockSize, value); return _cacheValuePool.get(cacheBlockSize); } private CacheValue createCacheValue(int cacheBlockSize) { switch (_store) { case ON_HEAP: return new ByteArrayCacheValue(cacheBlockSize); case OFF_HEAP: return new UnsafeAllocateCacheValue(cacheBlockSize); default: throw new RuntimeException("Unknown type [" + _store + "]"); } } public void returnToPool(CacheValue cacheValue) { if (cacheValue == null || cacheValue.isEvicted()) { return; } try { BlockingQueue<CacheValue> blockingQueue = getPool(cacheValue.length()); if (!blockingQueue.offer(cacheValue)) { _detroyed.mark(); cacheValue.release(); } } catch (EvictionException e) { return; } } @Override public void close() { for (Entry<Integer, BlockingQueue<CacheValue>> e : _cacheValuePool.entrySet()) { BlockingQueue<CacheValue> queue = _cacheValuePool.remove(e.getKey()); for (CacheValue cacheValue : queue) { cacheValue.release(); } } } }