blob: 9f42b47b416fb4623f0f5a51d648e521088631f2 [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.storm.localizer;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* A set of resources that we can look at to see which ones we retain and which ones should be
* removed.
*/
public class LocalizedResourceRetentionSet {
public static final Logger LOG = LoggerFactory.getLogger(LocalizedResourceRetentionSet.class);
private long _delSize;
private long _currentSize;
// targetSize in Bytes
private long _targetSize;
private final SortedMap<LocalizedResource, LocalizedResourceSet> _noReferences;
LocalizedResourceRetentionSet(long targetSize) {
this(targetSize, new LRUComparator());
}
LocalizedResourceRetentionSet(long targetSize, Comparator<? super LocalizedResource> cmp) {
this(targetSize, new TreeMap<LocalizedResource, LocalizedResourceSet>(cmp));
}
LocalizedResourceRetentionSet(long targetSize,
SortedMap<LocalizedResource, LocalizedResourceSet> retain) {
this._noReferences = retain;
this._targetSize = targetSize;
}
// for testing
protected int getSizeWithNoReferences() {
return _noReferences.size();
}
protected void addResourcesForSet(Iterator<LocalizedResource> setIter, LocalizedResourceSet set) {
for (Iterator<LocalizedResource> iter = setIter; setIter.hasNext(); ) {
LocalizedResource lrsrc = iter.next();
_currentSize += lrsrc.getSize();
if (lrsrc.getRefCount() > 0) {
// always retain resources in use
continue;
}
LOG.debug("adding {} to be checked for cleaning", lrsrc.getKey());
_noReferences.put(lrsrc, set);
}
}
public void addResources(LocalizedResourceSet set) {
addResourcesForSet(set.getLocalFilesIterator(), set);
addResourcesForSet(set.getLocalArchivesIterator(), set);
}
public void cleanup() {
LOG.debug("cleanup target size: {} current size is: {}", _targetSize, _currentSize);
for (Iterator<Map.Entry<LocalizedResource, LocalizedResourceSet>> i =
_noReferences.entrySet().iterator();
_currentSize - _delSize > _targetSize && i.hasNext();) {
Map.Entry<LocalizedResource, LocalizedResourceSet> rsrc = i.next();
LocalizedResource resource = rsrc.getKey();
LocalizedResourceSet set = rsrc.getValue();
if (resource != null && set.remove(resource)) {
if (deleteResource(resource)) {
_delSize += resource.getSize();
LOG.info("deleting: " + resource.getFilePath() + " size of: " + resource.getSize());
i.remove();
} else {
// since it failed to delete add it back so it gets retried
set.add(resource.getKey(), resource, resource.isUncompressed());
}
}
}
}
protected boolean deleteResource(LocalizedResource resource){
try {
String fileWithVersion = resource.getFilePathWithVersion();
String currentSymlinkName = resource.getCurrentSymlinkPath();
String versionFile = resource.getVersionFilePath();
File deletePath = new File(fileWithVersion);
if (resource.isUncompressed()) {
// this doesn't follow symlinks, which is what we want
FileUtils.deleteDirectory(deletePath);
} else {
Files.delete(deletePath.toPath());
}
Files.delete(new File(currentSymlinkName).toPath());
Files.delete(new File(versionFile).toPath());
return true;
} catch (IOException e) {
LOG.warn("Could not delete: {}", resource.getFilePath());
}
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Cache: ").append(_currentSize).append(", ");
sb.append("Deleted: ").append(_delSize);
return sb.toString();
}
static class LRUComparator implements Comparator<LocalizedResource> {
public int compare(LocalizedResource r1, LocalizedResource r2) {
long ret = r1.getLastAccessTime() - r2.getLastAccessTime();
if (0 == ret) {
return System.identityHashCode(r1) - System.identityHashCode(r2);
}
return ret > 0 ? 1 : -1;
}
}
}