/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.master.file;
import alluxio.AlluxioURI;
import alluxio.Constants;
import alluxio.heartbeat.HeartbeatExecutor;
import alluxio.master.file.meta.Inode;
import alluxio.master.file.meta.InodeTree;
import alluxio.master.file.meta.LockedInodePath;
import alluxio.master.file.meta.TtlBucket;
import alluxio.master.file.meta.TtlBucketList;
import alluxio.master.file.options.DeleteOptions;
import alluxio.master.file.options.FreeOptions;
import alluxio.wire.TtlAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
/**
* This class represents the executor for periodic inode ttl check.
*/
@NotThreadSafe
final class InodeTtlChecker implements HeartbeatExecutor {
private static final Logger LOG = LoggerFactory.getLogger(InodeTtlChecker.class);
private final FileSystemMaster mFileSystemMaster;
private final InodeTree mInodeTree;
private final TtlBucketList mTtlBuckets;
/**
* Constructs a new {@link InodeTtlChecker}.
*/
public InodeTtlChecker(FileSystemMaster fileSystemMaster, InodeTree inodeTree,
TtlBucketList ttlBuckets) {
mFileSystemMaster = fileSystemMaster;
mInodeTree = inodeTree;
mTtlBuckets = ttlBuckets;
}
@Override
public void heartbeat() {
Set<TtlBucket> expiredBuckets = mTtlBuckets.getExpiredBuckets(System.currentTimeMillis());
for (TtlBucket bucket : expiredBuckets) {
for (Inode inode : bucket.getInodes()) {
AlluxioURI path = null;
try (LockedInodePath inodePath = mInodeTree
.lockFullInodePath(inode.getId(), InodeTree.LockMode.READ)) {
path = inodePath.getUri();
} catch (Exception e) {
LOG.error("Exception trying to clean up {} for ttl check: {}", inode.toString(),
e.toString());
}
if (path != null) {
try {
TtlAction ttlAction = inode.getTtlAction();
LOG.debug("Path {} TTL has expired, performing action {}", path.getPath(), ttlAction);
switch (ttlAction) {
case FREE:
// public free method will lock the path, and check WRITE permission required at
// parent of file
if (inode.isDirectory()) {
mFileSystemMaster
.free(path, FreeOptions.defaults().setForced(true).setRecursive(true));
} else {
mFileSystemMaster.free(path, FreeOptions.defaults().setForced(true));
}
// Reset state
inode.setTtl(Constants.NO_TTL);
inode.setTtlAction(TtlAction.DELETE);
mTtlBuckets.remove(inode);
break;
case DELETE:// Default if not set is DELETE
// public delete method will lock the path, and check WRITE permission required at
// parent of file
if (inode.isDirectory()) {
mFileSystemMaster.delete(path, DeleteOptions.defaults().setRecursive(true));
} else {
mFileSystemMaster.delete(path, DeleteOptions.defaults().setRecursive(false));
}
break;
default:
LOG.error("Unknown ttl action {}", ttlAction);
}
} catch (Exception e) {
LOG.error("Exception trying to clean up {} for ttl check", inode.toString(), e);
}
}
}
}
mTtlBuckets.removeBuckets(expiredBuckets);
}
@Override
public void close() {
// Nothing to clean up
}
}