EmptyCache.java
// 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.
// This file is copied from
// https://github.com/trinodb/trino/blob/438/lib/trino-cache/src/main/java/io/trino/cache/EmptyCache.java
// and modified by Doris
package org.apache.doris.common;
import com.google.common.cache.AbstractLoadingCache;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
import com.google.common.cache.CacheStats;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import javax.annotation.Nullable;
class EmptyCache<K, V>
extends AbstractLoadingCache<K, V> {
private final CacheLoader<? super K, V> loader;
private final StatsCounter statsCounter;
EmptyCache(CacheLoader<? super K, V> loader, boolean recordStats) {
this.loader = Objects.requireNonNull(loader, "loader is null");
this.statsCounter = recordStats ? new SimpleStatsCounter() : new NoopStatsCounter();
}
@Override
public V getIfPresent(Object key) {
statsCounter.recordMisses(1);
return null;
}
@Override
public V get(K key)
throws ExecutionException {
return get(key, () -> loader.load(key));
}
@Override
public ImmutableMap<K, V> getAll(Iterable<? extends K> keys)
throws ExecutionException {
try {
Set<K> keySet = ImmutableSet.copyOf(keys);
statsCounter.recordMisses(keySet.size());
@SuppressWarnings("unchecked") // safe since all keys extend K
ImmutableMap<K, V> result = (ImmutableMap<K, V>) loader.loadAll(keySet);
for (K key : keySet) {
if (!result.containsKey(key)) {
throw new InvalidCacheLoadException("loadAll failed to return a value for " + key);
}
}
statsCounter.recordLoadSuccess(1);
return result;
} catch (RuntimeException e) {
statsCounter.recordLoadException(1);
throw new UncheckedExecutionException(e);
} catch (Exception e) {
statsCounter.recordLoadException(1);
throw new ExecutionException(e);
}
}
@Override
public V get(K key, Callable<? extends V> valueLoader)
throws ExecutionException {
statsCounter.recordMisses(1);
try {
V value = valueLoader.call();
statsCounter.recordLoadSuccess(1);
return value;
} catch (RuntimeException e) {
statsCounter.recordLoadException(1);
throw new UncheckedExecutionException(e);
} catch (Exception e) {
statsCounter.recordLoadException(1);
throw new ExecutionException(e);
}
}
@Override
public void put(K key, V value) {
// Cache, even if configured to evict everything immediately, should allow writes.
}
@Override
public void refresh(K key) {}
@Override
public void invalidate(Object key) {}
@Override
public void invalidateAll(Iterable<?> keys) {}
@Override
public void invalidateAll() {
}
@Override
public long size() {
return 0;
}
@Override
public CacheStats stats() {
return statsCounter.snapshot();
}
@Override
public ConcurrentMap<K, V> asMap() {
return new ConcurrentMap<K, V>() {
@Override
public V putIfAbsent(K key, V value) {
// Cache, even if configured to evict everything immediately, should allow writes.
// putIfAbsent returns the previous value
return null;
}
@Override
public boolean remove(Object key, Object value) {
return false;
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
return false;
}
@Override
public V replace(K key, V value) {
return null;
}
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public boolean containsKey(Object key) {
return false;
}
@Override
public boolean containsValue(Object value) {
return false;
}
@Override
@Nullable
public V get(Object key) {
return null;
}
@Override
@Nullable
public V put(K key, V value) {
// Cache, even if configured to evict everything immediately, should allow writes.
return null;
}
@Override
@Nullable
public V remove(Object key) {
return null;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
// Cache, even if configured to evict everything immediately, should allow writes.
}
@Override
public void clear() {
}
@Override
public Set<K> keySet() {
return ImmutableSet.of();
}
@Override
public Collection<V> values() {
return ImmutableSet.of();
}
@Override
public Set<Entry<K, V>> entrySet() {
return ImmutableSet.of();
}
};
}
private static class NoopStatsCounter
implements StatsCounter {
private static final CacheStats EMPTY_STATS = new SimpleStatsCounter().snapshot();
@Override
public void recordHits(int count) {}
@Override
public void recordMisses(int count) {}
@Override
public void recordLoadSuccess(long loadTime) {}
@Override
public void recordLoadException(long loadTime) {}
@Override
public void recordEviction() {}
@Override
public CacheStats snapshot() {
return EMPTY_STATS;
}
}
}