blob: 6e999d57bdd20c7d5ddcfbb639c1d21525257c5c [file] [log] [blame]
/*
* 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.solr.store.blockcache;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.solr.store.blockcache.BlockCache.OnRelease;
import com.github.benmanes.caffeine.cache.Caffeine;
/**
* @lucene.experimental
*/
public class BlockDirectoryCache implements Cache {
private final BlockCache blockCache;
private final AtomicInteger counter = new AtomicInteger();
private final com.github.benmanes.caffeine.cache.Cache<String,Integer> names;
private Set<BlockCacheKey> keysToRelease;
private final String path;
private final Metrics metrics;
public BlockDirectoryCache(BlockCache blockCache, String path, Metrics metrics) {
this(blockCache, path, metrics, false);
}
public BlockDirectoryCache(BlockCache blockCache, String path, Metrics metrics, boolean releaseBlocks) {
this.blockCache = blockCache;
this.path = path;
this.metrics = metrics;
names = Caffeine.newBuilder().maximumSize(50000).build();
if (releaseBlocks) {
keysToRelease = Collections.newSetFromMap(new ConcurrentHashMap<BlockCacheKey,Boolean>(1024, 0.75f, 512));
blockCache.setOnRelease(new OnRelease() {
@Override
public void release(BlockCacheKey key) {
keysToRelease.remove(key);
}
});
}
}
/**
* Expert: mostly for tests
*
* @lucene.experimental
*/
public BlockCache getBlockCache() {
return blockCache;
}
@Override
public void delete(String name) {
names.invalidate(name);
}
@Override
public void update(String name, long blockId, int blockOffset, byte[] buffer,
int offset, int length) {
Integer file = names.getIfPresent(name);
if (file == null) {
file = counter.incrementAndGet();
names.put(name, file);
}
BlockCacheKey blockCacheKey = new BlockCacheKey();
blockCacheKey.setPath(path);
blockCacheKey.setBlock(blockId);
blockCacheKey.setFile(file);
if (blockCache.store(blockCacheKey, blockOffset, buffer, offset, length) && keysToRelease != null) {
keysToRelease.add(blockCacheKey);
}
}
@Override
public boolean fetch(String name, long blockId, int blockOffset, byte[] b,
int off, int lengthToReadInBlock) {
Integer file = names.getIfPresent(name);
if (file == null) {
return false;
}
BlockCacheKey blockCacheKey = new BlockCacheKey();
blockCacheKey.setPath(path);
blockCacheKey.setBlock(blockId);
blockCacheKey.setFile(file);
boolean fetch = blockCache.fetch(blockCacheKey, b, blockOffset, off,
lengthToReadInBlock);
return fetch;
}
@Override
public long size() {
return blockCache.getSize();
}
@Override
public void renameCacheFile(String source, String dest) {
Integer file = names.getIfPresent(source);
names.invalidate(source);
// possible if the file is empty
if (file != null) {
names.put(dest, file);
}
}
@Override
public void releaseResources() {
if (keysToRelease != null) {
for (BlockCacheKey key : keysToRelease) {
blockCache.release(key);
}
}
}
}