/**
* 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.hadoop.hdfs;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.hadoop.fs.FileStatus;
/**
* FileStatusCache to avoid issuing duplicating requests for the same path.
* The cache uses LRU policy to replace an entry when the cache is full.
*/
public class FileStatusCache {
private class FileStatusCacheEntry {
public long lastUpdateTime;
public FileStatus fileStatus;
public FileStatusCacheEntry(long currentTime, FileStatus fileStatus) {
this.lastUpdateTime = currentTime;
this.fileStatus = fileStatus;
}
}
private final long expireTime;
private final int cacheSize;
//Set the default cache size to 1000
private static final int DEFAULT_FILE_STATUS_CACHE_SIZE = 10;
//Set the default expire time to 1s
private static final long DEFAULT_FILE_STATUS_CACHE_INTERVAL = 1000L;
public static final FileStatus nullFileStatus = new FileStatus();
private final LinkedHashMap<String, FileStatusCacheEntry> cache = new LinkedHashMap<String, FileStatusCacheEntry>() {
protected boolean removeEldestEntry(Map.Entry<String, FileStatusCacheEntry> eldest) {
return size() > cacheSize;
}
};
public FileStatusCache(long timeInterval, int cacheSize){
expireTime = timeInterval;
this.cacheSize = cacheSize;
//cacheSize equals zero would cause priorityBlockingQueue create exception.
if (cacheSize == 0) {
cacheSize = DEFAULT_FILE_STATUS_CACHE_SIZE;
}
}
public FileStatusCache() {
expireTime = DEFAULT_FILE_STATUS_CACHE_INTERVAL;
cacheSize = DEFAULT_FILE_STATUS_CACHE_SIZE;
}
public synchronized FileStatus get(String path) {
FileStatusCacheEntry cacheEntry;
long elapsedTime;
if (expireTime == 0) {
return null;
}
cacheEntry = cache.get(path);
if (cacheEntry == null) {
return nullFileStatus;
}
elapsedTime = System.currentTimeMillis() - cacheEntry.lastUpdateTime;
if (elapsedTime > expireTime) {
return nullFileStatus;
}
return cacheEntry.fileStatus;
}
//Invalidate all cache entry in the cache which will simplify the implementation.
public synchronized void clear() {
cache.clear();
}
public synchronized void set(String path, FileStatus fileStatus) {
FileStatusCacheEntry cacheEntry;
if (expireTime == 0) {
return;
}
//Force the cache update
//Remove current cache entry from the linked list and insert it later.
cacheEntry = cache.remove(path);
if (cacheEntry == null) {
//Create a new entry to insert.
cacheEntry = new FileStatusCacheEntry(System.currentTimeMillis(), fileStatus);
}
// Cache will remove the eldest entry.
cache.put(path, cacheEntry);
cacheEntry.fileStatus = fileStatus;
cacheEntry.lastUpdateTime = System.currentTimeMillis();
}
}