HADOOP-6432. Add Statistics support in FileContext. Contributed by jitendra.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1066282 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f593f14bfb
commit
449478c832
|
@ -4,6 +4,8 @@ Trunk (unreleased changes)
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
|
||||||
|
HADOOP-6432. Add Statistics support in FileContext. (jitendra)
|
||||||
|
|
||||||
HADOOP-6904. Support method based RPC compatiblity. (hairong)
|
HADOOP-6904. Support method based RPC compatiblity. (hairong)
|
||||||
|
|
||||||
NEW FEATURES
|
NEW FEATURES
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.lang.reflect.Constructor;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
@ -60,9 +60,8 @@ public abstract class AbstractFileSystem {
|
||||||
static final Log LOG = LogFactory.getLog(AbstractFileSystem.class);
|
static final Log LOG = LogFactory.getLog(AbstractFileSystem.class);
|
||||||
|
|
||||||
/** Recording statistics per a file system class. */
|
/** Recording statistics per a file system class. */
|
||||||
private static final Map<Class<? extends AbstractFileSystem>, Statistics>
|
private static final Map<URI, Statistics>
|
||||||
STATISTICS_TABLE =
|
STATISTICS_TABLE = new HashMap<URI, Statistics>();
|
||||||
new IdentityHashMap<Class<? extends AbstractFileSystem>, Statistics>();
|
|
||||||
|
|
||||||
/** Cache of constructors for each file system class. */
|
/** Cache of constructors for each file system class. */
|
||||||
private static final Map<Class<?>, Constructor<?>> CONSTRUCTOR_CACHE =
|
private static final Map<Class<?>, Constructor<?>> CONSTRUCTOR_CACHE =
|
||||||
|
@ -145,36 +144,69 @@ public abstract class AbstractFileSystem {
|
||||||
return (AbstractFileSystem) newInstance(clazz, uri, conf);
|
return (AbstractFileSystem) newInstance(clazz, uri, conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the statistics for a particular file system.
|
* Get the statistics for a particular file system.
|
||||||
* @param cls the class to lookup
|
*
|
||||||
|
* @param uri
|
||||||
|
* used as key to lookup STATISTICS_TABLE. Only scheme and authority
|
||||||
|
* part of the uri are used.
|
||||||
* @return a statistics object
|
* @return a statistics object
|
||||||
*/
|
*/
|
||||||
public static synchronized Statistics getStatistics(String scheme,
|
protected static synchronized Statistics getStatistics(URI uri) {
|
||||||
Class<? extends AbstractFileSystem> cls) {
|
String scheme = uri.getScheme();
|
||||||
Statistics result = STATISTICS_TABLE.get(cls);
|
if (scheme == null) {
|
||||||
|
throw new IllegalArgumentException("Scheme not defined in the uri: "
|
||||||
|
+ uri);
|
||||||
|
}
|
||||||
|
URI baseUri = getBaseUri(uri);
|
||||||
|
Statistics result = STATISTICS_TABLE.get(baseUri);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = new Statistics(scheme);
|
result = new Statistics(scheme);
|
||||||
STATISTICS_TABLE.put(cls, result);
|
STATISTICS_TABLE.put(baseUri, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static URI getBaseUri(URI uri) {
|
||||||
|
String scheme = uri.getScheme();
|
||||||
|
String authority = uri.getAuthority();
|
||||||
|
String baseUriString = scheme + "://";
|
||||||
|
if (authority != null) {
|
||||||
|
baseUriString = baseUriString + authority;
|
||||||
|
} else {
|
||||||
|
baseUriString = baseUriString + "/";
|
||||||
|
}
|
||||||
|
return URI.create(baseUriString);
|
||||||
|
}
|
||||||
|
|
||||||
public static synchronized void clearStatistics() {
|
public static synchronized void clearStatistics() {
|
||||||
for(Statistics stat: STATISTICS_TABLE.values()) {
|
for(Statistics stat: STATISTICS_TABLE.values()) {
|
||||||
stat.reset();
|
stat.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints statistics for all file systems.
|
||||||
|
*/
|
||||||
public static synchronized void printStatistics() {
|
public static synchronized void printStatistics() {
|
||||||
for (Map.Entry<Class<? extends AbstractFileSystem>, Statistics> pair:
|
for (Map.Entry<URI, Statistics> pair : STATISTICS_TABLE.entrySet()) {
|
||||||
STATISTICS_TABLE.entrySet()) {
|
System.out.println(" FileSystem " + pair.getKey().getScheme() + "://"
|
||||||
System.out.println(" FileSystem " + pair.getKey().getName() +
|
+ pair.getKey().getAuthority() + ": " + pair.getValue());
|
||||||
": " + pair.getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static synchronized Map<URI, Statistics> getAllStatistics() {
|
||||||
|
Map<URI, Statistics> statsMap = new HashMap<URI, Statistics>(
|
||||||
|
STATISTICS_TABLE.size());
|
||||||
|
for (Map.Entry<URI, Statistics> pair : STATISTICS_TABLE.entrySet()) {
|
||||||
|
URI key = pair.getKey();
|
||||||
|
Statistics value = pair.getValue();
|
||||||
|
Statistics newStatsObj = new Statistics(value);
|
||||||
|
statsMap.put(URI.create(key.toString()), newStatsObj);
|
||||||
|
}
|
||||||
|
return statsMap;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main factory method for creating a file system. Get a file system for
|
* The main factory method for creating a file system. Get a file system for
|
||||||
* the URI's scheme and authority. The scheme of the <code>uri</code>
|
* the URI's scheme and authority. The scheme of the <code>uri</code>
|
||||||
|
@ -211,7 +243,7 @@ public abstract class AbstractFileSystem {
|
||||||
final boolean authorityNeeded, final int defaultPort)
|
final boolean authorityNeeded, final int defaultPort)
|
||||||
throws URISyntaxException {
|
throws URISyntaxException {
|
||||||
myUri = getUri(uri, supportedScheme, authorityNeeded, defaultPort);
|
myUri = getUri(uri, supportedScheme, authorityNeeded, defaultPort);
|
||||||
statistics = getStatistics(supportedScheme, getClass());
|
statistics = getStatistics(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.apache.hadoop.HadoopIllegalArgumentException;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.FileSystem.Statistics;
|
||||||
import org.apache.hadoop.fs.Options.CreateOpts;
|
import org.apache.hadoop.fs.Options.CreateOpts;
|
||||||
import org.apache.hadoop.fs.Options.Rename;
|
import org.apache.hadoop.fs.Options.Rename;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
|
@ -768,8 +769,8 @@ public final class FileContext {
|
||||||
*
|
*
|
||||||
* @throws AccessControlException If access is denied
|
* @throws AccessControlException If access is denied
|
||||||
* @throws FileAlreadyExistsException If <code>dst</code> already exists and
|
* @throws FileAlreadyExistsException If <code>dst</code> already exists and
|
||||||
* <code>options</options> has {@link Rename#OVERWRITE} option
|
* <code>options</options> has {@link Options.Rename#OVERWRITE}
|
||||||
* false.
|
* option false.
|
||||||
* @throws FileNotFoundException If <code>src</code> does not exist
|
* @throws FileNotFoundException If <code>src</code> does not exist
|
||||||
* @throws ParentNotDirectoryException If parent of <code>dst</code> is not a
|
* @throws ParentNotDirectoryException If parent of <code>dst</code> is not a
|
||||||
* directory
|
* directory
|
||||||
|
@ -2226,4 +2227,40 @@ public final class FileContext {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the statistics for a particular file system
|
||||||
|
*
|
||||||
|
* @param uri
|
||||||
|
* the uri to lookup the statistics. Only scheme and authority part
|
||||||
|
* of the uri are used as the key to store and lookup.
|
||||||
|
* @return a statistics object
|
||||||
|
*/
|
||||||
|
public static Statistics getStatistics(URI uri) {
|
||||||
|
return AbstractFileSystem.getStatistics(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all the statistics stored in AbstractFileSystem, for all the file
|
||||||
|
* systems.
|
||||||
|
*/
|
||||||
|
public static void clearStatistics() {
|
||||||
|
AbstractFileSystem.clearStatistics();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the statistics to standard output. File System is identified by the
|
||||||
|
* scheme and authority.
|
||||||
|
*/
|
||||||
|
public static void printStatistics() {
|
||||||
|
AbstractFileSystem.printStatistics();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Map of uri and statistics for each filesystem instantiated. The uri
|
||||||
|
* consists of scheme and authority for the filesystem.
|
||||||
|
*/
|
||||||
|
public static Map<URI, Statistics> getAllStatistics() {
|
||||||
|
return AbstractFileSystem.getAllStatistics();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2007,6 +2007,18 @@ public abstract class FileSystem extends Configured implements Closeable {
|
||||||
this.scheme = scheme;
|
this.scheme = scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor.
|
||||||
|
*
|
||||||
|
* @param st
|
||||||
|
* The input Statistics object which is cloned.
|
||||||
|
*/
|
||||||
|
public Statistics(Statistics st) {
|
||||||
|
this.scheme = st.scheme;
|
||||||
|
this.bytesRead = new AtomicLong(st.bytesRead.longValue());
|
||||||
|
this.bytesWritten = new AtomicLong(st.bytesWritten.longValue());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the bytes read in the statistics
|
* Increment the bytes read in the statistics
|
||||||
* @param newBytes the additional bytes read
|
* @param newBytes the additional bytes read
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/**
|
||||||
|
* 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.fs;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.hadoop.fs.FileSystem.Statistics;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.fs.FileContextTestHelper.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Base class to test {@link FileContext} Statistics.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public abstract class FCStatisticsBaseTest {
|
||||||
|
|
||||||
|
static protected int blockSize = 512;
|
||||||
|
static protected int numBlocks = 1;
|
||||||
|
|
||||||
|
//fc should be set appropriately by the deriving test.
|
||||||
|
protected static FileContext fc = null;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStatistics() throws IOException, URISyntaxException {
|
||||||
|
URI fsUri = getFsUri();
|
||||||
|
Statistics stats = FileContext.getStatistics(fsUri);
|
||||||
|
Assert.assertEquals(0, stats.getBytesRead());
|
||||||
|
Path filePath = getTestRootPath(fc, "file1");
|
||||||
|
createFile(fc, filePath, numBlocks, blockSize);
|
||||||
|
|
||||||
|
Assert.assertEquals(0, stats.getBytesRead());
|
||||||
|
verifyWrittenBytes(stats);
|
||||||
|
FSDataInputStream fstr = fc.open(filePath);
|
||||||
|
byte[] buf = new byte[blockSize];
|
||||||
|
int bytesRead = fstr.read(buf, 0, blockSize);
|
||||||
|
Assert.assertEquals(blockSize, bytesRead);
|
||||||
|
verifyReadBytes(stats);
|
||||||
|
verifyWrittenBytes(stats);
|
||||||
|
verifyReadBytes(FileContext.getStatistics(getFsUri()));
|
||||||
|
Map<URI, Statistics> statsMap = FileContext.getAllStatistics();
|
||||||
|
URI exactUri = getSchemeAuthorityUri();
|
||||||
|
verifyWrittenBytes(statsMap.get(exactUri));
|
||||||
|
fc.delete(filePath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bytes read may be different for different file systems. This method should
|
||||||
|
* throw assertion error if bytes read are incorrect.
|
||||||
|
*
|
||||||
|
* @param stats
|
||||||
|
*/
|
||||||
|
protected abstract void verifyReadBytes(Statistics stats);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bytes written may be different for different file systems. This method should
|
||||||
|
* throw assertion error if bytes written are incorrect.
|
||||||
|
*
|
||||||
|
* @param stats
|
||||||
|
*/
|
||||||
|
protected abstract void verifyWrittenBytes(Statistics stats);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the filesystem uri. Should be set
|
||||||
|
* @return URI
|
||||||
|
*/
|
||||||
|
protected abstract URI getFsUri();
|
||||||
|
|
||||||
|
protected URI getSchemeAuthorityUri() {
|
||||||
|
URI uri = getFsUri();
|
||||||
|
String SchemeAuthString = uri.getScheme() + "://";
|
||||||
|
if (uri.getAuthority() == null) {
|
||||||
|
SchemeAuthString += "/";
|
||||||
|
} else {
|
||||||
|
SchemeAuthString += uri.getAuthority();
|
||||||
|
}
|
||||||
|
return URI.create(SchemeAuthString);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* 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.fs;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.apache.hadoop.fs.FileSystem.Statistics;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.fs.FileContextTestHelper.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Tests the File Context Statistics for {@link LocalFileSystem}
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class TestLocalFsFCStatistics extends FCStatisticsBaseTest {
|
||||||
|
|
||||||
|
static final String LOCAL_FS_ROOT_URI = "file:///tmp/test";
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
fc = FileContext.getLocalFSFileContext();
|
||||||
|
fc.mkdir(getTestRootPath(fc, "test"), FileContext.DEFAULT_PERM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
fc.delete(getTestRootPath(fc, "test"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void verifyReadBytes(Statistics stats) {
|
||||||
|
Assert.assertEquals(blockSize, stats.getBytesRead());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void verifyWrittenBytes(Statistics stats) {
|
||||||
|
//Extra 12 bytes are written apart from the block.
|
||||||
|
Assert.assertEquals(blockSize + 12, stats.getBytesWritten());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected URI getFsUri() {
|
||||||
|
return URI.create(LOCAL_FS_ROOT_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue