org.apache.phoenix.cache.TenantCacheImpl Maven / Gradle / Ivy
The newest version!
/*
* 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.phoenix.cache;
import java.io.Closeable;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.binary.Hex;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.coprocessor.ServerCachingProtocol.ServerCacheFactory;
import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr;
import org.apache.phoenix.memory.MemoryManager;
import org.apache.phoenix.memory.MemoryManager.MemoryChunk;
import org.apache.phoenix.util.Closeables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Ticker;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
/**
*
* Cache per tenant on server side. Tracks memory usage for each
* tenat as well and rolling up usage to global memory manager.
*
*
* @since 0.1
*/
public class TenantCacheImpl implements TenantCache {
private static final Logger LOGGER = LoggerFactory.getLogger(TenantCacheImpl.class);
private final int maxTimeToLiveMs;
private final int maxPersistenceTimeToLiveMs;
private final MemoryManager memoryManager;
private final Ticker ticker;
// Two caches exist: the "serverCaches" cache which is used for handling live
// queries, and the "persistentServerCaches" cache which is used to store data
// between queries. If we are out of memory, attempt to clear out entries from
// the persistent cache before throwing an exception.
private volatile Cache serverCaches;
private volatile Cache persistentServerCaches;
private final long EVICTION_MARGIN_BYTES = 10000000;
private static class CacheEntry implements Comparable, Closeable {
private ImmutableBytesPtr cacheId;
private ImmutableBytesWritable cachePtr;
private int hits;
private int liveQueriesCount;
private boolean usePersistentCache;
private long size;
private Closeable closeable;
public CacheEntry(ImmutableBytesPtr cacheId, ImmutableBytesWritable cachePtr,
ServerCacheFactory cacheFactory, byte[] txState, MemoryChunk chunk,
boolean usePersistentCache, boolean useProtoForIndexMaintainer,
int clientVersion) throws SQLException {
this.cacheId = cacheId;
this.cachePtr = cachePtr;
this.size = cachePtr.getLength();
this.hits = 0;
this.liveQueriesCount = 0;
this.usePersistentCache = usePersistentCache;
this.closeable = cacheFactory.newCache(cachePtr, txState, chunk, useProtoForIndexMaintainer, clientVersion);
}
public void close() throws IOException {
this.closeable.close();
}
synchronized public void incrementLiveQueryCount() {
liveQueriesCount++;
hits++;
}
synchronized public void decrementLiveQueryCount() {
liveQueriesCount--;
}
synchronized public boolean isLive() {
return liveQueriesCount > 0;
}
public boolean getUsePersistentCache() {
return usePersistentCache;
}
public ImmutableBytesPtr getCacheId() {
return cacheId;
}
private Float rank() {
return (float)hits;
}
@Override
public int compareTo(CacheEntry o) {
return rank().compareTo(o.rank());
}
}
public TenantCacheImpl(MemoryManager memoryManager, int maxTimeToLiveMs, int maxPersistenceTimeToLiveMs) {
this(memoryManager, maxTimeToLiveMs, maxPersistenceTimeToLiveMs, Ticker.systemTicker());
}
public TenantCacheImpl(MemoryManager memoryManager, int maxTimeToLiveMs, int maxPersistenceTimeToLiveMs, Ticker ticker) {
this.memoryManager = memoryManager;
this.maxTimeToLiveMs = maxTimeToLiveMs;
this.maxPersistenceTimeToLiveMs = maxPersistenceTimeToLiveMs;
this.ticker = ticker;
}
public Ticker getTicker() {
return ticker;
}
// For testing
public void cleanUp() {
synchronized(this) {
if (serverCaches != null) {
serverCaches.cleanUp();
}
if (persistentServerCaches != null) {
persistentServerCaches.cleanUp();
}
}
}
@Override
public MemoryManager getMemoryManager() {
return memoryManager;
}
private Cache getServerCaches() {
/* Delay creation of this map until it's needed */
if (serverCaches == null) {
synchronized(this) {
if (serverCaches == null) {
serverCaches = buildCache(maxTimeToLiveMs, false);
}
}
}
return serverCaches;
}
private Cache getPersistentServerCaches() {
/* Delay creation of this map until it's needed */
if (persistentServerCaches == null) {
synchronized(this) {
if (persistentServerCaches == null) {
persistentServerCaches = buildCache(maxPersistenceTimeToLiveMs, true);
}
}
}
return persistentServerCaches;
}
private Cache buildCache(final int ttl, final boolean isPersistent) {
CacheBuilder
© 2015 - 2024 Weber Informatics LLC | Privacy Policy