Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* 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.io.IOException;
import java.io.OutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;
import org.apache.commons.logging.*;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FilterFileSystem;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.Syncable;
import org.apache.hadoop.fs.FSInputStream;
import org.apache.hadoop.fs.RawLocalFileSystem;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.metrics.LookasideMetrics;
import org.apache.hadoop.util.Progressable;
import org.apache.hadoop.util.ReflectionUtils;
/**
* This is an implementation of a FileSystem that caches data on locally
* mounted devices. It is a stackable filesystem on the client. It uses
* a local path to cache entire files.
*
* Typically, this should be used when IO from a locally mounted
* device has lower latencies than the underlying filesystem.
* The cache is a typical implementation of a LRU cache. It uses
* the name of the specified file as an index into the local cache.
* This is a write-through cache, every write to a file is
* cached in the cache. Also, writes are synchronous, every write
* is written to the cache as well as the underlying filessytem.
* Invalidation of the cache occurs when
* the client removes a file from the filesystem.
*
* The cache is local to this instance of the LookasideCacheFileSystem
* object. If the application is using another instance of the FileSystem
* object to manipulate files, then this cache can stale.
*
* There are two configurable settings:
* fs.lookasidecache.size : The size (in bytes) of the cache
* when eviction starts.
* Default is 10 MB.
* fs.lookasidecache.evict.percent: A single eviction iteration will
* continue until the percent of free
* space in the cache reaches this value.
* Default is 10%.
* fs.lookasidecache.dir : The pathname where files are cached
* There is no default value.
* fs.hdfs.impl : Set to org.apache.hadoop.
* hdfs.LookasideCacheFileSystem to enable
* this feature.
* fs.lookasidecache.underlyingfs.impl: The name of the FileSystem above
* which the LookasideCacheFileSystem is
* layered.
* The default is DistributedFileSystem.
*/
public class LookasideCacheFileSystem extends FilterFileSystem
implements LookasideCache.Eviction {
public static final Log LOG = LogFactory.getLog(LookasideCacheFileSystem.class);
Configuration conf;
Path cachePath; // the directory where to cache files
String cacheDir; // string representation of cachePath
URI cacheURI; // URI representation of cachePath
FileSystem cacheFs; // the fs where the local cache resides
LookasideMetrics metrics; // metrics updater.
// The LRU cache is here.
LookasideCache lookasideCache;
LookasideCacheFileSystem() throws IOException {
}
public LookasideCacheFileSystem(FileSystem fs) throws IOException {
super(fs);
}
/* Initialize a LookasideCacheFileSystem
*/
public void initialize(URI name, Configuration conf) throws IOException {
this.conf = conf;
Class> clazz = conf.getClass("fs.lookasidecache.underlyingfs.impl",
DistributedFileSystem.class);
if (clazz == null) {
throw new IOException("No FileSystem for " +
"fs.lookasidecache.underlyingfs.impl.");
}
this.fs = (FileSystem)ReflectionUtils.newInstance(clazz, null);
super.initialize(name, conf);
// find configured cache directory
cacheDir = conf.get("fs.lookasidecache.dir");
if (cacheDir == null) {
LOG.info("fs.lookasidecache.dir is not defined");
return;
}
cacheDir += "/" + System.currentTimeMillis();
cachePath = new Path(cacheDir);
assert cachePath.isAbsolute();
cacheURI = URI.create("file:///" + cacheDir);
if (cacheURI == null) {
LOG.info("fs.lookasidecache.dir is not defined");
return;
}
if (LOG.isDebugEnabled()) {
LOG.debug("CacheDir is " + cacheURI);
}
// create an instance of a RawLocalFileSystem to read from the cache
cacheFs = new RawLocalFileSystem();
cacheFs.initialize(cacheURI, conf);
// Create the cachedir if it does not exist
// There could be pre-exisiting files in the cachedir, do not do
// anything to them. They will not be served by this cache, but they
// will not be deleted by this cache either.
cacheFs.mkdirs(cachePath);
// create a lookaside cache
lookasideCache = new LookasideCache(conf, this);
// create a metrics updater object
metrics = new LookasideMetrics();
}
/*
* Returns the underlying filesystem
*/
public FileSystem getFileSystem() throws IOException {
return fs;
}
/*
* Returns the local filesystem where the cache is available
*/
public FileSystem getCacheFileSystem() throws IOException {
return cacheFs;
}
/**
* Maps a hdfs path into a pathname in the local cache. In the current
* implementation, the cachePath is the same as the hdfs pathname.
*/
Path mapCachePath(Path hdfsPath) {
assert hdfsPath.isAbsolute();
Path value = new Path(cacheDir + Path.SEPARATOR + hdfsPath);
return value;
}
/**
* Insert a file into the cache. If the cache is exceeding capacity,
* then this call can, in turn, call backinto evictCache().
*/
void addCache(Path hdfsPath, Path localPath, long size) throws IOException {
assert size == new File(localPath.toString()).length();
assert size == fs.getFileStatus(hdfsPath).getLen();
lookasideCache.addCache(hdfsPath, localPath, size);
}
/**
* Remove a file from the cache.
*/
void removeCache(Path hdfsPath) throws IOException {
lookasideCache.removeCache(hdfsPath);
}
/**
* Evicts a file from the cache. If the cache is exceeding capacity,
* then the cache calls this method to indicate that it is evicting
* a file from the cache. This is part of the Eviction Interface.
*/
public void evictCache(Path hdfsPath, Path localPath, long size)
throws IOException {
boolean done = cacheFs.delete(localPath, false);
if (!done) {
if (LOG.isDebugEnabled()) {
LOG.debug("Evict for path: " + hdfsPath +
" local path " + localPath + " unsuccessful.");
}
}
}
@Override
public FSDataInputStream open(Path f, int bufferSize) throws IOException {
// if the file exists, is non-zero size and exists in the cache, then
// open it from the cache. If we open it successfully, then we do not have
// to worry about it being evicted from the cache while we have it open
// because the Linux OS will not actually delete the file till all open
// handles are closed.
Path localPath = null;
try {
FileStatus stat = getFileStatus(f);
if (cacheFs != null && stat.getLen() > 0) {
localPath = lookasideCache.getCache(f);
if (localPath != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("LookasideCache open " + f + " from local cache at " +
localPath);
}
// paranoia, verify that sizes match
File localFile = new File(localPath.toString());
if (localFile.length() != stat.getLen()) {
LOG.warn("LookasideCache hdfsfile " + f +
" has size " + stat.getLen() +
" but does not match cache file " + localFile +
" which has size " + localFile.length() +
". Ignoring... not using the cache.");
} else {
return cacheFs.open(localPath, bufferSize);
}
}
}
} catch (Exception e) {
LOG.info("Unable to find hdfs file " + f + " in cache file " +
localPath + ". Reading from HDFS..");
}
return fs.open(f, bufferSize); // send to underlying filesystem
}
/**
* Close filesystem
*/
@Override
public void close() throws IOException {
super.close();
if (fs != null) {
try {
fs.close();
fs = null;
} catch(IOException ie) {
//this might already be closed, ignore
}
}
if (cacheFs != null) {
try {
cacheFs.close();
cacheFs = null;
} catch(IOException ie) {
//this might already be closed, ignore
}
}
}
/**
* Create new file. We start writing the data into underlying
* filessystem as well as the cacheFileSystem.
*/
@Override
public FSDataOutputStream create(Path f, FsPermission permission,
boolean overwrite,
int bufferSize, short replication, long blockSize,
Progressable progress) throws IOException {
FSDataOutputStream fd = new FSDataOutputStream(
new CacheOutputStream(conf, this, f,
permission, overwrite, bufferSize,
replication, blockSize, progress));
return fd;
}
/**
* Delete a file.
*/
@Override
public boolean delete(Path f, boolean recursive) throws IOException {
boolean val = fs.delete(f, recursive);
if (cacheFs != null) {
Path localPath = mapCachePath(f);
lookasideCache.removeCache(f);
try {
cacheFs.delete(localPath, recursive);
} catch (FileNotFoundException nfe) {
// do nothing
} catch (Exception e) {
LOG.info("LookasideCacheFileSystem unable to find entry in " +
" local cache to delete " + localPath +
". Ignoring...");
}
}
return val;
}
@Override
public boolean delete(Path f) throws IOException {
boolean val = fs.delete(f);
if (cacheFs != null) {
Path localPath = mapCachePath(f);
try {
cacheFs.delete(localPath);
} catch (FileNotFoundException nfe) {
// do nothing
} catch (Exception e) {
LOG.info("LookasideCacheFileSystem unable to find entry in " +
" local cache to delete " + localPath +
". Ignoring...");
}
lookasideCache.removeCache(f);
}
return val;
}
@Override
public boolean rename(Path src, Path dst) throws IOException {
boolean val = fs.rename(src, dst);
if (cacheFs != null) {
Path localPath = mapCachePath(dst);
try {
cacheFs.rename(mapCachePath(src), localPath);
} catch (FileNotFoundException nfe) {
// do nothing
} catch (Exception e) {
LOG.info("LookasideCacheFileSystem unable to find entry in " +
" local cache to rename " + mapCachePath(src) +
" to " + localPath +
". Ignoring...");
}
lookasideCache.renameCache(src, dst, localPath);
}
return val;
}
/**
* Layered FileSystem OuputStream. We use it to write to both
* the underlying filessytem as well as the cache file system.
* We do not reserve space in the cache filesystem up-front, rather
* we start writing to the cache file system, and when the entire
* file is written and closed, we insert an entry into the cache.
* This, in turn, triggers a cache eviction process if necessary.
*/
private static class CacheOutputStream extends OutputStream
implements Syncable {
private final Configuration conf;
private LookasideCacheFileSystem lfs;
private FileSystem cacheFs;
private Path hdfsPath;
private Path localPath;
private FSDataOutputStream cachefd;
private FSDataOutputStream hd;
private boolean hasError = false;
private long filesize;
CacheOutputStream(Configuration conf, LookasideCacheFileSystem lfs,
Path hdfsPath, FsPermission permission, boolean overwrite,
int buffersize, short replication, long blockSize,
Progressable progress) throws IOException {
this.conf = conf;
this.hdfsPath = hdfsPath;
this.localPath = lfs.mapCachePath(hdfsPath);
this.lfs = lfs;
this.filesize = 0;
this.cacheFs = lfs.getCacheFileSystem();
this.hd = lfs.fs.create(hdfsPath, permission, overwrite,
buffersize, replication, blockSize,
progress);
// if we are creating a file with the overwrite flag, then
// delete any earlier versions from the cache. It will be
// re-inserted into the cache when the file is closed.
if (overwrite) {
lfs.removeCache(hdfsPath);
}
try {
this.cachefd = cacheFs.create(localPath, permission, overwrite,
buffersize, replication, blockSize,
progress);
} catch (Exception e) {
this.hasError = true; // do not write to cache anymore
if (LOG.isDebugEnabled()) {
LOG.debug("Unable to create cache file " + localPath);
}
}
}
/**
* Once we successfully close the cache file, add it to the cache.
*/
public void close() throws IOException {
hd.close();
if (!hasError) {
cachefd.close();
lfs.addCache(hdfsPath, localPath, filesize);
}
}
public void flush() throws IOException {
hd.flush();
try {
if (!hasError) {
cachefd.flush();
}
} catch (IOException e) { // unexpected exception
hasError = true; // no more caching
}
}
public void write(byte[] b, int off, int len) throws IOException {
hd.write(b, off, len);
filesize += len;
try {
if (!hasError) {
cachefd.write(b, off, len);
}
} catch (IOException e) { // unexpected exception
hasError = true; // no more caching
}
}
public void write(int b) throws IOException {
hd.write(b);
filesize += 1;
try {
if (!hasError) {
cachefd.write(b);
}
} catch (IOException e) { // unexpected exception
hasError = true; // no more caching
}
}
/** {@inheritDoc} */
public void sync() throws IOException {
hd.sync();
try {
if (!hasError) {
cachefd.sync();
}
} catch (IOException e) { // unexpected exception
hasError = true; // no more caching
}
}
}
}