diff --git a/CHANGES.txt b/CHANGES.txt index 09294df28743c..f6eefa23e0463 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,6 @@ Hadoop Change Log -Trunk (unreleased changes) +Release 0.22.0 - Unreleased INCOMPATIBLE CHANGES @@ -41,6 +41,9 @@ Trunk (unreleased changes) HADOOP-7013. Add boolean field isCorrupt to BlockLocation. (Patrick Kling via hairong) + HADOOP-6978. Adds support for NativeIO using JNI. + (Todd Lipcon, Devaraj Das & Owen O'Malley via ddas) + IMPROVEMENTS HADOOP-6644. util.Shell getGROUPS_FOR_USER_COMMAND method name @@ -190,6 +193,9 @@ Trunk (unreleased changes) HADOOP-6884. Add LOG.isDebugEnabled() guard for each LOG.debug(..). (Erik Steffl via szetszwo) + HADOOP-6683. ZlibCompressor does not fully utilize the buffer. + (Kang Xiao via eli) + BUG FIXES HADOOP-6638. try to relogin in a case of failed RPC connection (expired @@ -337,6 +343,9 @@ Trunk (unreleased changes) HADOOP-6496. HttpServer sends wrong content-type for CSS files (and others). (Todd Lipcon via tomwhite) + HADOOP-7057. IOUtils.readFully and IOUtils.skipFully have typo in + exception creation's message. (cos) + Release 0.21.1 - Unreleased IMPROVEMENTS @@ -364,6 +373,12 @@ Release 0.21.1 - Unreleased HADOOP-6954. Sources JARs are not correctly published to the Maven repository. (tomwhite) + HADOOP-7052. misspelling of threshold in conf/log4j.properties. + (Jingguo Yao via eli) + + HADOOP-7053. wrong FSNamesystem Audit logging setting in + conf/log4j.properties. (Jingguo Yao via eli) + Release 0.21.0 - 2010-08-13 INCOMPATIBLE CHANGES diff --git a/build.xml b/build.xml index d84bd96747ba2..41b206c4cda3d 100644 --- a/build.xml +++ b/build.xml @@ -96,7 +96,7 @@ + value="http://download.oracle.com/javase/6/docs/api"/> @@ -366,6 +366,7 @@ + + + + diff --git a/conf/log4j.properties b/conf/log4j.properties index 75b513737df13..55d2f6ea85397 100644 --- a/conf/log4j.properties +++ b/conf/log4j.properties @@ -17,7 +17,7 @@ hadoop.mapreduce.jobsummary.log.file=hadoop-mapreduce.jobsummary.log log4j.rootLogger=${hadoop.root.logger}, EventCounter # Logging Threshold -log4j.threshhold=ALL +log4j.threshold=ALL # # Daily Rolling File Appender @@ -100,13 +100,13 @@ log4j.category.SecurityLogger=INFO,DRFAS # FSNamesystem Audit logging # All audit events are logged at INFO level # -log4j.logger.org.apache.hadoop.fs.FSNamesystem.audit=WARN +log4j.logger.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=WARN # Custom Logging levels #log4j.logger.org.apache.hadoop.mapred.JobTracker=DEBUG #log4j.logger.org.apache.hadoop.mapred.TaskTracker=DEBUG -#log4j.logger.org.apache.hadoop.fs.FSNamesystem=DEBUG +#log4j.logger.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=DEBUG # Jets3t library log4j.logger.org.jets3t.service.impl.rest.httpclient.RestS3Service=ERROR diff --git a/ivy.xml b/ivy.xml index 2e1c64e6690e6..29dffabb74340 100644 --- a/ivy.xml +++ b/ivy.xml @@ -269,6 +269,22 @@ + + + + + + + oro 2.0.8 + + com.google.protobuf + protobuf-java + 2.3.0 + + + org.apache.hadoop + libthrift + 0.5.0.0 + + + org.yaml + snakeyaml + 1.7 + org.apache.hadoop avro diff --git a/ivy/ivysettings.xml b/ivy/ivysettings.xml index 21ce1cdfc931a..621aa2d3e39a3 100644 --- a/ivy/ivysettings.xml +++ b/ivy/ivysettings.xml @@ -30,6 +30,9 @@ + @@ -37,6 +40,7 @@ + diff --git a/ivy/libraries.properties b/ivy/libraries.properties index 36fb821746b7b..7695a7cd15c03 100644 --- a/ivy/libraries.properties +++ b/ivy/libraries.properties @@ -62,6 +62,8 @@ mina-core.version=2.0.0-M5 oro.version=2.0.8 +protobuf.version=2.3.0 + rats-lib.version=0.6 servlet.version=4.0.6 @@ -69,6 +71,9 @@ servlet-api-2.5.version=6.1.14 servlet-api.version=2.5 slf4j-api.version=1.5.11 slf4j-log4j12.version=1.5.11 +snakeyaml.version=1.7 + +thrift.version=0.5.0.0 wagon-http.version=1.0-beta-2 diff --git a/src/java/core-default.xml b/src/java/core-default.xml index 467cbca389d6d..eb6081e2abd9b 100644 --- a/src/java/core-default.xml +++ b/src/java/core-default.xml @@ -155,8 +155,8 @@ - io.serializations - org.apache.hadoop.io.serializer.WritableSerialization,org.apache.hadoop.io.serializer.avro.AvroSpecificSerialization,org.apache.hadoop.io.serializer.avro.AvroReflectSerialization + hadoop.serializations + org.apache.hadoop.io.serial.lib.WritableSerialization,org.apache.hadoop.io.serial.lib.protobuf.ProtoBufSerialization,org.apache.hadoop.io.serial.lib.thrift.ThriftSerialization,org.apache.hadoop.io.serial.lib.avro.AvroSerialization,org.apache.hadoop.io.serial.lib.CompatibilitySerialization A list of serialization classes that can be used for obtaining serializers and deserializers. diff --git a/src/java/org/apache/hadoop/fs/CommonConfigurationKeysPublic.java b/src/java/org/apache/hadoop/fs/CommonConfigurationKeysPublic.java index a401630cfde3b..dc3f63884e294 100644 --- a/src/java/org/apache/hadoop/fs/CommonConfigurationKeysPublic.java +++ b/src/java/org/apache/hadoop/fs/CommonConfigurationKeysPublic.java @@ -138,9 +138,11 @@ public class CommonConfigurationKeysPublic { public static final String IO_SORT_FACTOR_KEY = "io.sort.factor"; /** Default value for IO_SORT_FACTOR_DEFAULT */ public static final int IO_SORT_FACTOR_DEFAULT = 100; - /** See core-default.xml */ + /** Defines the list of the deprecated serializations. */ public static final String IO_SERIALIZATIONS_KEY = "io.serializations"; - + /** Defines the list of serializations */ + public static final String HADOOP_SERIALIZATIONS_KEY = "hadoop.serializations"; + /** See core-default.xml */ public static final String TFILE_IO_CHUNK_SIZE_KEY = "tfile.io.chunk.size"; /** Default value for TFILE_IO_CHUNK_SIZE_DEFAULT */ diff --git a/src/java/org/apache/hadoop/io/ArrayFile.java b/src/java/org/apache/hadoop/io/ArrayFile.java index bee5fd2cb430c..8a7f29299aefa 100644 --- a/src/java/org/apache/hadoop/io/ArrayFile.java +++ b/src/java/org/apache/hadoop/io/ArrayFile.java @@ -40,7 +40,7 @@ public static class Writer extends MapFile.Writer { /** Create the named file for values of the named class. */ public Writer(Configuration conf, FileSystem fs, - String file, Class valClass) + String file, Class valClass) throws IOException { super(conf, new Path(file), keyClass(LongWritable.class), valueClass(valClass)); @@ -48,7 +48,7 @@ public Writer(Configuration conf, FileSystem fs, /** Create the named file for values of the named class. */ public Writer(Configuration conf, FileSystem fs, - String file, Class valClass, + String file, Class valClass, CompressionType compress, Progressable progress) throws IOException { super(conf, new Path(file), @@ -59,7 +59,7 @@ public Writer(Configuration conf, FileSystem fs, } /** Append a value to the file. */ - public synchronized void append(Writable value) throws IOException { + public synchronized void append(Object value) throws IOException { super.append(count, value); // add to map count.set(count.get()+1); // increment count } @@ -81,20 +81,31 @@ public synchronized void seek(long n) throws IOException { seek(key); } - /** Read and return the next value in the file. */ + @Deprecated public synchronized Writable next(Writable value) throws IOException { - return next(key, value) ? value : null; + return (Writable) next((Object) value); + } + + /** Read and return the next value in the file. */ + public synchronized Object next(Object value) throws IOException { + key = (LongWritable) nextKey(key); + return key == null? null : getCurrentValue(value); } /** Returns the key associated with the most recent call to {@link - * #seek(long)}, {@link #next(Writable)}, or {@link - * #get(long,Writable)}. */ + * #seek(long)}, {@link #next(Object)}, or {@link + * #get(long,Object)}. */ public synchronized long key() throws IOException { return key.get(); } + @Deprecated + public synchronized Writable get(long n, Writable value) throws IOException{ + return (Writable) get(n, (Object) value); + } + /** Return the nth value in the file. */ - public synchronized Writable get(long n, Writable value) + public synchronized Object get(long n, Object value) throws IOException { key.set(n); return get(key, value); diff --git a/src/java/org/apache/hadoop/io/BloomMapFile.java b/src/java/org/apache/hadoop/io/BloomMapFile.java index ab68ce7f60b1c..5344e94939eb7 100644 --- a/src/java/org/apache/hadoop/io/BloomMapFile.java +++ b/src/java/org/apache/hadoop/io/BloomMapFile.java @@ -31,7 +31,7 @@ import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.SequenceFile.CompressionType; import org.apache.hadoop.io.compress.CompressionCodec; -import org.apache.hadoop.util.Options; +import org.apache.hadoop.io.serial.Serialization; import org.apache.hadoop.util.Progressable; import org.apache.hadoop.util.bloom.DynamicBloomFilter; import org.apache.hadoop.util.bloom.Filter; @@ -42,7 +42,7 @@ * This class extends {@link MapFile} and provides very much the same * functionality. However, it uses dynamic Bloom filters to provide * quick membership test for keys, and it offers a fast version of - * {@link Reader#get(WritableComparable, Writable)} operation, especially in + * {@link Reader#get(Object, Object)} operation, especially in * case of sparsely populated MapFile-s. */ @InterfaceAudience.Public @@ -82,7 +82,9 @@ public static class Writer extends MapFile.Writer { private DataOutputBuffer buf = new DataOutputBuffer(); private FileSystem fs; private Path dir; + private final Serialization keySerialization; + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, Class keyClass, @@ -92,6 +94,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, compression(compress, codec), progressable(progress)); } + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, Class keyClass, @@ -101,6 +104,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, compression(compress), progressable(progress)); } + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, Class keyClass, @@ -110,6 +114,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, compression(compress)); } + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, WritableComparator comparator, Class valClass, @@ -120,6 +125,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, progressable(progress)); } + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, WritableComparator comparator, Class valClass, @@ -129,6 +135,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, progressable(progress)); } + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, WritableComparator comparator, Class valClass, CompressionType compress) @@ -137,6 +144,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, valueClass(valClass), compression(compress)); } + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, WritableComparator comparator, Class valClass) throws IOException { @@ -144,6 +152,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, valueClass(valClass)); } + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, Class keyClass, @@ -151,12 +160,14 @@ public Writer(Configuration conf, FileSystem fs, String dirName, this(conf, new Path(dirName), keyClass(keyClass), valueClass(valClass)); } + @SuppressWarnings("unchecked") public Writer(Configuration conf, Path dir, SequenceFile.Writer.Option... options) throws IOException { super(conf, dir, options); this.fs = dir.getFileSystem(conf); this.dir = dir; initBloomFilter(conf); + keySerialization = (Serialization) getKeySerialization(); } private synchronized void initBloomFilter(Configuration conf) { @@ -174,11 +185,10 @@ private synchronized void initBloomFilter(Configuration conf) { } @Override - public synchronized void append(WritableComparable key, Writable val) - throws IOException { + public synchronized void append(Object key, Object val) throws IOException { super.append(key, val); buf.reset(); - key.write(buf); + keySerialization.serialize(buf, key); bloomKey.set(byteArrayForBloomKey(buf), 1.0); bloomFilter.add(bloomKey); } @@ -198,11 +208,14 @@ public static class Reader extends MapFile.Reader { private DynamicBloomFilter bloomFilter; private DataOutputBuffer buf = new DataOutputBuffer(); private Key bloomKey = new Key(); + private final Serialization keySerialization; + @SuppressWarnings("unchecked") public Reader(Path dir, Configuration conf, SequenceFile.Reader.Option... options) throws IOException { super(dir, conf, options); initBloomFilter(dir, conf); + keySerialization = (Serialization) getKeySerialization(); } @Deprecated @@ -245,26 +258,40 @@ private void initBloomFilter(Path dirName, * @return false iff key doesn't exist, true if key probably exists. * @throws IOException */ - public boolean probablyHasKey(WritableComparable key) throws IOException { + public boolean probablyHasKey(Object key) throws IOException { if (bloomFilter == null) { return true; } buf.reset(); - key.write(buf); + keySerialization.serialize(buf, key); bloomKey.set(byteArrayForBloomKey(buf), 1.0); return bloomFilter.membershipTest(bloomKey); } /** * Fast version of the - * {@link MapFile.Reader#get(WritableComparable, Writable)} method. First + * {@link MapFile.Reader#get(Object, Object)} method. First * it checks the Bloom filter for the existence of the key, and only if * present it performs the real get operation. This yields significant * performance improvements for get operations on sparsely populated files. */ + @SuppressWarnings("unchecked") + @Deprecated @Override - public synchronized Writable get(WritableComparable key, Writable val) - throws IOException { + public synchronized Writable get(WritableComparable key, + Writable value) throws IOException { + return (Writable) get((Object) key, (Object) value); + } + + /** + * Fast version of the + * {@link MapFile.Reader#get(Object, Object)} method. First + * it checks the Bloom filter for the existence of the key, and only if + * present it performs the real get operation. This yields significant + * performance improvements for get operations on sparsely populated files. + */ + @Override + public synchronized Object get(Object key, Object val) throws IOException { if (!probablyHasKey(key)) { return null; } diff --git a/src/java/org/apache/hadoop/io/DataInputBuffer.java b/src/java/org/apache/hadoop/io/DataInputBuffer.java index cc5500f32f502..8fdaad11365ee 100644 --- a/src/java/org/apache/hadoop/io/DataInputBuffer.java +++ b/src/java/org/apache/hadoop/io/DataInputBuffer.java @@ -93,4 +93,20 @@ public byte[] getData() { /** Returns the length of the input. */ public int getLength() { return buffer.getLength(); } + public String toString() { + StringBuilder sb = new StringBuilder(3 * buffer.getLength() + 10); + byte[] bytes = getData(); + for(int i=0; i < buffer.getLength(); i++) { + sb.append(' '); + String num = Integer.toHexString(0xff & bytes[i]); + // if it is only one digit, add a leading 0. + if (num.length() < 2) { + sb.append('0'); + } + sb.append(num); + } + sb.append("; pos="); + sb.append(buffer.getPosition()); + return sb.toString(); + } } diff --git a/src/java/org/apache/hadoop/io/DefaultStringifier.java b/src/java/org/apache/hadoop/io/DefaultStringifier.java index 6cd1f49722058..9b54de3a874d9 100644 --- a/src/java/org/apache/hadoop/io/DefaultStringifier.java +++ b/src/java/org/apache/hadoop/io/DefaultStringifier.java @@ -26,17 +26,15 @@ import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.io.serializer.Deserializer; -import org.apache.hadoop.io.serializer.Serialization; -import org.apache.hadoop.io.serializer.SerializationFactory; -import org.apache.hadoop.io.serializer.Serializer; +import org.apache.hadoop.io.serial.Serialization; +import org.apache.hadoop.io.serial.SerializationFactory; import org.apache.hadoop.util.GenericsUtil; /** * DefaultStringifier is the default implementation of the {@link Stringifier} * interface which stringifies the objects using base64 encoding of the - * serialized version of the objects. The {@link Serializer} and - * {@link Deserializer} are obtained from the {@link SerializationFactory}. + * serialized version of the objects. The {@link Serialization} + * is obtained from the {@link SerializationFactory}. *
* DefaultStringifier offers convenience methods to store/load objects to/from * the configuration. @@ -49,43 +47,37 @@ public class DefaultStringifier implements Stringifier { private static final String SEPARATOR = ","; - private Serializer serializer; + private final Serialization serialization; - private Deserializer deserializer; + private final DataInputBuffer inBuf; - private DataInputBuffer inBuf; - - private DataOutputBuffer outBuf; + private final DataOutputBuffer outBuf; + private final Configuration conf; + @SuppressWarnings("unchecked") public DefaultStringifier(Configuration conf, Class c) { - SerializationFactory factory = new SerializationFactory(conf); - this.serializer = factory.getSerializer(c); - this.deserializer = factory.getDeserializer(c); + SerializationFactory factory = SerializationFactory.getInstance(conf); this.inBuf = new DataInputBuffer(); this.outBuf = new DataOutputBuffer(); - try { - serializer.open(outBuf); - deserializer.open(inBuf); - } catch (IOException ex) { - throw new RuntimeException(ex); - } + this.conf = conf; + this.serialization = (Serialization) factory.getSerializationByType(c); } public T fromString(String str) throws IOException { try { byte[] bytes = Base64.decodeBase64(str.getBytes("UTF-8")); inBuf.reset(bytes, bytes.length); - T restored = deserializer.deserialize(null); + T restored = serialization.deserialize(inBuf, null, conf); return restored; } catch (UnsupportedCharsetException ex) { - throw new IOException(ex.toString()); + throw new IOException("problem finding utf-8", ex); } } public String toString(T obj) throws IOException { outBuf.reset(); - serializer.serialize(obj); + serialization.serialize(outBuf, obj); byte[] buf = new byte[outBuf.getLength()]; System.arraycopy(outBuf.getData(), 0, buf, 0, buf.length); return new String(Base64.encodeBase64(buf)); @@ -94,8 +86,6 @@ public String toString(T obj) throws IOException { public void close() throws IOException { inBuf.close(); outBuf.close(); - deserializer.close(); - serializer.close(); } /** diff --git a/src/java/org/apache/hadoop/io/IOUtils.java b/src/java/org/apache/hadoop/io/IOUtils.java index aa3450d55d5f7..f7d27a7aebde5 100644 --- a/src/java/org/apache/hadoop/io/IOUtils.java +++ b/src/java/org/apache/hadoop/io/IOUtils.java @@ -115,7 +115,7 @@ public static void readFully( InputStream in, byte buf[], while ( toRead > 0 ) { int ret = in.read( buf, off, toRead ); if ( ret < 0 ) { - throw new IOException( "Premeture EOF from inputStream"); + throw new IOException( "Premature EOF from inputStream"); } toRead -= ret; off += ret; @@ -132,7 +132,7 @@ public static void skipFully( InputStream in, long len ) throws IOException { while ( len > 0 ) { long ret = in.skip( len ); if ( ret < 0 ) { - throw new IOException( "Premeture EOF from inputStream"); + throw new IOException( "Premature EOF from inputStream"); } len -= ret; } diff --git a/src/java/org/apache/hadoop/io/MapFile.java b/src/java/org/apache/hadoop/io/MapFile.java index 8250145b8b725..5d4bad53d25e7 100644 --- a/src/java/org/apache/hadoop/io/MapFile.java +++ b/src/java/org/apache/hadoop/io/MapFile.java @@ -18,24 +18,25 @@ package org.apache.hadoop.io; +import java.io.EOFException; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.io.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.util.Options; -import org.apache.hadoop.fs.*; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; -import org.apache.hadoop.conf.*; -import org.apache.hadoop.util.Progressable; -import org.apache.hadoop.util.ReflectionUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.SequenceFile.CompressionType; -import org.apache.hadoop.io.SequenceFile.Reader; -import org.apache.hadoop.io.SequenceFile.Writer; import org.apache.hadoop.io.compress.CompressionCodec; -import org.apache.hadoop.io.compress.DefaultCodec; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.serial.Serialization; +import org.apache.hadoop.io.serial.SerializationFactory; +import org.apache.hadoop.util.Progressable; /** A file-based map from keys to values. * @@ -68,8 +69,11 @@ protected MapFile() {} // no public ctor /** Writes a new map. */ public static class Writer implements java.io.Closeable { - private SequenceFile.Writer data; - private SequenceFile.Writer index; + private final SequenceFile.Writer data; + private final SequenceFile.Writer index; + private final Configuration conf; + private final Serialization keySerialization; + private final Serialization valueSerialization; final private static String INDEX_INTERVAL = "io.map.index.interval"; private int indexInterval = 128; @@ -78,10 +82,11 @@ public static class Writer implements java.io.Closeable { private LongWritable position = new LongWritable(); // the following fields are used only for checking key order - private WritableComparator comparator; - private DataInputBuffer inBuf = new DataInputBuffer(); - private DataOutputBuffer outBuf = new DataOutputBuffer(); - private WritableComparable lastKey; + private final RawComparator comparator; + private final DataInputBuffer inBuf = new DataInputBuffer(); + private DataOutputBuffer lastKey; + private final DataOutputBuffer currentKey = new DataOutputBuffer(); + private final DataOutputBuffer currentValue = new DataOutputBuffer(); /** What's the position (in bytes) we wrote when we got the last index */ private long lastIndexPos = -1; @@ -97,6 +102,7 @@ public static class Writer implements java.io.Closeable { /** Create the named map for keys of the named class. * @deprecated Use Writer(Configuration, Path, Option...) instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, Class keyClass, @@ -107,6 +113,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, /** Create the named map for keys of the named class. * @deprecated Use Writer(Configuration, Path, Option...) instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, Class keyClass, Class valClass, @@ -119,6 +126,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, /** Create the named map for keys of the named class. * @deprecated Use Writer(Configuration, Path, Option...) instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, Class keyClass, Class valClass, @@ -131,6 +139,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, /** Create the named map for keys of the named class. * @deprecated Use Writer(Configuration, Path, Option...) instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, Class keyClass, Class valClass, @@ -142,6 +151,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, /** Create the named map using the named key comparator. * @deprecated Use Writer(Configuration, Path, Option...) instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, WritableComparator comparator, Class valClass @@ -153,6 +163,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, /** Create the named map using the named key comparator. * @deprecated Use Writer(Configuration, Path, Option...) instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, WritableComparator comparator, Class valClass, @@ -164,6 +175,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, /** Create the named map using the named key comparator. * @deprecated Use Writer(Configuration, Path, Option...)} instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, WritableComparator comparator, Class valClass, @@ -177,6 +189,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, /** Create the named map using the named key comparator. * @deprecated Use Writer(Configuration, Path, Option...) instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(Configuration conf, FileSystem fs, String dirName, WritableComparator comparator, Class valClass, @@ -190,28 +203,18 @@ public Writer(Configuration conf, FileSystem fs, String dirName, // our options are a superset of sequence file writer options public static interface Option extends SequenceFile.Writer.Option { } - private static class KeyClassOption extends Options.ClassOption - implements Option { - KeyClassOption(Class value) { + private static class ComparatorOption extends Options.ComparatorOption + implements Option{ + ComparatorOption(RawComparator value) { super(value); } } - - private static class ComparatorOption implements Option { - private final WritableComparator value; - ComparatorOption(WritableComparator value) { - this.value = value; - } - WritableComparator getValue() { - return value; - } - } - public static Option keyClass(Class value) { - return new KeyClassOption(value); + public static SequenceFile.Writer.Option keyClass(Class value) { + return new SequenceFile.Writer.KeyClassOption(value); } - public static Option comparator(WritableComparator value) { + public static Option comparator(RawComparator value) { return new ComparatorOption(value); } @@ -234,31 +237,27 @@ public static SequenceFile.Writer.Option progressable(Progressable value) { return SequenceFile.Writer.progressable(value); } + public static + SequenceFile.Writer.Option keySerialization(Serialization value) { + return SequenceFile.Writer.keySerialization(value); + } + + public static + SequenceFile.Writer.Option valueSerialization(Serialization value) { + return SequenceFile.Writer.valueSerialization(value); + } + @SuppressWarnings("unchecked") public Writer(Configuration conf, Path dirName, SequenceFile.Writer.Option... opts ) throws IOException { - KeyClassOption keyClassOption = - Options.getOption(KeyClassOption.class, opts); + this.conf = conf; ComparatorOption comparatorOption = Options.getOption(ComparatorOption.class, opts); - if ((keyClassOption == null) == (comparatorOption == null)) { - throw new IllegalArgumentException("key class or comparator option " - + "must be set"); - } + this.indexInterval = conf.getInt(INDEX_INTERVAL, this.indexInterval); - Class keyClass; - if (keyClassOption == null) { - this.comparator = comparatorOption.getValue(); - keyClass = comparator.getKeyClass(); - } else { - keyClass= - (Class) keyClassOption.getValue(); - this.comparator = WritableComparator.get(keyClass); - } - this.lastKey = comparator.newKey(); FileSystem fs = dirName.getFileSystem(conf); if (!fs.mkdirs(dirName)) { @@ -269,13 +268,18 @@ public Writer(Configuration conf, SequenceFile.Writer.Option[] dataOptions = Options.prependOptions(opts, - SequenceFile.Writer.file(dataFile), - SequenceFile.Writer.keyClass(keyClass)); + SequenceFile.Writer.file(dataFile)); this.data = SequenceFile.createWriter(conf, dataOptions); + keySerialization = (Serialization) data.getKeySerialization(); + valueSerialization = (Serialization) data.getValueSerialization(); + if (comparatorOption != null) { + comparator = comparatorOption.getValue(); + } else { + comparator = keySerialization.getRawComparator(); + } SequenceFile.Writer.Option[] indexOptions = Options.prependOptions(opts, SequenceFile.Writer.file(indexFile), - SequenceFile.Writer.keyClass(keyClass), SequenceFile.Writer.valueClass(LongWritable.class), SequenceFile.Writer.compression(CompressionType.BLOCK)); this.index = SequenceFile.createWriter(conf, indexOptions); @@ -296,6 +300,22 @@ public static void setIndexInterval(Configuration conf, int interval) { conf.setInt(INDEX_INTERVAL, interval); } + /** + * Get the serialization used for the keys + * @return the key serialization + */ + public Serialization getKeySerialization() { + return data.getKeySerialization(); + } + + /** + * Get the serialization used for the values + * @return the value serialization + */ + public Serialization getValueSerialization() { + return data.getValueSerialization(); + } + /** Close the map. */ public synchronized void close() throws IOException { data.close(); @@ -304,10 +324,14 @@ public synchronized void close() throws IOException { /** Append a key/value pair to the map. The key must be greater or equal * to the previous key added to the map. */ - public synchronized void append(WritableComparable key, Writable val) + public synchronized void append(Object key, Object val) throws IOException { - checkKey(key); + currentKey.reset(); + keySerialization.serialize(currentKey, key); + checkKey(currentKey, key); + currentValue.reset(); + valueSerialization.serialize(currentValue, val); long pos = data.getLength(); // Only write an index if we've changed positions. In a block compressed @@ -323,17 +347,21 @@ public synchronized void append(WritableComparable key, Writable val) size++; } - private void checkKey(WritableComparable key) throws IOException { + private void checkKey(DataOutputBuffer serialKey, Object key + ) throws IOException { // check that keys are well-ordered - if (size != 0 && comparator.compare(lastKey, key) > 0) - throw new IOException("key out of order: "+key+" after "+lastKey); - - // update lastKey with a copy of key by writing and reading - outBuf.reset(); - key.write(outBuf); // write new key - - inBuf.reset(outBuf.getData(), outBuf.getLength()); - lastKey.readFields(inBuf); // read into lastKey + if (lastKey == null) { + lastKey = new DataOutputBuffer(); + } else if (comparator.compare(lastKey.getData(), 0, lastKey.getLength(), + serialKey.getData(),0,serialKey.getLength()) + > 0) { + // rebuild the previous key so that we can explain what's wrong + inBuf.reset(lastKey.getData(), 0, lastKey.getLength()); + Object prevKey = keySerialization.deserialize(inBuf, null, conf); + throw new IOException("key out of order: "+ key +" after "+ prevKey); + } + lastKey.reset(); + lastKey.write(serialKey.getData(), 0, serialKey.getLength()); } } @@ -346,9 +374,12 @@ public static class Reader implements java.io.Closeable { * files using less memory. */ private int INDEX_SKIP = 0; - private WritableComparator comparator; + private RawComparator comparator; + private Serialization keySerialization; + private final Configuration conf; - private WritableComparable nextKey; + private DataOutputBuffer nextKey = new DataOutputBuffer(); + private DataInputBuffer inBuf = new DataInputBuffer(); private long seekPosition = -1; private int seekIndex = -1; private long firstPosition; @@ -362,36 +393,55 @@ public static class Reader implements java.io.Closeable { // the index, in memory private int count = -1; - private WritableComparable[] keys; + private byte[][] keys; private long[] positions; - /** Returns the class of keys in this file. */ + /** Returns the class of keys in this file. + * @deprecated Use {@link #getKeySerialization} instead. + */ + @Deprecated public Class getKeyClass() { return data.getKeyClass(); } - /** Returns the class of values in this file. */ + /** Returns the class of values in this file. + * @deprecated Use {@link #getValueSerialization} instead. + */ + @Deprecated public Class getValueClass() { return data.getValueClass(); } + /** + * Get the key serialization for this map file. + * @return the serialization for the key + */ + public Serialization getKeySerialization() { + return keySerialization; + } + + /** + * Get the value serialization for this map file. + * @return the serialization for the value + */ + public Serialization getValueSerialization() { + return data.getValueSerialization(); + } public static interface Option extends SequenceFile.Reader.Option {} public static Option comparator(WritableComparator value) { return new ComparatorOption(value); } - static class ComparatorOption implements Option { - private final WritableComparator value; - ComparatorOption(WritableComparator value) { - this.value = value; - } - WritableComparator getValue() { - return value; + static class ComparatorOption extends Options.ComparatorOption + implements Option { + ComparatorOption(RawComparator value) { + super(value); } } public Reader(Path dir, Configuration conf, SequenceFile.Reader.Option... opts) throws IOException { + this.conf = conf; ComparatorOption comparatorOption = Options.getOption(ComparatorOption.class, opts); - WritableComparator comparator = + RawComparator comparator = comparatorOption == null ? null : comparatorOption.getValue(); INDEX_SKIP = conf.getInt("io.map.index.skip", 0); open(dir, comparator, conf, opts); @@ -415,8 +465,9 @@ public Reader(FileSystem fs, String dirName, WritableComparator comparator, this(new Path(dirName), conf, comparator(comparator)); } + @SuppressWarnings("unchecked") protected synchronized void open(Path dir, - WritableComparator comparator, + RawComparator comparator, Configuration conf, SequenceFile.Reader.Option... options ) throws IOException { @@ -426,13 +477,13 @@ protected synchronized void open(Path dir, // open the data this.data = createDataFileReader(dataFile, conf, options); this.firstPosition = data.getPosition(); + keySerialization = (Serialization) data.getKeySerialization(); - if (comparator == null) - this.comparator = - WritableComparator.get(data.getKeyClass(). - asSubclass(WritableComparable.class)); - else + if (comparator == null) { + this.comparator = keySerialization.getRawComparator(); + } else { this.comparator = comparator; + } // open the index SequenceFile.Reader.Option[] indexOptions = @@ -463,19 +514,25 @@ private void readIndex() throws IOException { try { int skip = INDEX_SKIP; LongWritable position = new LongWritable(); - WritableComparable lastKey = null; + byte[] lastKey = null; long lastIndex = -1; - ArrayList keyBuilder = new ArrayList(1024); - while (true) { - WritableComparable k = comparator.newKey(); - - if (!index.next(k, position)) - break; + ArrayList keyBuilder = new ArrayList(1024); + DataOutputBuffer key = new DataOutputBuffer(); + while (index.nextRawKey(key) > 0) { + position = (LongWritable) index.getCurrentValue(position); // check order to make sure comparator is compatible - if (lastKey != null && comparator.compare(lastKey, k) > 0) - throw new IOException("key out of order: "+k+" after "+lastKey); - lastKey = k; + if (lastKey != null && + comparator.compare(lastKey, 0, lastKey.length, + key.getData(), 0 , key.getLength()) > 0) { + inBuf.reset(lastKey, 0, lastKey.length); + Object prevKey = keySerialization.deserialize(inBuf, null, conf); + inBuf.reset(key.getData(), 0, key.getLength()); + Object curKey = keySerialization.deserialize(inBuf, null, conf); + throw new IOException("key out of order: "+ curKey + " after " + + prevKey); + } + lastKey = Arrays.copyOf(key.getData(), key.getLength()); if (skip > 0) { skip--; continue; // skip this entry @@ -483,28 +540,28 @@ private void readIndex() throws IOException { skip = INDEX_SKIP; // reset skip } - // don't read an index that is the same as the previous one. Block - // compressed map files used to do this (multiple entries would point - // at the same block) - if (position.get() == lastIndex) - continue; + // don't read an index that is the same as the previous one. Block + // compressed map files used to do this (multiple entries would point + // at the same block) + if (position.get() == lastIndex) + continue; if (count == positions.length) { - positions = Arrays.copyOf(positions, positions.length * 2); + positions = Arrays.copyOf(positions, positions.length * 2); } - keyBuilder.add(k); + keyBuilder.add(lastKey); positions[count] = position.get(); count++; } - this.keys = keyBuilder.toArray(new WritableComparable[count]); + this.keys = keyBuilder.toArray(new byte[count][]); positions = Arrays.copyOf(positions, count); } catch (EOFException e) { LOG.warn("Unexpected EOF reading " + index + - " at entry #" + count + ". Ignoring."); + " at entry #" + count + ". Ignoring."); } finally { - indexClosed = true; + indexClosed = true; index.close(); } } @@ -517,22 +574,23 @@ public synchronized void reset() throws IOException { /** Get the key at approximately the middle of the file. Or null if the * file is empty. */ - public synchronized WritableComparable midKey() throws IOException { + public synchronized Object midKey() throws IOException { readIndex(); if (count == 0) { return null; } - return keys[(count - 1) / 2]; + byte[] rawKey = keys[(count -1) / 2]; + inBuf.reset(rawKey, 0, rawKey.length); + return keySerialization.deserialize(inBuf, null, conf); } /** Reads the final key from the file. * * @param key key to read into */ - public synchronized void finalKey(WritableComparable key) - throws IOException { + public synchronized Object finalKey(Object key) throws IOException { long originalPosition = data.getPosition(); // save position try { @@ -542,8 +600,12 @@ public synchronized void finalKey(WritableComparable key) } else { reset(); // start at the beginning } - while (data.next(key)) {} // scan to eof - + Object prevKey = null; + do { + prevKey = key; + key = data.nextKey(key); + } while (key != null); + return prevKey; } finally { data.seek(originalPosition); // restore position } @@ -553,7 +615,7 @@ public synchronized void finalKey(WritableComparable key) * first entry after the named key. Returns true iff the named key exists * in this map. */ - public synchronized boolean seek(WritableComparable key) throws IOException { + public synchronized boolean seek(Object key) throws IOException { return seekInternal(key) == 0; } @@ -565,7 +627,7 @@ public synchronized boolean seek(WritableComparable key) throws IOException { * < 0 - positioned at next record * 1 - no more records in file */ - private synchronized int seekInternal(WritableComparable key) + private synchronized int seekInternal(Object key) throws IOException { return seekInternal(key, false); } @@ -582,19 +644,24 @@ private synchronized int seekInternal(WritableComparable key) * < 0 - positioned at next record * 1 - no more records in file */ - private synchronized int seekInternal(WritableComparable key, - final boolean before) - throws IOException { + private synchronized int seekInternal(Object key, + final boolean before + ) throws IOException { readIndex(); // make sure index is read + DataOutputBuffer keyBuffer = new DataOutputBuffer(); + keySerialization.serialize(keyBuffer, key); if (seekIndex != -1 // seeked before && seekIndex+1 < count - && comparator.compare(key, keys[seekIndex+1])<0 // before next indexed - && comparator.compare(key, nextKey) - >= 0) { // but after last seeked + && comparator.compare(keyBuffer.getData(), 0, keyBuffer.getLength(), + keys[seekIndex+1], 0, keys[seekIndex+1].length) + < 0 // before next indexed + && comparator.compare(keyBuffer.getData(), 0, keyBuffer.getLength(), + nextKey.getData(), 0, nextKey.getLength()) + >= 0) { // but after last seeked // do nothing } else { - seekIndex = binarySearch(key); + seekIndex = binarySearch(keyBuffer.getData(), keyBuffer.getLength()); if (seekIndex < 0) // decode insertion point seekIndex = -seekIndex-2; @@ -605,17 +672,15 @@ private synchronized int seekInternal(WritableComparable key, } data.seek(seekPosition); - if (nextKey == null) - nextKey = comparator.newKey(); - // If we're looking for the key before, we need to keep track // of the position we got the current key as well as the position // of the key before it. long prevPosition = -1; long curPosition = seekPosition; - while (data.next(nextKey)) { - int c = comparator.compare(key, nextKey); + while (data.nextRawKey(nextKey) != -1) { + int c = comparator.compare(keyBuffer.getData(), 0, keyBuffer.getLength(), + nextKey.getData(), 0 , nextKey.getLength()); if (c <= 0) { // at or beyond desired if (before && c != 0) { if (prevPosition == -1) { @@ -627,7 +692,7 @@ private synchronized int seekInternal(WritableComparable key, } else { // We have a previous record to back up to data.seek(prevPosition); - data.next(nextKey); + data.nextRawKey(nextKey); // now that we've rewound, the search key must be greater than this key return 1; } @@ -639,18 +704,24 @@ private synchronized int seekInternal(WritableComparable key, curPosition = data.getPosition(); } } - + // if we have fallen off the end of the file and we want the before key + // then back up to the previous key + if (before && prevPosition != -1) { + data.seek(prevPosition); + data.nextRawKey(nextKey); + } return 1; } - private int binarySearch(WritableComparable key) { + private int binarySearch(byte[] key, int length) { int low = 0; int high = count-1; while (low <= high) { int mid = (low + high) >>> 1; - WritableComparable midVal = keys[mid]; - int cmp = comparator.compare(midVal, key); + byte[] midVal = keys[mid]; + int cmp = comparator.compare(midVal, 0, midVal.length, + key, 0, length); if (cmp < 0) low = mid + 1; @@ -664,18 +735,59 @@ else if (cmp > 0) /** Read the next key/value pair in the map into key and * val. Returns true if such a pair exists and false when at - * the end of the map */ + * the end of the map + * @deprecated Use {@link #nextKey} and {@link #getCurrentValue} instead. + */ + @SuppressWarnings("unchecked") + @Deprecated public synchronized boolean next(WritableComparable key, Writable val) throws IOException { return data.next(key, val); } + + /** + * Read the next key in the map. + * @param reusable an object that may be re-used for holding the next key + * @return the key that was read or null if there is not another key + * @throws IOException + */ + public Object nextKey(Object reusable) throws IOException { + return data.nextKey(reusable); + } + + /** + * Get the current value in the map. + * @param reusable an object that may be re-used for hold the value + * @return the value that was read in + * @throws IOException + */ + public Object getCurrentValue(Object reusable) throws IOException { + return data.getCurrentValue(reusable); + } + + /** + * Return the value for the named key, or null if none exists. + * @param key the key to look for + * @param value a object to read into + * @return the value that was found or null if the key wasn't found + * @throws IOException + * @deprecated Use {@link #seek} and {@link #getCurrentValue} instead. + */ + @SuppressWarnings("unchecked") + @Deprecated + public synchronized Writable get(WritableComparable key, + Writable value) throws IOException { + if (seek(key)) { + return (Writable) data.getCurrentValue(value); + } else { + return null; + } + } /** Return the value for the named key, or null if none exists. */ - public synchronized Writable get(WritableComparable key, Writable val) - throws IOException { + public synchronized Object get(Object key, Object val) throws IOException{ if (seek(key)) { - data.getCurrentValue(val); - return val; + return data.getCurrentValue(val); } else return null; } @@ -689,9 +801,8 @@ public synchronized Writable get(WritableComparable key, Writable val) - * @param val - data value if key is found - * @return - the key that was the closest match or null if eof. */ - public synchronized WritableComparable getClosest(WritableComparable key, - Writable val) - throws IOException { + public Object getClosest(Object key, + Object val) throws IOException { return getClosest(key, val, false); } @@ -705,9 +816,10 @@ public synchronized WritableComparable getClosest(WritableComparable key, * return the record that sorts just after. * @return - the key that was the closest match or null if eof. */ - public synchronized WritableComparable getClosest(WritableComparable key, - Writable val, final boolean before) - throws IOException { + public synchronized Object getClosest(Object key, + Object val, + final boolean before + ) throws IOException { int c = seekInternal(key, before); @@ -720,7 +832,9 @@ public synchronized WritableComparable getClosest(WritableComparable key, } data.getCurrentValue(val); - return nextKey; + // deserialize the key + inBuf.reset(nextKey.getData(), 0, nextKey.getLength()); + return keySerialization.deserialize(inBuf, null, conf); } /** Close the map. */ @@ -764,17 +878,24 @@ public static void delete(FileSystem fs, String name) throws IOException { * @return number of valid entries in this MapFile, or -1 if no fixing was needed * @throws Exception */ + @SuppressWarnings("unchecked") public static long fix(FileSystem fs, Path dir, - Class keyClass, - Class valueClass, boolean dryrun, - Configuration conf) throws Exception { + Class keyClass, + Class valueClass, boolean dryrun, + Configuration conf) throws IOException { String dr = (dryrun ? "[DRY RUN ] " : ""); Path data = new Path(dir, DATA_FILE_NAME); Path index = new Path(dir, INDEX_FILE_NAME); int indexInterval = conf.getInt(Writer.INDEX_INTERVAL, 128); + SerializationFactory factory = SerializationFactory.getInstance(conf); + Serialization keySerialization = (Serialization) + factory.getSerializationByType(keyClass); + Serialization valueSerialization = (Serialization) + factory.getSerializationByType(valueClass); if (!fs.exists(data)) { // there's nothing we can do to fix this! - throw new Exception(dr + "Missing data file in " + dir + ", impossible to fix this."); + throw new IOException(dr + "Missing data file in " + dir + + ", impossible to fix this."); } if (fs.exists(index)) { // no fixing needed @@ -782,17 +903,17 @@ public static long fix(FileSystem fs, Path dir, } SequenceFile.Reader dataReader = new SequenceFile.Reader(conf, SequenceFile.Reader.file(data)); - if (!dataReader.getKeyClass().equals(keyClass)) { - throw new Exception(dr + "Wrong key class in " + dir + ", expected" + keyClass.getName() + - ", got " + dataReader.getKeyClass().getName()); + if (!dataReader.getKeySerialization().equals(keySerialization)) { + throw new IOException(dr + "Wrong key serialization in " + dir + + ", expected" + keySerialization + + ", got " + dataReader.getKeySerialization()); } - if (!dataReader.getValueClass().equals(valueClass)) { - throw new Exception(dr + "Wrong value class in " + dir + ", expected" + valueClass.getName() + - ", got " + dataReader.getValueClass().getName()); + if (!dataReader.getValueSerialization().equals(valueSerialization)) { + throw new IOException(dr + "Wrong value serialization in " + dir + + ", expected" + valueSerialization + + ", got " + dataReader.getValueSerialization()); } long cnt = 0L; - Writable key = ReflectionUtils.newInstance(keyClass, conf); - Writable value = ReflectionUtils.newInstance(valueClass, conf); SequenceFile.Writer indexWriter = null; if (!dryrun) { indexWriter = @@ -805,7 +926,10 @@ public static long fix(FileSystem fs, Path dir, try { long pos = 0L; LongWritable position = new LongWritable(); - while(dataReader.next(key, value)) { + Object key = null; + Object value = null; + while((key = dataReader.nextKey(key)) != null) { + value = dataReader.getCurrentValue(value); cnt++; if (cnt % indexInterval == 0) { position.set(pos); @@ -834,21 +958,21 @@ public static void main(String[] args) throws Exception { String out = args[1]; Configuration conf = new Configuration(); - FileSystem fs = FileSystem.getLocal(conf); - MapFile.Reader reader = new MapFile.Reader(fs, in, conf); + MapFile.Reader reader = new MapFile.Reader(new Path(in), conf); + Serialization keySerialization = reader.getKeySerialization(); + Serialization valueSerialization = reader.getValueSerialization(); MapFile.Writer writer = - new MapFile.Writer(conf, fs, out, - reader.getKeyClass().asSubclass(WritableComparable.class), - reader.getValueClass()); + new MapFile.Writer(conf, new Path(out), + Writer.keySerialization(keySerialization), + Writer.valueSerialization(valueSerialization)); - WritableComparable key = - ReflectionUtils.newInstance(reader.getKeyClass().asSubclass(WritableComparable.class), conf); - Writable value = - ReflectionUtils.newInstance(reader.getValueClass().asSubclass(Writable.class), conf); + Object key = null; + Object value = null; - while (reader.next(key, value)) // copy all entries + while ((key = reader.nextKey(key)) != null) { // copy all entries + value = reader.getCurrentValue(value); writer.append(key, value); - + } writer.close(); } diff --git a/src/java/org/apache/hadoop/io/RawComparator.java b/src/java/org/apache/hadoop/io/RawComparator.java index 11539442c8527..88e93e962a713 100644 --- a/src/java/org/apache/hadoop/io/RawComparator.java +++ b/src/java/org/apache/hadoop/io/RawComparator.java @@ -22,7 +22,6 @@ import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; -import org.apache.hadoop.io.serializer.DeserializerComparator; /** *

@@ -30,12 +29,15 @@ * objects. *

* @param - * @see DeserializerComparator + * @deprecated Use {@link org.apache.hadoop.io.serial.RawComparator} instead. */ @InterfaceAudience.Public @InterfaceStability.Stable -public interface RawComparator extends Comparator { +@Deprecated +public interface RawComparator + extends Comparator, org.apache.hadoop.io.serial.RawComparator { + @Override public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2); } diff --git a/src/java/org/apache/hadoop/io/SecureIOUtils.java b/src/java/org/apache/hadoop/io/SecureIOUtils.java new file mode 100644 index 0000000000000..321b0e89db66e --- /dev/null +++ b/src/java/org/apache/hadoop/io/SecureIOUtils.java @@ -0,0 +1,208 @@ +/** + * 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.io; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileStatus; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.permission.FsPermission; +import org.apache.hadoop.io.nativeio.Errno; +import org.apache.hadoop.io.nativeio.NativeIO; +import org.apache.hadoop.io.nativeio.NativeIOException; +import org.apache.hadoop.io.nativeio.NativeIO.Stat; +import org.apache.hadoop.security.UserGroupInformation; + +/** + * This class provides secure APIs for opening and creating files on the local + * disk. The main issue this class tries to handle is that of symlink traversal. + *
+ * An example of such an attack is: + *
    + *
  1. Malicious user removes his task's syslog file, and puts a link to the + * jobToken file of a target user.
  2. + *
  3. Malicious user tries to open the syslog file via the servlet on the + * tasktracker.
  4. + *
  5. The tasktracker is unaware of the symlink, and simply streams the contents + * of the jobToken file. The malicious user can now access potentially sensitive + * map outputs, etc. of the target user's job.
  6. + *
+ * A similar attack is possible involving task log truncation, but in that case + * due to an insecure write to a file. + *
+ */ +public class SecureIOUtils { + + /** + * Ensure that we are set up to run with the appropriate native support code. + * If security is disabled, and the support code is unavailable, this class + * still tries its best to be secure, but is vulnerable to some race condition + * attacks. + * + * If security is enabled but the support code is unavailable, throws a + * RuntimeException since we don't want to run insecurely. + */ + static { + boolean shouldBeSecure = UserGroupInformation.isSecurityEnabled(); + boolean canBeSecure = NativeIO.isAvailable(); + + if (!canBeSecure && shouldBeSecure) { + throw new RuntimeException( + "Secure IO is not possible without native code extensions."); + } + + // Pre-cache an instance of the raw FileSystem since we sometimes + // do secure IO in a shutdown hook, where this call could fail. + try { + rawFilesystem = FileSystem.getLocal(new Configuration()).getRaw(); + } catch (IOException ie) { + throw new RuntimeException( + "Couldn't obtain an instance of RawLocalFileSystem."); + } + + // SecureIO just skips security checks in the case that security is + // disabled + skipSecurity = !canBeSecure; + } + + private final static boolean skipSecurity; + private final static FileSystem rawFilesystem; + + /** + * Open the given File for read access, verifying the expected user/group + * constraints. + * @param f the file that we are trying to open + * @param expectedOwner the expected user owner for the file + * @param expectedGroup the expected group owner for the file + * @throws IOException if an IO Error occurred, or the user/group does not + * match + */ + public static FileInputStream openForRead(File f, String expectedOwner, + String expectedGroup) throws IOException { + if (skipSecurity) { + // Subject to race conditions but this is the best we can do + FileStatus status = + rawFilesystem.getFileStatus(new Path(f.getAbsolutePath())); + checkStat(f, status.getOwner(), status.getGroup(), + expectedOwner, expectedGroup); + return new FileInputStream(f); + } + + FileInputStream fis = new FileInputStream(f); + boolean success = false; + try { + Stat stat = NativeIO.fstat(fis.getFD()); + checkStat(f, stat.getOwner(), stat.getGroup(), expectedOwner, + expectedGroup); + success = true; + return fis; + } finally { + if (!success) { + fis.close(); + } + } + } + + private static FileOutputStream insecureCreateForWrite(File f, + int permissions) throws IOException { + // If we can't do real security, do a racy exists check followed by an + // open and chmod + if (f.exists()) { + throw new AlreadyExistsException("File " + f + " already exists"); + } + FileOutputStream fos = new FileOutputStream(f); + boolean success = false; + try { + rawFilesystem.setPermission(new Path(f.getAbsolutePath()), + new FsPermission((short)permissions)); + success = true; + return fos; + } finally { + if (!success) { + fos.close(); + } + } + } + + /** + * Open the specified File for write access, ensuring that it does not exist. + * @param f the file that we want to create + * @param permissions we want to have on the file (if security is enabled) + * + * @throws AlreadyExistsException if the file already exists + * @throws IOException if any other error occurred + */ + public static FileOutputStream createForWrite(File f, int permissions) + throws IOException { + if (skipSecurity) { + return insecureCreateForWrite(f, permissions); + } else { + // Use the native wrapper around open(2) + try { + FileDescriptor fd = NativeIO.open(f.getAbsolutePath(), + NativeIO.O_WRONLY | NativeIO.O_CREAT | NativeIO.O_EXCL, + permissions); + return new FileOutputStream(fd); + } catch (NativeIOException nioe) { + if (nioe.getErrno() == Errno.EEXIST) { + throw new AlreadyExistsException(nioe); + } + throw nioe; + } + } + } + + private static void checkStat(File f, String owner, String group, + String expectedOwner, + String expectedGroup) throws IOException { + if (expectedOwner != null && + !expectedOwner.equals(owner)) { + throw new IOException( + "Owner '" + owner + "' for path " + f + " did not match " + + "expected owner '" + expectedOwner + "'"); + } + if (expectedGroup != null && + !expectedGroup.equals(group)) { + throw new IOException( + "Group '" + group + "' for path " + f + " did not match " + + "expected group '" + expectedGroup + "'"); + } + } + + /** + * Signals that an attempt to create a file at a given pathname has failed + * because another file already existed at that path. + */ + public static class AlreadyExistsException extends IOException { + private static final long serialVersionUID = 1L; + + public AlreadyExistsException(String msg) { + super(msg); + } + + public AlreadyExistsException(Throwable cause) { + super(cause); + } + } +} diff --git a/src/java/org/apache/hadoop/io/SequenceFile.java b/src/java/org/apache/hadoop/io/SequenceFile.java index b3f1630dd4952..91aed3257d84f 100644 --- a/src/java/org/apache/hadoop/io/SequenceFile.java +++ b/src/java/org/apache/hadoop/io/SequenceFile.java @@ -34,12 +34,14 @@ import org.apache.hadoop.io.compress.DefaultCodec; import org.apache.hadoop.io.compress.GzipCodec; import org.apache.hadoop.io.compress.zlib.ZlibFactory; -import org.apache.hadoop.io.serializer.Deserializer; -import org.apache.hadoop.io.serializer.Serializer; -import org.apache.hadoop.io.serializer.SerializationFactory; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.serial.Serialization; +import org.apache.hadoop.io.serial.SerializationFactory; +import org.apache.hadoop.io.serial.TypedSerialization; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; -import org.apache.hadoop.conf.*; +import org.apache.hadoop.conf.Configurable; +import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.util.Progressable; import org.apache.hadoop.util.Progress; import org.apache.hadoop.util.ReflectionUtils; @@ -93,10 +95,16 @@ * version number (e.g. SEQ4 or SEQ6) * *
  • - * keyClassName -key class + * key serialization name *
  • *
  • - * valueClassName - value class + * key serialization configuration + *
  • + *
  • + * value serialization name + *
  • + *
  • + * value serialization data *
  • *
  • * compression - A boolean which specifies if compression is turned on for @@ -134,7 +142,7 @@ * *
  • *
  • - * A sync-marker every few 100 bytes or so. + * A sync-marker every 2000 bytes or so. *
  • * * @@ -153,7 +161,7 @@ * * *
  • - * A sync-marker every few 100 bytes or so. + * A sync-marker every 2000 bytes or so. *
  • * * @@ -165,6 +173,7 @@ *
  • * Record Block *
      + *
    • sync-marker
    • *
    • Compressed key-lengths block-size
    • *
    • Compressed key-lengths block
    • *
    • Compressed keys block-size
    • @@ -175,9 +184,6 @@ *
    • Compressed values block
    • *
    *
  • - *
  • - * A sync-marker every few 100 bytes or so. - *
  • * * *

    The compressed blocks of key lengths and value lengths consist of the @@ -196,8 +202,9 @@ private SequenceFile() {} // no public ctor private static final byte BLOCK_COMPRESS_VERSION = (byte)4; private static final byte CUSTOM_COMPRESS_VERSION = (byte)5; private static final byte VERSION_WITH_METADATA = (byte)6; + private static final byte SERIALIZATION_VERSION = (byte) 7; private static byte[] VERSION = new byte[] { - (byte)'S', (byte)'E', (byte)'Q', VERSION_WITH_METADATA + (byte)'S', (byte)'E', (byte)'Q', SERIALIZATION_VERSION }; private static final int SYNC_ESCAPE = -1; // "length" of sync entries @@ -285,6 +292,7 @@ public static Writer createWriter(Configuration conf, Writer.Option... opts * instead. */ @Deprecated + @SuppressWarnings("unchecked") public static Writer createWriter(FileSystem fs, Configuration conf, Path name, Class keyClass, Class valClass) throws IOException { @@ -306,6 +314,7 @@ public static Writer createWriter(Configuration conf, Writer.Option... opts * instead. */ @Deprecated + @SuppressWarnings("unchecked") public static Writer createWriter(FileSystem fs, Configuration conf, Path name, Class keyClass, Class valClass, @@ -330,6 +339,7 @@ public static Writer createWriter(Configuration conf, Writer.Option... opts * instead. */ @Deprecated + @SuppressWarnings("unchecked") public static Writer createWriter(FileSystem fs, Configuration conf, Path name, Class keyClass, Class valClass, CompressionType compressionType, @@ -355,6 +365,7 @@ public static Writer createWriter(Configuration conf, Writer.Option... opts * instead. */ @Deprecated + @SuppressWarnings("unchecked") public static Writer createWriter(FileSystem fs, Configuration conf, Path name, Class keyClass, Class valClass, CompressionType compressionType, @@ -381,6 +392,7 @@ public static Writer createWriter(Configuration conf, Writer.Option... opts * instead. */ @Deprecated + @SuppressWarnings("unchecked") public static Writer createWriter(FileSystem fs, Configuration conf, Path name, Class keyClass, Class valClass, @@ -413,6 +425,7 @@ public static Writer createWriter(Configuration conf, Writer.Option... opts * instead. */ @Deprecated + @SuppressWarnings("unchecked") public static Writer createWriter(FileSystem fs, Configuration conf, Path name, Class keyClass, Class valClass, int bufferSize, @@ -444,6 +457,7 @@ public static Writer createWriter(Configuration conf, Writer.Option... opts * @deprecated Use {@link #createWriter(Configuration, Writer.Option...)} * instead. */ + @SuppressWarnings("unchecked") @Deprecated public static Writer createWriter(FileSystem fs, Configuration conf, Path name, @@ -471,6 +485,7 @@ public static Writer createWriter(Configuration conf, Writer.Option... opts * instead. */ @Deprecated + @SuppressWarnings("unchecked") public static Writer createWriter(Configuration conf, FSDataOutputStream out, Class keyClass, Class valClass, @@ -495,6 +510,7 @@ public static Writer createWriter(Configuration conf, Writer.Option... opts * @deprecated Use {@link #createWriter(Configuration, Writer.Option...)} * instead. */ + @SuppressWarnings("unchecked") @Deprecated public static Writer createWriter(Configuration conf, FSDataOutputStream out, @@ -527,18 +543,44 @@ public void writeCompressedBytes(DataOutputStream outStream) * Size of stored data. */ public int getSize(); + } + + /** + * Make an InputStream from a ValueBytes. + * @param bytes the bytes to provide as input + * @return a new input stream with the bytes + * @throws IOException + */ + private static InputStream readUncompressedBytes(ValueBytes bytes + ) throws IOException { + DataInputBuffer result = new DataInputBuffer(); + if (bytes instanceof UncompressedBytes) { + MutableValueBytes concrete = (MutableValueBytes) bytes; + result.reset(concrete.data, concrete.dataSize); + } else { + DataOutputBuffer outBuf = new DataOutputBuffer(); + bytes.writeUncompressedBytes(outBuf); + result.reset(outBuf.getData(), outBuf.getLength()); + } + return result; + } + - private static class UncompressedBytes implements ValueBytes { - private int dataSize; - private byte[] data; - - private UncompressedBytes() { + private static abstract class MutableValueBytes implements ValueBytes { + protected byte[] data; + protected int dataSize; + + MutableValueBytes() { data = null; dataSize = 0; } + + public int getSize() { + return dataSize; + } - private void reset(DataInputStream in, int length) throws IOException { + void reset(DataInputStream in, int length) throws IOException { if (data == null) { data = new byte[length]; } else if (length > data.length) { @@ -548,10 +590,14 @@ private void reset(DataInputStream in, int length) throws IOException { in.readFully(data, 0, length); dataSize = length; } - - public int getSize() { - return dataSize; + + void set(MutableValueBytes other) { + data = other.data; + dataSize = other.dataSize; } + } + + private static class UncompressedBytes extends MutableValueBytes { public void writeUncompressedBytes(DataOutputStream outStream) throws IOException { @@ -566,34 +612,15 @@ public void writeCompressedBytes(DataOutputStream outStream) } // UncompressedBytes - private static class CompressedBytes implements ValueBytes { - private int dataSize; - private byte[] data; + private static class CompressedBytes extends MutableValueBytes { DataInputBuffer rawData = null; CompressionCodec codec = null; CompressionInputStream decompressedStream = null; private CompressedBytes(CompressionCodec codec) { - data = null; - dataSize = 0; this.codec = codec; } - private void reset(DataInputStream in, int length) throws IOException { - if (data == null) { - data = new byte[length]; - } else if (length > data.length) { - data = new byte[Math.max(length, data.length * 2)]; - } - dataSize = -1; - in.readFully(data, 0, length); - dataSize = length; - } - - public int getSize() { - return dataSize; - } - public void writeUncompressedBytes(DataOutputStream outStream) throws IOException { if (decompressedStream == null) { @@ -738,9 +765,6 @@ public static class Writer implements java.io.Closeable { boolean ownOutputStream = true; DataOutputBuffer buffer = new DataOutputBuffer(); - Class keyClass; - Class valClass; - private final CompressionType compress; CompressionCodec codec = null; CompressionOutputStream deflateFilter = null; @@ -748,9 +772,8 @@ public static class Writer implements java.io.Closeable { Metadata metadata = null; Compressor compressor = null; - protected Serializer keySerializer; - protected Serializer uncompressedValSerializer; - protected Serializer compressedValSerializer; + protected Serialization keySerialization; + protected Serialization valueSerialization; // Insert a globally unique 16-byte value every few entries, so that one // can seek into the middle of a file and then synchronize with record @@ -817,6 +840,20 @@ static class ValueClassOption extends Options.ClassOption } } + static class KeySerialization extends Options.SerializationOption + implements Option { + KeySerialization(Serialization value) { + super(value); + } + } + + static class ValueSerialization extends Options.SerializationOption + implements Option { + ValueSerialization(Serialization value) { + super(value); + } + } + static class MetadataOption implements Option { private final Metadata value; MetadataOption(Metadata value) { @@ -878,6 +915,14 @@ public static Option progressable(Progressable value) { return new ProgressableOption(value); } + public static Option keySerialization(Serialization value) { + return new KeySerialization(value); + } + + public static Option valueSerialization(Serialization value) { + return new ValueSerialization(value); + } + public static Option keyClass(Class value) { return new KeyClassOption(value); } @@ -905,6 +950,7 @@ public static Option compression(CompressionType value, * @param options the options used when creating the writer * @throws IOException if it fails */ + @SuppressWarnings("unchecked") Writer(Configuration conf, Option... opts) throws IOException { BlockSizeOption blockSizeOption = @@ -917,6 +963,10 @@ public static Option compression(CompressionType value, Options.getOption(ProgressableOption.class, opts); FileOption fileOption = Options.getOption(FileOption.class, opts); StreamOption streamOption = Options.getOption(StreamOption.class, opts); + KeySerialization keySerializationOption = + Options.getOption(KeySerialization.class, opts); + ValueSerialization valueSerializationOption = + Options.getOption(ValueSerialization.class, opts); KeyClassOption keyClassOption = Options.getOption(KeyClassOption.class, opts); ValueClassOption valueClassOption = @@ -936,6 +986,15 @@ public static Option compression(CompressionType value, throw new IllegalArgumentException("file modifier options not " + "compatible with stream"); } + // exactly one of serialization or class must be set. + if ((keySerializationOption == null) == (keyClassOption == null)) { + throw new IllegalArgumentException("Either keySerialization or " + + " keyClass must be set."); + } + if ((valueSerializationOption == null) == (valueClassOption == null)) { + throw new IllegalArgumentException("Either valueSerialization or " + + " valueClass must be set."); + } FSDataOutputStream out; boolean ownStream = fileOption != null; @@ -955,10 +1014,31 @@ public static Option compression(CompressionType value, } else { out = streamOption.getValue(); } - Class keyClass = keyClassOption == null ? - Object.class : keyClassOption.getValue(); - Class valueClass = valueClassOption == null ? - Object.class : valueClassOption.getValue(); + + // find the key serialization by parameter or by key type + Serialization keySerialization; + if (keyClassOption != null) { + Class keyClass = keyClassOption.getValue(); + SerializationFactory factory = SerializationFactory.getInstance(conf); + keySerialization = + (Serialization) factory.getSerializationByType(keyClass); + } else { + keySerialization = + (Serialization) keySerializationOption.getValue(); + } + + // find the value serialization by parameter or by value type + Serialization valueSerialization; + if (valueClassOption != null) { + Class valueClass = valueClassOption.getValue(); + SerializationFactory factory = SerializationFactory.getInstance(conf); + valueSerialization = + (Serialization) factory.getSerializationByType(valueClass); + } else { + valueSerialization = + (Serialization) valueSerializationOption.getValue(); + } + Metadata metadata = metadataOption == null ? new Metadata() : metadataOption.getValue(); this.compress = compressionTypeOption.getValue(); @@ -971,7 +1051,8 @@ public static Option compression(CompressionType value, "GzipCodec without native-hadoop " + "code!"); } - init(conf, out, ownStream, keyClass, valueClass, codec, metadata); + init(conf, out, ownStream, keySerialization, valueSerialization, + codec, metadata); } /** Create the named file. @@ -979,11 +1060,15 @@ public static Option compression(CompressionType value, * {@link SequenceFile#createWriter(Configuration, Writer.Option...)} * instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(FileSystem fs, Configuration conf, Path name, Class keyClass, Class valClass) throws IOException { this.compress = CompressionType.NONE; - init(conf, fs.create(name), true, keyClass, valClass, null, + SerializationFactory factory = SerializationFactory.getInstance(conf); + init(conf, fs.create(name), true, + factory.getSerializationByType(keyClass), + factory.getSerializationByType(valClass), null, new Metadata()); } @@ -992,12 +1077,16 @@ public Writer(FileSystem fs, Configuration conf, Path name, * {@link SequenceFile#createWriter(Configuration, Writer.Option...)} * instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(FileSystem fs, Configuration conf, Path name, Class keyClass, Class valClass, Progressable progress, Metadata metadata) throws IOException { this.compress = CompressionType.NONE; - init(conf, fs.create(name, progress), true, keyClass, valClass, + SerializationFactory factory = SerializationFactory.getInstance(conf); + init(conf, fs.create(name, progress), true, + factory.getSerializationByType(keyClass), + factory.getSerializationByType(valClass), null, metadata); } @@ -1006,15 +1095,18 @@ public Writer(FileSystem fs, Configuration conf, Path name, * {@link SequenceFile#createWriter(Configuration, Writer.Option...)} * instead. */ + @SuppressWarnings("unchecked") @Deprecated public Writer(FileSystem fs, Configuration conf, Path name, Class keyClass, Class valClass, int bufferSize, short replication, long blockSize, Progressable progress, Metadata metadata) throws IOException { this.compress = CompressionType.NONE; + SerializationFactory factory = SerializationFactory.getInstance(conf); init(conf, fs.create(name, true, bufferSize, replication, blockSize, progress), - true, keyClass, valClass, null, metadata); + true, factory.getSerializationByType(keyClass), + factory.getSerializationByType(valClass), null, metadata); } boolean isCompressed() { return compress != CompressionType.NONE; } @@ -1024,8 +1116,20 @@ public Writer(FileSystem fs, Configuration conf, Path name, private void writeFileHeader() throws IOException { out.write(VERSION); - Text.writeString(out, keyClass.getName()); - Text.writeString(out, valClass.getName()); + + // write out key serialization + Text.writeString(out, keySerialization.getName()); + buffer.reset(); + keySerialization.serializeSelf(buffer); + WritableUtils.writeVInt(out, buffer.getLength()); + out.write(buffer.getData(), 0, buffer.getLength()); + + // write out value serialization + Text.writeString(out, valueSerialization.getName()); + buffer.reset(); + valueSerialization.serializeSelf(buffer); + WritableUtils.writeVInt(out, buffer.getLength()); + out.write(buffer.getData(), 0, buffer.getLength()); out.writeBoolean(this.isCompressed()); out.writeBoolean(this.isBlockCompressed()); @@ -1039,40 +1143,74 @@ private void writeFileHeader() } /** Initialize. */ - @SuppressWarnings("unchecked") void init(Configuration conf, FSDataOutputStream out, boolean ownStream, - Class keyClass, Class valClass, + Serialization keySerialization, + Serialization valueSerialization, CompressionCodec codec, Metadata metadata) throws IOException { this.conf = conf; this.out = out; this.ownOutputStream = ownStream; - this.keyClass = keyClass; - this.valClass = valClass; + this.keySerialization = keySerialization; + this.valueSerialization = valueSerialization; this.codec = codec; this.metadata = metadata; - SerializationFactory serializationFactory = new SerializationFactory(conf); - this.keySerializer = serializationFactory.getSerializer(keyClass); - this.keySerializer.open(buffer); - this.uncompressedValSerializer = serializationFactory.getSerializer(valClass); - this.uncompressedValSerializer.open(buffer); if (this.codec != null) { ReflectionUtils.setConf(this.codec, this.conf); this.compressor = CodecPool.getCompressor(this.codec); this.deflateFilter = this.codec.createOutputStream(buffer, compressor); this.deflateOut = new DataOutputStream(new BufferedOutputStream(deflateFilter)); - this.compressedValSerializer = serializationFactory.getSerializer(valClass); - this.compressedValSerializer.open(deflateOut); } writeFileHeader(); } - /** Returns the class of keys in this file. */ - public Class getKeyClass() { return keyClass; } + /** Returns the class of keys in this file. Only works for + * if a TypedSerialization is used, otherwise Object is returned. + * @deprecated Use {@link #getKeySerialization} instead. + */ + @SuppressWarnings("unchecked") + @Deprecated + public Class getKeyClass() { + Class result = null; + if (keySerialization instanceof TypedSerialization) { + TypedSerialization typed = (TypedSerialization) keySerialization; + result = typed.getSpecificType(); + } + return result == null ? Object.class : result; + } + + + /** Returns the class of values in this file. Only works for + * if a TypedSerialization is used, otherwise Object is returned. + * @deprecated Use {@link #getValueSerialization} instead. + */ + @SuppressWarnings("unchecked") + @Deprecated + public Class getValueClass() { + Class result = null; + if (valueSerialization instanceof TypedSerialization) { + TypedSerialization typed = (TypedSerialization) valueSerialization; + result = typed.getSpecificType(); + } + return result == null ? Object.class : result; + } - /** Returns the class of values in this file. */ - public Class getValueClass() { return valClass; } + /** + * Return the serialization that is used to serialize the keys. + * @return the key serialization + */ + public Serialization getKeySerialization() { + return keySerialization; + } + + /** + * Return the serialization that is used to serialize the values. + * @return the value serialization + */ + public Serialization getValueSerialization() { + return valueSerialization; + } /** Returns the compression codec of data in this file. */ public CompressionCodec getCompressionCodec() { return codec; } @@ -1091,12 +1229,6 @@ public void sync() throws IOException { /** Close the file. */ public synchronized void close() throws IOException { - keySerializer.close(); - uncompressedValSerializer.close(); - if (compressedValSerializer != null) { - compressedValSerializer.close(); - } - CodecPool.returnCompressor(compressor); compressor = null; @@ -1119,27 +1251,20 @@ synchronized void checkAndWriteSync() throws IOException { } } - /** Append a key/value pair. */ - public void append(Writable key, Writable val) - throws IOException { + /** Append a key/value pair. + */ + public void append(Writable key, Writable val) throws IOException { append((Object) key, (Object) val); } /** Append a key/value pair. */ - @SuppressWarnings("unchecked") public synchronized void append(Object key, Object val) throws IOException { - if (key.getClass() != keyClass) - throw new IOException("wrong key class: "+key.getClass().getName() - +" is not "+keyClass); - if (val.getClass() != valClass) - throw new IOException("wrong value class: "+val.getClass().getName() - +" is not "+valClass); buffer.reset(); // Append the 'key' - keySerializer.serialize(key); + keySerialization.serialize(buffer, key); int keyLength = buffer.getLength(); if (keyLength < 0) throw new IOException("negative length keys not allowed: " + key); @@ -1147,11 +1272,11 @@ public synchronized void append(Object key, Object val) // Append the 'value' if (compress == CompressionType.RECORD) { deflateFilter.resetState(); - compressedValSerializer.serialize(val); + valueSerialization.serialize(deflateFilter, val); deflateOut.flush(); deflateFilter.finish(); } else { - uncompressedValSerializer.serialize(val); + valueSerialization.serialize(buffer, val); } // Write the record out @@ -1200,27 +1325,18 @@ static class RecordCompressWriter extends Writer { } /** Append a key/value pair. */ - @SuppressWarnings("unchecked") - public synchronized void append(Object key, Object val) - throws IOException { - if (key.getClass() != keyClass) - throw new IOException("wrong key class: "+key.getClass().getName() - +" is not "+keyClass); - if (val.getClass() != valClass) - throw new IOException("wrong value class: "+val.getClass().getName() - +" is not "+valClass); - - buffer.reset(); + public synchronized void append(Object key, Object val) throws IOException { // Append the 'key' - keySerializer.serialize(key); + buffer.reset(); + keySerialization.serialize(buffer, key); int keyLength = buffer.getLength(); if (keyLength < 0) throw new IOException("negative length keys not allowed: " + key); // Compress 'value' and append it deflateFilter.resetState(); - compressedValSerializer.serialize(val); + valueSerialization.serialize(deflateFilter, val); deflateOut.flush(); deflateFilter.finish(); @@ -1267,10 +1383,6 @@ static class BlockCompressWriter extends Writer { super(conf, options); compressionBlockSize = conf.getInt("io.seqfile.compress.blocksize", 1000000); - keySerializer.close(); - keySerializer.open(keyBuffer); - uncompressedValSerializer.close(); - uncompressedValSerializer.open(valBuffer); } /** Workhorse to check and write out compressed data/lengths */ @@ -1326,24 +1438,18 @@ public synchronized void close() throws IOException { } /** Append a key/value pair. */ - @SuppressWarnings("unchecked") - public synchronized void append(Object key, Object val) - throws IOException { - if (key.getClass() != keyClass) - throw new IOException("wrong key class: "+key+" is not "+keyClass); - if (val.getClass() != valClass) - throw new IOException("wrong value class: "+val+" is not "+valClass); + public synchronized void append(Object key, Object val) throws IOException { // Save key/value into respective buffers int oldKeyLength = keyBuffer.getLength(); - keySerializer.serialize(key); + keySerialization.serialize(keyBuffer, key); int keyLength = keyBuffer.getLength() - oldKeyLength; if (keyLength < 0) throw new IOException("negative length keys not allowed: " + key); WritableUtils.writeVInt(keyLenBuffer, keyLength); int oldValLength = valBuffer.getLength(); - uncompressedValSerializer.serialize(val); + valueSerialization.serialize(valBuffer, val); int valLength = valBuffer.getLength() - oldValLength; WritableUtils.writeVInt(valLenBuffer, valLength); @@ -1393,15 +1499,9 @@ private static int getBufferSize(Configuration conf) { public static class Reader implements java.io.Closeable { private String filename; private FSDataInputStream in; - private DataOutputBuffer outBuf = new DataOutputBuffer(); private byte version; - private String keyClassName; - private String valClassName; - private Class keyClass; - private Class valClass; - private CompressionCodec codec = null; private Metadata metadata = null; @@ -1411,8 +1511,6 @@ public static class Reader implements java.io.Closeable { private long headerEnd; private long end; - private int keyLength; - private int recordLength; private boolean decompress; private boolean blockCompressed; @@ -1420,17 +1518,12 @@ public static class Reader implements java.io.Closeable { private Configuration conf; private int noBufferedRecords = 0; - private boolean lazyDecompress = true; - private boolean valuesDecompressed = true; - - private int noBufferedKeys = 0; - private int noBufferedValues = 0; private DataInputBuffer keyLenBuffer = null; private CompressionInputStream keyLenInFilter = null; private DataInputStream keyLenIn = null; private Decompressor keyLenDecompressor = null; - private DataInputBuffer keyBuffer = null; + private DataInputBuffer keyBlockBuffer = null; private CompressionInputStream keyInFilter = null; private DataInputStream keyIn = null; private Decompressor keyDecompressor = null; @@ -1444,8 +1537,13 @@ public static class Reader implements java.io.Closeable { private DataInputStream valIn = null; private Decompressor valDecompressor = null; - private Deserializer keyDeserializer; - private Deserializer valDeserializer; + // used for object serialization + private DataOutputBuffer keyBuffer; + private MutableValueBytes valueBytes; + private DataInputBuffer serialBuffer; + + private Serialization keySerialization; + private Serialization valueSerialization; /** * A tag interface for all of the Reader options @@ -1470,6 +1568,24 @@ public static Option stream(FSDataInputStream value) { return new InputStreamOption(value); } + /** + * Create an option to specify the required key serialization. + * @param value the serialization to deserialize the key with + * @return a new option + */ + public static Option keySerialization(Serialization value) { + return new KeySerializationOption(value); + } + + /** + * Create an option to specify the required value serialization. + * @param value the serialization to deserialize the value with + * @return a new option + */ + public static Option valueSerialization(Serialization value) { + return new ValueSerializationOption(value); + } + /** * Create an option to specify the starting byte to read. * @param value the number of bytes to skip over @@ -1541,6 +1657,22 @@ private OnlyHeaderOption() { } } + private static class KeySerializationOption + extends Options.SerializationOption + implements Option { + private KeySerializationOption(Serialization value) { + super(value); + } + } + + private static class ValueSerializationOption + extends Options.SerializationOption + implements Option { + private ValueSerializationOption(Serialization value) { + super(value); + } + } + public Reader(Configuration conf, Option... opts) throws IOException { // Look up the options, these are null if not set FileOption fileOpt = Options.getOption(FileOption.class, opts); @@ -1551,6 +1683,11 @@ public Reader(Configuration conf, Option... opts) throws IOException { BufferSizeOption bufOpt = Options.getOption(BufferSizeOption.class,opts); OnlyHeaderOption headerOnly = Options.getOption(OnlyHeaderOption.class, opts); + KeySerializationOption keyOpt = + Options.getOption(KeySerializationOption.class, opts); + ValueSerializationOption valueOpt = + Options.getOption(ValueSerializationOption.class, opts); + // check for consistency if ((fileOpt == null) == (streamOpt == null)) { throw new @@ -1560,6 +1697,7 @@ public Reader(Configuration conf, Option... opts) throws IOException { throw new IllegalArgumentException("buffer size can only be set when" + " a file is specified."); } + // figure out the real values Path filename = null; FSDataInputStream file; @@ -1577,8 +1715,12 @@ public Reader(Configuration conf, Option... opts) throws IOException { file = streamOpt.getValue(); } long start = startOpt == null ? 0 : startOpt.getValue(); + // really set up - initialize(filename, file, start, len, conf, headerOnly != null); + initialize(filename, file, start, len, conf, + (keyOpt == null ? null : keyOpt.getValue()), + (valueOpt == null ? null : valueOpt.getValue()), + headerOnly != null); } /** @@ -1614,6 +1756,8 @@ public Reader(FSDataInputStream in, int buffersize, /** Common work of the constructors. */ private void initialize(Path filename, FSDataInputStream in, long start, long length, Configuration conf, + Serialization keySerialization, + Serialization valueSerialization, boolean tempReader) throws IOException { if (in == null) { throw new IllegalArgumentException("in == null"); @@ -1625,12 +1769,11 @@ private void initialize(Path filename, FSDataInputStream in, try { seek(start); this.end = this.in.getPos() + length; - System.out.println("Setting end to " + end); // if it wrapped around, use the max if (end < length) { end = Long.MAX_VALUE; } - init(tempReader); + init(tempReader, keySerialization, valueSerialization); succeeded = true; } finally { if (!succeeded) { @@ -1654,7 +1797,34 @@ protected FSDataInputStream openFile(FileSystem fs, Path file, int bufferSize, long length) throws IOException { return fs.open(file, bufferSize); } - + + @SuppressWarnings("unchecked") + private + Serialization readSerialization(SerializationFactory factory, + Serialization override + ) throws IOException { + String serializationName = Text.readString(in); + Serialization result; + if (override == null) { + result = factory.getSerialization(serializationName); + } else { + if (!serializationName.equals(override.getName())) { + throw new IllegalArgumentException("using serialization " + + override.getName() + + " instead of " + + serializationName); + } + result = override; + } + int keySerialLength = WritableUtils.readVInt(in); + DataInputBuffer buffer = new DataInputBuffer(); + byte[] bytes = new byte[keySerialLength]; + in.readFully(bytes); + buffer.reset(bytes, keySerialLength); + result.deserializeSelf(buffer, conf); + return (Serialization) result; + } + /** * Initialize the {@link Reader} * @param tmpReader true if we are constructing a temporary @@ -1663,7 +1833,10 @@ protected FSDataInputStream openFile(FileSystem fs, Path file, * false otherwise. * @throws IOException */ - private void init(boolean tempReader) throws IOException { + @SuppressWarnings({ "unchecked", "deprecation" }) + private void init(boolean tempReader, + Serialization keySerialization, + Serialization valueSerialization) throws IOException { byte[] versionBlock = new byte[VERSION.length]; in.readFully(versionBlock); @@ -1677,17 +1850,39 @@ private void init(boolean tempReader) throws IOException { if (version > VERSION[3]) throw new VersionMismatchException(VERSION[3], version); - if (version < BLOCK_COMPRESS_VERSION) { - UTF8 className = new UTF8(); + SerializationFactory factory = SerializationFactory.getInstance(conf); + if (version < SERIALIZATION_VERSION) { + String keyClassName; + String valueClassName; + if (version < BLOCK_COMPRESS_VERSION) { + UTF8 className = new UTF8(); - className.readFields(in); - keyClassName = className.toString(); // key class name + className.readFields(in); + keyClassName = className.toString(); // key class name - className.readFields(in); - valClassName = className.toString(); // val class name + className.readFields(in); + valueClassName = className.toString(); // val class name + } else { + keyClassName = Text.readString(in); + valueClassName = Text.readString(in); + } + try { + this.keySerialization = (Serialization) + factory.getSerializationByType(conf.getClassByName(keyClassName)); + } catch (ClassNotFoundException cnf) { + throw new RuntimeException("key class " + keyClassName + + " not found"); + } + try { + this.valueSerialization = (Serialization) + factory.getSerializationByType(conf.getClassByName(valueClassName)); + } catch (ClassNotFoundException cnf) { + throw new RuntimeException("value class " + valueClassName + + " not found"); + } } else { - keyClassName = Text.readString(in); - valClassName = Text.readString(in); + this.keySerialization = readSerialization(factory, keySerialization); + this.valueSerialization = readSerialization(factory,valueSerialization); } if (version > 2) { // if version > 2 @@ -1733,6 +1928,8 @@ private void init(boolean tempReader) throws IOException { // Initialize... *not* if this we are constructing a temporary Reader if (!tempReader) { + keyBuffer = new DataOutputBuffer(); + serialBuffer = new DataInputBuffer(); valBuffer = new DataInputBuffer(); if (decompress) { valDecompressor = CodecPool.getDecompressor(codec); @@ -1744,7 +1941,7 @@ private void init(boolean tempReader) throws IOException { if (blockCompressed) { keyLenBuffer = new DataInputBuffer(); - keyBuffer = new DataInputBuffer(); + keyBlockBuffer = new DataInputBuffer(); valLenBuffer = new DataInputBuffer(); keyLenDecompressor = CodecPool.getDecompressor(codec); @@ -1753,7 +1950,8 @@ private void init(boolean tempReader) throws IOException { keyLenIn = new DataInputStream(keyLenInFilter); keyDecompressor = CodecPool.getDecompressor(codec); - keyInFilter = codec.createInputStream(keyBuffer, keyDecompressor); + keyInFilter = codec.createInputStream(keyBlockBuffer, + keyDecompressor); keyIn = new DataInputStream(keyInFilter); valLenDecompressor = CodecPool.getDecompressor(codec); @@ -1761,27 +1959,10 @@ private void init(boolean tempReader) throws IOException { valLenDecompressor); valLenIn = new DataInputStream(valLenInFilter); } - - SerializationFactory serializationFactory = - new SerializationFactory(conf); - this.keyDeserializer = - getDeserializer(serializationFactory, getKeyClass()); - if (!blockCompressed) { - this.keyDeserializer.open(valBuffer); - } else { - this.keyDeserializer.open(keyIn); - } - this.valDeserializer = - getDeserializer(serializationFactory, getValueClass()); - this.valDeserializer.open(valIn); + valueBytes = (MutableValueBytes) createValueBytes(); } } - @SuppressWarnings("unchecked") - private Deserializer getDeserializer(SerializationFactory sf, Class c) { - return sf.getDeserializer(c); - } - /** Close the file. */ public synchronized void close() throws IOException { // Return the decompressors to the pool @@ -1792,49 +1973,80 @@ public synchronized void close() throws IOException { keyLenDecompressor = keyDecompressor = null; valLenDecompressor = valDecompressor = null; - if (keyDeserializer != null) { - keyDeserializer.close(); - } - if (valDeserializer != null) { - valDeserializer.close(); - } - // Close the input-stream in.close(); } - /** Returns the name of the key class. */ + /** + * Return the name of the key class. It only works for + * TypedSerializations and otherwise returns Object. + * @return the key class name + * @deprecated Use {@link #getKeySerialization()} instead. + */ + @Deprecated public String getKeyClassName() { - return keyClassName; + return getKeyClass().getName(); } - /** Returns the class of keys in this file. */ + /** + * Get the class of the keys in this file. It only works for + * TypedSerializations and otherwise returns Object. + * @return the class of the keys + * @deprecated Use {@link #getKeySerialization()} instead. + */ + @Deprecated + @SuppressWarnings("unchecked") public synchronized Class getKeyClass() { - if (null == keyClass) { - try { - keyClass = WritableName.getClass(getKeyClassName(), conf); - } catch (IOException e) { - throw new RuntimeException(e); - } + Class result = null; + if (keySerialization instanceof TypedSerialization) { + TypedSerialization typed = (TypedSerialization) keySerialization; + result = typed.getSpecificType(); } - return keyClass; + return result == null ? Object.class : result; } - /** Returns the name of the value class. */ + /** + * Return the name of the value class. It only works for + * TypedSerializations and otherwise returns Object. + * @return the value class name + * @deprecated Use {@link #getValueSerialization()} instead. + */ + @Deprecated public String getValueClassName() { - return valClassName; + return getValueClass().getName(); } - /** Returns the class of values in this file. */ + /** + * Get the class of the values in this file. It only works for + * TypedSerializations and otherwise returns Object. + * @return the class of the values + * @deprecated Use {@link #getValueSerialization()} instead. + */ + @Deprecated + @SuppressWarnings("unchecked") public synchronized Class getValueClass() { - if (null == valClass) { - try { - valClass = WritableName.getClass(getValueClassName(), conf); - } catch (IOException e) { - throw new RuntimeException(e); - } + Class result = null; + if (valueSerialization instanceof TypedSerialization) { + TypedSerialization typed = (TypedSerialization) valueSerialization; + result = typed.getSpecificType(); } - return valClass; + return result == null ? Object.class : result; + } + + /** + * Get the serialization for the key. + * @return the key serialization + */ + public Serialization getKeySerialization() { + return keySerialization; + } + + /** + * Get the serialization for the value. + * @return the value serialization + */ + public Serialization getValueSerialization() { + return valueSerialization; } /** Returns true if values are compressed. */ @@ -1888,16 +2100,9 @@ private synchronized void readBuffer(DataInputBuffer buffer, /** Read the next 'compressed' block */ private synchronized void readBlock() throws IOException { - // Check if we need to throw away a whole block of - // 'values' due to 'lazy decompression' - if (lazyDecompress && !valuesDecompressed) { - in.seek(WritableUtils.readVInt(in)+in.getPos()); - in.seek(WritableUtils.readVInt(in)+in.getPos()); - } // Reset internal states - noBufferedKeys = 0; noBufferedValues = 0; noBufferedRecords = 0; - valuesDecompressed = false; + noBufferedRecords = 0; //Process sync if (sync != null) { @@ -1913,55 +2118,11 @@ private synchronized void readBlock() throws IOException { // Read key lengths and keys readBuffer(keyLenBuffer, keyLenInFilter); - readBuffer(keyBuffer, keyInFilter); - noBufferedKeys = noBufferedRecords; + readBuffer(keyBlockBuffer, keyInFilter); // Read value lengths and values - if (!lazyDecompress) { - readBuffer(valLenBuffer, valLenInFilter); - readBuffer(valBuffer, valInFilter); - noBufferedValues = noBufferedRecords; - valuesDecompressed = true; - } - } - - /** - * Position valLenIn/valIn to the 'value' - * corresponding to the 'current' key - */ - private synchronized void seekToCurrentValue() throws IOException { - if (!blockCompressed) { - if (decompress) { - valInFilter.resetState(); - } - valBuffer.reset(); - } else { - // Check if this is the first value in the 'block' to be read - if (lazyDecompress && !valuesDecompressed) { - // Read the value lengths and values - readBuffer(valLenBuffer, valLenInFilter); - readBuffer(valBuffer, valInFilter); - noBufferedValues = noBufferedRecords; - valuesDecompressed = true; - } - - // Calculate the no. of bytes to skip - // Note: 'current' key has already been read! - int skipValBytes = 0; - int currentKey = noBufferedKeys + 1; - for (int i=noBufferedValues; i > currentKey; --i) { - skipValBytes += WritableUtils.readVInt(valLenIn); - --noBufferedValues; - } - - // Skip to the 'val' corresponding to 'current' key - if (skipValBytes > 0) { - if (valIn.skipBytes(skipValBytes) != skipValBytes) { - throw new IOException("Failed to seek to " + currentKey + - "(th) value!"); - } - } - } + readBuffer(valLenBuffer, valLenInFilter); + readBuffer(valBuffer, valInFilter); } /** @@ -1969,148 +2130,27 @@ private synchronized void seekToCurrentValue() throws IOException { * @param val : The 'value' to be read. * @throws IOException */ - public synchronized void getCurrentValue(Writable val) - throws IOException { - if (val instanceof Configurable) { - ((Configurable) val).setConf(this.conf); - } - - // Position stream to 'current' value - seekToCurrentValue(); - - if (!blockCompressed) { - val.readFields(valIn); - - if (valIn.read() > 0) { - LOG.info("available bytes: " + valIn.available()); - throw new IOException(val+" read "+(valBuffer.getPosition()-keyLength) - + " bytes, should read " + - (valBuffer.getLength()-keyLength)); - } - } else { - // Get the value - int valLength = WritableUtils.readVInt(valLenIn); - val.readFields(valIn); - - // Read another compressed 'value' - --noBufferedValues; - - // Sanity check - if ((valLength < 0) && LOG.isDebugEnabled()) { - LOG.debug(val + " is a zero-length value"); - } - } - - } - - /** - * Get the 'value' corresponding to the last read 'key'. - * @param val : The 'value' to be read. - * @throws IOException - */ - public synchronized Object getCurrentValue(Object val) - throws IOException { - if (val instanceof Configurable) { - ((Configurable) val).setConf(this.conf); - } - - // Position stream to 'current' value - seekToCurrentValue(); - - if (!blockCompressed) { - val = deserializeValue(val); - - if (valIn.read() > 0) { - LOG.info("available bytes: " + valIn.available()); - throw new IOException(val+" read "+(valBuffer.getPosition()-keyLength) - + " bytes, should read " + - (valBuffer.getLength()-keyLength)); - } - } else { - // Get the value - int valLength = WritableUtils.readVInt(valLenIn); - val = deserializeValue(val); - - // Read another compressed 'value' - --noBufferedValues; - - // Sanity check - if ((valLength < 0) && LOG.isDebugEnabled()) { - LOG.debug(val + " is a zero-length value"); - } - } - return val; - - } - - @SuppressWarnings("unchecked") - private Object deserializeValue(Object val) throws IOException { - return valDeserializer.deserialize(val); - } - - /** Read the next key in the file into key, skipping its - * value. True if another entry exists, and false at end of file. */ - public synchronized boolean next(Writable key) throws IOException { - if (key.getClass() != getKeyClass()) - throw new IOException("wrong key class: "+key.getClass().getName() - +" is not "+keyClass); - - if (!blockCompressed) { - outBuf.reset(); - - keyLength = next(outBuf); - if (keyLength < 0) - return false; - - valBuffer.reset(outBuf.getData(), outBuf.getLength()); - - key.readFields(valBuffer); - valBuffer.mark(0); - if (valBuffer.getPosition() != keyLength) - throw new IOException(key + " read " + valBuffer.getPosition() - + " bytes, should read " + keyLength); - } else { - //Reset syncSeen - syncSeen = false; - - if (noBufferedKeys == 0) { - try { - readBlock(); - } catch (EOFException eof) { - return false; - } - } - - int keyLength = WritableUtils.readVInt(keyLenIn); - - // Sanity check - if (keyLength < 0) { - return false; - } - - //Read another compressed 'key' - key.readFields(keyIn); - --noBufferedKeys; - } - - return true; + public synchronized Object getCurrentValue(Object val) throws IOException { + return valueSerialization.deserialize(readUncompressedBytes(valueBytes), + val, conf); } /** Read the next key/value pair in the file into key and * val. Returns true if such a pair exists and false when at - * end of file */ - public synchronized boolean next(Writable key, Writable val) - throws IOException { - if (val.getClass() != getValueClass()) - throw new IOException("wrong value class: "+val+" is not "+valClass); + * end of file + * @deprecated Use {@link #next(Object)} and + * {@link #getCurrentValue(Object)} to iterate through keys and values. + */ + @Deprecated + public synchronized boolean next(Writable key, + Writable val) throws IOException { - boolean more = next(key); - - if (more) { + if (nextKey(key) == null) { + return false; + } else { getCurrentValue(val); + return true; } - - return more; } /** @@ -2141,32 +2181,6 @@ private synchronized int readRecordLength() throws IOException { return length; } - /** Read the next key/value pair in the file into buffer. - * Returns the length of the key read, or -1 if at end of file. The length - * of the value may be computed by calling buffer.getLength() before and - * after calls to this method. */ - /** @deprecated Call {@link #nextRaw(DataOutputBuffer,SequenceFile.ValueBytes)}. */ - @Deprecated - synchronized int next(DataOutputBuffer buffer) throws IOException { - // Unsupported for block-compressed sequence files - if (blockCompressed) { - throw new IOException("Unsupported call for block-compressed" + - " SequenceFiles - use SequenceFile.Reader.next(DataOutputStream, ValueBytes)"); - } - try { - int length = readRecordLength(); - if (length == -1) { - return -1; - } - int keyLength = in.readInt(); - buffer.write(in, length); - return keyLength; - } catch (ChecksumException e) { // checksum failure - handleChecksumException(e); - return next(buffer); - } - } - public ValueBytes createValueBytes() { ValueBytes val = null; if (!decompress || blockCompressed) { @@ -2178,14 +2192,15 @@ public ValueBytes createValueBytes() { } /** - * Read 'raw' records. + * Read 'raw' records. Doesn't reset the key buffer. The new key appends + * on to the current contents. * @param key - The buffer into which the key is read - * @param val - The 'raw' value + * @param value - The 'raw' value * @return Returns the total record length or -1 for end of file * @throws IOException */ - public synchronized int nextRaw(DataOutputBuffer key, ValueBytes val) - throws IOException { + public synchronized int nextRaw(DataOutputBuffer key, + ValueBytes value) throws IOException { if (!blockCompressed) { int length = readRecordLength(); if (length == -1) { @@ -2194,13 +2209,7 @@ public synchronized int nextRaw(DataOutputBuffer key, ValueBytes val) int keyLength = in.readInt(); int valLength = length - keyLength; key.write(in, keyLength); - if (decompress) { - CompressedBytes value = (CompressedBytes)val; - value.reset(in, valLength); - } else { - UncompressedBytes value = (UncompressedBytes)val; - value.reset(in, valLength); - } + ((MutableValueBytes) value).reset(in, valLength); return length; } else { @@ -2208,29 +2217,23 @@ public synchronized int nextRaw(DataOutputBuffer key, ValueBytes val) syncSeen = false; // Read 'key' - if (noBufferedKeys == 0) { + if (noBufferedRecords == 0) { if (in.getPos() >= end) return -1; - try { - readBlock(); - } catch (EOFException eof) { - return -1; - } + readBlock(); } int keyLength = WritableUtils.readVInt(keyLenIn); if (keyLength < 0) { throw new IOException("zero length key found!"); } key.write(keyIn, keyLength); - --noBufferedKeys; + --noBufferedRecords; // Read raw 'value' - seekToCurrentValue(); int valLength = WritableUtils.readVInt(valLenIn); - UncompressedBytes rawValue = (UncompressedBytes)val; + UncompressedBytes rawValue = (UncompressedBytes)value; rawValue.reset(valIn, valLength); - --noBufferedValues; return (keyLength+valLength); } @@ -2243,95 +2246,47 @@ public synchronized int nextRaw(DataOutputBuffer key, ValueBytes val) * @return Returns the key length or -1 for end of file * @throws IOException */ - public synchronized int nextRawKey(DataOutputBuffer key) - throws IOException { - if (!blockCompressed) { - recordLength = readRecordLength(); - if (recordLength == -1) { - return -1; - } - keyLength = in.readInt(); - key.write(in, keyLength); - return keyLength; - } else { - //Reset syncSeen - syncSeen = false; - - // Read 'key' - if (noBufferedKeys == 0) { - if (in.getPos() >= end) - return -1; - - try { - readBlock(); - } catch (EOFException eof) { - return -1; - } - } - int keyLength = WritableUtils.readVInt(keyLenIn); - if (keyLength < 0) { - throw new IOException("zero length key found!"); - } - key.write(keyIn, keyLength); - --noBufferedKeys; - - return keyLength; - } - + public synchronized int nextRawKey(DataOutputBuffer key) throws IOException{ + key.reset(); + return nextRaw(key, valueBytes); } - /** Read the next key in the file, skipping its - * value. Return null at end of file. */ - public synchronized Object next(Object key) throws IOException { - if (key != null && key.getClass() != getKeyClass()) { - throw new IOException("wrong key class: "+key.getClass().getName() - +" is not "+keyClass); - } - - if (!blockCompressed) { - outBuf.reset(); - - keyLength = next(outBuf); - if (keyLength < 0) - return null; - - valBuffer.reset(outBuf.getData(), outBuf.getLength()); - - key = deserializeKey(key); - valBuffer.mark(0); - if (valBuffer.getPosition() != keyLength) - throw new IOException(key + " read " + valBuffer.getPosition() - + " bytes, should read " + keyLength); - } else { - //Reset syncSeen - syncSeen = false; - - if (noBufferedKeys == 0) { - try { - readBlock(); - } catch (EOFException eof) { - return null; - } - } - - int keyLength = WritableUtils.readVInt(keyLenIn); - - // Sanity check - if (keyLength < 0) { - return null; - } - - //Read another compressed 'key' - key = deserializeKey(key); - --noBufferedKeys; - } + /** + * Read the next key in the file. + * The value is available via {@link #getCurrentValue}. + * @param key if not null, may be used to hold the next key + * @return true if a key was read, false if eof + * @throws IOException + * @deprecated Use {@link #nextKey} instead. + */ + @Deprecated + public boolean next(Writable key) throws IOException { + return nextKey(key) != null; + } - return key; + /** + * Read the next key from the file. + * @param key if not null, may be used to hold the next key + * @return the key that was read + * @throws IOException + * @deprecated Use {@link #nextKey} instead. + */ + @Deprecated + public Object next(Object key) throws IOException { + return nextKey(key); } - @SuppressWarnings("unchecked") - private Object deserializeKey(Object key) throws IOException { - return keyDeserializer.deserialize(key); + /** Read the next key in the file. + * The value is available via {@link #getCurrentValue}. + */ + public synchronized Object nextKey(Object key) throws IOException { + keyBuffer.reset(); + int recordLen = nextRaw(keyBuffer, valueBytes); + if (recordLen < 0) { + return null; + } + serialBuffer.reset(keyBuffer.getData(), keyBuffer.getLength()); + return keySerialization.deserialize(serialBuffer, key, conf); } /** @@ -2340,31 +2295,9 @@ private Object deserializeKey(Object key) throws IOException { * @return Returns the value length * @throws IOException */ - public synchronized int nextRawValue(ValueBytes val) - throws IOException { - - // Position stream to current value - seekToCurrentValue(); - - if (!blockCompressed) { - int valLength = recordLength - keyLength; - if (decompress) { - CompressedBytes value = (CompressedBytes)val; - value.reset(in, valLength); - } else { - UncompressedBytes value = (UncompressedBytes)val; - value.reset(in, valLength); - } - - return valLength; - } else { - int valLength = WritableUtils.readVInt(valLenIn); - UncompressedBytes rawValue = (UncompressedBytes)val; - rawValue.reset(valIn, valLength); - --noBufferedValues; - return valLength; - } - + public synchronized int nextRawValue(ValueBytes val) throws IOException { + ((MutableValueBytes) val).set(valueBytes); + return val.getSize(); } private void handleChecksumException(ChecksumException e) @@ -2391,8 +2324,7 @@ synchronized void ignoreSync() { public synchronized void seek(long position) throws IOException { in.seek(position); if (blockCompressed) { // trigger block read - noBufferedKeys = 0; - valuesDecompressed = true; + noBufferedRecords = 0; } } @@ -2447,58 +2379,172 @@ public String toString() { } - /** Sorts key/value pairs in a sequence-format file. + /** Sorts key/value pairs in a sequence-format file. This class is no longer + * used by Hadoop and will be removed in a later release. * - *

    For best performance, applications should make sure that the {@link - * Writable#readFields(DataInput)} implementation of their keys is - * very efficient. In particular, it should avoid allocating memory. + *

    For best performance, applications should make sure that the + * {@link RawComparator} that is used is efficient. */ + @Deprecated public static class Sorter { - private RawComparator comparator; + private final RawComparator comparator; + private Writer.Option[] options; + private final Configuration conf; + private final FileContext fc; + private int memory; // bytes + private int factor; // merged per pass + private final Serialization keySerialization; + private final Serialization valueSerialization; private MergeSort mergeSort; //the implementation of merge sort private Path[] inFiles; // when merging or sorting private Path outFile; + + private CompressionType compressType; + private CompressionCodec compressCodec; + + /** + * Look at the first input file's header to figure out the compression for + * the output. + * @throws IOException + */ + private void setCompressionType() throws IOException { + if (inFiles == null || inFiles.length == 0) { + return; + } + Reader reader = new Reader(conf, Reader.file(inFiles[0]), + new Reader.OnlyHeaderOption()); + compressType = reader.getCompressionType(); + compressCodec = reader.getCompressionCodec(); + reader.close(); + } - private int memory; // bytes - private int factor; // merged per pass + public static interface Option extends Writer.Option { } + + public static Option comparator(RawComparator value) { + return new ComparatorOption(value); + } + + private static class ComparatorOption extends Options.ComparatorOption + implements Option { + private ComparatorOption(RawComparator value) { + super(value); + } + } - private FileSystem fs = null; + /** + * Create a Sorter. + * @param conf the configuration for the Sorter + * @param options the options controlling the sort, in particular the + * comparator that will sort the data and the options to write the + * output SequenceFiles. Since the bytes are not deserialized during the + * sort, the serialization for keys and values of the inputs must match + * the options for writing the SequenceFiles. + */ + public Sorter(Configuration conf, Writer.Option... options ) { + this.options = options; + this.conf = conf; + this.memory = conf.getInt("io.sort.mb", 100) * 1024 * 1024; + this.factor = conf.getInt("io.sort.factor", 100); + try { + fc = FileContext.getFileContext(conf); + } catch (UnsupportedFileSystemException ex) { + throw new IllegalArgumentException("can't load default filesystem", ex); + } + ComparatorOption compareOpt = Options.getOption(ComparatorOption.class, + options); + keySerialization = getSerialization(Writer.KeySerialization.class, + Writer.KeyClassOption.class, + options); + valueSerialization = getSerialization(Writer.ValueSerialization.class, + Writer.ValueClassOption.class, + options); + if (compareOpt == null) { + comparator = keySerialization.getRawComparator(); + } else { + comparator = compareOpt.getValue(); + } + } - private Class keyClass; - private Class valClass; + private + Serialization getSerialization(Class serialOpt, + Class classOpt, + Writer.Option[] options) { + Options.SerializationOption serialOption = (Options.SerializationOption) + Options.getOption(serialOpt, options); + if (serialOption != null) { + return serialOption.getValue(); + } else { + Options.ClassOption classOption = (Options.ClassOption) + Options.getOption(classOpt, options); + if (classOption == null) { + throw new IllegalArgumentException("Must specify either a " + + "serializer, or " + + "a class"); + } + Class cls = classOption.getValue(); + return SerializationFactory.getInstance(conf). + getSerializationByType(cls); + } + } - private Configuration conf; - private Metadata metadata; - - private Progressable progressable = null; + /** + * Check to ensure the serialization of the input files matches the + * serialization we are using for the output. If they are not, it would + * corrupt the outputs since we copy the keys and values as raw bytes. + * @param reader the reader for the input file + * @param filename the filename of the file + * @throws IllegalArgumentException if the serialization is wrong + */ + private void checkSerialization(Reader reader, + Path filename) { + if (!reader.getKeySerialization().equals(keySerialization)) { + throw new IllegalArgumentException("key serialization of " + + filename + + " does not match output" + + " parameters"); + } + if (!reader.getValueSerialization().equals(valueSerialization)) { + throw new IllegalArgumentException("value serialization of " + + filename + + " does not match output" + + " parameters"); + } + } - /** Sort and merge files containing the named classes. */ + /** Sort and merge files containing the named classes. + * @deprecated Use Sorter(Configuration, Option...) instead. + */ + @SuppressWarnings("unchecked") + @Deprecated public Sorter(FileSystem fs, Class keyClass, Class valClass, Configuration conf) { - this(fs, WritableComparator.get(keyClass), keyClass, valClass, conf); + this(conf, Writer.keyClass(keyClass), Writer.valueClass(valClass)); } - /** Sort and merge using an arbitrary {@link RawComparator}. */ + /** Sort and merge using an arbitrary {@link RawComparator}. + * @deprecated Use Sorter(Configuration, Option...) instead. + */ + @SuppressWarnings("unchecked") + @Deprecated public Sorter(FileSystem fs, RawComparator comparator, Class keyClass, Class valClass, Configuration conf) { - this(fs, comparator, keyClass, valClass, conf, new Metadata()); + this(conf, comparator(comparator), Writer.keyClass(keyClass), + Writer.valueClass(valClass)); } - /** Sort and merge using an arbitrary {@link RawComparator}. */ + /** Sort and merge using an arbitrary {@link RawComparator}. + * @deprecated Use Sorter(Configuration, Option...) instead. + */ + @SuppressWarnings("unchecked") + @Deprecated public Sorter(FileSystem fs, RawComparator comparator, Class keyClass, Class valClass, Configuration conf, Metadata metadata) { - this.fs = fs; - this.comparator = comparator; - this.keyClass = keyClass; - this.valClass = valClass; - this.memory = conf.getInt("io.sort.mb", 100) * 1024 * 1024; - this.factor = conf.getInt("io.sort.factor", 100); - this.conf = conf; - this.metadata = metadata; + this(conf, comparator(comparator), Writer.keyClass(keyClass), + Writer.valueClass(valClass), Writer.metadata(metadata)); } /** Set the number of streams to merge at once.*/ @@ -2513,9 +2559,13 @@ public Sorter(FileSystem fs, RawComparator comparator, Class keyClass, /** Get the total amount of buffer memory, in bytes.*/ public int getMemory() { return memory; } - /** Set the progressable object in order to report progress. */ + /** Set the progressable object in order to report progress. + * @deprecated the progressable should be set when the Sorter is created. + */ + @Deprecated public void setProgressable(Progressable progressable) { - this.progressable = progressable; + options = Options.prependOptions(options, + Writer.progressable(progressable)); } /** @@ -2526,12 +2576,12 @@ public void setProgressable(Progressable progressable) { */ public void sort(Path[] inFiles, Path outFile, boolean deleteInput) throws IOException { - if (fs.exists(outFile)) { + if (fc.util().exists(outFile)) { throw new IOException("already exists: " + outFile); } - this.inFiles = inFiles; this.outFile = outFile; + setCompressionType(); int segments = sortPass(deleteInput); if (segments > 1) { @@ -2549,10 +2599,12 @@ public void sort(Path[] inFiles, Path outFile, public RawKeyValueIterator sortAndIterate(Path[] inFiles, Path tempDir, boolean deleteInput) throws IOException { Path outFile = new Path(tempDir + Path.SEPARATOR + "all.2"); - if (fs.exists(outFile)) { + if (fc.util().exists(outFile)) { throw new IOException("already exists: " + outFile); } this.inFiles = inFiles; + setCompressionType(); + //outFile will basically be used as prefix for temp files in the cases //where sort outputs multiple sorted segments. For the single segment //case, the outputFile itself will contain the sorted data for that @@ -2578,11 +2630,8 @@ public void sort(Path inFile, Path outFile) throws IOException { } private int sortPass(boolean deleteInput) throws IOException { - if(LOG.isDebugEnabled()) { - LOG.debug("running sort pass"); - } + LOG.debug("running sort pass"); SortPass sortPass = new SortPass(); // make the SortPass - sortPass.setProgressable(progressable); mergeSort = new MergeSort(sortPass.new SeqFileComparator()); try { return sortPass.run(deleteInput); // run it @@ -2604,30 +2653,22 @@ private class SortPass { private int[] keyLengths = new int[keyOffsets.length]; private ValueBytes[] rawValues = new ValueBytes[keyOffsets.length]; - private ArrayList segmentLengths = new ArrayList(); - private Reader in = null; private FSDataOutputStream out = null; private FSDataOutputStream indexOut = null; private Path outName; - private Progressable progressable = null; - public int run(boolean deleteInput) throws IOException { int segments = 0; int currentFile = 0; boolean atEof = (currentFile >= inFiles.length); - CompressionType compressionType; - CompressionCodec codec = null; - segmentLengths.clear(); if (atEof) { return 0; } // Initialize - in = new Reader(fs, inFiles[currentFile], conf); - compressionType = in.getCompressionType(); - codec = in.getCompressionCodec(); + in = new Reader(conf, Reader.file(inFiles[currentFile])); + checkSerialization(in, inFiles[currentFile]); for (int i=0; i < rawValues.length; ++i) { rawValues[i] = null; @@ -2642,21 +2683,24 @@ public int run(boolean deleteInput) throws IOException { // Read a record into buffer // Note: Attempt to re-use 'rawValue' as far as possible - int keyOffset = rawKeys.getLength(); - ValueBytes rawValue = - (count == keyOffsets.length || rawValues[count] == null) ? - in.createValueBytes() : - rawValues[count]; + int keyOffset = rawKeys.getLength(); + ValueBytes rawValue; + if (count == keyOffsets.length || rawValues[count] == null) { + rawValue = in.createValueBytes(); + } else { + rawValue = rawValues[count]; + } int recordLength = in.nextRaw(rawKeys, rawValue); if (recordLength == -1) { in.close(); if (deleteInput) { - fs.delete(inFiles[currentFile], true); + fc.delete(inFiles[currentFile], true); } currentFile += 1; atEof = currentFile >= inFiles.length; if (!atEof) { - in = new Reader(fs, inFiles[currentFile], conf); + in = new Reader(conf, Reader.file(inFiles[currentFile])); + checkSerialization(in, inFiles[currentFile]); } else { in = null; } @@ -2678,17 +2722,10 @@ public int run(boolean deleteInput) throws IOException { } // buffer is full -- sort & flush it - if(LOG.isDebugEnabled()) { - LOG.debug("flushing segment " + segments); - } + LOG.debug("flushing segment " + segments); rawBuffer = rawKeys.getData(); sort(count); - // indicate we're making progress - if (progressable != null) { - progressable.progress(); - } - flush(count, bytesProcessed, compressionType, codec, - segments==0 && atEof); + flush(count, bytesProcessed, segments==0 && atEof); segments++; } return segments; @@ -2731,22 +2768,23 @@ private ValueBytes[] grow(ValueBytes[] old, int newLength) { } private void flush(int count, int bytesProcessed, - CompressionType compressionType, - CompressionCodec codec, boolean done) throws IOException { if (out == null) { outName = done ? outFile : outFile.suffix(".0"); - out = fs.create(outName); + out = fc.create(outName, EnumSet.of(CreateFlag.CREATE)); if (!done) { - indexOut = fs.create(outName.suffix(".index")); + indexOut = fc.create(outName.suffix(".index"), + EnumSet.of(CreateFlag.CREATE)); } } long segmentStart = out.getPos(); - Writer writer = createWriter(conf, Writer.stream(out), - Writer.keyClass(keyClass), Writer.valueClass(valClass), - Writer.compression(compressionType, codec), - Writer.metadata(done ? metadata : new Metadata())); + Writer writer = + createWriter(conf, + Options.prependOptions(options, + Writer.stream(out), + Writer.compression(compressType, + compressCodec))); if (!done) { writer.sync = null; // disable sync on temp files @@ -2778,12 +2816,6 @@ public int compare(IntWritable I, IntWritable J) { } } - /** set the progressable object in order to report progress */ - public void setProgressable(Progressable progressable) - { - this.progressable = progressable; - } - } // SequenceFile.Sorter.SortPass /** The interface to iterate over raw keys/values of SequenceFiles. */ @@ -2824,7 +2856,7 @@ public RawKeyValueIterator merge(List segments, Path tmpDir) throws IOException { // pass in object to report progress, if present - MergeQueue mQueue = new MergeQueue(segments, tmpDir, progressable); + MergeQueue mQueue = new MergeQueue(segments, tmpDir); return mQueue.merge(); } @@ -2863,13 +2895,13 @@ public RawKeyValueIterator merge(Path [] inNames, boolean deleteInputs, ArrayList a = new ArrayList (); for (int i = 0; i < inNames.length; i++) { SegmentDescriptor s = new SegmentDescriptor(0, - fs.getFileStatus(inNames[i]).getLen(), inNames[i]); + fc.getFileStatus(inNames[i]).getLen(), inNames[i]); s.preserveInput(!deleteInputs); s.doSync(); a.add(s); } this.factor = factor; - MergeQueue mQueue = new MergeQueue(a, tmpDir, progressable); + MergeQueue mQueue = new MergeQueue(a, tmpDir); return mQueue.merge(); } @@ -2892,45 +2924,16 @@ public RawKeyValueIterator merge(Path [] inNames, Path tempDir, ArrayList a = new ArrayList (); for (int i = 0; i < inNames.length; i++) { SegmentDescriptor s = new SegmentDescriptor(0, - fs.getFileStatus(inNames[i]).getLen(), inNames[i]); + fc.getFileStatus(inNames[i]).getLen(), inNames[i]); s.preserveInput(!deleteInputs); s.doSync(); a.add(s); } factor = (inNames.length < factor) ? inNames.length : factor; - // pass in object to report progress, if present - MergeQueue mQueue = new MergeQueue(a, tempDir, progressable); + MergeQueue mQueue = new MergeQueue(a, tempDir); return mQueue.merge(); } - /** - * Clones the attributes (like compression of the input file and creates a - * corresponding Writer - * @param inputFile the path of the input file whose attributes should be - * cloned - * @param outputFile the path of the output file - * @param prog the Progressable to report status during the file write - * @return Writer - * @throws IOException - */ - public Writer cloneFileAttributes(Path inputFile, Path outputFile, - Progressable prog) throws IOException { - Reader reader = new Reader(conf, - Reader.file(inputFile), - new Reader.OnlyHeaderOption()); - CompressionType compress = reader.getCompressionType(); - CompressionCodec codec = reader.getCompressionCodec(); - reader.close(); - - Writer writer = createWriter(conf, - Writer.file(outputFile), - Writer.keyClass(keyClass), - Writer.valueClass(valClass), - Writer.compression(compress, codec), - Writer.progressable(prog)); - return writer; - } - /** * Writes records from RawKeyValueIterator into a file represented by the * passed writer @@ -2953,12 +2956,17 @@ public void writeFile(RawKeyValueIterator records, Writer writer) * @throws IOException */ public void merge(Path[] inFiles, Path outFile) throws IOException { - if (fs.exists(outFile)) { + if (fc.util().exists(outFile)) { throw new IOException("already exists: " + outFile); } + this.inFiles = inFiles; + setCompressionType(); RawKeyValueIterator r = merge(inFiles, false, outFile.getParent()); - Writer writer = cloneFileAttributes(inFiles[0], outFile, null); - + Writer writer = + createWriter(conf, Options.prependOptions + (options, + Writer.file(outFile), + Writer.compression(compressType, compressCodec))); writeFile(r, writer); writer.close(); @@ -2966,11 +2974,11 @@ public void merge(Path[] inFiles, Path outFile) throws IOException { /** sort calls this to generate the final merged output */ private int mergePass(Path tmpDir) throws IOException { - if(LOG.isDebugEnabled()) { - LOG.debug("running merge pass"); - } - Writer writer = cloneFileAttributes( - outFile.suffix(".0"), outFile, null); + LOG.debug("running merge pass"); + Writer writer = + createWriter(conf, Options.prependOptions + (options, Writer.file(outFile), + Writer.compression(compressType, compressCodec))); RawKeyValueIterator r = merge(outFile.suffix(".0"), outFile.suffix(".0.index"), tmpDir); writeFile(r, writer); @@ -2994,12 +3002,12 @@ private RawKeyValueIterator merge(Path inName, Path indexIn, Path tmpDir) //the contained segments during the merge process & hence don't need //them anymore SegmentContainer container = new SegmentContainer(inName, indexIn); - MergeQueue mQueue = new MergeQueue(container.getSegmentList(), tmpDir, progressable); + MergeQueue mQueue = new MergeQueue(container.getSegmentList(), tmpDir); return mQueue.merge(); } /** This class implements the core of the merge logic */ - private class MergeQueue extends PriorityQueue + private class MergeQueue extends PriorityQueue implements RawKeyValueIterator { private boolean compress; private boolean blockCompress; @@ -3009,7 +3017,6 @@ private class MergeQueue extends PriorityQueue private float progPerByte; private Progress mergeProgress = new Progress(); private Path tmpDir; - private Progressable progress = null; //handle to the progress reporting object private SegmentDescriptor minSegment; //a TreeMap used to store the segments sorted by size (segment offset and @@ -3017,8 +3024,7 @@ private class MergeQueue extends PriorityQueue private Map sortedSegmentSizes = new TreeMap(); - @SuppressWarnings("unchecked") - public void put(SegmentDescriptor stream) throws IOException { + public void addSegment(SegmentDescriptor stream) throws IOException { if (size() == 0) { compress = stream.in.isCompressed(); blockCompress = stream.in.isBlockCompressed(); @@ -3026,29 +3032,23 @@ public void put(SegmentDescriptor stream) throws IOException { blockCompress != stream.in.isBlockCompressed()) { throw new IOException("All merged files must be compressed or not."); } - super.put(stream); + put(stream); } /** * A queue of file segments to merge * @param segments the file segments to merge * @param tmpDir a relative local directory to save intermediate files in - * @param progress the reference to the Progressable object */ public MergeQueue(List segments, - Path tmpDir, Progressable progress) { + Path tmpDir) { int size = segments.size(); for (int i = 0; i < size; i++) { sortedSegmentSizes.put(segments.get(i), null); } this.tmpDir = tmpDir; - this.progress = progress; } protected boolean lessThan(Object a, Object b) { - // indicate we're making progress - if (progress != null) { - progress.progress(); - } SegmentDescriptor msa = (SegmentDescriptor)a; SegmentDescriptor msb = (SegmentDescriptor)b; return comparator.compare(msa.getKey().getData(), 0, @@ -3167,7 +3167,7 @@ public RawKeyValueIterator merge() throws IOException { //feed the streams to the priority queue initialize(segmentsToMerge.size()); clear(); for (int i = 0; i < segmentsToMerge.size(); i++) { - put(segmentsToMerge.get(i)); + addSegment(segmentsToMerge.get(i)); } //if we have lesser number of segments remaining, then just return the //iterator, else do another single level merge @@ -3198,12 +3198,14 @@ public RawKeyValueIterator merge() throws IOException { Path outputFile = lDirAlloc.getLocalPathForWrite( tmpFilename.toString(), approxOutputSize, conf); - if(LOG.isDebugEnabled()) { - LOG.debug("writing intermediate results to " + outputFile); - } - Writer writer = cloneFileAttributes( - fs.makeQualified(segmentsToMerge.get(0).segmentPathName), - fs.makeQualified(outputFile), null); + LOG.debug("writing intermediate results to " + outputFile); + Writer writer = + createWriter(conf, + Options.prependOptions + (options, + Writer.file(outputFile), + Writer.compression(compressType, + compressCodec))); writer.sync = null; //disable sync for temp files writeFile(this, writer); writer.close(); @@ -3214,7 +3216,7 @@ public RawKeyValueIterator merge() throws IOException { SegmentDescriptor tempSegment = new SegmentDescriptor(0, - fs.getFileStatus(outputFile).getLen(), outputFile); + fc.getFileStatus(outputFile).getLen(), outputFile); //put the segment back in the TreeMap sortedSegmentSizes.put(tempSegment, null); numSegments = sortedSegmentSizes.size(); @@ -3244,7 +3246,8 @@ public SegmentDescriptor[] getSegmentDescriptors(int numDescriptors) { numDescriptors = sortedSegmentSizes.size(); SegmentDescriptor[] SegmentDescriptors = new SegmentDescriptor[numDescriptors]; - Iterator iter = sortedSegmentSizes.keySet().iterator(); + Iterator iter = + sortedSegmentSizes.keySet().iterator(); int i = 0; while (i < numDescriptors) { SegmentDescriptors[i++] = (SegmentDescriptor)iter.next(); @@ -3258,7 +3261,7 @@ public SegmentDescriptor[] getSegmentDescriptors(int numDescriptors) { * provide a customized cleanup method implementation. In this * implementation, cleanup closes the file handle and deletes the file */ - public class SegmentDescriptor implements Comparable { + public class SegmentDescriptor implements Comparable { long segmentOffset; //the start of the segment in the file long segmentLength; //the length of the segment @@ -3292,8 +3295,8 @@ public boolean shouldPreserveInput() { return preserveInput; } - public int compareTo(Object o) { - SegmentDescriptor that = (SegmentDescriptor)o; + @Override + public int compareTo(SegmentDescriptor that) { if (this.segmentLength != that.segmentLength) { return (this.segmentLength < that.segmentLength ? -1 : 1); } @@ -3329,24 +3332,16 @@ public int hashCode() { public boolean nextRawKey() throws IOException { if (in == null) { int bufferSize = getBufferSize(conf); - if (fs.getUri().getScheme().startsWith("ramfs")) { - bufferSize = conf.getInt("io.bytes.per.checksum", 512); - } Reader reader = new Reader(conf, Reader.file(segmentPathName), Reader.bufferSize(bufferSize), Reader.start(segmentOffset), Reader.length(segmentLength)); + checkSerialization(reader, segmentPathName); //sometimes we ignore syncs especially for temp merge files if (ignoreSync) reader.ignoreSync(); - if (reader.getKeyClass() != keyClass) - throw new IOException("wrong key class: " + reader.getKeyClass() + - " is not " + keyClass); - if (reader.getValueClass() != valClass) - throw new IOException("wrong value class: "+reader.getValueClass()+ - " is not " + valClass); this.in = reader; rawKey = new DataOutputBuffer(); } @@ -3384,7 +3379,7 @@ private void close() throws IOException { public void cleanup() throws IOException { close(); if (!preserveInput) { - fs.delete(segmentPathName, true); + fc.delete(segmentPathName, true); } } } // SequenceFile.Sorter.SegmentDescriptor @@ -3439,8 +3434,8 @@ private class SegmentContainer { * generates a single output file with an associated index file */ public SegmentContainer(Path inName, Path indexIn) throws IOException { //get the segments from indexIn - FSDataInputStream fsIndexIn = fs.open(indexIn); - long end = fs.getFileStatus(indexIn).getLen(); + FSDataInputStream fsIndexIn = fc.open(indexIn); + long end = fc.getFileStatus(indexIn).getLen(); while (fsIndexIn.getPos() < end) { long segmentOffset = WritableUtils.readVLong(fsIndexIn); long segmentLength = WritableUtils.readVLong(fsIndexIn); @@ -3449,7 +3444,7 @@ public SegmentContainer(Path inName, Path indexIn) throws IOException { segmentLength, segmentName, this)); } fsIndexIn.close(); - fs.delete(indexIn, true); + fc.delete(indexIn, true); numSegmentsContained = segments.size(); this.inName = inName; } @@ -3460,7 +3455,7 @@ public List getSegmentList() { public void cleanup() throws IOException { numSegmentsCleanedUp++; if (numSegmentsCleanedUp == numSegmentsContained) { - fs.delete(inName, true); + fc.delete(inName, true); } } } //SequenceFile.Sorter.SegmentContainer diff --git a/src/java/org/apache/hadoop/io/SetFile.java b/src/java/org/apache/hadoop/io/SetFile.java index ed3babe95b6d0..25d4925cd3739 100644 --- a/src/java/org/apache/hadoop/io/SetFile.java +++ b/src/java/org/apache/hadoop/io/SetFile.java @@ -31,6 +31,7 @@ public class SetFile extends MapFile { protected SetFile() {} // no public ctor + private static final NullWritable NULL_WRITABLE = NullWritable.get(); /** * Write a new set file. @@ -41,8 +42,10 @@ public static class Writer extends MapFile.Writer { * @deprecated pass a Configuration too */ public Writer(FileSystem fs, String dirName, - Class keyClass) throws IOException { - super(new Configuration(), fs, dirName, keyClass, NullWritable.class); + Class keyClass + ) throws IOException { + super(new Configuration(), new Path(dirName), + keyClass(keyClass), valueClass(NullWritable.class)); } /** Create a set naming the element class and compression type. */ @@ -59,6 +62,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, SequenceFile.CompressionType compress) throws IOException { super(conf, new Path(dirName), comparator(comparator), + keyClass(comparator.getKeyClass()), valueClass(NullWritable.class), compression(compress)); } @@ -66,7 +70,7 @@ public Writer(Configuration conf, FileSystem fs, String dirName, /** Append a key to a set. The key must be strictly greater than the * previous key added to the set. */ public void append(WritableComparable key) throws IOException{ - append(key, NullWritable.get()); + append(key, NULL_WRITABLE); } } @@ -94,7 +98,7 @@ public boolean seek(WritableComparable key) * true if such a key exists and false when at the end of the set. */ public boolean next(WritableComparable key) throws IOException { - return next(key, NullWritable.get()); + return next(key, NULL_WRITABLE); } /** Read the matching key from a set into key. diff --git a/src/java/org/apache/hadoop/io/compress/zlib/ZlibCompressor.java b/src/java/org/apache/hadoop/io/compress/zlib/ZlibCompressor.java index 4cb10e6da62a7..8839bc98fa011 100644 --- a/src/java/org/apache/hadoop/io/compress/zlib/ZlibCompressor.java +++ b/src/java/org/apache/hadoop/io/compress/zlib/ZlibCompressor.java @@ -53,6 +53,7 @@ public class ZlibCompressor implements Compressor { private int userBufOff = 0, userBufLen = 0; private Buffer uncompressedDirectBuf = null; private int uncompressedDirectBufOff = 0, uncompressedDirectBufLen = 0; + private boolean keepUncompressedBuf = false; private Buffer compressedDirectBuf = null; private boolean finish, finished; @@ -269,6 +270,7 @@ public synchronized void setInput(byte[] b, int off, int len) { this.userBuf = b; this.userBufOff = off; this.userBufLen = len; + uncompressedDirectBufOff = 0; setInputFromSavedData(); // Reinitialize zlib's output direct buffer @@ -276,21 +278,13 @@ public synchronized void setInput(byte[] b, int off, int len) { compressedDirectBuf.position(directBufferSize); } + //copy enough data from userBuf to uncompressedDirectBuf synchronized void setInputFromSavedData() { - uncompressedDirectBufOff = 0; - uncompressedDirectBufLen = userBufLen; - if (uncompressedDirectBufLen > directBufferSize) { - uncompressedDirectBufLen = directBufferSize; - } - - // Reinitialize zlib's input direct buffer - uncompressedDirectBuf.rewind(); - ((ByteBuffer)uncompressedDirectBuf).put(userBuf, userBufOff, - uncompressedDirectBufLen); - - // Note how much data is being fed to zlib - userBufOff += uncompressedDirectBufLen; - userBufLen -= uncompressedDirectBufLen; + int len = Math.min(userBufLen, uncompressedDirectBuf.remaining()); + ((ByteBuffer)uncompressedDirectBuf).put(userBuf, userBufOff, len); + userBufLen -= len; + userBufOff += len; + uncompressedDirectBufLen = uncompressedDirectBuf.position(); } public synchronized void setDictionary(byte[] b, int off, int len) { @@ -310,12 +304,21 @@ public synchronized boolean needsInput() { } // Check if zlib has consumed all input - if (uncompressedDirectBufLen <= 0) { + // compress should be invoked if keepUncompressedBuf true + if (keepUncompressedBuf && uncompressedDirectBufLen > 0) + return false; + + if (uncompressedDirectBuf.remaining() > 0) { // Check if we have consumed all user-input if (userBufLen <= 0) { return true; } else { + // copy enough data from userBuf to uncompressedDirectBuf setInputFromSavedData(); + if (uncompressedDirectBuf.remaining() > 0) // uncompressedDirectBuf is not full + return true; + else + return false; } } @@ -359,6 +362,17 @@ public synchronized int compress(byte[] b, int off, int len) n = deflateBytesDirect(); compressedDirectBuf.limit(n); + // Check if zlib consumed all input buffer + // set keepUncompressedBuf properly + if (uncompressedDirectBufLen <= 0) { // zlib consumed all input buffer + keepUncompressedBuf = false; + uncompressedDirectBuf.clear(); + uncompressedDirectBufOff = 0; + uncompressedDirectBufLen = 0; + } else { // zlib did not consume all input buffer + keepUncompressedBuf = true; + } + // Get atmost 'len' bytes n = Math.min(n, len); ((ByteBuffer)compressedDirectBuf).get(b, off, n); @@ -393,6 +407,7 @@ public synchronized void reset() { finished = false; uncompressedDirectBuf.rewind(); uncompressedDirectBufOff = uncompressedDirectBufLen = 0; + keepUncompressedBuf = false; compressedDirectBuf.limit(directBufferSize); compressedDirectBuf.position(directBufferSize); userBufOff = userBufLen = 0; diff --git a/src/java/org/apache/hadoop/io/file/tfile/BCFile.java b/src/java/org/apache/hadoop/io/file/tfile/BCFile.java index 6b4fdd89aa29e..83b4e99c11498 100644 --- a/src/java/org/apache/hadoop/io/file/tfile/BCFile.java +++ b/src/java/org/apache/hadoop/io/file/tfile/BCFile.java @@ -198,7 +198,6 @@ public void finish() throws IOException { public class BlockAppender extends DataOutputStream { private final BlockRegister blockRegister; private final WBlockState wBlkState; - @SuppressWarnings("hiding") private boolean closed = false; /** @@ -282,15 +281,32 @@ public void close() throws IOException { * @throws IOException * @see Compression#getSupportedAlgorithms */ + @Deprecated public Writer(FSDataOutputStream fout, String compressionName, Configuration conf) throws IOException { + this(fout, Compression.getCompressionAlgorithmByName(compressionName), + conf); + } + + /** + * Constructor + * + * @param fout + * FS output stream. + * @param compression + * The compression algorithm, which will be used for all + * data blocks. + * @throws IOException + */ + public Writer(FSDataOutputStream fout, Algorithm compression, + Configuration conf) throws IOException { if (fout.getPos() != 0) { throw new IOException("Output file not at zero offset."); } this.out = fout; this.conf = conf; - dataIndex = new DataIndex(compressionName); + dataIndex = new DataIndex(compression); metaIndex = new MetaIndex(); fsOutputBuffer = new BytesWritable(); Magic.write(fout); @@ -650,6 +666,14 @@ public String getDefaultCompressionName() { return dataIndex.getDefaultCompressionAlgorithm().getName(); } + /** + * Get the default compression algorithm. + * @return the default compression algorithm + */ + public Algorithm getDefaultCompression() { + return dataIndex.getDefaultCompressionAlgorithm(); + } + /** * Get version of BCFile file being read. * @@ -870,12 +894,16 @@ public DataIndex(DataInput in) throws IOException { } } + public DataIndex(Algorithm defaultCompression) { + this.defaultCompressionAlgorithm = defaultCompression; + listRegions = new ArrayList(); + } + // for write + @Deprecated public DataIndex(String defaultCompressionAlgorithmName) { - this.defaultCompressionAlgorithm = - Compression - .getCompressionAlgorithmByName(defaultCompressionAlgorithmName); - listRegions = new ArrayList(); + this(Compression + .getCompressionAlgorithmByName(defaultCompressionAlgorithmName)); } public Algorithm getDefaultCompressionAlgorithm() { diff --git a/src/java/org/apache/hadoop/io/file/tfile/CompareUtils.java b/src/java/org/apache/hadoop/io/file/tfile/CompareUtils.java index a9cb1ec1c3de5..3c5a87701f647 100644 --- a/src/java/org/apache/hadoop/io/file/tfile/CompareUtils.java +++ b/src/java/org/apache/hadoop/io/file/tfile/CompareUtils.java @@ -19,8 +19,7 @@ import java.io.Serializable; import java.util.Comparator; -import org.apache.hadoop.io.RawComparator; -import org.apache.hadoop.io.WritableComparator; +import org.apache.hadoop.io.serial.RawComparator; class CompareUtils { /** @@ -36,9 +35,9 @@ private CompareUtils() { */ public static final class BytesComparator implements Comparator { - private RawComparator cmp; + private RawComparator cmp; - public BytesComparator(RawComparator cmp) { + public BytesComparator(RawComparator cmp) { this.cmp = cmp; } @@ -73,7 +72,9 @@ public long magnitude() { } } - public static final class ScalarComparator implements Comparator, Serializable { + @SuppressWarnings("serial") + public static final class ScalarComparator + implements Comparator, Serializable { @Override public int compare(Scalar o1, Scalar o2) { long diff = o1.magnitude() - o2.magnitude(); @@ -83,16 +84,4 @@ public int compare(Scalar o1, Scalar o2) { } } - public static final class MemcmpRawComparator implements - RawComparator, Serializable { - @Override - public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { - return WritableComparator.compareBytes(b1, s1, l1, b2, s2, l2); - } - - @Override - public int compare(Object o1, Object o2) { - throw new RuntimeException("Object comparison not supported"); - } - } } diff --git a/src/java/org/apache/hadoop/io/file/tfile/Compression.java b/src/java/org/apache/hadoop/io/file/tfile/Compression.java index ec947299d2d24..3f1ec7f6976a9 100644 --- a/src/java/org/apache/hadoop/io/file/tfile/Compression.java +++ b/src/java/org/apache/hadoop/io/file/tfile/Compression.java @@ -39,7 +39,7 @@ /** * Compression related stuff. */ -final class Compression { +final public class Compression { static final Log LOG = LogFactory.getLog(Compression.class); /** @@ -71,7 +71,7 @@ public void flush() throws IOException { /** * Compression algorithms. */ - static enum Algorithm { + public static enum Algorithm { LZO(TFile.COMPRESSION_LZO) { private transient boolean checked = false; private static final String defaultClazz = @@ -99,7 +99,7 @@ public synchronized boolean isSupported() { } @Override - CompressionCodec getCodec() throws IOException { + synchronized CompressionCodec getCodec() throws IOException { if (!isSupported()) { throw new IOException( "LZO codec class not specified. Did you forget to set property " @@ -160,7 +160,7 @@ public synchronized OutputStream createCompressionStream( private transient DefaultCodec codec; @Override - CompressionCodec getCodec() { + synchronized CompressionCodec getCodec() { if (codec == null) { codec = new DefaultCodec(); codec.setConf(conf); diff --git a/src/java/org/apache/hadoop/io/file/tfile/RawComparable.java b/src/java/org/apache/hadoop/io/file/tfile/RawComparable.java index 0369ce112a0a6..5b5f86fc851cd 100644 --- a/src/java/org/apache/hadoop/io/file/tfile/RawComparable.java +++ b/src/java/org/apache/hadoop/io/file/tfile/RawComparable.java @@ -22,7 +22,7 @@ import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; -import org.apache.hadoop.io.RawComparator; +import org.apache.hadoop.io.serial.RawComparator; /** * Interface for objects that can be compared through {@link RawComparator}. diff --git a/src/java/org/apache/hadoop/io/file/tfile/TFile.java b/src/java/org/apache/hadoop/io/file/tfile/TFile.java index 0b9ed9d2b391b..ae7eb0bc114ec 100644 --- a/src/java/org/apache/hadoop/io/file/tfile/TFile.java +++ b/src/java/org/apache/hadoop/io/file/tfile/TFile.java @@ -41,16 +41,18 @@ import org.apache.hadoop.io.DataInputBuffer; import org.apache.hadoop.io.DataOutputBuffer; import org.apache.hadoop.io.IOUtils; -import org.apache.hadoop.io.RawComparator; import org.apache.hadoop.io.WritableComparator; import org.apache.hadoop.io.file.tfile.BCFile.Reader.BlockReader; import org.apache.hadoop.io.file.tfile.BCFile.Writer.BlockAppender; import org.apache.hadoop.io.file.tfile.Chunk.ChunkDecoder; import org.apache.hadoop.io.file.tfile.Chunk.ChunkEncoder; -import org.apache.hadoop.io.file.tfile.CompareUtils.BytesComparator; -import org.apache.hadoop.io.file.tfile.CompareUtils.MemcmpRawComparator; +import org.apache.hadoop.io.file.tfile.Compression.Algorithm; +import org.apache.hadoop.io.serial.lib.MemcmpRawComparator; import org.apache.hadoop.io.file.tfile.Utils.Version; -import org.apache.hadoop.io.serializer.JavaSerializationComparator; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.serial.lib.DeserializationRawComparator; +import org.apache.hadoop.util.Options; +import org.apache.hadoop.util.ReflectionUtils; /** * A TFile is a container of key-value pairs. Both keys and values are type-less @@ -165,16 +167,56 @@ static int getFSOutputBufferSize(Configuration conf) { public static final String COMPARATOR_MEMCMP = "memcmp"; /** comparator prefix: java class */ public static final String COMPARATOR_JCLASS = "jclass:"; + /** user-managed comparator */ + public static final String COMPARATOR_USER_MANAGED = "user"; /** - * Make a raw comparator from a string name. - * - * @param name - * Comparator name - * @return A RawComparable comparator. + * A constant that is used to represent memcmp sort order in the tfile. */ - static public Comparator makeComparator(String name) { - return TFileMeta.makeComparator(name); + public static final RawComparator MEMCMP = new MemcmpRawComparator(); + + /** + * The kinds of comparators that tfile supports. + */ + public static enum ComparatorKind { + NONE(""), MEMCMP(COMPARATOR_MEMCMP), USER_MANAGED(COMPARATOR_USER_MANAGED); + + private String name; + + ComparatorKind(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public static ComparatorKind fromString(String val) { + if (val == null || val.length() == 0) { + return NONE; + } + for (ComparatorKind kind: values()) { + if (kind.name.equals(val)) { + return kind; + } + } + if (val.startsWith(COMPARATOR_JCLASS)) { + return USER_MANAGED; + } + throw new IllegalArgumentException("Comparator kind " + val + + " unknown."); + } + + static ComparatorKind fromComparator(RawComparator comparator) { + if (comparator == null) { + return NONE; + } else if (comparator.getClass() == MemcmpRawComparator.class){ + return MEMCMP; + } else { + return USER_MANAGED; + } + } } // Prevent the instantiation of TFiles @@ -242,9 +284,10 @@ private enum State { State state = State.READY; Configuration conf; long errorCount = 0; + private final RawComparator comparator; /** - * Constructor + * Constructor for a TFile Writer. * * @param fsdos * output stream for writing. Must be at position 0. @@ -255,7 +298,7 @@ private enum State { * @param compressName * Name of the compression algorithm. Must be one of the strings * returned by {@link TFile#getSupportedCompressionAlgorithms()}. - * @param comparator + * @param comparatorName * Leave comparator as null or empty string if TFile is not sorted. * Otherwise, provide the string name for the comparison algorithm * for keys. Two kinds of comparators are supported. @@ -269,7 +312,7 @@ private enum State { * constructed through the default constructor (with no * parameters). Parameterized RawComparators such as * {@link WritableComparator} or - * {@link JavaSerializationComparator} may not be directly used. + * {@link DeserializationRawComparator} may not be directly used. * One should write a wrapper class that inherits from such classes * and use its default constructor to perform proper * initialization. @@ -277,15 +320,156 @@ private enum State { * @param conf * The configuration object. * @throws IOException + * @deprecated Use Writer(Configuration,Option...) instead. */ public Writer(FSDataOutputStream fsdos, int minBlockSize, - String compressName, String comparator, Configuration conf) - throws IOException { - sizeMinBlock = minBlockSize; - tfileMeta = new TFileMeta(comparator); - tfileIndex = new TFileIndex(tfileMeta.getComparator()); + String compressName, String comparatorName, + Configuration conf) throws IOException { + this(conf, stream(fsdos), blockSize(minBlockSize), + compress(Compression.getCompressionAlgorithmByName(compressName)), + comparatorName(comparatorName)); + } + + /** + * Marker class for all of the Writer options. + */ + public static interface Option {} + + /** + * Create an option with a output stream. + * @param value output stream for writing. Must be at position 0. + * @return the new option + */ + public static Option stream(FSDataOutputStream value) { + return new StreamOption(value); + } + + /** + * Create an option for the compression algorithm. + * @param value the compression algorithm to use. + * @return the new option + */ + public static Option compress(Algorithm value) { + return new CompressOption(value); + } + + /** + * Create an option for the minimum block size. + * @param value the minimum number of bytes that a compression block will + * contain. + * @return the new option + */ + public static Option blockSize(int value) { + return new BlockSizeOption(value); + } + + /** + * Create an option for specifying the comparator. + * @param value the comparator for indexing and searching the file + * @return the new option + */ + public static Option comparator(RawComparator value) { + return new ComparatorOption(value); + } + + /** + * Create an option for the comparator from a string. This is intended to + * support old clients that specified the comparator name and expected + * the reader to be able to read it. + * @param value + * @return the new option + */ + public static Option comparatorName(String value) { + return new ComparatorNameOption(value); + } + + private static class StreamOption extends Options.FSDataOutputStreamOption + implements Option { + StreamOption(FSDataOutputStream value) { + super(value); + } + } + + private static class CompressOption implements Option { + private Algorithm value; + CompressOption(Algorithm value) { + this.value = value; + } + Algorithm getValue() { + return value; + } + } + + private static class BlockSizeOption extends Options.IntegerOption + implements Option { + BlockSizeOption(int value) { + super(value); + } + } + + private static class ComparatorOption implements Option { + private RawComparator value; + ComparatorOption(RawComparator value) { + this.value = value; + } + RawComparator getValue() { + return value; + } + } + + private static class ComparatorNameOption extends Options.StringOption + implements Option { + ComparatorNameOption(String value) { + super(value); + } + } - writerBCF = new BCFile.Writer(fsdos, compressName, conf); + /** + * Constructor + * + * @param conf + * The configuration object. + * @param options + * the options for controlling the file. + * @throws IOException + */ + public Writer(Configuration conf, Option... options) throws IOException { + BlockSizeOption blockSize = Options.getOption(BlockSizeOption.class, + options); + ComparatorOption comparatorOpt = Options.getOption(ComparatorOption.class, + options); + ComparatorNameOption comparatorNameOpt = + Options.getOption(ComparatorNameOption.class, options); + CompressOption compressOpt = Options.getOption(CompressOption.class, + options); + StreamOption stream = Options.getOption(StreamOption.class, options); + + if (stream == null) { + throw new IllegalArgumentException("Must provide a stream"); + } + if (comparatorOpt != null && comparatorNameOpt != null) { + throw new IllegalArgumentException("Can only provide one comparator" + + " option"); + } + + sizeMinBlock = blockSize == null ? 1048576 : blockSize.getValue(); + String comparatorName; + if (comparatorOpt != null) { + comparator = comparatorOpt.getValue(); + comparatorName = ComparatorKind.fromComparator(comparator).toString(); + } else if (comparatorNameOpt != null) { + comparatorName = comparatorNameOpt.getValue(); + comparator = makeComparator(comparatorName); + } else { + comparator = null; + comparatorName = null; + } + tfileMeta = new TFileMeta(comparatorName); + tfileIndex = new TFileIndex(comparator); + Algorithm compress = + compressOpt == null ? Algorithm.NONE : compressOpt.getValue(); + + writerBCF = new BCFile.Writer(stream.getValue(), compress, conf); currentKeyBufferOS = new BoundedByteArrayOutputStream(MAX_KEY_SIZE); lastKeyBufferOS = new BoundedByteArrayOutputStream(MAX_KEY_SIZE); this.conf = conf; @@ -455,8 +639,8 @@ public void close() throws IOException { if (tfileMeta.isSorted() && tfileMeta.getRecordCount()>0) { byte[] lastKey = lastKeyBufferOS.getBuffer(); int lastLen = lastKeyBufferOS.size(); - if (tfileMeta.getComparator().compare(key, 0, len, lastKey, 0, - lastLen) < 0) { + // check sort order unless this is the first key + if (comparator.compare(key, 0, len, lastKey, 0, lastLen) < 0) { throw new IOException("Keys are not added in sorted order"); } } @@ -687,7 +871,7 @@ public static class Reader implements Closeable { // TFile index, it is loaded lazily. TFileIndex tfileIndex = null; final TFileMeta tfileMeta; - final BytesComparator comparator; + private RawComparator comparator = null; // global begin and end locations. private final Location begin; @@ -784,6 +968,17 @@ public boolean equals(Object obj) { if (recordIndex != other.recordIndex) return false; return true; } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Location("); + builder.append(blockIndex); + builder.append(", "); + builder.append(recordIndex); + builder.append(")"); + return builder.toString(); + } } /** @@ -798,8 +993,8 @@ public boolean equals(Object obj) { * @param conf * @throws IOException */ - public Reader(FSDataInputStream fsdis, long fileLength, Configuration conf) - throws IOException { + public Reader(FSDataInputStream fsdis, long fileLength, Configuration conf + ) throws IOException { readerBCF = new BCFile.Reader(fsdis, fileLength, conf); // first, read TFile meta @@ -809,13 +1004,29 @@ public Reader(FSDataInputStream fsdis, long fileLength, Configuration conf) } finally { brMeta.close(); } + comparator = makeComparator(tfileMeta.getComparatorName()); - comparator = tfileMeta.getComparator(); // Set begin and end locations. begin = new Location(0, 0); end = new Location(readerBCF.getBlockCount(), 0); } + /** + * Set the comparator for reading this file. May only be called once for + * each Reader. + * @param comparator a comparator for this file. + */ + public void setComparator(RawComparator comparator) { + ComparatorKind kind = ComparatorKind.fromComparator(comparator); + if (kind != tfileMeta.getComparatorKind()) { + throw new IllegalArgumentException("Illegal comparator for this tfile: " + + kind + + " instead of " + + tfileMeta.getComparatorKind()); + } + this.comparator = comparator; + } + /** * Close the reader. The state of the Reader object is undefined after * close. Calling close() for multiple times has no effect. @@ -843,6 +1054,14 @@ Location end() { return end; } + /** + * Get the version of the tfile format. + * @return the version of the file + */ + public Version getFileVersion() { + return tfileMeta.getVersion(); + } + /** * Get the string representation of the comparator. * @@ -851,7 +1070,15 @@ Location end() { * provided during the TFile creation time will be returned. */ public String getComparatorName() { - return tfileMeta.getComparatorString(); + return tfileMeta.getComparatorKind().toString(); + } + + /** + * Get the compression algorithm. + * @return the compression algorithm used + */ + public Algorithm getCompression() { + return readerBCF.getDefaultCompression(); } /** @@ -882,8 +1109,7 @@ synchronized void checkTFileDataIndex() throws IOException { BlockReader brIndex = readerBCF.getMetaBlock(TFileIndex.BLOCK_NAME); try { tfileIndex = - new TFileIndex(readerBCF.getBlockCount(), brIndex, tfileMeta - .getComparator()); + new TFileIndex(readerBCF.getBlockCount(), brIndex, comparator); } finally { brIndex.close(); } @@ -947,7 +1173,7 @@ public int compare(Scanner.Entry o1, Scanner.Entry o2) { * * @return a Comparator that can compare RawComparable's. */ - public Comparator getComparator() { + public RawComparator getComparator() { return comparator; } @@ -1006,6 +1232,10 @@ int compareKeys(byte[] a, int o1, int l1, byte[] b, int o2, int l2) { if (!isSorted()) { throw new RuntimeException("Cannot compare keys for unsorted TFiles."); } + if (comparator == null) { + throw new + RuntimeException("Cannot compare keys until comparator is set"); + } return comparator.compare(a, o1, l1, b, o2, l2); } @@ -1013,7 +1243,12 @@ int compareKeys(RawComparable a, RawComparable b) { if (!isSorted()) { throw new RuntimeException("Cannot compare keys for unsorted TFiles."); } - return comparator.compare(a, b); + if (comparator == null) { + throw new + RuntimeException("Cannot compare keys until comparator is set"); + } + return comparator.compare(a.buffer(), a.offset(), a.size(), + b.buffer(), b.offset(), b.size()); } /** @@ -1028,7 +1263,9 @@ int compareKeys(RawComparable a, RawComparable b) { */ Location getLocationNear(long offset) { int blockIndex = readerBCF.getBlockIndexNear(offset); - if (blockIndex == -1) return end; + if (blockIndex == -1) { + return end; + } return new Location(blockIndex, 0); } @@ -1089,7 +1326,8 @@ public Scanner createScanner() throws IOException { * contains zero key-value pairs even if length is positive. * @throws IOException */ - public Scanner createScannerByByteRange(long offset, long length) throws IOException { + public Scanner createScannerByByteRange(long offset, + long length) throws IOException { return new Scanner(this, offset, offset + length); } @@ -2032,20 +2270,20 @@ BlockReader getBlockReader(int blockIndex) throws IOException { /** * Data structure representing "TFile.meta" meta block. */ - static final class TFileMeta { + private static final class TFileMeta { final static String BLOCK_NAME = "TFile.meta"; - final Version version; + private final Version version; private long recordCount; - private final String strComparator; - private final BytesComparator comparator; + private final ComparatorKind comparatorKind; + private final String comparatorName; // ctor for writes - public TFileMeta(String comparator) { + public TFileMeta(String comparatorName) { // set fileVersion to API version when we create it. version = TFile.API_VERSION; recordCount = 0; - strComparator = (comparator == null) ? "" : comparator; - this.comparator = makeComparator(strComparator); + this.comparatorKind = ComparatorKind.fromString(comparatorName); + this.comparatorName = comparatorName; } // ctor for reads @@ -2055,42 +2293,14 @@ public TFileMeta(DataInput in) throws IOException { throw new RuntimeException("Incompatible TFile fileVersion."); } recordCount = Utils.readVLong(in); - strComparator = Utils.readString(in); - comparator = makeComparator(strComparator); - } - - @SuppressWarnings("unchecked") - static BytesComparator makeComparator(String comparator) { - if (comparator.length() == 0) { - // unsorted keys - return null; - } - if (comparator.equals(COMPARATOR_MEMCMP)) { - // default comparator - return new BytesComparator(new MemcmpRawComparator()); - } else if (comparator.startsWith(COMPARATOR_JCLASS)) { - String compClassName = - comparator.substring(COMPARATOR_JCLASS.length()).trim(); - try { - Class compClass = Class.forName(compClassName); - // use its default ctor to create an instance - return new BytesComparator((RawComparator) compClass - .newInstance()); - } catch (Exception e) { - throw new IllegalArgumentException( - "Failed to instantiate comparator: " + comparator + "(" - + e.toString() + ")"); - } - } else { - throw new IllegalArgumentException("Unsupported comparator: " - + comparator); - } + comparatorName = Utils.readString(in); + comparatorKind = ComparatorKind.fromString(comparatorName); } public void write(DataOutput out) throws IOException { TFile.API_VERSION.write(out); Utils.writeVLong(out, recordCount); - Utils.writeString(out, strComparator); + Utils.writeString(out, comparatorName); } public long getRecordCount() { @@ -2102,20 +2312,20 @@ public void incRecordCount() { } public boolean isSorted() { - return !strComparator.equals(""); - } - - public String getComparatorString() { - return strComparator; + return comparatorKind != ComparatorKind.NONE; } - public BytesComparator getComparator() { - return comparator; + public ComparatorKind getComparatorKind() { + return comparatorKind; } public Version getVersion() { return version; } + + public String getComparatorName() { + return comparatorName; + } } // END: class MetaTFileMeta /** @@ -2126,7 +2336,7 @@ static class TFileIndex { private ByteArray firstKey; private final ArrayList index; private final ArrayList recordNumIndex; - private final BytesComparator comparator; + private final RawComparator comparator; private long sum = 0; /** @@ -2134,7 +2344,7 @@ static class TFileIndex { * * @throws IOException */ - public TFileIndex(int entryCount, DataInput in, BytesComparator comparator) + public TFileIndex(int entryCount, DataInput in, RawComparator comparator) throws IOException { index = new ArrayList(entryCount); recordNumIndex = new ArrayList(entryCount); @@ -2217,7 +2427,7 @@ public int upperBound(RawComparable key) { /** * For writing to file. */ - public TFileIndex(BytesComparator comparator) { + public TFileIndex(RawComparator comparator) { index = new ArrayList(); recordNumIndex = new ArrayList(); this.comparator = comparator; @@ -2331,6 +2541,58 @@ public void write(DataOutput out) throws IOException { } } + /** + * Make a raw comparator from a string name. + * + * @param name + * Comparator name + * @return A RawComparable comparator. + */ + static RawComparator makeComparator(String comparator) { + if (comparator == null || comparator.length() == 0) { + // unsorted keys + return null; + } + if (comparator.equals(COMPARATOR_MEMCMP)) { + // default comparator + return MEMCMP; + } else if (comparator.equals(COMPARATOR_USER_MANAGED)) { + // the user needs to set it explicitly + return null; + } else if (comparator.startsWith(COMPARATOR_JCLASS)) { + // if it is a jclass string, we try to create it for them + // this only happens in old tfiles + String compClassName = + comparator.substring(COMPARATOR_JCLASS.length()).trim(); + try { + Class compClass = Class.forName(compClassName); + // use its default ctor to create an instance + return (RawComparator) ReflectionUtils.newInstance(compClass, null); + } catch (ClassNotFoundException cnfe) { + throw new IllegalArgumentException("Comparator class " + compClassName + + " not found."); + } + } else { + throw new IllegalArgumentException("Unsupported comparator: " + + comparator); + } + } + + /** + * Create a stringification of a given comparator + * @param comparator the comparator to stringify, may be null + * @return the string identifying this comparator + */ + static String stringifyComparator(RawComparator comparator) { + if (comparator == null) { + return ""; + } else if (comparator.getClass() == MemcmpRawComparator.class){ + return COMPARATOR_MEMCMP; + } else { + return COMPARATOR_USER_MANAGED; + } + } + /** * Dumping the TFile information. * diff --git a/src/java/org/apache/hadoop/io/file/tfile/TFileDumper.java b/src/java/org/apache/hadoop/io/file/tfile/TFileDumper.java index f065e62d0f56c..f0508b920669a 100644 --- a/src/java/org/apache/hadoop/io/file/tfile/TFileDumper.java +++ b/src/java/org/apache/hadoop/io/file/tfile/TFileDumper.java @@ -106,7 +106,7 @@ static public void dumpInfo(String file, PrintStream out, Configuration conf) int blockCnt = reader.readerBCF.getBlockCount(); int metaBlkCnt = reader.readerBCF.metaIndex.index.size(); properties.put("BCFile Version", reader.readerBCF.version.toString()); - properties.put("TFile Version", reader.tfileMeta.version.toString()); + properties.put("TFile Version", reader.getFileVersion().toString()); properties.put("File Length", Long.toString(length)); properties.put("Data Compression", reader.readerBCF .getDefaultCompressionName()); diff --git a/src/java/org/apache/hadoop/io/file/tfile/Utils.java b/src/java/org/apache/hadoop/io/file/tfile/Utils.java index 12148efa348df..58b6117624b7d 100644 --- a/src/java/org/apache/hadoop/io/file/tfile/Utils.java +++ b/src/java/org/apache/hadoop/io/file/tfile/Utils.java @@ -26,6 +26,7 @@ import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.io.Text; +import org.apache.hadoop.io.serial.RawComparator; /** * Supporting Utility classes used by TFile, and shared by users of TFile. @@ -414,15 +415,16 @@ public int hashCode() { * @return The index to the desired element if it exists; or list.size() * otherwise. */ - public static int lowerBound(List list, T key, - Comparator cmp) { + public static + int lowerBound(List list, T key, RawComparator cmp) { int low = 0; int high = list.size(); while (low < high) { int mid = (low + high) >>> 1; T midVal = list.get(mid); - int ret = cmp.compare(midVal, key); + int ret = cmp.compare(midVal.buffer(), midVal.offset(), midVal.size(), + key.buffer(), key.offset(), key.size()); if (ret < 0) low = mid + 1; else high = mid; @@ -445,15 +447,16 @@ public static int lowerBound(List list, T key, * @return The index to the desired element if it exists; or list.size() * otherwise. */ - public static int upperBound(List list, T key, - Comparator cmp) { + public static + int upperBound(List list, T key, RawComparator cmp) { int low = 0; int high = list.size(); while (low < high) { int mid = (low + high) >>> 1; T midVal = list.get(mid); - int ret = cmp.compare(midVal, key); + int ret = cmp.compare(midVal.buffer(), midVal.offset(), midVal.size(), + key.buffer(), key.offset(), key.size()); if (ret <= 0) low = mid + 1; else high = mid; @@ -490,6 +493,35 @@ public static int lowerBound(List> list, return low; } + /** + * Lower bound binary search. Find the index to the first element in the list + * that compares greater than or equal to key. + * + * @param + * Type of the input key. + * @param list + * The list + * @param key + * The input key. + * @return The index to the desired element if it exists; or list.size() + * otherwise. + */ + public static int lowerBound(List list, + T key, Comparator cmp) { + int low = 0; + int high = list.size(); + + while (low < high) { + int mid = (low + high) >>> 1; + T midVal = list.get(mid); + int ret = cmp.compare(midVal, key); + if (ret < 0) + low = mid + 1; + else high = mid; + } + return low; + } + /** * Upper bound binary search. Find the index to the first element in the list * that compares greater than the input key. diff --git a/src/java/org/apache/hadoop/io/nativeio/Errno.java b/src/java/org/apache/hadoop/io/nativeio/Errno.java new file mode 100644 index 0000000000000..b48f76da18e98 --- /dev/null +++ b/src/java/org/apache/hadoop/io/nativeio/Errno.java @@ -0,0 +1,60 @@ +/** + * 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.io.nativeio; + +/** + * Enum representing POSIX errno values. + */ +public enum Errno { + EPERM, + ENOENT, + ESRCH, + EINTR, + EIO, + ENXIO, + E2BIG, + ENOEXEC, + EBADF, + ECHILD, + EAGAIN, + ENOMEM, + EACCES, + EFAULT, + ENOTBLK, + EBUSY, + EEXIST, + EXDEV, + ENODEV, + ENOTDIR, + EISDIR, + EINVAL, + ENFILE, + EMFILE, + ENOTTY, + ETXTBSY, + EFBIG, + ENOSPC, + ESPIPE, + EROFS, + EMLINK, + EPIPE, + EDOM, + ERANGE, + + UNKNOWN; +} diff --git a/src/java/org/apache/hadoop/io/nativeio/NativeIO.java b/src/java/org/apache/hadoop/io/nativeio/NativeIO.java new file mode 100644 index 0000000000000..6e16c73fb93c0 --- /dev/null +++ b/src/java/org/apache/hadoop/io/nativeio/NativeIO.java @@ -0,0 +1,126 @@ +/** + * 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.io.nativeio; + +import java.io.FileDescriptor; +import java.io.IOException; + +import org.apache.hadoop.util.NativeCodeLoader; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +/** + * JNI wrappers for various native IO-related calls not available in Java. + * These functions should generally be used alongside a fallback to another + * more portable mechanism. + */ +public class NativeIO { + // Flags for open() call from bits/fcntl.h + public static final int O_RDONLY = 00; + public static final int O_WRONLY = 01; + public static final int O_RDWR = 02; + public static final int O_CREAT = 0100; + public static final int O_EXCL = 0200; + public static final int O_NOCTTY = 0400; + public static final int O_TRUNC = 01000; + public static final int O_APPEND = 02000; + public static final int O_NONBLOCK = 04000; + public static final int O_SYNC = 010000; + public static final int O_ASYNC = 020000; + public static final int O_FSYNC = O_SYNC; + public static final int O_NDELAY = O_NONBLOCK; + + private static final Log LOG = LogFactory.getLog(NativeIO.class); + + private static boolean nativeLoaded = false; + + static { + if (NativeCodeLoader.isNativeCodeLoaded()) { + try { + initNative(); + nativeLoaded = true; + } catch (Throwable t) { + // This can happen if the user has an older version of libhadoop.so + // installed - in this case we can continue without native IO + // after warning + LOG.error("Unable to initialize NativeIO libraries", t); + } + } + } + + /** + * Return true if the JNI-based native IO extensions are available. + */ + public static boolean isAvailable() { + return NativeCodeLoader.isNativeCodeLoaded() && nativeLoaded; + } + + /** Wrapper around open(2) */ + public static native FileDescriptor open(String path, int flags, int mode) throws IOException; + /** Wrapper around fstat(2) */ + public static native Stat fstat(FileDescriptor fd) throws IOException; + /** Initialize the JNI method ID and class ID cache */ + private static native void initNative(); + + + /** + * Result type of the fstat call + */ + public static class Stat { + private String owner, group; + private int mode; + + // Mode constants + public static final int S_IFMT = 0170000; /* type of file */ + public static final int S_IFIFO = 0010000; /* named pipe (fifo) */ + public static final int S_IFCHR = 0020000; /* character special */ + public static final int S_IFDIR = 0040000; /* directory */ + public static final int S_IFBLK = 0060000; /* block special */ + public static final int S_IFREG = 0100000; /* regular */ + public static final int S_IFLNK = 0120000; /* symbolic link */ + public static final int S_IFSOCK = 0140000; /* socket */ + public static final int S_IFWHT = 0160000; /* whiteout */ + public static final int S_ISUID = 0004000; /* set user id on execution */ + public static final int S_ISGID = 0002000; /* set group id on execution */ + public static final int S_ISVTX = 0001000; /* save swapped text even after use */ + public static final int S_IRUSR = 0000400; /* read permission, owner */ + public static final int S_IWUSR = 0000200; /* write permission, owner */ + public static final int S_IXUSR = 0000100; /* execute/search permission, owner */ + + Stat(String owner, String group, int mode) { + this.owner = owner; + this.group = group; + this.mode = mode; + } + + public String toString() { + return "Stat(owner='" + owner + "', group='" + group + "'" + + ", mode=" + mode + ")"; + } + + public String getOwner() { + return owner; + } + public String getGroup() { + return group; + } + public int getMode() { + return mode; + } + } +} diff --git a/src/java/org/apache/hadoop/io/nativeio/NativeIOException.java b/src/java/org/apache/hadoop/io/nativeio/NativeIOException.java new file mode 100644 index 0000000000000..5064df5d861e9 --- /dev/null +++ b/src/java/org/apache/hadoop/io/nativeio/NativeIOException.java @@ -0,0 +1,46 @@ +/** + * 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.io.nativeio; + +import java.io.IOException; + +/** + * An exception generated by a call to the native IO code. + * + * These exceptions simply wrap errno result codes. + */ +public class NativeIOException extends IOException { + private static final long serialVersionUID = 1L; + + private Errno errno; + + public NativeIOException(String msg, Errno errno) { + super(msg); + this.errno = errno; + } + + public Errno getErrno() { + return errno; + } + + public String toString() { + return errno.toString() + ": " + super.getMessage(); + } +} + + diff --git a/src/java/org/apache/hadoop/io/serial/RawComparator.java b/src/java/org/apache/hadoop/io/serial/RawComparator.java new file mode 100644 index 0000000000000..e1536651ac3e6 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/RawComparator.java @@ -0,0 +1,45 @@ +/** + * 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.io.serial; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; + +/** + * A compare function that compares two sets of bytes. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public interface RawComparator { + + /** + * Compare the two serialized keys. This must be stable, so: + * compare(b1,s1,l1,b2,s2,l2) = -compare(b2,s2,l2,b1,s1,l2) for all buffers. + * @param b1 the left data buffer to compare + * @param s1 the first index in b1 to compare + * @param l1 the number of bytes in b1 to compare + * @param b2 the right data buffer to compare + * @param s2 the first index in b2 to compare + * @param l2 the number of bytes in b2 to compare + * @return negative if b1 is less than b2, 0 if they are equal, positive if + * b1 is greater than b2. + */ + public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2); + +} diff --git a/src/java/org/apache/hadoop/io/serial/Serialization.java b/src/java/org/apache/hadoop/io/serial/Serialization.java new file mode 100644 index 0000000000000..338d1ef0124d3 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/Serialization.java @@ -0,0 +1,145 @@ +/** + * 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.io.serial; + +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configuration; + +/** + * The primary interface to provide serialization. + * @param the parent type that it will serialize + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public abstract class Serialization implements Cloneable { + + /** + * Serialize the given object to the OutputStream. + * @param stream the stream to serialize to + * @param object the object to serialize + * @throws IOException if the serialization fails + */ + public abstract void serialize(OutputStream stream, + T object) throws IOException; + + /** + * Deserialize the given object from the InputStream. + * @param stream the stream to deserialize from + * @param reusableObject an object (or null) that may be reused by the + * serializer + * @param conf the user's configuration + * @return the object that was created or reused with the data in it + * @throws IOException if the deserialization fails + */ + public abstract T deserialize(InputStream stream, + T reusableObject, + Configuration conf) throws IOException; + + /** + * Get the default raw comparator for the given serializer + * @return a comparator that will compare bytes + */ + public abstract RawComparator getRawComparator(); + + /** + * Serialize the serializer's configuration to the output stream. + * @param out the stream to serialize to + * @throws IOException if the serialization fails + */ + public abstract void serializeSelf(OutputStream out) throws IOException; + + /** + * Modify the serialization's configuration to reflect the contents of the + * input stream. + * @param in the stream to read from + * @param conf the configuration + * @throws IOException if the deserialization fails + */ + public abstract void deserializeSelf(InputStream in, + Configuration conf) throws IOException; + + /** + * Generate the state of the serialization in a human-friendly string. + * @return the textual representation of the serialization state + */ + @Override + public abstract String toString(); + + /** + * Restore the state of the serialization from a human-friendly string. + * @param metadata the string that was generated by toString + * @throws IOException + */ + public abstract void fromString(String metadata) throws IOException; + + /** + * Get the name for this kind of serialization, which must be unique. This + * name is used to identify the serialization that was used to write a + * particular file. + * @return the unique name + */ + public String getName() { + return getClass().getName(); + } + + /** + * Ensure the InputStream is a DataInput, wrapping it if necessary + * @param in the input stream to wrap + * @return the wrapped stream + */ + protected DataInput ensureDataInput(InputStream in) { + if (in instanceof DataInput) { + return (DataInput) in; + } else { + return new DataInputStream(in); + } + } + + /** + * Ensure the OutputStream is a DataOutput, wrapping it if necessary. + * @param out the output stream to wrap + * @return the wrapped stream + */ + protected DataOutput ensureDataOutput(OutputStream out) { + if (out instanceof DataOutput) { + return (DataOutput) out; + } else { + return new DataOutputStream(out); + } + } + + @SuppressWarnings("unchecked") + @Override + public Serialization clone() { + try { + return (Serialization) super.clone(); + } catch (CloneNotSupportedException e) { + throw new IllegalArgumentException("Can't clone object " + this, e); + } + } +} diff --git a/src/java/org/apache/hadoop/io/serial/SerializationFactory.java b/src/java/org/apache/hadoop/io/serial/SerializationFactory.java new file mode 100644 index 0000000000000..a6c00ed7d16f5 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/SerializationFactory.java @@ -0,0 +1,139 @@ +/** + * 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.io.serial; + +import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SERIALIZATIONS_KEY; +import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.IO_SERIALIZATIONS_KEY; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.serial.lib.CompatibilitySerialization; +import org.apache.hadoop.io.serial.lib.WritableSerialization; +import org.apache.hadoop.io.serial.lib.avro.AvroSerialization; +import org.apache.hadoop.io.serial.lib.protobuf.ProtoBufSerialization; +import org.apache.hadoop.io.serial.lib.thrift.ThriftSerialization; +import org.apache.hadoop.util.ReflectionUtils; + +/** + * A factory that finds and creates Serializations. + * + * There are two methods. The first finds a Serialization by its name (ie. + * avro, writable, thrift, etc.). The second finds a TypedSerialization based + * on the type that needs to be serialized. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public class SerializationFactory { + private static final Log LOG = LogFactory.getLog(SerializationFactory.class); + + private final List> typedSerializations = + new ArrayList>(); + private final Map> serializations = + new HashMap>(); + + public SerializationFactory(Configuration conf) { + Class[] classes = + conf.getClasses(HADOOP_SERIALIZATIONS_KEY, + new Class[]{WritableSerialization.class, + ProtoBufSerialization.class, + ThriftSerialization.class, + AvroSerialization.class, + CompatibilitySerialization.class}); + for(Class cls: classes) { + if (Serialization.class.isAssignableFrom(cls)) { + Serialization serial = + (Serialization) ReflectionUtils.newInstance(cls, conf); + if (serial instanceof TypedSerialization) { + typedSerializations.add((TypedSerialization) serial); + } + String name = serial.getName(); + if (serializations.containsKey(name)) { + throw new IllegalArgumentException("Two serializations have the" + + " same name: " + name); + } + serializations.put(serial.getName(), serial); + LOG.debug("Adding serialization " + serial.getName()); + } else { + throw new IllegalArgumentException("Unknown serialization class " + + cls.getName()); + } + } + } + + private static final Map FACTORY_CACHE = + new HashMap(); + + /** + * Get the cached factory for the given configuration. Two configurations + * that have the same io.configurations value will be considered identical + * because we can't keep a reference to the Configuration without locking it + * in memory. + * @param conf the configuration + * @return the factory for a given configuration + */ + public static synchronized + SerializationFactory getInstance(Configuration conf) { + String serializerNames = conf.get(HADOOP_SERIALIZATIONS_KEY, "*default*"); + String obsoleteSerializerNames = conf.get(IO_SERIALIZATIONS_KEY, "*default*"); + String key = serializerNames + " " + obsoleteSerializerNames; + SerializationFactory result = FACTORY_CACHE.get(key); + if (result == null) { + result = new SerializationFactory(conf); + FACTORY_CACHE.put(key, result); + } + return result; + } + + /** + * Look up a serialization by name and return a clone of it. + * @param name + * @return a newly cloned serialization of the right name + */ + public Serialization getSerialization(String name) { + return serializations.get(name).clone(); + } + + /** + * Find the first acceptable serialization for a given type. + * @param cls the class that should be serialized + * @return a serialization that should be used to serialize the class + */ + @SuppressWarnings("unchecked") + public TypedSerialization getSerializationByType(Class cls){ + for (TypedSerialization serial: typedSerializations) { + if (serial.accept(cls)) { + TypedSerialization result = + (TypedSerialization) serial.clone(); + result.setSpecificType(cls); + return result; + } + } + throw new IllegalArgumentException("Could not find a serialization to"+ + " accept " + cls.getName()); + } + +} diff --git a/src/java/org/apache/hadoop/io/serial/TypedSerialization.java b/src/java/org/apache/hadoop/io/serial/TypedSerialization.java new file mode 100644 index 0000000000000..f7a22523e0624 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/TypedSerialization.java @@ -0,0 +1,140 @@ +package org.apache.hadoop.io.serial; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata; +import org.yaml.snakeyaml.Yaml; + +/** + * An abstract base class for serializers that handle types under a given + * parent type. Generally, their metadata consists of the class name of the + * specific type that is being serialized. + *

    + * Typically, TypedSerializations have two types. The first is the base type, + * which is the static parent type that it can serialize. The other is the + * specific type that this instance is current serializing. + * @param the base type that a given class of Serializers will serialize. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public abstract class TypedSerialization extends Serialization { + protected Class specificType; + + protected TypedSerialization() { + } + + protected TypedSerialization(Class specificType) { + this.specificType = specificType; + } + + /** + * Get the base class that this method of serialization can handle. + * @return the base class + */ + public abstract Class getBaseType(); + + public void setSpecificType(Class cls) { + specificType = cls; + } + + public Class getSpecificType() { + return specificType; + } + + /** + * Can this serialization serialize/deserialize a given class + * @param candidateClass the class in question + * @return true if the class can be serialized + */ + public boolean accept(Class candidateClass) { + return getBaseType().isAssignableFrom(candidateClass); + } + + /** + * Read the specific class as the metadata. + * @throws IOException when class not found or the deserialization fails + */ + @Override + public void deserializeSelf(InputStream in, + Configuration conf) throws IOException { + TypedSerializationMetadata data = TypedSerializationMetadata.parseFrom(in); + if (data.hasTypename()) { + setSpecificTypeByName(data.getTypename()); + } + } + + /** + * Write the specific class name as the metadata. + */ + @Override + public void serializeSelf(OutputStream out) throws IOException { + TypedSerializationMetadata.newBuilder(). + setTypename(specificType == null ? "" : specificType.getName()). + build().writeTo(out); + } + + private static final String CLASS_ATTRIBUTE = "class"; + + @SuppressWarnings("unchecked") + @Override + public void fromString(String meta) throws IOException { + Yaml yaml = new Yaml(); + Map map = (Map) yaml.load(meta); + String cls = map.get(CLASS_ATTRIBUTE); + setSpecificTypeByName(cls); + } + + @SuppressWarnings("unchecked") + private void setSpecificTypeByName(String name) throws IOException { + if (name == null || name.length() == 0) { + specificType = null; + } else { + try { + setSpecificType((Class) Class.forName(name)); + } catch (ClassNotFoundException e) { + throw new IOException("serializer class not found " + name, e); + } + } + } + + public String toString() { + Yaml yaml = new Yaml(); + Map map = new HashMap(); + if (specificType != null) { + map.put(CLASS_ATTRIBUTE, specificType.getName()); + } + return yaml.dump(map); + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object right) { + if (this == right) { + return true; + } else if (right == null || right.getClass() != getClass()) { + return false; + } else { + TypedSerialization rightTyped = (TypedSerialization) right; + return specificType == rightTyped.specificType; + } + } + + @Override + public int hashCode() { + return specificType == null ? 42 : specificType.hashCode(); + } + + @Override + public TypedSerialization clone() { + TypedSerialization result = (TypedSerialization) super.clone(); + result.specificType = specificType; + return result; + } +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/CompatibilitySerialization.java b/src/java/org/apache/hadoop/io/serial/lib/CompatibilitySerialization.java new file mode 100644 index 0000000000000..9728334dac7e5 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/CompatibilitySerialization.java @@ -0,0 +1,146 @@ +/** + * 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.io.serial.lib; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.avro.Schema; +import org.apache.avro.reflect.ReflectData; +import org.apache.avro.specific.SpecificData; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configurable; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.WritableComparator; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.serial.TypedSerialization; +import org.apache.hadoop.io.serial.lib.avro.AvroComparator; +import org.apache.hadoop.util.ReflectionUtils; + +/** + * This class allows user-defined old style serializers to run inside the new + * framework. This will only be used for user serializations that haven't been + * ported yet. + */ +@SuppressWarnings("deprecation") +@InterfaceAudience.Public +@InterfaceStability.Evolving +public class CompatibilitySerialization extends TypedSerialization + implements Configurable { + private org.apache.hadoop.io.serializer.SerializationFactory factory; + + @SuppressWarnings("unchecked") + private org.apache.hadoop.io.serializer.Serialization + serialization = null; + + public CompatibilitySerialization() { + // NOTHING + } + + @Override + public CompatibilitySerialization clone() { + CompatibilitySerialization result = + (CompatibilitySerialization) super.clone(); + result.factory = factory; + result.serialization = serialization; + return result; + } + + @Override + public Class getBaseType() { + return Object.class; + } + + @Override + public boolean accept(Class candidateClass) { + return factory.getSerialization(candidateClass) != null; + } + + @Override + public void setSpecificType(Class cls) { + super.setSpecificType(cls); + serialization = factory.getSerialization(cls); + } + + @SuppressWarnings("unchecked") + @Override + public Object deserialize(InputStream stream, Object reusableObject, + Configuration conf) throws IOException { + org.apache.hadoop.io.serializer.Deserializer deserializer = + serialization.getDeserializer(specificType); + deserializer.open(stream); + Object result = deserializer.deserialize(reusableObject); + // if the object is new, configure it + if (result != reusableObject) { + ReflectionUtils.setConf(result, conf); + } + return result; + } + + @SuppressWarnings("unchecked") + @Override + public RawComparator getRawComparator() { + if (specificType == null) { + throw new + IllegalArgumentException("Must have specific type for comparision"); + } else if (serialization instanceof + org.apache.hadoop.io.serializer.WritableSerialization) { + return WritableComparator.get((Class) specificType); + } else if (serialization instanceof + org.apache.hadoop.io.serializer.avro.AvroReflectSerialization){ + Schema schema = ReflectData.get().getSchema(specificType); + return new AvroComparator(schema); + } else if (serialization instanceof + org.apache.hadoop.io.serializer.avro.AvroSpecificSerialization){ + Schema schema = SpecificData.get().getSchema(specificType); + return new AvroComparator(schema); + } else if (Comparable.class.isAssignableFrom(specificType)) { + // if the type is comparable, we can deserialize + return new DeserializationRawComparator(this, null); + } else { + return new MemcmpRawComparator(); + } + } + + @SuppressWarnings("unchecked") + @Override + public void serialize(OutputStream stream, Object object) throws IOException { + org.apache.hadoop.io.serializer.Serializer serializer = + serialization.getSerializer(specificType); + serializer.open(stream); + serializer.serialize(object); + } + + @Override + public String getName() { + return "compatibility"; + } + + @Override + public Configuration getConf() { + return null; + } + + @Override + public void setConf(Configuration conf) { + factory = new org.apache.hadoop.io.serializer.SerializationFactory(conf); + } +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/DeserializationRawComparator.java b/src/java/org/apache/hadoop/io/serial/lib/DeserializationRawComparator.java new file mode 100644 index 0000000000000..f0ba94675b5d6 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/DeserializationRawComparator.java @@ -0,0 +1,81 @@ +/** + * 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.io.serial.lib; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.DataInputBuffer; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.serial.Serialization; + +/** + *

    + * A {@link RawComparator} that uses a {@link Serialization} + * object to deserialize objects that are then compared via + * their {@link Comparable} interfaces. + *

    + * @param + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public class DeserializationRawComparator> + implements RawComparator { + private final Serialization serialization; + private final Configuration conf; + + private static final class ReusableObjects> { + DataInputBuffer buf = new DataInputBuffer(); + T left = null; + T right = null; + } + + private static final ThreadLocal> REUSE_FACTORY = + new ThreadLocal>(){ + @SuppressWarnings("unchecked") + @Override + protected ReusableObjects initialValue() { + return new ReusableObjects(); + } + }; + + public DeserializationRawComparator(Serialization serialization, + Configuration conf) { + this.serialization = serialization; + this.conf = conf; + } + + @SuppressWarnings("unchecked") + @Override + public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { + ReusableObjects reuse = (ReusableObjects) REUSE_FACTORY.get(); + try { + reuse.buf.reset(b1, s1, l1); + reuse.left = serialization.deserialize(reuse.buf, reuse.left, conf); + reuse.buf.reset(b2, s2, l2); + reuse.right = serialization.deserialize(reuse.buf, reuse.right, conf); + return reuse.left.compareTo(reuse.right); + } catch (IOException e) { + throw new RuntimeException("Error in deserialization",e); + } + } + +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/JavaSerialization.java b/src/java/org/apache/hadoop/io/serial/lib/JavaSerialization.java new file mode 100644 index 0000000000000..1f458e3ed02dc --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/JavaSerialization.java @@ -0,0 +1,110 @@ +/** + * 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.io.serial.lib; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.serial.TypedSerialization; + +/** + * A serialization binding for Java serialization. It has the advantage of + * handling all serializable Java types, but is not space or time efficient. In + * particular, the type information is repeated in each record. + * It is not enabled by default. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public class JavaSerialization extends TypedSerialization { + + @Override + public Serializable deserialize(InputStream stream, + Serializable reusableObject, + Configuration conf) throws IOException { + ObjectInputStream ois = new ObjectInputStream(stream) { + @Override protected void readStreamHeader() { + // no header + } + }; + try { + // ignore passed-in object + Serializable result = (Serializable) ois.readObject(); + return result; + } catch (ClassNotFoundException e) { + throw new IOException(e.toString()); + } + } + + @Override + public void deserializeSelf(InputStream in, Configuration conf) { + // nothing + } + + @SuppressWarnings("unchecked") + @Override + public RawComparator getRawComparator() { + return new DeserializationRawComparator(this, null); + } + + @Override + public void serialize(OutputStream stream, Serializable object + ) throws IOException { + ObjectOutputStream oos = new ObjectOutputStream(stream) { + @Override protected void writeStreamHeader() { + // no header + } + }; + oos.reset(); // clear (class) back-references + oos.writeObject(object); + oos.flush(); + } + + @Override + public void serializeSelf(OutputStream out) throws IOException { + // nothing + } + + @Override + public Class getBaseType() { + return Serializable.class; + } + + @Override + public String getName() { + return "java"; + } + + @Override + public void fromString(String metadata) { + // NOTHING + } + + @Override + public String toString() { + return ""; + } +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/MemcmpRawComparator.java b/src/java/org/apache/hadoop/io/serial/lib/MemcmpRawComparator.java new file mode 100644 index 0000000000000..35c20051ffec5 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/MemcmpRawComparator.java @@ -0,0 +1,19 @@ +package org.apache.hadoop.io.serial.lib; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.WritableComparator; + +/** + * A raw comparator that compares byte strings in lexicographical order. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public final class MemcmpRawComparator implements RawComparator { + @Override + public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { + return WritableComparator.compareBytes(b1, s1, l1, b2, s2, l2); + } + +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/SerializationMetadata.java b/src/java/org/apache/hadoop/io/serial/lib/SerializationMetadata.java new file mode 100644 index 0000000000000..cbd8a783fa097 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/SerializationMetadata.java @@ -0,0 +1,763 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: src/protobuf/SerializationMetadata.proto + +package org.apache.hadoop.io.serial.lib; + +public final class SerializationMetadata { + private SerializationMetadata() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + } + public static final class TypedSerializationMetadata extends + com.google.protobuf.GeneratedMessage { + // Use TypedSerializationMetadata.newBuilder() to construct. + private TypedSerializationMetadata() { + initFields(); + } + private TypedSerializationMetadata(boolean noInit) {} + + private static final TypedSerializationMetadata defaultInstance; + public static TypedSerializationMetadata getDefaultInstance() { + return defaultInstance; + } + + public TypedSerializationMetadata getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.apache.hadoop.io.serial.lib.SerializationMetadata.internal_static_org_apache_hadoop_io_serial_lib_TypedSerializationMetadata_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.apache.hadoop.io.serial.lib.SerializationMetadata.internal_static_org_apache_hadoop_io_serial_lib_TypedSerializationMetadata_fieldAccessorTable; + } + + // optional string typename = 1; + public static final int TYPENAME_FIELD_NUMBER = 1; + private boolean hasTypename; + private java.lang.String typename_ = ""; + public boolean hasTypename() { return hasTypename; } + public java.lang.String getTypename() { return typename_; } + + private void initFields() { + } + public final boolean isInitialized() { + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (hasTypename()) { + output.writeString(1, getTypename()); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasTypename()) { + size += com.google.protobuf.CodedOutputStream + .computeStringSize(1, getTypename()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder { + private org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata result; + + // Construct using org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata(); + return builder; + } + + protected org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata.getDescriptor(); + } + + public org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata getDefaultInstanceForType() { + return org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata buildPartial() { + if (result == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } + org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata) { + return mergeFrom((org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata other) { + if (other == org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata.getDefaultInstance()) return this; + if (other.hasTypename()) { + setTypename(other.getTypename()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + return this; + } + break; + } + case 10: { + setTypename(input.readString()); + break; + } + } + } + } + + + // optional string typename = 1; + public boolean hasTypename() { + return result.hasTypename(); + } + public java.lang.String getTypename() { + return result.getTypename(); + } + public Builder setTypename(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasTypename = true; + result.typename_ = value; + return this; + } + public Builder clearTypename() { + result.hasTypename = false; + result.typename_ = getDefaultInstance().getTypename(); + return this; + } + + // @@protoc_insertion_point(builder_scope:org.apache.hadoop.io.serial.lib.TypedSerializationMetadata) + } + + static { + defaultInstance = new TypedSerializationMetadata(true); + org.apache.hadoop.io.serial.lib.SerializationMetadata.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:org.apache.hadoop.io.serial.lib.TypedSerializationMetadata) + } + + public static final class AvroMetadata extends + com.google.protobuf.GeneratedMessage { + // Use AvroMetadata.newBuilder() to construct. + private AvroMetadata() { + initFields(); + } + private AvroMetadata(boolean noInit) {} + + private static final AvroMetadata defaultInstance; + public static AvroMetadata getDefaultInstance() { + return defaultInstance; + } + + public AvroMetadata getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.apache.hadoop.io.serial.lib.SerializationMetadata.internal_static_org_apache_hadoop_io_serial_lib_AvroMetadata_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.apache.hadoop.io.serial.lib.SerializationMetadata.internal_static_org_apache_hadoop_io_serial_lib_AvroMetadata_fieldAccessorTable; + } + + public enum Kind + implements com.google.protobuf.ProtocolMessageEnum { + SPECIFIC(0, 1), + GENERIC(1, 2), + REFLECTION(2, 3), + ; + + + public final int getNumber() { return value; } + + public static Kind valueOf(int value) { + switch (value) { + case 1: return SPECIFIC; + case 2: return GENERIC; + case 3: return REFLECTION; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public Kind findValueByNumber(int number) { + return Kind.valueOf(number) + ; } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + return getDescriptor().getValues().get(index); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.getDescriptor().getEnumTypes().get(0); + } + + private static final Kind[] VALUES = { + SPECIFIC, GENERIC, REFLECTION, + }; + public static Kind valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + return VALUES[desc.getIndex()]; + } + private final int index; + private final int value; + private Kind(int index, int value) { + this.index = index; + this.value = value; + } + + static { + org.apache.hadoop.io.serial.lib.SerializationMetadata.getDescriptor(); + } + + // @@protoc_insertion_point(enum_scope:org.apache.hadoop.io.serial.lib.AvroMetadata.Kind) + } + + // optional string schema = 1; + public static final int SCHEMA_FIELD_NUMBER = 1; + private boolean hasSchema; + private java.lang.String schema_ = ""; + public boolean hasSchema() { return hasSchema; } + public java.lang.String getSchema() { return schema_; } + + // optional .org.apache.hadoop.io.serial.lib.AvroMetadata.Kind kind = 2; + public static final int KIND_FIELD_NUMBER = 2; + private boolean hasKind; + private org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.Kind kind_; + public boolean hasKind() { return hasKind; } + public org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.Kind getKind() { return kind_; } + + private void initFields() { + kind_ = org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.Kind.SPECIFIC; + } + public final boolean isInitialized() { + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (hasSchema()) { + output.writeString(1, getSchema()); + } + if (hasKind()) { + output.writeEnum(2, getKind().getNumber()); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasSchema()) { + size += com.google.protobuf.CodedOutputStream + .computeStringSize(1, getSchema()); + } + if (hasKind()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, getKind().getNumber()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder { + private org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata result; + + // Construct using org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata(); + return builder; + } + + protected org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.getDescriptor(); + } + + public org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata getDefaultInstanceForType() { + return org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata buildPartial() { + if (result == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } + org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata) { + return mergeFrom((org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata other) { + if (other == org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.getDefaultInstance()) return this; + if (other.hasSchema()) { + setSchema(other.getSchema()); + } + if (other.hasKind()) { + setKind(other.getKind()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + return this; + } + break; + } + case 10: { + setSchema(input.readString()); + break; + } + case 16: { + int rawValue = input.readEnum(); + org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.Kind value = org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.Kind.valueOf(rawValue); + if (value == null) { + unknownFields.mergeVarintField(2, rawValue); + } else { + setKind(value); + } + break; + } + } + } + } + + + // optional string schema = 1; + public boolean hasSchema() { + return result.hasSchema(); + } + public java.lang.String getSchema() { + return result.getSchema(); + } + public Builder setSchema(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasSchema = true; + result.schema_ = value; + return this; + } + public Builder clearSchema() { + result.hasSchema = false; + result.schema_ = getDefaultInstance().getSchema(); + return this; + } + + // optional .org.apache.hadoop.io.serial.lib.AvroMetadata.Kind kind = 2; + public boolean hasKind() { + return result.hasKind(); + } + public org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.Kind getKind() { + return result.getKind(); + } + public Builder setKind(org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.Kind value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasKind = true; + result.kind_ = value; + return this; + } + public Builder clearKind() { + result.hasKind = false; + result.kind_ = org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.Kind.SPECIFIC; + return this; + } + + // @@protoc_insertion_point(builder_scope:org.apache.hadoop.io.serial.lib.AvroMetadata) + } + + static { + defaultInstance = new AvroMetadata(true); + org.apache.hadoop.io.serial.lib.SerializationMetadata.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:org.apache.hadoop.io.serial.lib.AvroMetadata) + } + + private static com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_hadoop_io_serial_lib_TypedSerializationMetadata_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_org_apache_hadoop_io_serial_lib_TypedSerializationMetadata_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_hadoop_io_serial_lib_AvroMetadata_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_org_apache_hadoop_io_serial_lib_AvroMetadata_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n(src/protobuf/SerializationMetadata.pro" + + "to\022\037org.apache.hadoop.io.serial.lib\".\n\032T" + + "ypedSerializationMetadata\022\020\n\010typename\030\001 " + + "\001(\t\"\223\001\n\014AvroMetadata\022\016\n\006schema\030\001 \001(\t\022@\n\004" + + "kind\030\002 \001(\01622.org.apache.hadoop.io.serial" + + ".lib.AvroMetadata.Kind\"1\n\004Kind\022\014\n\010SPECIF" + + "IC\020\001\022\013\n\007GENERIC\020\002\022\016\n\nREFLECTION\020\003" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + internal_static_org_apache_hadoop_io_serial_lib_TypedSerializationMetadata_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_org_apache_hadoop_io_serial_lib_TypedSerializationMetadata_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_org_apache_hadoop_io_serial_lib_TypedSerializationMetadata_descriptor, + new java.lang.String[] { "Typename", }, + org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata.class, + org.apache.hadoop.io.serial.lib.SerializationMetadata.TypedSerializationMetadata.Builder.class); + internal_static_org_apache_hadoop_io_serial_lib_AvroMetadata_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_org_apache_hadoop_io_serial_lib_AvroMetadata_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_org_apache_hadoop_io_serial_lib_AvroMetadata_descriptor, + new java.lang.String[] { "Schema", "Kind", }, + org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.class, + org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata.Builder.class); + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + } + + public static void internalForceInit() {} + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/WritableSerialization.java b/src/java/org/apache/hadoop/io/serial/lib/WritableSerialization.java new file mode 100644 index 0000000000000..332b75a9c1ba0 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/WritableSerialization.java @@ -0,0 +1,93 @@ +/** + * 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.io.serial.lib; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.io.WritableComparable; +import org.apache.hadoop.io.WritableComparator; +import org.apache.hadoop.io.serial.TypedSerialization; +import org.apache.hadoop.util.ReflectionUtils; + +/** + * A {@link TypedSerialization} for {@link Writable}s that delegates to + * {@link Writable#write} and {@link Writable#readFields}. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public class WritableSerialization extends TypedSerialization { + + public WritableSerialization() {} + + public WritableSerialization(Class specificType) { + super(specificType); + } + + @Override + public Writable deserialize(InputStream stream, + Writable w, + Configuration conf) throws IOException { + Writable writable; + if (w == null) { + writable = (Writable) ReflectionUtils.newInstance(specificType, conf); + } else { + if (w.getClass() != specificType) { + throw new IllegalArgumentException("Type mismatch in deserialization: "+ + "expected: " + specificType + + "; received " + w.getClass()); + } + writable = w; + } + writable.readFields(ensureDataInput(stream)); + return writable; + } + + @Override + public void serialize(OutputStream out, Writable w) throws IOException { + if (specificType != w.getClass()) { + throw new IOException("Type mismatch in serialization: expected " + + specificType + "; received " + w.getClass()); + } + w.write(ensureDataOutput(out)); + } + + @Override + @SuppressWarnings("unchecked") + public RawComparator getRawComparator() { + return (RawComparator) WritableComparator.get( + (Class) specificType); + } + + @Override + public Class getBaseType() { + return Writable.class; + } + + @Override + public String getName() { + return "writable"; + } +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/avro/AvroComparator.java b/src/java/org/apache/hadoop/io/serial/lib/avro/AvroComparator.java new file mode 100644 index 0000000000000..62ccc178cc593 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/avro/AvroComparator.java @@ -0,0 +1,47 @@ +/** + * 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.io.serial.lib.avro; + +import org.apache.avro.Schema; +import org.apache.avro.io.BinaryData; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.io.serial.RawComparator; + +/** + *

    + * A {@link RawComparator} that uses Avro to extract data from the + * source stream and compare their contents without explicit + * deserialization. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public class AvroComparator implements RawComparator { + + private final Schema schema; + + public AvroComparator(final Schema s) { + this.schema = s; + } + + public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { + return BinaryData.compare(b1, s1, b2, s2, schema); + } + +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/avro/AvroReflectSerializable.java b/src/java/org/apache/hadoop/io/serial/lib/avro/AvroReflectSerializable.java new file mode 100644 index 0000000000000..b6d69c7b7ea68 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/avro/AvroReflectSerializable.java @@ -0,0 +1,33 @@ +/** + * 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.io.serial.lib.avro; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; + +/** + * Tag interface for Avro 'reflect' serializable classes. Classes implementing + * this interface can be serialized/deserialized using + * {@link AvroSerialization}. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public interface AvroReflectSerializable { + +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/avro/AvroSerialization.java b/src/java/org/apache/hadoop/io/serial/lib/avro/AvroSerialization.java new file mode 100644 index 0000000000000..f76b237d55a96 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/avro/AvroSerialization.java @@ -0,0 +1,333 @@ +/** + * 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.io.serial.lib.avro; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.avro.Schema; +import org.apache.avro.generic.GenericDatumReader; +import org.apache.avro.generic.GenericDatumWriter; +import org.apache.avro.io.Decoder; +import org.apache.avro.io.DecoderFactory; +import org.apache.avro.io.BinaryEncoder; +import org.apache.avro.io.DatumReader; +import org.apache.avro.io.DatumWriter; +import org.apache.avro.io.Encoder; +import org.apache.avro.reflect.ReflectData; +import org.apache.avro.reflect.ReflectDatumReader; +import org.apache.avro.reflect.ReflectDatumWriter; +import org.apache.avro.specific.SpecificData; +import org.apache.avro.specific.SpecificDatumReader; +import org.apache.avro.specific.SpecificDatumWriter; +import org.apache.avro.specific.SpecificRecord; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configurable; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.serial.TypedSerialization; +import org.apache.hadoop.io.serial.lib.SerializationMetadata.AvroMetadata; +import org.apache.hadoop.util.ReflectionUtils; +import org.yaml.snakeyaml.Yaml; + +/** + * A binding for Avro binary serialization. It handles generic, specific, and + * reflection Java Avro serialization. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public class AvroSerialization extends TypedSerialization + implements Configurable { + /** + * Key to configure packages that contain classes to be serialized and + * deserialized using this class. Multiple packages can be specified using + * comma-separated list. + */ + public static final String AVRO_REFLECT_PACKAGES = "avro.reflect.pkgs"; + + public static enum Kind { + GENERIC(AvroMetadata.Kind.GENERIC), + SPECIFIC(AvroMetadata.Kind.SPECIFIC), + REFLECTION(AvroMetadata.Kind.REFLECTION); + + private static final EnumMap translation = + new EnumMap(AvroMetadata.Kind.class); + static { + for (Kind value: Kind.class.getEnumConstants()) { + translation.put(value.kind, value); + } + } + + private AvroMetadata.Kind kind; + private Kind(AvroMetadata.Kind kind) { + this.kind = kind; + } + + /** + * Get the serialized form of the given enumeration. + * @return the serializable kind + */ + @InterfaceAudience.Private + public AvroMetadata.Kind getMetadataKind() { + return kind; + } + + /** + * Get the kind from the serialization enumeration. + * @param kind the serialization enumeration + * @return the internal kind + */ + @InterfaceAudience.Private + public static Kind fromMetadataKind(AvroMetadata.Kind kind) { + return translation.get(kind); + } + } + + private static final DecoderFactory decoderFactory = + DecoderFactory.defaultFactory(); + + private Configuration conf; + private Set packages; + private Kind kind; + private Schema schema; + private DatumWriter writer; + private DatumReader reader; + private Encoder encoder; + private Decoder decoder; + + private void setKind(Kind kind) { + this.kind = kind; + if (kind != null) { + switch (kind) { + case GENERIC: + writer = new GenericDatumWriter(); + reader = new GenericDatumReader(); + break; + case SPECIFIC: + writer = new SpecificDatumWriter(); + reader = new SpecificDatumReader(); + break; + case REFLECTION: + writer = new ReflectDatumWriter(); + reader = new ReflectDatumReader(); + break; + } + } + } + + public AvroSerialization() { + this(null); + } + + public AvroSerialization(Kind kind) { + setKind(kind); + encoder = new BinaryEncoder(null); + decoder = decoderFactory.createBinaryDecoder((InputStream) null, null); + } + + /** + * Get the schema. + * @return the avro schema + */ + public Schema getSchema() { + return schema; + } + + /** + * Set the schema to the given value. + * @param schema the new schema + * @return returns this serialization so that you can use it like a builder + */ + public AvroSerialization setSchema(Schema schema) { + this.schema = schema; + if (kind != null) { + writer.setSchema(schema); + reader.setSchema(schema); + } + return this; + } + + @Override + public void serialize(OutputStream out, Object obj) throws IOException { + encoder.init(out); + writer.write(obj, encoder); + encoder.flush(); + } + + @Override + public Object deserialize(InputStream in, Object reuse, Configuration conf + ) throws IOException { + decoder.init(in); + Object result = reader.read(reuse, decoder); + // configure the object, if it wants to be + if (result != reuse) { + ReflectionUtils.setConf(result, conf); + } + return result; + } + + /** + * Provides a raw comparator for Avro-encoded serialized data. + * @return a RawComparator parameterized for the specified Avro schema. + */ + @Override + public RawComparator getRawComparator() { + return new AvroComparator(schema); + } + + @Override + public AvroSerialization clone() { + AvroSerialization result = (AvroSerialization) super.clone(); + result.setKind(kind); + result.setSchema(schema); + return result; + } + + @Override + public void deserializeSelf(InputStream in, + Configuration conf) throws IOException { + AvroMetadata meta = AvroMetadata.parseFrom(in); + if (kind == null) { + setKind(Kind.fromMetadataKind(meta.getKind())); + } + setSchema(Schema.parse(meta.getSchema())); + } + + @Override + public void serializeSelf(OutputStream out) throws IOException { + AvroMetadata.newBuilder().setKind(kind.kind).setSchema(schema.toString()). + build().writeTo(out); + } + + private static final String KIND_ATTRIBUTE = "kind"; + private static final String SCHEMA_ATTRIBUTE = "schema"; + + @SuppressWarnings("unchecked") + @Override + public void fromString(String meta) throws IOException { + Yaml yaml = new Yaml(); + Map map = (Map) yaml.load(meta); + String value = map.get(KIND_ATTRIBUTE); + if (kind == null && value != null) { + setKind(Kind.valueOf(value)); + } + value = map.get(SCHEMA_ATTRIBUTE); + setSchema(Schema.parse(value)); + } + + public String toString() { + Yaml yaml = new Yaml(); + Map map = new HashMap(); + if (kind != null) { + map.put(KIND_ATTRIBUTE, kind.toString()); + } + map.put(SCHEMA_ATTRIBUTE, schema.toString()); + return yaml.dump(map); + } + + private boolean isReflection(Class cls) { + return AvroReflectSerializable.class.isAssignableFrom(cls) || + getPackages().contains(cls.getPackage().getName()); + } + + private Set getPackages() { + if (packages == null) { + String[] pkgList = conf.getStrings(AVRO_REFLECT_PACKAGES); + packages = new HashSet(); + if (pkgList != null) { + for (String pkg : pkgList) { + packages.add(pkg.trim()); + } + } + } + return packages; + } + + private boolean isSpecific(Class cls) { + return SpecificRecord.class.isAssignableFrom(cls); + } + + @Override + public boolean accept(Class cls) { + return isSpecific(cls) || isReflection(cls); + } + + @Override + public void setSpecificType(Class cls) { + super.setSpecificType(cls); + if (isSpecific(cls)) { + setKind(Kind.SPECIFIC); + setSchema(SpecificData.get().getSchema(cls)); + } else if (isReflection(cls)) { + setKind(Kind.REFLECTION); + setSchema(ReflectData.get().getSchema(cls)); + } else { + throw new IllegalArgumentException("class " + cls.getName() + + " can't infer schema."); + } + } + + @Override + public Class getBaseType() { + // Unlike most of the typed serializations, we don't have a + // single base type and the work has to be done in a special accept method. + return Object.class; + } + + @Override + public String getName() { + return "avro"; + } + + @Override + public Configuration getConf() { + return conf; + } + + @Override + public void setConf(Configuration conf) { + if (conf != this.conf) { + this.conf = conf; + // clear the cache of packages + packages = null; + } + } + + public boolean equals(Object right) { + if (this == right) { + return true; + } else if (right == null || right.getClass() != getClass()) { + return false; + } else { + AvroSerialization rightTyped = (AvroSerialization) right; + return rightTyped.kind == kind && rightTyped.schema.equals(schema); + } + } + + public int hashCode() { + return schema.hashCode() * 5 + kind.hashCode(); + } +} diff --git a/src/java/org/apache/hadoop/io/serializer/package.html b/src/java/org/apache/hadoop/io/serial/lib/avro/package.html similarity index 55% rename from src/java/org/apache/hadoop/io/serializer/package.html rename to src/java/org/apache/hadoop/io/serial/lib/avro/package.html index 58c8a3a5c3bb5..ce565f6206b5f 100644 --- a/src/java/org/apache/hadoop/io/serializer/package.html +++ b/src/java/org/apache/hadoop/io/serial/lib/avro/package.html @@ -20,17 +20,23 @@

    -This package provides a mechanism for using different serialization frameworks -in Hadoop. The property "io.serializations" defines a list of -{@link org.apache.hadoop.io.serializer.Serialization}s that know how to create -{@link org.apache.hadoop.io.serializer.Serializer}s and -{@link org.apache.hadoop.io.serializer.Deserializer}s. +This package provides Avro serialization in Hadoop. This can be used to +serialize/deserialize Avro types in Hadoop.

    -To add a new serialization framework write an implementation of -{@link org.apache.hadoop.io.serializer.Serialization} and add its name to the -"io.serializations" property. +Use {@link org.apache.hadoop.io.serializer.avro.AvroSpecificSerialization} for +serialization of classes generated by Avro's 'specific' compiler. +

    + +

    +Use {@link org.apache.hadoop.io.serializer.avro.AvroReflectSerialization} for +other classes. +{@link org.apache.hadoop.io.serializer.avro.AvroReflectSerialization} work for +any class which is either in the package list configured via +{@link org.apache.hadoop.io.serializer.avro.AvroReflectSerialization#AVRO_REFLECT_PACKAGES} +or implement {@link org.apache.hadoop.io.serializer.avro.AvroReflectSerializable} +interface.

    diff --git a/src/java/org/apache/hadoop/io/serial/lib/protobuf/ProtoBufComparator.java b/src/java/org/apache/hadoop/io/serial/lib/protobuf/ProtoBufComparator.java new file mode 100644 index 0000000000000..363052c9c8b65 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/protobuf/ProtoBufComparator.java @@ -0,0 +1,490 @@ +/** + * 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.io.serial.lib.protobuf; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.hadoop.io.serial.RawComparator; + +import com.google.protobuf.ByteString; +import com.google.protobuf.CodedInputStream; +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.EnumValueDescriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Descriptors.FieldDescriptor.Type; +import com.google.protobuf.Message; + +public class ProtoBufComparator implements RawComparator { + static final int WIRETYPE_VARINT = 0; + static final int WIRETYPE_FIXED64 = 1; + static final int WIRETYPE_LENGTH_DELIMITED = 2; + static final int WIRETYPE_START_GROUP = 3; + static final int WIRETYPE_END_GROUP = 4; + static final int WIRETYPE_FIXED32 = 5; + + static final int TAG_TYPE_BITS = 3; + static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1; + + private final Map> fieldCache = + new HashMap>(); + private final List topFields; + + /** + * Create a comparator that will compare serialized messages of a particular + * class. + * @param cls the specific class to compare + */ + public ProtoBufComparator(Class cls) { + if (!Message.class.isAssignableFrom(cls)) { + throw new IllegalArgumentException("Type " + cls + + "must be a generated protobuf class"); + } + try { + Method getDescriptor = cls.getDeclaredMethod("getDescriptor"); + topFields = addToCache((Descriptor) getDescriptor.invoke(null)); + } catch (Exception e) { + throw new IllegalArgumentException("Can't get descriptors for " + cls, e); + } + } + + /** + * Define a comparator so that we can sort the fields by their field ids. + */ + private static class FieldIdComparator implements Comparator{ + + @Override + public int compare(FieldDescriptor left, FieldDescriptor right) { + int leftId = left.getNumber(); + int rightId = right.getNumber(); + if (leftId == rightId) { + return 0; + } else { + return leftId < rightId ? -1 : 1; + } + } + } + + private static final FieldIdComparator FIELD_COMPARE= new FieldIdComparator(); + + /** + * Add all of the types that are recursively nested under the given one + * to the cache. The fields are sorted by field id. + * @param type the type to add + * @return the list of sorted fields for the given type + */ + private List addToCache(Descriptor type) { + List fields = + new ArrayList(type.getFields()); + Collections.sort(fields, FIELD_COMPARE); + fieldCache.put(type, fields); + for(Descriptor subMessage: type.getNestedTypes()) { + if (!fieldCache.containsKey(subMessage)) { + addToCache(subMessage); + } + } + return fields; + } + + /** + * Compare two serialized protocol buffers using the natural sort order. + * @param b1 the left serialized value + * @param s1 the first byte index in b1 to compare + * @param l1 the number of bytes in b1 to compare + * @param b2 the right serialized value + * @param s2 the first byte index in b2 to compare + * @param l2 the number of bytes in b2 to compare + */ + @Override + public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { + CodedInputStream left = CodedInputStream.newInstance(b1,s1,l1); + CodedInputStream right = CodedInputStream.newInstance(b2, s2, l2); + try { + return compareMessage(left, right, topFields); + } catch (IOException ie) { + throw new IllegalArgumentException("problem running compare", ie); + } + } + + /** + * Advance the stream to the given fieldId or one that is larger. + * @param stream the stream to read + * @param currentTag the last tag that was read from this stream + * @param fieldId the id of the field we are looking for + * @return the last tag that was read or 0 for end of stream + * @throws IOException + */ + private int advanceTo(CodedInputStream stream, + int currentTag, + int fieldId) throws IOException { + int goal = fieldId << TAG_TYPE_BITS; + // if we've already seen the right tag, return it + if (currentTag > goal) { + return currentTag; + } + while (!stream.isAtEnd()) { + currentTag = stream.readTag(); + if (currentTag > goal) { + return currentTag; + } else { + stream.skipField(currentTag); + } + } + return 0; + } + + /** + * Check compatibility between the logical type in the schema and the + * wiretype. Incompatible fields are ignored. + * @param tag the tag (id and wiretype) of the field + * @param type the logical type of the field + * @return true if we should use this field for comparing + */ + private boolean isCompatible(int tag, Type type) { + int wiretype = tag & TAG_TYPE_MASK; + switch (type) { + case BOOL: + case ENUM: + case INT32: + case INT64: + case SINT32: + case SINT64: + case UINT32: + case UINT64: + return wiretype == WIRETYPE_VARINT || + wiretype == WIRETYPE_LENGTH_DELIMITED; + + case BYTES: + case MESSAGE: + case STRING: + return wiretype == WIRETYPE_LENGTH_DELIMITED; + + case FLOAT: + case FIXED32: + case SFIXED32: + return wiretype == WIRETYPE_LENGTH_DELIMITED || + wiretype == WIRETYPE_FIXED32; + + case DOUBLE: + case SFIXED64: + case FIXED64: + return wiretype == WIRETYPE_LENGTH_DELIMITED || + wiretype == WIRETYPE_FIXED64; + + case GROUP: + // don't bother dealing with groups, since they aren't used outside of + // the protobuf mothership. + return false; + + default: + throw new IllegalArgumentException("Unknown field type " + type); + } + } + + /** + * Compare two serialized messages of the same type. + * @param left the left message + * @param right the right message + * @param fields the fields of the message + * @return -1, 0, or 1 if left is less, equal or greater than right + * @throws IOException + */ + private int compareMessage(CodedInputStream left, CodedInputStream right, + List fields + ) throws IOException { + int leftTag = 0; + int rightTag = 0; + for(FieldDescriptor field: fields) { + int fieldId = field.getNumber(); + Type fieldType = field.getType(); + int wireFormat = 0; + leftTag = advanceTo(left, leftTag, fieldId); + rightTag = advanceTo(right, rightTag, fieldId); + boolean leftDefault = (leftTag >>> TAG_TYPE_BITS) != fieldId; + boolean rightDefault = (rightTag >>> TAG_TYPE_BITS) != fieldId; + // if the fieldType and wiretypes aren't compatible, skip field + if (!leftDefault && !isCompatible(leftTag, fieldType)) { + leftDefault = true; + left.skipField(leftTag); + } + if (!rightDefault && !isCompatible(rightTag, fieldType)) { + rightDefault = true; + right.skipField(leftTag); + } + if (!leftDefault) { + wireFormat = leftTag & TAG_TYPE_MASK; + // ensure both sides use the same representation + if (!rightDefault && leftTag != rightTag) { + return leftTag < rightTag ? -1 : 1; + } + } else if (rightDefault) { + continue; + } + int result; + switch (wireFormat) { + case WIRETYPE_LENGTH_DELIMITED: + switch (fieldType) { + case STRING: + String leftStr = + leftDefault ? (String) field.getDefaultValue() : left.readString(); + String rightStr = + rightDefault ? (String) field.getDefaultValue() :right.readString(); + result = leftStr.compareTo(rightStr); + if (result != 0) { + return result; + } + break; + case BYTES: + result = compareBytes(leftDefault ? + (ByteString) field.getDefaultValue() : + left.readBytes(), + rightDefault ? + (ByteString) field.getDefaultValue() : + right.readBytes()); + if (result != 0) { + return result; + } + break; + default: + // handle nested messages and packed fields + if (leftDefault) { + return -1; + } else if (rightDefault) { + return 1; + } + int leftLimit = left.readRawVarint32(); + int rightLimit = right.readRawVarint32(); + int oldLeft = left.pushLimit(leftLimit); + int oldRight = right.pushLimit(rightLimit); + while (left.getBytesUntilLimit() > 0 && + right.getBytesUntilLimit() > 0) { + result = compareField(field, left, right, false, false); + if (result != 0) { + return result; + } + } + if (right.getBytesUntilLimit() > 0) { + return -1; + } else if (left.getBytesUntilLimit() > 0) { + return 1; + } + left.popLimit(oldLeft); + right.popLimit(oldRight); + } + break; + case WIRETYPE_VARINT: + case WIRETYPE_FIXED32: + case WIRETYPE_FIXED64: + result = compareField(field, left, right, leftDefault, rightDefault); + if (result != 0) { + return result; + } + break; + default: + throw new IllegalArgumentException("Unknown field encoding " + + wireFormat); + } + } + return 0; + } + + /** + * Compare a single field inside of a message. This is used for both packed + * and unpacked fields. It assumes the wire type has already been checked. + * @param field the type of the field that we are comparing + * @param left the left value + * @param right the right value + * @param leftDefault use the default value instead of the left value + * @param rightDefault use the default value instead of the right value + * @return -1, 0, 1 depending on whether left is less, equal or greater than + * right + * @throws IOException + */ + private int compareField(FieldDescriptor field, + CodedInputStream left, + CodedInputStream right, + boolean leftDefault, + boolean rightDefault) throws IOException { + switch (field.getType()) { + case BOOL: + boolean leftBool = leftDefault ? + (Boolean) field.getDefaultValue() : left.readBool(); + boolean rightBool = rightDefault ? + (Boolean) field.getDefaultValue() : right.readBool(); + if (leftBool == rightBool) { + return 0; + } else { + return rightBool ? -1 : 1; + } + case DOUBLE: + return + Double.compare(leftDefault ? + (Double) field.getDefaultValue(): left.readDouble(), + rightDefault ? + (Double) field.getDefaultValue() :right.readDouble()); + case ENUM: + return compareInt32(leftDefault ? intDefault(field) : left.readEnum(), + rightDefault ? intDefault(field) : right.readEnum()); + case FIXED32: + return compareUInt32(leftDefault ? intDefault(field) : left.readFixed32(), + rightDefault?intDefault(field):right.readFixed32()); + case FIXED64: + return compareUInt64(leftDefault? longDefault(field) : left.readFixed64(), + rightDefault?longDefault(field):right.readFixed64()); + case FLOAT: + return Float.compare(leftDefault ? + (Float) field.getDefaultValue() : left.readFloat(), + rightDefault ? + (Float) field.getDefaultValue():right.readFloat()); + case INT32: + return compareInt32(leftDefault?intDefault(field):left.readInt32(), + rightDefault?intDefault(field):right.readInt32()); + case INT64: + return compareInt64(leftDefault?longDefault(field):left.readInt64(), + rightDefault?longDefault(field):right.readInt64()); + case MESSAGE: + return compareMessage(left, right, + fieldCache.get(field.getMessageType())); + case SFIXED32: + return compareInt32(leftDefault ?intDefault(field):left.readSFixed32(), + rightDefault ?intDefault(field):right.readSFixed32()); + case SFIXED64: + return compareInt64(leftDefault ? longDefault(field) :left.readSFixed64(), + rightDefault?longDefault(field):right.readSFixed64()); + case SINT32: + return compareInt32(leftDefault?intDefault(field):left.readSInt32(), + rightDefault?intDefault(field):right.readSInt32()); + case SINT64: + return compareInt64(leftDefault ? longDefault(field) : left.readSInt64(), + rightDefault?longDefault(field):right.readSInt64()); + case UINT32: + return compareUInt32(leftDefault ? intDefault(field) :left.readUInt32(), + rightDefault ? intDefault(field):right.readUInt32()); + case UINT64: + return compareUInt64(leftDefault ? longDefault(field) :left.readUInt64(), + rightDefault?longDefault(field) :right.readUInt64()); + default: + throw new IllegalArgumentException("unknown field type " + field); + } + } + + /** + * Compare 32 bit signed integers. + * @param left + * @param right + * @return -1, 0 ,1 if left is less, equal, or greater to right + */ + private static int compareInt32(int left, int right) { + if (left == right) { + return 0; + } else { + return left < right ? -1 : 1; + } + } + + /** + * Compare 64 bit signed integers. + * @param left + * @param right + * @return -1, 0 ,1 if left is less, equal, or greater to right + */ + private static int compareInt64(long left, long right) { + if (left == right) { + return 0; + } else { + return left < right ? -1 : 1; + } + } + + /** + * Compare 32 bit logically unsigned integers. + * @param left + * @param right + * @return -1, 0 ,1 if left is less, equal, or greater to right + */ + private static int compareUInt32(int left, int right) { + if (left == right) { + return 0; + } else { + return left + Integer.MIN_VALUE < right + Integer.MIN_VALUE ? -1 : 1; + } + } + + /** + * Compare two byte strings using memcmp semantics + * @param left + * @param right + * @return -1, 0, 1 if left is less, equal, or greater than right + */ + private static int compareBytes(ByteString left, ByteString right) { + int size = Math.min(left.size(), right.size()); + for(int i = 0; i < size; ++i) { + int leftByte = left.byteAt(i) & 0xff; + int rightByte = right.byteAt(i) & 0xff; + if (leftByte != rightByte) { + return leftByte < rightByte ? -1 : 1; + } + } + if (left.size() != right.size()) { + return left.size() < right.size() ? -1 : 1; + } + return 0; + } + + /** + * Compare 32 bit logically unsigned integers. + * @param left + * @param right + * @return -1, 0 ,1 if left is less, equal, or greater to right + */ + private static int compareUInt64(long left, long right) { + if (left == right) { + return 0; + } else { + return left + Long.MIN_VALUE < right + Long.MIN_VALUE ? -1 : 1; + } + } + + /** + * Get the integer default, including dereferencing enum values. + * @param field the field + * @return the integer default value + */ + private static int intDefault(FieldDescriptor field) { + if (field.getType() == Type.ENUM) { + return ((EnumValueDescriptor) field.getDefaultValue()).getNumber(); + } else { + return (Integer) field.getDefaultValue(); + } + } + + /** + * Get the long default value for the given field. + * @param field the field + * @return the default value + */ + private static long longDefault(FieldDescriptor field) { + return (Long) field.getDefaultValue(); + } +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/protobuf/ProtoBufSerialization.java b/src/java/org/apache/hadoop/io/serial/lib/protobuf/ProtoBufSerialization.java new file mode 100644 index 0000000000000..b87c83dbd2407 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/protobuf/ProtoBufSerialization.java @@ -0,0 +1,114 @@ +/** + * 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.io.serial.lib.protobuf; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import com.google.protobuf.Message; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.serial.TypedSerialization; + +/** + * A binding for Protocol Buffer serialization. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public class ProtoBufSerialization extends TypedSerialization{ + private Method builderFactory; + + public ProtoBufSerialization() {} + public ProtoBufSerialization(Class cls) { + super(cls); + setBuilderFactory(cls); + } + + @Override + public ProtoBufSerialization clone() { + ProtoBufSerialization result = (ProtoBufSerialization) super.clone(); + result.builderFactory = builderFactory; + return result; + } + + @Override + public Class getBaseType() { + return Message.class; + } + + private void setBuilderFactory(Class cls) { + if (cls == null) { + builderFactory = null; + } else { + try { + builderFactory = cls.getDeclaredMethod("parseFrom", + InputStream.class); + } catch (NoSuchMethodException nsme) { + throw new IllegalArgumentException("Can't find parseFrom in " + + cls.getName()); + } + } + } + + @Override + public void setSpecificType(Class cls) { + super.setSpecificType(cls); + setBuilderFactory(cls); + } + + @Override + public Message deserialize(InputStream stream, Message reusableObject, + Configuration conf) throws IOException { + try { + return (Message) builderFactory.invoke(null, stream); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException("can't access parseFrom " + + " on " + getSpecificType().getName()); + } catch (InvocationTargetException e) { + throw new IllegalArgumentException("can't invoke parseFrom " + + " on " + getSpecificType().getName()); + } + } + + @Override + public RawComparator getRawComparator() { + return new ProtoBufComparator(getSpecificType()); + } + + @Override + public void serialize(OutputStream stream, + Message object) throws IOException { + if (specificType != object.getClass()) { + throw new IOException("Type mismatch in serialization: expected " + + specificType + "; received " + object.getClass()); + } + object.writeTo(stream); + } + + @Override + public String getName() { + return "protobuf"; + } +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/thrift/StreamTransport.java b/src/java/org/apache/hadoop/io/serial/lib/thrift/StreamTransport.java new file mode 100644 index 0000000000000..03310f1ee6f3d --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/thrift/StreamTransport.java @@ -0,0 +1,88 @@ +/** + * 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.io.serial.lib.thrift; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.thrift.transport.TTransport; +import org.apache.thrift.transport.TTransportException; + +/** + * Define a Thrift transport that we can dynamically change the input and + * output stream. Otherwise, we need to recreate the encoder and decoder + * for each object. + */ +class StreamTransport extends TTransport { + private InputStream in = null; + private OutputStream out = null; + + void open(InputStream in) { + if (this.in != null || this.out != null) { + throw new IllegalStateException("opening an open transport"); + } + this.in = in; + } + + void open(OutputStream out) { + if (this.in != null || this.out != null) { + throw new IllegalStateException("opening an open transport"); + } + this.out = out; + } + + @Override + public void close() { + if (in != null) { + in = null; + } else if (out != null) { + out = null; + } + } + + @Override + public boolean isOpen() { + return in != null || out != null; + } + + @Override + public void open() { + // NOTHING + } + + @Override + public int read(byte[] buf, int off, int len) throws TTransportException { + try { + return in.read(buf, off, len); + } catch (IOException ie) { + throw new TTransportException("problem reading stream", ie); + } + } + + @Override + public void write(byte[] buf, int off, int len) throws TTransportException { + try { + out.write(buf, off, len); + } catch (IOException ie) { + throw new TTransportException("problem writing stream", ie); + } + } + +} diff --git a/src/java/org/apache/hadoop/io/serial/lib/thrift/ThriftSerialization.java b/src/java/org/apache/hadoop/io/serial/lib/thrift/ThriftSerialization.java new file mode 100644 index 0000000000000..9d3bbffb5da80 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/lib/thrift/ThriftSerialization.java @@ -0,0 +1,110 @@ +/** + * 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.io.serial.lib.thrift; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.serial.TypedSerialization; +import org.apache.hadoop.io.serial.lib.DeserializationRawComparator; +import org.apache.hadoop.util.ReflectionUtils; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TCompactProtocol; +import org.apache.thrift.protocol.TProtocol; + +/** + * Serialize using the compact Thrift representation. + */ +@SuppressWarnings("unchecked") +@InterfaceAudience.Public +@InterfaceStability.Stable +public class ThriftSerialization extends TypedSerialization { + private final TProtocol protocol; + private final StreamTransport transport; + + public ThriftSerialization() { + transport = new StreamTransport(); + protocol = new TCompactProtocol(transport); + } + + public ThriftSerialization(Class cls) { + this(); + setSpecificType(cls); + } + + @Override + public Class getBaseType() { + return TBase.class; + } + + @Override + public TBase deserialize(InputStream stream, TBase reusableObject, + Configuration conf) throws IOException { + transport.open(stream); + TBase result = reusableObject; + if (result == null) { + result = ReflectionUtils.newInstance(getSpecificType(), conf); + } else { + if (specificType != result.getClass()) { + throw new IOException("Type mismatch in deserialization: expected " + + specificType + "; received " + result.getClass()); + } + } + try { + result.read(protocol); + transport.close(); + } catch (TException te) { + transport.close(); + throw new IOException("problem reading thrift object", te); + } + return result; + } + + @Override + public RawComparator getRawComparator() { + return new DeserializationRawComparator(this, null); + } + + @Override + public void serialize(OutputStream stream, TBase object) throws IOException { + if (specificType != object.getClass()) { + throw new IOException("Type mismatch in serialization: expected " + + specificType + "; received " + object.getClass()); + } + + transport.open(stream); + try { + object.write(protocol); + transport.close(); + } catch (TException te) { + transport.close(); + throw new IOException("problem writing thrift object", te); + } + } + + @Override + public String getName() { + return "thrift"; + } +} diff --git a/src/java/org/apache/hadoop/io/serial/package-info.java b/src/java/org/apache/hadoop/io/serial/package-info.java new file mode 100644 index 0000000000000..2da74a87bd33d --- /dev/null +++ b/src/java/org/apache/hadoop/io/serial/package-info.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +/** + * This package provides a generic interface to multiple serialization + * frameworks. The propoeraty "hadoop.serializations" defines a list of + * {@link org.apache.hadoop.io.serial.Serialization} objects. Each + * serialization has a name and associated metadata, which is interpreted by + * that serialization. + *

    + * The system is pluggable, but the currently supported frameworks are: + *

      + *
    • Writable - the traditional Hadoop serialization + *
    • Protocol Buffers + *
    • Thrift + *
    • Avro + *
    • Java serialization - not recommended for real work loads + *
    + * + * The {@link org.apache.hadoop.io.serial.SerializationFactory} provides + * accessors for finding Serializations either by name or by type. + * Serializations associated with a set of types extend + * {@link org.apache.hadoop.io.serial.TypedSerialization} and can determine + * whether they can accept a given type. They are the default serialization + * for the types they accept. + *

    + * + * To add a new serialization framework write an implementation of + * Serialization and add its name to the "hadoop.serializations" property. + * + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +package org.apache.hadoop.io.serial; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; diff --git a/src/java/org/apache/hadoop/io/serializer/Deserializer.java b/src/java/org/apache/hadoop/io/serializer/Deserializer.java index 3b727d906b6f0..b8da1f83c66fe 100644 --- a/src/java/org/apache/hadoop/io/serializer/Deserializer.java +++ b/src/java/org/apache/hadoop/io/serializer/Deserializer.java @@ -36,9 +36,12 @@ * {@link #deserialize(Object)}. *

    * @param + * @deprecated Use {@link org.apache.hadoop.io.serial.Serialization} + * instead. */ @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"}) @InterfaceStability.Evolving +@Deprecated public interface Deserializer { /** *

    Prepare the deserializer for reading.

    diff --git a/src/java/org/apache/hadoop/io/serializer/DeserializerComparator.java b/src/java/org/apache/hadoop/io/serializer/DeserializerComparator.java index 7e74cb773224c..7a20016d166ce 100644 --- a/src/java/org/apache/hadoop/io/serializer/DeserializerComparator.java +++ b/src/java/org/apache/hadoop/io/serializer/DeserializerComparator.java @@ -38,9 +38,13 @@ * on byte representations. *

    * @param + * @deprecated Use + * {@link org.apache.hadoop.io.serial.lib.DeserializationRawComparator} + * instead. */ @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"}) @InterfaceStability.Evolving +@Deprecated public abstract class DeserializerComparator implements RawComparator { private InputBuffer buffer = new InputBuffer(); diff --git a/src/java/org/apache/hadoop/io/serializer/JavaSerialization.java b/src/java/org/apache/hadoop/io/serializer/JavaSerialization.java index 61d6f171c9c41..ec12ecd72af2d 100644 --- a/src/java/org/apache/hadoop/io/serializer/JavaSerialization.java +++ b/src/java/org/apache/hadoop/io/serializer/JavaSerialization.java @@ -24,20 +24,21 @@ import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.Serializable; -import java.util.Map; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; -import org.apache.hadoop.io.RawComparator; /** *

    * An experimental {@link Serialization} for Java {@link Serializable} classes. *

    * @see JavaSerializationComparator + * @deprecated Use {@link org.apache.hadoop.io.serial.lib.JavaSerialization} + * instead. */ @InterfaceAudience.Public @InterfaceStability.Unstable +@Deprecated public class JavaSerialization implements Serialization { static class JavaSerializationDeserializer diff --git a/src/java/org/apache/hadoop/io/serializer/JavaSerializationComparator.java b/src/java/org/apache/hadoop/io/serializer/JavaSerializationComparator.java index 12927bea14da5..92650f9454145 100644 --- a/src/java/org/apache/hadoop/io/serializer/JavaSerializationComparator.java +++ b/src/java/org/apache/hadoop/io/serializer/JavaSerializationComparator.java @@ -33,9 +33,13 @@ *

    * @param * @see JavaSerialization + * @deprecated Use + * {@link org.apache.hadoop.io.serial.lib.DeserializationRawComparator} + * instead. */ @InterfaceAudience.Public @InterfaceStability.Unstable +@Deprecated public class JavaSerializationComparator> extends DeserializerComparator { diff --git a/src/java/org/apache/hadoop/io/serializer/Serialization.java b/src/java/org/apache/hadoop/io/serializer/Serialization.java index 6f2097f7bf9da..3671e8de44ad4 100644 --- a/src/java/org/apache/hadoop/io/serializer/Serialization.java +++ b/src/java/org/apache/hadoop/io/serializer/Serialization.java @@ -26,9 +26,13 @@ * Encapsulates a {@link Serializer}/{@link Deserializer} pair. *

    * @param + * @deprecated Use + * {@link org.apache.hadoop.io.serial.Serialization} + * instead. */ @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"}) @InterfaceStability.Evolving +@Deprecated public interface Serialization { /** diff --git a/src/java/org/apache/hadoop/io/serializer/SerializationFactory.java b/src/java/org/apache/hadoop/io/serializer/SerializationFactory.java index dee314aea4341..9e99367f5c7e0 100644 --- a/src/java/org/apache/hadoop/io/serializer/SerializationFactory.java +++ b/src/java/org/apache/hadoop/io/serializer/SerializationFactory.java @@ -36,9 +36,13 @@ *

    * A factory for {@link Serialization}s. *

    + * @deprecated Use + * {@link org.apache.hadoop.io.serial.SerializationFactory} + * instead. */ @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"}) @InterfaceStability.Evolving +@Deprecated public class SerializationFactory extends Configured { private static final Log LOG = diff --git a/src/java/org/apache/hadoop/io/serializer/Serializer.java b/src/java/org/apache/hadoop/io/serializer/Serializer.java index 63d3738de88b7..66ae7883ccd81 100644 --- a/src/java/org/apache/hadoop/io/serializer/Serializer.java +++ b/src/java/org/apache/hadoop/io/serializer/Serializer.java @@ -36,9 +36,13 @@ * {@link #serialize(Object)}. *

    * @param + * @deprecated Use + * {@link org.apache.hadoop.io.serial.Serialization} + * instead. */ @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"}) @InterfaceStability.Evolving +@Deprecated public interface Serializer { /** *

    Prepare the serializer for writing.

    diff --git a/src/java/org/apache/hadoop/io/serializer/WritableSerialization.java b/src/java/org/apache/hadoop/io/serializer/WritableSerialization.java index 8511d25bcde65..30e773c0e7729 100644 --- a/src/java/org/apache/hadoop/io/serializer/WritableSerialization.java +++ b/src/java/org/apache/hadoop/io/serializer/WritableSerialization.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.Map; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; @@ -36,9 +35,13 @@ * A {@link Serialization} for {@link Writable}s that delegates to * {@link Writable#write(java.io.DataOutput)} and * {@link Writable#readFields(java.io.DataInput)}. + * @deprecated Use + * {@link org.apache.hadoop.io.serial.lib.WritableSerialization} + * instead. */ @InterfaceAudience.Public @InterfaceStability.Evolving +@Deprecated public class WritableSerialization extends Configured implements Serialization { static class WritableDeserializer extends Configured diff --git a/src/java/org/apache/hadoop/io/serializer/avro/AvroReflectSerializable.java b/src/java/org/apache/hadoop/io/serializer/avro/AvroReflectSerializable.java index 4a748223e5fc5..49fdf6e2810a9 100644 --- a/src/java/org/apache/hadoop/io/serializer/avro/AvroReflectSerializable.java +++ b/src/java/org/apache/hadoop/io/serializer/avro/AvroReflectSerializable.java @@ -25,9 +25,13 @@ * Tag interface for Avro 'reflect' serializable classes. Classes implementing * this interface can be serialized/deserialized using * {@link AvroReflectSerialization}. + * @deprecated Use {@link org.apache.hadoop.io.serial.lib.avro.AvroReflectSerializable} + * instead. */ @InterfaceAudience.Public @InterfaceStability.Evolving -public interface AvroReflectSerializable { +@Deprecated +public interface AvroReflectSerializable + extends org.apache.hadoop.io.serial.lib.avro.AvroReflectSerializable { } diff --git a/src/java/org/apache/hadoop/io/serializer/avro/AvroReflectSerialization.java b/src/java/org/apache/hadoop/io/serializer/avro/AvroReflectSerialization.java index 5636b597e33a4..2c24144e203d7 100644 --- a/src/java/org/apache/hadoop/io/serializer/avro/AvroReflectSerialization.java +++ b/src/java/org/apache/hadoop/io/serializer/avro/AvroReflectSerialization.java @@ -35,11 +35,13 @@ * serialization, it must either be in the package list configured via * avro.reflect.pkgs or implement * {@link AvroReflectSerializable} interface. - * + * @deprecated Use {@link org.apache.hadoop.io.serial.lib.avro.AvroSerialization} + * instead. */ @SuppressWarnings("unchecked") @InterfaceAudience.Public @InterfaceStability.Evolving +@Deprecated public class AvroReflectSerialization extends AvroSerialization{ /** diff --git a/src/java/org/apache/hadoop/io/serializer/avro/AvroSerialization.java b/src/java/org/apache/hadoop/io/serializer/avro/AvroSerialization.java index 27bb255696db6..402a0ad64542e 100644 --- a/src/java/org/apache/hadoop/io/serializer/avro/AvroSerialization.java +++ b/src/java/org/apache/hadoop/io/serializer/avro/AvroSerialization.java @@ -37,9 +37,12 @@ /** * Base class for providing serialization to Avro types. + * @deprecated Use {@link org.apache.hadoop.io.serial.lib.avro.AvroSerialization} + * instead. */ @InterfaceAudience.Public @InterfaceStability.Evolving +@Deprecated public abstract class AvroSerialization extends Configured implements Serialization{ diff --git a/src/java/org/apache/hadoop/io/serializer/avro/AvroSpecificSerialization.java b/src/java/org/apache/hadoop/io/serializer/avro/AvroSpecificSerialization.java index e49d7a09dd53a..4ce8c72fe09c9 100644 --- a/src/java/org/apache/hadoop/io/serializer/avro/AvroSpecificSerialization.java +++ b/src/java/org/apache/hadoop/io/serializer/avro/AvroSpecificSerialization.java @@ -30,10 +30,13 @@ /** * Serialization for Avro Specific classes. This serialization is to be used * for classes generated by Avro's 'specific' compiler. + * @deprecated Use {@link org.apache.hadoop.io.serial.lib.avro.AvroSerialization} + * instead. */ @SuppressWarnings("unchecked") @InterfaceAudience.Public @InterfaceStability.Evolving +@Deprecated public class AvroSpecificSerialization extends AvroSerialization{ diff --git a/src/java/org/apache/hadoop/io/serializer/package-info.java b/src/java/org/apache/hadoop/io/serializer/package-info.java new file mode 100644 index 0000000000000..b7214457a0f54 --- /dev/null +++ b/src/java/org/apache/hadoop/io/serializer/package-info.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/** + * This deprecated package provides a mechanism for using different + * serialization frameworks in Hadoop. The property "io.serializations" + * defines a list of + * {@link org.apache.hadoop.io.serializer.Serialization}s that know how to + * create {@link org.apache.hadoop.io.serializer.Serializer}s and + * {@link org.apache.hadoop.io.serializer.Deserializer}s. + *

    + * + * To add a new serialization framework write an implementation of + * {@link org.apache.hadoop.io.serializer.Serialization} and add its name to + * the "io.serializations" property. + *

    + * + * This package has been replaced by the {@link org.apache.hadoop.io.serial} + * package. + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +@Deprecated +package org.apache.hadoop.io.serializer; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; diff --git a/src/java/org/apache/hadoop/security/SaslRpcServer.java b/src/java/org/apache/hadoop/security/SaslRpcServer.java index cc594b8d0e923..77a328e40f18b 100644 --- a/src/java/org/apache/hadoop/security/SaslRpcServer.java +++ b/src/java/org/apache/hadoop/security/SaslRpcServer.java @@ -239,7 +239,7 @@ public void handle(Callback[] callbacks) throws InvalidToken, if (ac.isAuthorized()) { if (LOG.isDebugEnabled()) { String username = getIdentifier(authzid, secretManager).getUser() - .getUserName().toString(); + .getUserName(); LOG.debug("SASL server DIGEST-MD5 callback: setting " + "canonicalized client ID: " + username); } diff --git a/src/java/org/apache/hadoop/util/Options.java b/src/java/org/apache/hadoop/util/Options.java index 23169e3af3533..88709561713e0 100644 --- a/src/java/org/apache/hadoop/util/Options.java +++ b/src/java/org/apache/hadoop/util/Options.java @@ -22,6 +22,8 @@ import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.serial.RawComparator; +import org.apache.hadoop.io.serial.Serialization; /** * This class allows generic access to variable length type-safe parameter @@ -79,6 +81,16 @@ public long getValue() { } } + public static abstract class SerializationOption { + private final Serialization value; + protected SerializationOption(Serialization value) { + this.value = value; + } + public Serialization getValue() { + return value; + } + } + public static abstract class PathOption { private final Path value; protected PathOption(Path value) { @@ -119,6 +131,16 @@ public Progressable getValue() { } } + public static abstract class ComparatorOption { + private final RawComparator value; + protected ComparatorOption(RawComparator value) { + this.value = value; + } + public RawComparator getValue() { + return value; + } + } + /** * Find the first option of the required class. * @param the static class to find @@ -129,8 +151,7 @@ public Progressable getValue() { * @throws IOException */ @SuppressWarnings("unchecked") - public static T getOption(Class cls, base [] opts - ) throws IOException { + public static T getOption(Class cls, base [] opts) { for(base o: opts) { if (o.getClass() == cls) { return (T) o; diff --git a/src/java/org/apache/hadoop/util/ReflectionUtils.java b/src/java/org/apache/hadoop/util/ReflectionUtils.java index 0387c7e8b8e0a..f9dac1fdd3ffb 100644 --- a/src/java/org/apache/hadoop/util/ReflectionUtils.java +++ b/src/java/org/apache/hadoop/util/ReflectionUtils.java @@ -37,9 +37,9 @@ import org.apache.hadoop.io.DataInputBuffer; import org.apache.hadoop.io.DataOutputBuffer; import org.apache.hadoop.io.Writable; -import org.apache.hadoop.io.serializer.Deserializer; -import org.apache.hadoop.io.serializer.SerializationFactory; -import org.apache.hadoop.io.serializer.Serializer; +import org.apache.hadoop.io.serial.SerializationFactory; +import org.apache.hadoop.io.serial.Serialization; +import org.apache.hadoop.io.serial.lib.WritableSerialization; /** * General reflection utils @@ -49,7 +49,6 @@ public class ReflectionUtils { private static final Class[] EMPTY_ARRAY = new Class[]{}; - volatile private static SerializationFactory serialFactory = null; /** * Cache of constructors for each class. Pins the classes so they @@ -257,43 +256,59 @@ protected synchronized CopyInCopyOutBuffer initialValue() { } }; - private static SerializationFactory getFactory(Configuration conf) { - if (serialFactory == null) { - serialFactory = new SerializationFactory(conf); - } - return serialFactory; - } - /** - * Make a copy of the writable object using serialization to a buffer + * Make a copy of the object using serialization to a buffer * @param dst the object to copy from * @param src the object to copy into, which is destroyed * @throws IOException */ @SuppressWarnings("unchecked") public static T copy(Configuration conf, - T src, T dst) throws IOException { + T src, T dst) throws IOException { + SerializationFactory factory = SerializationFactory.getInstance(conf); + Class cls = (Class) src.getClass(); + Serialization serializer = + (Serialization) factory.getSerializationByType(cls); + return copy(conf, src, dst, serializer); + } + + /** + * Make a copy of the object with the given serialization. + * @param the type to copy + * @param conf the configuration to initialize the new object with + * @param src the object to copy + * @param dst the object to copy into, which can be null + * @param serial the serialization to use + * @return the new object that was copied into + * @throws IOException + */ + @SuppressWarnings("unchecked") + public static T copy(Configuration conf, T src, T dst, + Serialization serial) throws IOException { CopyInCopyOutBuffer buffer = cloneBuffers.get(); buffer.outBuffer.reset(); - SerializationFactory factory = getFactory(conf); + SerializationFactory factory = SerializationFactory.getInstance(conf); Class cls = (Class) src.getClass(); - Serializer serializer = factory.getSerializer(cls); - serializer.open(buffer.outBuffer); - serializer.serialize(src); + Serialization serializer = + (Serialization) factory.getSerializationByType(cls); + serializer.serialize(buffer.outBuffer, src); buffer.moveData(); - Deserializer deserializer = factory.getDeserializer(cls); - deserializer.open(buffer.inBuffer); - dst = deserializer.deserialize(dst); - return dst; + return serializer.deserialize(buffer.inBuffer, dst, conf); } + private static Configuration defaultConfiguration = null; + private static synchronized Configuration getDefaultConfiguration() { + if (defaultConfiguration == null) { + defaultConfiguration = new Configuration(); + } + return defaultConfiguration; + } + @Deprecated public static void cloneWritableInto(Writable dst, Writable src) throws IOException { - CopyInCopyOutBuffer buffer = cloneBuffers.get(); - buffer.outBuffer.reset(); - src.write(buffer.outBuffer); - buffer.moveData(); - dst.readFields(buffer.inBuffer); + WritableSerialization serial = new WritableSerialization(); + serial.setSpecificType(src.getClass()); + copy(getDefaultConfiguration(), src, dst, serial); } } diff --git a/src/native/Makefile.am b/src/native/Makefile.am index c731a6d4e4d69..b99e24a67b9c0 100644 --- a/src/native/Makefile.am +++ b/src/native/Makefile.am @@ -33,7 +33,8 @@ export PLATFORM = $(shell echo $$OS_NAME | tr [A-Z] [a-z]) AM_CPPFLAGS = @JNI_CPPFLAGS@ -I$(HADOOP_NATIVE_SRCDIR)/src \ -Isrc/org/apache/hadoop/io/compress/zlib \ - -Isrc/org/apache/hadoop/security + -Isrc/org/apache/hadoop/security \ + -Isrc/org/apache/hadoop/io/nativeio/ AM_LDFLAGS = @JNI_LDFLAGS@ -m$(JVM_DATA_MODEL) AM_CFLAGS = -g -Wall -fPIC -O2 -m$(JVM_DATA_MODEL) @@ -41,8 +42,12 @@ lib_LTLIBRARIES = libhadoop.la libhadoop_la_SOURCES = src/org/apache/hadoop/io/compress/zlib/ZlibCompressor.c \ src/org/apache/hadoop/io/compress/zlib/ZlibDecompressor.c \ src/org/apache/hadoop/security/getGroup.c \ - src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c -libhadoop_la_LDFLAGS = -version-info 1:0:0 + src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c \ + src/org/apache/hadoop/io/nativeio/file_descriptor.c \ + src/org/apache/hadoop/io/nativeio/errno_enum.c \ + src/org/apache/hadoop/io/nativeio/NativeIO.c + +libhadoop_la_LDFLAGS = -version-info 1:0:0 $(AM_LDFLAGS) libhadoop_la_LIBADD = -ldl -ljvm # diff --git a/src/native/Makefile.in b/src/native/Makefile.in index d71b8745a1042..554fcb8c567ea 100644 --- a/src/native/Makefile.in +++ b/src/native/Makefile.in @@ -93,7 +93,8 @@ libLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(lib_LTLIBRARIES) libhadoop_la_DEPENDENCIES = am_libhadoop_la_OBJECTS = ZlibCompressor.lo ZlibDecompressor.lo \ - getGroup.lo JniBasedUnixGroupsMapping.lo + getGroup.lo JniBasedUnixGroupsMapping.lo file_descriptor.lo \ + errno_enum.lo NativeIO.lo libhadoop_la_OBJECTS = $(am_libhadoop_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I. depcomp = $(SHELL) $(top_srcdir)/config/depcomp @@ -222,7 +223,8 @@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ AM_CPPFLAGS = @JNI_CPPFLAGS@ -I$(HADOOP_NATIVE_SRCDIR)/src \ -Isrc/org/apache/hadoop/io/compress/zlib \ - -Isrc/org/apache/hadoop/security + -Isrc/org/apache/hadoop/security \ + -Isrc/org/apache/hadoop/io/nativeio/ AM_LDFLAGS = @JNI_LDFLAGS@ -m$(JVM_DATA_MODEL) AM_CFLAGS = -g -Wall -fPIC -O2 -m$(JVM_DATA_MODEL) @@ -230,9 +232,12 @@ lib_LTLIBRARIES = libhadoop.la libhadoop_la_SOURCES = src/org/apache/hadoop/io/compress/zlib/ZlibCompressor.c \ src/org/apache/hadoop/io/compress/zlib/ZlibDecompressor.c \ src/org/apache/hadoop/security/getGroup.c \ - src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c + src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c \ + src/org/apache/hadoop/io/nativeio/file_descriptor.c \ + src/org/apache/hadoop/io/nativeio/errno_enum.c \ + src/org/apache/hadoop/io/nativeio/NativeIO.c -libhadoop_la_LDFLAGS = -version-info 1:0:0 +libhadoop_la_LDFLAGS = -version-info 1:0:0 $(AM_LDFLAGS) libhadoop_la_LIBADD = -ldl -ljvm all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am @@ -326,8 +331,11 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JniBasedUnixGroupsMapping.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NativeIO.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ZlibCompressor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ZlibDecompressor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errno_enum.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_descriptor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getGroup.Plo@am__quote@ .c.o: @@ -379,6 +387,27 @@ JniBasedUnixGroupsMapping.lo: src/org/apache/hadoop/security/JniBasedUnixGroupsM @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o JniBasedUnixGroupsMapping.lo `test -f 'src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c' || echo '$(srcdir)/'`src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c +file_descriptor.lo: src/org/apache/hadoop/io/nativeio/file_descriptor.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT file_descriptor.lo -MD -MP -MF "$(DEPDIR)/file_descriptor.Tpo" -c -o file_descriptor.lo `test -f 'src/org/apache/hadoop/io/nativeio/file_descriptor.c' || echo '$(srcdir)/'`src/org/apache/hadoop/io/nativeio/file_descriptor.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/file_descriptor.Tpo" "$(DEPDIR)/file_descriptor.Plo"; else rm -f "$(DEPDIR)/file_descriptor.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/org/apache/hadoop/io/nativeio/file_descriptor.c' object='file_descriptor.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o file_descriptor.lo `test -f 'src/org/apache/hadoop/io/nativeio/file_descriptor.c' || echo '$(srcdir)/'`src/org/apache/hadoop/io/nativeio/file_descriptor.c + +errno_enum.lo: src/org/apache/hadoop/io/nativeio/errno_enum.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT errno_enum.lo -MD -MP -MF "$(DEPDIR)/errno_enum.Tpo" -c -o errno_enum.lo `test -f 'src/org/apache/hadoop/io/nativeio/errno_enum.c' || echo '$(srcdir)/'`src/org/apache/hadoop/io/nativeio/errno_enum.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/errno_enum.Tpo" "$(DEPDIR)/errno_enum.Plo"; else rm -f "$(DEPDIR)/errno_enum.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/org/apache/hadoop/io/nativeio/errno_enum.c' object='errno_enum.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o errno_enum.lo `test -f 'src/org/apache/hadoop/io/nativeio/errno_enum.c' || echo '$(srcdir)/'`src/org/apache/hadoop/io/nativeio/errno_enum.c + +NativeIO.lo: src/org/apache/hadoop/io/nativeio/NativeIO.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NativeIO.lo -MD -MP -MF "$(DEPDIR)/NativeIO.Tpo" -c -o NativeIO.lo `test -f 'src/org/apache/hadoop/io/nativeio/NativeIO.c' || echo '$(srcdir)/'`src/org/apache/hadoop/io/nativeio/NativeIO.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/NativeIO.Tpo" "$(DEPDIR)/NativeIO.Plo"; else rm -f "$(DEPDIR)/NativeIO.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/org/apache/hadoop/io/nativeio/NativeIO.c' object='NativeIO.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NativeIO.lo `test -f 'src/org/apache/hadoop/io/nativeio/NativeIO.c' || echo '$(srcdir)/'`src/org/apache/hadoop/io/nativeio/NativeIO.c + mostlyclean-libtool: -rm -f *.lo diff --git a/src/native/config.h.in b/src/native/config.h.in index 0fd92160bf8da..26f8b0fcfb243 100644 --- a/src/native/config.h.in +++ b/src/native/config.h.in @@ -3,6 +3,10 @@ /* The 'actual' dynamic-library for '-lz' */ #undef HADOOP_ZLIB_LIBRARY +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you + don't. */ +#undef HAVE_DECL_STRERROR_R + /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H @@ -39,6 +43,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H +/* Define to 1 if you have the `strerror_r' function. */ +#undef HAVE_STRERROR_R + /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H @@ -81,8 +88,17 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS +/* Define to 1 if strerror_r returns char *. */ +#undef STRERROR_R_CHAR_P + /* Version number of package */ #undef VERSION +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + /* Define to empty if `const' does not conform to ANSI C. */ #undef const diff --git a/src/native/configure b/src/native/configure index 96bedbb04ebb2..c84776150dd13 100755 --- a/src/native/configure +++ b/src/native/configure @@ -464,7 +464,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os SED EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL JNI_LDFLAGS JNI_CPPFLAGS LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os SED EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL JNI_LDFLAGS JNI_CPPFLAGS LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -1024,6 +1024,7 @@ if test -n "$ac_init_help"; then Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-largefile omit support for large files --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --enable-shared[=PKGS] @@ -1523,6 +1524,1301 @@ ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. ac_config_headers="$ac_config_headers config.h" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Check whether --enable-largefile or --disable-largefile was given. +if test "${enable_largefile+set}" = set; then + enableval="$enable_largefile" + +fi; +if test "$enable_largefile" != no; then + + echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5 +echo $ECHO_N "checking for special C compiler options needed for large files... $ECHO_C" >&6 +if test "${ac_cv_sys_largefile_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext + CC="$CC -n32" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sys_largefile_CC=' -n32'; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5 +echo "${ECHO_T}$ac_cv_sys_largefile_CC" >&6 + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +echo $ECHO_N "checking for _FILE_OFFSET_BITS value needed for large files... $ECHO_C" >&6 +if test "${ac_cv_sys_file_offset_bits+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + while :; do + ac_cv_sys_file_offset_bits=no + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sys_file_offset_bits=64; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + break +done +fi +echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5 +echo "${ECHO_T}$ac_cv_sys_file_offset_bits" >&6 +if test "$ac_cv_sys_file_offset_bits" != no; then + +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF + +fi +rm -f conftest* + echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5 +echo $ECHO_N "checking for _LARGE_FILES value needed for large files... $ECHO_C" >&6 +if test "${ac_cv_sys_large_files+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + while :; do + ac_cv_sys_large_files=no + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sys_large_files=1; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + break +done +fi +echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5 +echo "${ECHO_T}$ac_cv_sys_large_files" >&6 +if test "$ac_cv_sys_large_files" != no; then + +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF + +fi +rm -f conftest* +fi + am__api_version="1.9" # Find a good install program. We prefer a C program (faster), @@ -1786,6 +3082,71 @@ else fi rmdir .tst 2>/dev/null +DEPDIR="${am__leading_dot}deps" + + ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + # test to see if srcdir already configured if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then @@ -1916,23 +3277,132 @@ else echo "${ECHO_T}no" >&6 fi - STRIP=$ac_ct_STRIP + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir else - STRIP="$ac_cv_prog_STRIP" + am_cv_CC_dependencies_compiler_type=none fi fi -INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" - -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. -# Always define AMTAR for backward compatibility. - -AMTAR=${AMTAR-"${am_missing_run}tar"} +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type -am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi @@ -2255,225 +3725,24 @@ See \`config.log' for more details." >&2;} # Provide some information about the compiler. echo "$as_me:$LINENO:" \ - "checking for C compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 - (eval $ac_compiler --version &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 - (eval $ac_compiler -v &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 - (eval $ac_compiler -V &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 -echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 -ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` -if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 - (eval $ac_link_default) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - # Find the output, starting from the most likely. This scheme is -# not robust to junk in `.', hence go to wildcards (a.*) only as a last -# resort. - -# Be careful to initialize this variable, since it used to be cached. -# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. -ac_cv_exeext= -# b.out is created by i960 compilers. -for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) - ;; - conftest.$ac_ext ) - # This is the source file. - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - # FIXME: I believe we export ac_cv_exeext for Libtool, - # but it would be cool to find out if it's true. Does anybody - # maintain Libtool? --akim. - export ac_cv_exeext - break;; - * ) - break;; - esac -done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { echo "$as_me:$LINENO: error: C compiler cannot create executables -See \`config.log' for more details." >&5 -echo "$as_me: error: C compiler cannot create executables -See \`config.log' for more details." >&2;} - { (exit 77); exit 77; }; } -fi - -ac_exeext=$ac_cv_exeext -echo "$as_me:$LINENO: result: $ac_file" >&5 -echo "${ECHO_T}$ac_file" >&6 - -# Check the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -echo "$as_me:$LINENO: checking whether the C compiler works" >&5 -echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 -# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 -# If not cross compiling, check that we can run a simple program. -if test "$cross_compiling" != yes; then - if { ac_try='./$ac_file' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { echo "$as_me:$LINENO: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } - fi - fi -fi -echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6 - -rm -f a.out a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -# Check the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 -echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 -echo "$as_me:$LINENO: result: $cross_compiling" >&5 -echo "${ECHO_T}$cross_compiling" >&6 - -echo "$as_me:$LINENO: checking for suffix of executables" >&5 -echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - export ac_cv_exeext - break;; - * ) break;; - esac -done -else - { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi - -rm -f conftest$ac_cv_exeext -echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 -echo "${ECHO_T}$ac_cv_exeext" >&6 - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -echo "$as_me:$LINENO: checking for suffix of object files" >&5 -echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 -if test "${ac_cv_objext+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 -echo "${ECHO_T}$ac_cv_objext" >&6 -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then @@ -2787,260 +4056,86 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -continue -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -rm -f conftest* -if test -n "$ac_declaration"; then - echo '#ifdef __cplusplus' >>confdefs.h - echo $ac_declaration >>confdefs.h - echo '#endif' >>confdefs.h -fi - -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -DEPDIR="${am__leading_dot}deps" - - ac_config_commands="$ac_config_commands depfiles" - - -am_make=${MAKE-make} -cat > confinc << 'END' -am__doit: - @echo done -.PHONY: am__doit -END -# If we don't find an include directive, just comment out the code. -echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 -echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 -am__include="#" -am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# We grep out `Entering directory' and `Leaving directory' -# messages which can occur if `w' ends up in MAKEFLAGS. -# In particular we don't look at `^make:' because GNU make might -# be invoked under some other name (usually "gmake"), in which -# case it prints its new name instead of `make'. -if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then - am__include=include - am__quote= - _am_result=GNU -fi -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then - am__include=.include - am__quote="\"" - _am_result=BSD - fi -fi - - -echo "$as_me:$LINENO: result: $_am_result" >&5 -echo "${ECHO_T}$_am_result" >&6 -rm -f confinc confmf - -# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. -if test "${enable_dependency_tracking+set}" = set; then - enableval="$enable_dependency_tracking" - -fi; -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' -fi - - -if test "x$enable_dependency_tracking" != xno; then - AMDEP_TRUE= - AMDEP_FALSE='#' -else - AMDEP_TRUE='#' - AMDEP_FALSE= -fi - - - - -depcc="$CC" am_compiler_list= - -echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 -echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 -if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named `D' -- because `-MD' means `put the output - # in D'. - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with - # Solaris 8's {/usr,}/bin/sh. - touch sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - case $depmode in - nosideeffect) - # after this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - none) break ;; - esac - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. - if depmode=$depmode \ - source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : else - am_cv_CC_dependencies_compiler_type=none -fi + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 +continue fi -echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 -echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 -CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi -if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then - am__fastdepCC_TRUE= - am__fastdepCC_FALSE='#' else - am__fastdepCC_TRUE='#' - am__fastdepCC_FALSE= -fi + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu # Check whether --enable-shared or --disable-shared was given. if test "${enable_shared+set}" = set; then @@ -3632,7 +4727,6 @@ LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC - # Check whether --enable-libtool-lock or --disable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then enableval="$enable_libtool_lock" @@ -3664,7 +4758,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 3667 "configure"' > conftest.$ac_ext + echo '#line 4761 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -5263,7 +6357,7 @@ fi # Provide some information about the compiler. -echo "$as_me:5266:" \ +echo "$as_me:6360:" \ "checking for Fortran 77 compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 @@ -6326,11 +7420,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6329: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7423: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6333: \$? = $ac_status" >&5 + echo "$as_me:7427: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -6594,11 +7688,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6597: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7691: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6601: \$? = $ac_status" >&5 + echo "$as_me:7695: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -6698,11 +7792,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6701: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7795: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:6705: \$? = $ac_status" >&5 + echo "$as_me:7799: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -8167,7 +9261,7 @@ linux*) libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) - echo '#line 8170 "configure"' > conftest.$ac_ext + echo '#line 9264 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -9064,7 +10158,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:12604: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:11514: \$? = $ac_status" >&5 + echo "$as_me:12608: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -11611,11 +12705,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:11614: $lt_compile\"" >&5) + (eval echo "\"\$as_me:12708: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:11618: \$? = $ac_status" >&5 + echo "$as_me:12712: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -12147,7 +13241,7 @@ linux*) libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) - echo '#line 12150 "configure"' > conftest.$ac_ext + echo '#line 13244 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -13205,11 +14299,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:13208: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14302: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:13212: \$? = $ac_status" >&5 + echo "$as_me:14306: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -13309,11 +14403,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:13312: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14406: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:13316: \$? = $ac_status" >&5 + echo "$as_me:14410: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -14758,7 +15852,7 @@ linux*) libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) - echo '#line 14761 "configure"' > conftest.$ac_ext + echo '#line 15855 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -15536,11 +16630,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:15539: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16633: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:15543: \$? = $ac_status" >&5 + echo "$as_me:16637: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -15804,11 +16898,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:15807: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16901: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:15811: \$? = $ac_status" >&5 + echo "$as_me:16905: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -15908,11 +17002,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:15911: $lt_compile\"" >&5) + (eval echo "\"\$as_me:17005: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:15915: \$? = $ac_status" >&5 + echo "$as_me:17009: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -17377,7 +18471,7 @@ linux*) libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) - echo '#line 17380 "configure"' > conftest.$ac_ext + echo '#line 18474 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -19087,18 +20181,176 @@ fi done -JNI_CPPFLAGS="" -if test $JAVA_HOME != "" -then - for dir in `find $JAVA_HOME/include -follow -type d` - do - JNI_CPPFLAGS="$JNI_CPPFLAGS -I$dir" - done -fi -cppflags_bak=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $JNI_CPPFLAGS" +JNI_CPPFLAGS="" +if test $JAVA_HOME != "" +then + for dir in `find $JAVA_HOME/include -follow -type d` + do + JNI_CPPFLAGS="$JNI_CPPFLAGS -I$dir" + done +fi +cppflags_bak=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $JNI_CPPFLAGS" + +for ac_header in jni.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +else + { { echo "$as_me:$LINENO: error: Native java headers not found. Is \$JAVA_HOME set correctly?" >&5 +echo "$as_me: error: Native java headers not found. Is \$JAVA_HOME set correctly?" >&2;} + { (exit 1); exit 1; }; } +fi + +done + +CPPFLAGS=$cppflags_bak + + + -for ac_header in jni.h +for ac_header in zlib.h zconf.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then @@ -19243,20 +20495,54 @@ if test `eval echo '${'$as_ac_Header'}'` = yes; then #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF +echo "$as_me:$LINENO: checking Checking for the 'actual' dynamic-library for '-lz'" >&5 +echo $ECHO_N "checking Checking for the 'actual' dynamic-library for '-lz'... $ECHO_C" >&6 +if test "${ac_cv_libname_z+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 else - { { echo "$as_me:$LINENO: error: Native java headers not found. Is \$JAVA_HOME set correctly?" >&5 -echo "$as_me: error: Native java headers not found. Is \$JAVA_HOME set correctly?" >&2;} + + echo 'int main(int argc, char **argv){return 0;}' > conftest.c + if test -z "`${CC} ${LDFLAGS} -o conftest conftest.c -lz 2>&1`"; then + if test ! -z "`which objdump | grep -v 'no objdump'`"; then + ac_cv_libname_z="`objdump -p conftest | grep NEEDED | grep z | sed 's/\W*NEEDED\W*\(.*\)\W*$/\"\1\"/'`" + elif test ! -z "`which ldd | grep -v 'no ldd'`"; then + ac_cv_libname_z="`ldd conftest | grep z | sed 's/^[^A-Za-z0-9]*\([A-Za-z0-9\.]*\)[^A-Za-z0-9]*=>.*$/\"\1\"/'`" + elif test ! -z "`which otool | grep -v 'no otool'`"; then + ac_cv_libname_z=\"`otool -L conftest | grep z | sed -e 's/^ *//' -e 's/ .*//' -e 's/.*\/\(.*\)$/\1/'`\"; + else + { { echo "$as_me:$LINENO: error: Can't find either 'objdump' or 'ldd' or 'otool' to compute the dynamic library for '-lz'" >&5 +echo "$as_me: error: Can't find either 'objdump' or 'ldd' or 'otool' to compute the dynamic library for '-lz'" >&2;} + { (exit 1); exit 1; }; } + fi + else + ac_cv_libname_z=libnotfound.so + fi + rm -f conftest* + + +fi +echo "$as_me:$LINENO: result: $ac_cv_libname_z" >&5 +echo "${ECHO_T}$ac_cv_libname_z" >&6 + +cat >>confdefs.h <<_ACEOF +#define HADOOP_ZLIB_LIBRARY ${ac_cv_libname_z} +_ACEOF + + +else + { { echo "$as_me:$LINENO: error: Zlib headers were not found... native-hadoop library needs zlib to build. Please install the requisite zlib development package." >&5 +echo "$as_me: error: Zlib headers were not found... native-hadoop library needs zlib to build. Please install the requisite zlib development package." >&2;} { (exit 1); exit 1; }; } fi done -CPPFLAGS=$cppflags_bak -for ac_header in zlib.h zconf.h + +for ac_header in fcntl.h stdlib.h string.h unistd.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then @@ -19401,74 +20687,81 @@ if test `eval echo '${'$as_ac_Header'}'` = yes; then #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF -echo "$as_me:$LINENO: checking Checking for the 'actual' dynamic-library for '-lz'" >&5 -echo $ECHO_N "checking Checking for the 'actual' dynamic-library for '-lz'... $ECHO_C" >&6 -if test "${ac_cv_libname_z+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - - echo 'int main(int argc, char **argv){return 0;}' > conftest.c - if test -z "`${CC} ${LDFLAGS} -o conftest conftest.c -lz 2>&1`"; then - if test ! -z "`which objdump | grep -v 'no objdump'`"; then - ac_cv_libname_z="`objdump -p conftest | grep NEEDED | grep z | sed 's/\W*NEEDED\W*\(.*\)\W*$/\"\1\"/'`" - elif test ! -z "`which ldd | grep -v 'no ldd'`"; then - ac_cv_libname_z="`ldd conftest | grep z | sed 's/^[^A-Za-z0-9]*\([A-Za-z0-9\.]*\)[^A-Za-z0-9]*=>.*$/\"\1\"/'`" - else - { { echo "$as_me:$LINENO: error: Can't find either 'objdump' or 'ldd' to compute the dynamic library for '-lz'" >&5 -echo "$as_me: error: Can't find either 'objdump' or 'ldd' to compute the dynamic library for '-lz'" >&2;} - { (exit 1); exit 1; }; } - fi - else - ac_cv_libname_z=libnotfound.so - fi - rm -f conftest* - - -fi -echo "$as_me:$LINENO: result: $ac_cv_libname_z" >&5 -echo "${ECHO_T}$ac_cv_libname_z" >&6 - -cat >>confdefs.h <<_ACEOF -#define HADOOP_ZLIB_LIBRARY ${ac_cv_libname_z} -_ACEOF - - else - { { echo "$as_me:$LINENO: error: Zlib headers were not found... native-hadoop library needs zlib to build. Please install the requisite zlib development package." >&5 -echo "$as_me: error: Zlib headers were not found... native-hadoop library needs zlib to build. Please install the requisite zlib development package." >&2;} + { { echo "$as_me:$LINENO: error: Some system headers not found... please ensure their presence on your platform." >&5 +echo "$as_me: error: Some system headers not found... please ensure their presence on your platform." >&2;} { (exit 1); exit 1; }; } fi done - - - - -for ac_header in fcntl.h stdlib.h string.h unistd.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then +# Checks for typedefs, structures, and compiler characteristics. +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else - # Is the header compilable? -echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 @@ -19492,118 +20785,134 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_header_compiler=yes + ac_cv_c_const=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_header_compiler=no +ac_cv_c_const=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then -# Is the header present? -echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + + +# Checks for library functions. + +for ac_func in memset +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include <$ac_header> +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} _ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - ac_cpp_err=$ac_cpp_err$ac_c_werror_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then - ac_header_preproc=yes + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_header_preproc=no -fi -rm -f conftest.err conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6 - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( - cat <<\_ASBOX -## ------------------------------------------ ## -## Report this to the AC_PACKAGE_NAME lists. ## -## ------------------------------------------ ## -_ASBOX - ) | - sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" +eval "$as_ac_var=no" fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 - +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF -else - { { echo "$as_me:$LINENO: error: Some system headers not found... please ensure their presence on your platform." >&5 -echo "$as_me: error: Some system headers not found... please ensure their presence on your platform." >&2;} - { (exit 1); exit 1; }; } fi - done -# Checks for typedefs, structures, and compiler characteristics. -echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 -echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 -if test "${ac_cv_c_const+set}" = set; then +# Check for nonstandard STRERROR_R +echo "$as_me:$LINENO: checking whether strerror_r is declared" >&5 +echo $ECHO_N "checking whether strerror_r is declared... $ECHO_C" >&6 +if test "${ac_cv_have_decl_strerror_r+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF @@ -19612,55 +20921,12 @@ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ - +$ac_includes_default int main () { -/* FIXME: Include the comments suggested by Paul. */ -#ifndef __cplusplus - /* Ultrix mips cc rejects this. */ - typedef int charset[2]; - const charset x; - /* SunOS 4.1.1 cc rejects this. */ - char const *const *ccp; - char **p; - /* NEC SVR4.0.2 mips cc rejects this. */ - struct point {int x, y;}; - static struct point const zero = {0,0}; - /* AIX XL C 1.02.0.0 rejects this. - It does not let you subtract one const X* pointer from another in - an arm of an if-expression whose if-part is not a constant - expression */ - const char *g = "string"; - ccp = &g + (g ? g-g : 0); - /* HPUX 7.0 cc rejects these. */ - ++ccp; - p = (char**) ccp; - ccp = (char const *const *) p; - { /* SCO 3.2v4 cc rejects this. */ - char *t; - char const *s = 0 ? (char *) 0 : (char const *) 0; - - *t++ = 0; - } - { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ - int x[] = {25, 17}; - const int *foo = &x[0]; - ++foo; - } - { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ - typedef const int *iptr; - iptr p = 0; - ++p; - } - { /* AIX XL C 1.02.0.0 rejects this saying - "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ - struct s { int j; const int *ap[3]; }; - struct s *b; b->j = 5; - } - { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ - const int foo = 10; - } +#ifndef strerror_r + char *p = (char *) strerror_r; #endif ; @@ -19689,29 +20955,35 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_c_const=yes + ac_cv_have_decl_strerror_r=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_c_const=no +ac_cv_have_decl_strerror_r=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 -echo "${ECHO_T}$ac_cv_c_const" >&6 -if test $ac_cv_c_const = no; then +echo "$as_me:$LINENO: result: $ac_cv_have_decl_strerror_r" >&5 +echo "${ECHO_T}$ac_cv_have_decl_strerror_r" >&6 +if test $ac_cv_have_decl_strerror_r = yes; then -cat >>confdefs.h <<\_ACEOF -#define const +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRERROR_R 1 +_ACEOF + + +else + cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRERROR_R 0 _ACEOF + fi -# Checks for library functions. -for ac_func in memset +for ac_func in strerror_r do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -19812,6 +21084,123 @@ _ACEOF fi done +echo "$as_me:$LINENO: checking whether strerror_r returns char *" >&5 +echo $ECHO_N "checking whether strerror_r returns char *... $ECHO_C" >&6 +if test "${ac_cv_func_strerror_r_char_p+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + ac_cv_func_strerror_r_char_p=no + if test $ac_cv_have_decl_strerror_r = yes; then + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + char buf[100]; + char x = *strerror_r (0, buf, sizeof buf); + char *p = strerror_r (0, buf, sizeof buf); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_strerror_r_char_p=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + else + # strerror_r is not declared. Choose between + # systems that have relatively inaccessible declarations for the + # function. BeOS and DEC UNIX 4.0 fall in this category, but the + # former has a strerror_r that returns char*, while the latter + # has a strerror_r that returns `int'. + # This test should segfault on the DEC system. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + extern char *strerror_r (); +int +main () +{ +char buf[100]; + char x = *strerror_r (0, buf, sizeof buf); + exit (!isalpha (x)); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_strerror_r_char_p=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + fi + +fi +echo "$as_me:$LINENO: result: $ac_cv_func_strerror_r_char_p" >&5 +echo "${ECHO_T}$ac_cv_func_strerror_r_char_p" >&6 +if test $ac_cv_func_strerror_r_char_p = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STRERROR_R_CHAR_P 1 +_ACEOF + +fi + ac_config_files="$ac_config_files Makefile" @@ -20459,6 +21848,13 @@ s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t @@ -20481,13 +21877,6 @@ s,@am__leading_dot@,$am__leading_dot,;t t s,@AMTAR@,$AMTAR,;t t s,@am__tar@,$am__tar,;t t s,@am__untar@,$am__untar,;t t -s,@CC@,$CC,;t t -s,@CFLAGS@,$CFLAGS,;t t -s,@LDFLAGS@,$LDFLAGS,;t t -s,@CPPFLAGS@,$CPPFLAGS,;t t -s,@ac_ct_CC@,$ac_ct_CC,;t t -s,@EXEEXT@,$EXEEXT,;t t -s,@OBJEXT@,$OBJEXT,;t t s,@DEPDIR@,$DEPDIR,;t t s,@am__include@,$am__include,;t t s,@am__quote@,$am__quote,;t t diff --git a/src/native/configure.ac b/src/native/configure.ac index df118338761c1..94c86093b0c91 100644 --- a/src/native/configure.ac +++ b/src/native/configure.ac @@ -38,6 +38,7 @@ AC_INIT(src/org_apache_hadoop.h) AC_CONFIG_SRCDIR([src/org_apache_hadoop.h]) AC_CONFIG_AUX_DIR(config) AC_CONFIG_HEADER([config.h]) +AC_SYS_LARGEFILE AM_INIT_AUTOMAKE(hadoop,1.0.0) @@ -95,6 +96,9 @@ AC_C_CONST # Checks for library functions. AC_CHECK_FUNCS([memset]) +# Check for nonstandard STRERROR_R +AC_FUNC_STRERROR_R + AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/src/native/lib/Makefile.am b/src/native/lib/Makefile.am index 5d51cc5b76368..f33df0e9a857f 100644 --- a/src/native/lib/Makefile.am +++ b/src/native/lib/Makefile.am @@ -36,7 +36,7 @@ AM_LDFLAGS = @JNI_LDFLAGS@ -m$(JVM_DATA_MODEL) lib_LTLIBRARIES = libhadoop.la libhadoop_la_SOURCES = -libhadoop_la_LDFLAGS = -version-info 1:0:0 +libhadoop_la_LDFLAGS = -version-info 1:0:0 $(AM_LDFLAGS) libhadoop_la_LIBADD = $(HADOOP_OBJS) -ldl -ljvm # diff --git a/src/native/src/org/apache/hadoop/io/nativeio/NativeIO.c b/src/native/src/org/apache/hadoop/io/nativeio/NativeIO.c new file mode 100644 index 0000000000000..1c1a9896274c0 --- /dev/null +++ b/src/native/src/org/apache/hadoop/io/nativeio/NativeIO.c @@ -0,0 +1,277 @@ +/* + * 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. + */ + +// get the autoconf settings +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "org_apache_hadoop.h" +#include "org_apache_hadoop_io_nativeio_NativeIO.h" +#include "file_descriptor.h" +#include "errno_enum.h" + +// the NativeIO$Stat inner class and its constructor +static jclass stat_clazz; +static jmethodID stat_ctor; + +// the NativeIOException class and its constructor +static jclass nioe_clazz; +static jmethodID nioe_ctor; + +// Internal functions +static void throw_ioe(JNIEnv* env, int errnum); +static ssize_t get_pw_buflen(); + + +static void stat_init(JNIEnv *env) { + // Init Stat + jclass clazz = (*env)->FindClass(env, "org/apache/hadoop/io/nativeio/NativeIO$Stat"); + PASS_EXCEPTIONS(env); + stat_clazz = (*env)->NewGlobalRef(env, clazz); + stat_ctor = (*env)->GetMethodID(env, stat_clazz, "", + "(Ljava/lang/String;Ljava/lang/String;I)V"); +} + +static void stat_deinit(JNIEnv *env) { + if (stat_clazz != NULL) { + (*env)->DeleteGlobalRef(env, stat_clazz); + stat_clazz = NULL; + } +} + +static void nioe_init(JNIEnv *env) { + // Init NativeIOException + nioe_clazz = (*env)->FindClass( + env, "org/apache/hadoop/io/nativeio/NativeIOException"); + PASS_EXCEPTIONS(env); + + nioe_clazz = (*env)->NewGlobalRef(env, nioe_clazz); + nioe_ctor = (*env)->GetMethodID(env, nioe_clazz, "", + "(Ljava/lang/String;Lorg/apache/hadoop/io/nativeio/Errno;)V"); +} + +static void nioe_deinit(JNIEnv *env) { + if (nioe_clazz != NULL) { + (*env)->DeleteGlobalRef(env, nioe_clazz); + nioe_clazz = NULL; + } + nioe_ctor = NULL; +} + +/* + * private static native void initNative(); + * + * We rely on this function rather than lazy initialization because + * the lazy approach may have a race if multiple callers try to + * init at the same time. + */ +JNIEXPORT void JNICALL +Java_org_apache_hadoop_io_nativeio_NativeIO_initNative( + JNIEnv *env, jclass clazz) { + + stat_init(env); + PASS_EXCEPTIONS_GOTO(env, error); + nioe_init(env); + PASS_EXCEPTIONS_GOTO(env, error); + fd_init(env); + PASS_EXCEPTIONS_GOTO(env, error); + errno_enum_init(env); + PASS_EXCEPTIONS_GOTO(env, error); + return; +error: + // these are all idempodent and safe to call even if the + // class wasn't initted yet + stat_deinit(env); + nioe_deinit(env); + fd_deinit(env); + errno_enum_deinit(env); +} + +/* + * public static native Stat fstat(FileDescriptor fd); + */ +JNIEXPORT jobject JNICALL +Java_org_apache_hadoop_io_nativeio_NativeIO_fstat( + JNIEnv *env, jclass clazz, jobject fd_object) +{ + jobject ret = NULL; + char *pw_buf = NULL; + + int fd = fd_get(env, fd_object); + PASS_EXCEPTIONS_GOTO(env, cleanup); + + struct stat s; + int rc = fstat(fd, &s); + if (rc != 0) { + throw_ioe(env, errno); + goto cleanup; + } + + size_t pw_buflen = get_pw_buflen(); + if ((pw_buf = malloc(pw_buflen)) == NULL) { + THROW(env, "java/lang/OutOfMemoryError", "Couldn't allocate memory for pw buffer"); + goto cleanup; + } + + // Grab username + struct passwd pwd, *pwdp; + while ((rc = getpwuid_r(s.st_uid, &pwd, pw_buf, pw_buflen, &pwdp)) != 0) { + if (rc != ERANGE) { + throw_ioe(env, rc); + goto cleanup; + } + free(pw_buf); + pw_buflen *= 2; + if ((pw_buf = malloc(pw_buflen)) == NULL) { + THROW(env, "java/lang/OutOfMemoryError", "Couldn't allocate memory for pw buffer"); + goto cleanup; + } + } + assert(pwdp == &pwd); + + jstring jstr_username = (*env)->NewStringUTF(env, pwd.pw_name); + if (jstr_username == NULL) goto cleanup; + + // Grab group + struct group grp, *grpp; + while ((rc = getgrgid_r(s.st_gid, &grp, pw_buf, pw_buflen, &grpp)) != 0) { + if (rc != ERANGE) { + throw_ioe(env, rc); + goto cleanup; + } + free(pw_buf); + pw_buflen *= 2; + if ((pw_buf = malloc(pw_buflen)) == NULL) { + THROW(env, "java/lang/OutOfMemoryError", "Couldn't allocate memory for pw buffer"); + goto cleanup; + } + } + assert(grpp == &grp); + + jstring jstr_groupname = (*env)->NewStringUTF(env, grp.gr_name); + PASS_EXCEPTIONS_GOTO(env, cleanup); + + // Construct result + ret = (*env)->NewObject(env, stat_clazz, stat_ctor, + jstr_username, jstr_groupname, s.st_mode); + +cleanup: + if (pw_buf != NULL) free(pw_buf); + return ret; +} + + +/* + * public static native FileDescriptor open(String path, int flags, int mode); + */ +JNIEXPORT jobject JNICALL +Java_org_apache_hadoop_io_nativeio_NativeIO_open( + JNIEnv *env, jclass clazz, jstring j_path, + jint flags, jint mode) +{ + jobject ret = NULL; + + const char *path = (*env)->GetStringUTFChars(env, j_path, NULL); + if (path == NULL) goto cleanup; // JVM throws Exception for us + + int fd; + if (flags & O_CREAT) { + fd = open(path, flags, mode); + } else { + fd = open(path, flags); + } + + if (fd == -1) { + throw_ioe(env, errno); + goto cleanup; + } + + ret = fd_create(env, fd); + +cleanup: + if (path != NULL) { + (*env)->ReleaseStringUTFChars(env, j_path, path); + } + return ret; +} + +/* + * Throw a java.IO.IOException, generating the message from errno. + */ +static void throw_ioe(JNIEnv* env, int errnum) +{ + const char* message; + char buffer[80]; + jstring jstr_message; + + buffer[0] = 0; +#ifdef STRERROR_R_CHAR_P + // GNU strerror_r + message = strerror_r(errnum, buffer, sizeof(buffer)); + assert (message != NULL); +#else + int ret = strerror_r(errnum, buffer, sizeof(buffer)); + if (ret == 0) { + message = buffer; + } else { + message = "Unknown error"; + } +#endif + jobject errno_obj = errno_to_enum(env, errnum); + + if ((jstr_message = (*env)->NewStringUTF(env, message)) == NULL) + goto err; + + jthrowable obj = (jthrowable)(*env)->NewObject(env, nioe_clazz, nioe_ctor, + jstr_message, errno_obj); + if (obj == NULL) goto err; + + (*env)->Throw(env, obj); + return; + +err: + if (jstr_message != NULL) + (*env)->ReleaseStringUTFChars(env, jstr_message, message); +} + + +/* + * Determine how big a buffer we need for reentrant getpwuid_r and getgrnam_r + */ +ssize_t get_pw_buflen() { + size_t ret = 0; + #ifdef _SC_GETPW_R_SIZE_MAX + ret = sysconf(_SC_GETPW_R_SIZE_MAX); + #endif + return (ret > 512) ? ret : 512; +} +/** + * vim: sw=2: ts=2: et: + */ + diff --git a/src/native/src/org/apache/hadoop/io/nativeio/errno_enum.c b/src/native/src/org/apache/hadoop/io/nativeio/errno_enum.c new file mode 100644 index 0000000000000..76d1ff172521f --- /dev/null +++ b/src/native/src/org/apache/hadoop/io/nativeio/errno_enum.c @@ -0,0 +1,119 @@ +/* + * 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. + */ + #include + #include + #include + +#include "org_apache_hadoop.h" + +typedef struct errno_mapping { + int errno_val; + char *errno_str; +} errno_mapping_t; + +// Macro to define structs like {FOO, "FOO"} for each errno value +#define MAPPING(x) {x, #x} +static errno_mapping_t ERRNO_MAPPINGS[] = { + MAPPING(EPERM), + MAPPING(ENOENT), + MAPPING(ESRCH), + MAPPING(EINTR), + MAPPING(EIO), + MAPPING(ENXIO), + MAPPING(E2BIG), + MAPPING(ENOEXEC), + MAPPING(EBADF), + MAPPING(ECHILD), + MAPPING(EAGAIN), + MAPPING(ENOMEM), + MAPPING(EACCES), + MAPPING(EFAULT), + MAPPING(ENOTBLK), + MAPPING(EBUSY), + MAPPING(EEXIST), + MAPPING(EXDEV), + MAPPING(ENODEV), + MAPPING(ENOTDIR), + MAPPING(EISDIR), + MAPPING(EINVAL), + MAPPING(ENFILE), + MAPPING(EMFILE), + MAPPING(ENOTTY), + MAPPING(ETXTBSY), + MAPPING(EFBIG), + MAPPING(ENOSPC), + MAPPING(ESPIPE), + MAPPING(EROFS), + MAPPING(EMLINK), + MAPPING(EPIPE), + MAPPING(EDOM), + MAPPING(ERANGE), + {-1, NULL} +}; + +static jclass enum_class; +static jmethodID enum_valueOf; +static jclass errno_class; + +void errno_enum_init(JNIEnv *env) { + if (enum_class != NULL) return; + + enum_class = (*env)->FindClass(env, "java/lang/Enum"); + PASS_EXCEPTIONS(env); + enum_class = (*env)->NewGlobalRef(env, enum_class); + enum_valueOf = (*env)->GetStaticMethodID(env, enum_class, + "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;"); + PASS_EXCEPTIONS(env); + + errno_class = (*env)->FindClass(env, "org/apache/hadoop/io/nativeio/Errno"); + PASS_EXCEPTIONS(env); + errno_class = (*env)->NewGlobalRef(env, errno_class); +} + +void errno_enum_deinit(JNIEnv *env) { + if (enum_class != NULL) { + (*env)->DeleteGlobalRef(env, enum_class); + enum_class = NULL; + } + if (errno_class != NULL) { + (*env)->DeleteGlobalRef(env, errno_class); + errno_class = NULL; + } + enum_valueOf = NULL; +} + + +static char *errno_to_string(int errnum) { + int i; + for (i = 0; ERRNO_MAPPINGS[i].errno_str != NULL; i++) { + if (ERRNO_MAPPINGS[i].errno_val == errnum) + return ERRNO_MAPPINGS[i].errno_str; + } + return "UNKNOWN"; +} + +jobject errno_to_enum(JNIEnv *env, int errnum) { + char *str = errno_to_string(errnum); + assert(str != NULL); + + jstring jstr = (*env)->NewStringUTF(env, str); + PASS_EXCEPTIONS_RET(env, NULL); + + return (*env)->CallStaticObjectMethod( + env, enum_class, enum_valueOf, errno_class, jstr); +} diff --git a/src/native/src/org/apache/hadoop/io/nativeio/errno_enum.h b/src/native/src/org/apache/hadoop/io/nativeio/errno_enum.h new file mode 100644 index 0000000000000..1eee11a5f8283 --- /dev/null +++ b/src/native/src/org/apache/hadoop/io/nativeio/errno_enum.h @@ -0,0 +1,27 @@ +/* + * 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. + */ +#ifndef ERRNO_ENUM_H +#define ERRNO_ENUM_H + +#include + +void errno_enum_init(JNIEnv *env); +void errno_enum_deinit(JNIEnv *env); +jobject errno_to_enum(JNIEnv *env, int errnum); + +#endif diff --git a/src/native/src/org/apache/hadoop/io/nativeio/file_descriptor.c b/src/native/src/org/apache/hadoop/io/nativeio/file_descriptor.c new file mode 100644 index 0000000000000..0681db8f8324e --- /dev/null +++ b/src/native/src/org/apache/hadoop/io/nativeio/file_descriptor.c @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#include +#include "file_descriptor.h" +#include "org_apache_hadoop.h" + +// class of java.io.FileDescriptor +static jclass fd_class; +// the internal field for the integer fd +static jfieldID fd_descriptor; +// the no-argument constructor +static jmethodID fd_constructor; + + +void fd_init(JNIEnv* env) +{ + if (fd_class != NULL) return; // already initted + + fd_class = (*env)->FindClass(env, "java/io/FileDescriptor"); + PASS_EXCEPTIONS(env); + fd_class = (*env)->NewGlobalRef(env, fd_class); + + fd_descriptor = (*env)->GetFieldID(env, fd_class, "fd", "I"); + PASS_EXCEPTIONS(env); + fd_constructor = (*env)->GetMethodID(env, fd_class, "", "()V"); +} + +void fd_deinit(JNIEnv *env) { + if (fd_class != NULL) { + (*env)->DeleteGlobalRef(env, fd_class); + fd_class = NULL; + } + fd_descriptor = NULL; + fd_constructor = NULL; +} + +/* + * Given an instance 'obj' of java.io.FileDescriptor, return the + * underlying fd, or throw if unavailable + */ +int fd_get(JNIEnv* env, jobject obj) { + return (*env)->GetIntField(env, obj, fd_descriptor); +} + +/* + * Create a FileDescriptor object corresponding to the given int fd + */ +jobject fd_create(JNIEnv *env, int fd) { + jobject obj = (*env)->NewObject(env, fd_class, fd_constructor); + PASS_EXCEPTIONS_RET(env, NULL); + + (*env)->SetIntField(env, obj, fd_descriptor, fd); + return obj; +} diff --git a/src/native/src/org/apache/hadoop/io/nativeio/file_descriptor.h b/src/native/src/org/apache/hadoop/io/nativeio/file_descriptor.h new file mode 100644 index 0000000000000..3f689493bc595 --- /dev/null +++ b/src/native/src/org/apache/hadoop/io/nativeio/file_descriptor.h @@ -0,0 +1,28 @@ +/* + * 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. + */ +#ifndef FILE_DESCRIPTOR_H +#define FILE_DESCRIPTOR_H + +#include + +void fd_init(JNIEnv *env); +void fd_deinit(JNIEnv *env); + +int fd_get(JNIEnv* env, jobject obj); +jobject fd_create(JNIEnv *env, int fd); + +#endif diff --git a/src/native/src/org_apache_hadoop.h b/src/native/src/org_apache_hadoop.h index 325dcd6601fdf..c1513eeb8a991 100644 --- a/src/native/src/org_apache_hadoop.h +++ b/src/native/src/org_apache_hadoop.h @@ -50,6 +50,22 @@ } \ } +/* Helper macro to return if an exception is pending */ +#define PASS_EXCEPTIONS(env) \ + { \ + if ((*env)->ExceptionCheck(env)) return; \ + } + +#define PASS_EXCEPTIONS_GOTO(env, target) \ + { \ + if ((*env)->ExceptionCheck(env)) goto target; \ + } + +#define PASS_EXCEPTIONS_RET(env, ret) \ + { \ + if ((*env)->ExceptionCheck(env)) return (ret); \ + } + /** * A helper function to dlsym a 'symbol' from a given library-handle. * diff --git a/src/protobuf/SerializationMetadata.proto b/src/protobuf/SerializationMetadata.proto new file mode 100644 index 0000000000000..e4249632355eb --- /dev/null +++ b/src/protobuf/SerializationMetadata.proto @@ -0,0 +1,15 @@ +package org.apache.hadoop.io.serial.lib; + +message TypedSerializationMetadata { + optional string typename = 1; +} + +message AvroMetadata { + optional string schema = 1; + optional Kind kind = 2; + enum Kind { + SPECIFIC = 1; + GENERIC = 2; + REFLECTION = 3; + } +} \ No newline at end of file diff --git a/src/test/core/org/apache/hadoop/io/AvroKey.java b/src/test/core/org/apache/hadoop/io/AvroKey.java new file mode 100644 index 0000000000000..35e14885eace6 --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/AvroKey.java @@ -0,0 +1,21 @@ +package org.apache.hadoop.io; + +@SuppressWarnings("all") +public class AvroKey extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord { + public static final org.apache.avro.Schema SCHEMA$ = org.apache.avro.Schema.parse("{\"type\":\"record\",\"name\":\"AvroKey\",\"namespace\":\"org.apache.hadoop.io\",\"fields\":[{\"name\":\"value\",\"type\":\"int\"}]}"); + public int value; + public org.apache.avro.Schema getSchema() { return SCHEMA$; } + public java.lang.Object get(int field$) { + switch (field$) { + case 0: return value; + default: throw new org.apache.avro.AvroRuntimeException("Bad index"); + } + } + @SuppressWarnings(value="unchecked") + public void put(int field$, java.lang.Object value$) { + switch (field$) { + case 0: value = (java.lang.Integer)value$; break; + default: throw new org.apache.avro.AvroRuntimeException("Bad index"); + } + } +} diff --git a/src/test/core/org/apache/hadoop/io/AvroValue.java b/src/test/core/org/apache/hadoop/io/AvroValue.java new file mode 100644 index 0000000000000..9da257bfc13e2 --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/AvroValue.java @@ -0,0 +1,21 @@ +package org.apache.hadoop.io; + +@SuppressWarnings("all") +public class AvroValue extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord { + public static final org.apache.avro.Schema SCHEMA$ = org.apache.avro.Schema.parse("{\"type\":\"record\",\"name\":\"AvroValue\",\"namespace\":\"org.apache.hadoop.io\",\"fields\":[{\"name\":\"value\",\"type\":\"string\"}]}"); + public org.apache.avro.util.Utf8 value; + public org.apache.avro.Schema getSchema() { return SCHEMA$; } + public java.lang.Object get(int field$) { + switch (field$) { + case 0: return value; + default: throw new org.apache.avro.AvroRuntimeException("Bad index"); + } + } + @SuppressWarnings(value="unchecked") + public void put(int field$, java.lang.Object value$) { + switch (field$) { + case 0: value = (org.apache.avro.util.Utf8)value$; break; + default: throw new org.apache.avro.AvroRuntimeException("Bad index"); + } + } +} diff --git a/src/test/core/org/apache/hadoop/io/ProtoTest.java b/src/test/core/org/apache/hadoop/io/ProtoTest.java new file mode 100644 index 0000000000000..86bb526276fb9 --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/ProtoTest.java @@ -0,0 +1,641 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: src/test/core/org/apache/hadoop/io/ProtoTest.proto + +package org.apache.hadoop.io; + +public final class ProtoTest { + private ProtoTest() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + } + public static final class ProtoKey extends + com.google.protobuf.GeneratedMessage { + // Use ProtoKey.newBuilder() to construct. + private ProtoKey() { + initFields(); + } + private ProtoKey(boolean noInit) {} + + private static final ProtoKey defaultInstance; + public static ProtoKey getDefaultInstance() { + return defaultInstance; + } + + public ProtoKey getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.apache.hadoop.io.ProtoTest.internal_static_org_apache_hadoop_io_ProtoKey_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.apache.hadoop.io.ProtoTest.internal_static_org_apache_hadoop_io_ProtoKey_fieldAccessorTable; + } + + // required int32 value = 1; + public static final int VALUE_FIELD_NUMBER = 1; + private boolean hasValue; + private int value_ = 0; + public boolean hasValue() { return hasValue; } + public int getValue() { return value_; } + + private void initFields() { + } + public final boolean isInitialized() { + if (!hasValue) return false; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (hasValue()) { + output.writeInt32(1, getValue()); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasValue()) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(1, getValue()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + public static org.apache.hadoop.io.ProtoTest.ProtoKey parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoKey parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoKey parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoKey parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoKey parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoKey parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoKey parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.hadoop.io.ProtoTest.ProtoKey parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.hadoop.io.ProtoTest.ProtoKey parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoKey parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.apache.hadoop.io.ProtoTest.ProtoKey prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder { + private org.apache.hadoop.io.ProtoTest.ProtoKey result; + + // Construct using org.apache.hadoop.io.ProtoTest.ProtoKey.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new org.apache.hadoop.io.ProtoTest.ProtoKey(); + return builder; + } + + protected org.apache.hadoop.io.ProtoTest.ProtoKey internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new org.apache.hadoop.io.ProtoTest.ProtoKey(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.apache.hadoop.io.ProtoTest.ProtoKey.getDescriptor(); + } + + public org.apache.hadoop.io.ProtoTest.ProtoKey getDefaultInstanceForType() { + return org.apache.hadoop.io.ProtoTest.ProtoKey.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public org.apache.hadoop.io.ProtoTest.ProtoKey build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private org.apache.hadoop.io.ProtoTest.ProtoKey buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public org.apache.hadoop.io.ProtoTest.ProtoKey buildPartial() { + if (result == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } + org.apache.hadoop.io.ProtoTest.ProtoKey returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.apache.hadoop.io.ProtoTest.ProtoKey) { + return mergeFrom((org.apache.hadoop.io.ProtoTest.ProtoKey)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.apache.hadoop.io.ProtoTest.ProtoKey other) { + if (other == org.apache.hadoop.io.ProtoTest.ProtoKey.getDefaultInstance()) return this; + if (other.hasValue()) { + setValue(other.getValue()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + return this; + } + break; + } + case 8: { + setValue(input.readInt32()); + break; + } + } + } + } + + + // required int32 value = 1; + public boolean hasValue() { + return result.hasValue(); + } + public int getValue() { + return result.getValue(); + } + public Builder setValue(int value) { + result.hasValue = true; + result.value_ = value; + return this; + } + public Builder clearValue() { + result.hasValue = false; + result.value_ = 0; + return this; + } + + // @@protoc_insertion_point(builder_scope:org.apache.hadoop.io.ProtoKey) + } + + static { + defaultInstance = new ProtoKey(true); + org.apache.hadoop.io.ProtoTest.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:org.apache.hadoop.io.ProtoKey) + } + + public static final class ProtoValue extends + com.google.protobuf.GeneratedMessage { + // Use ProtoValue.newBuilder() to construct. + private ProtoValue() { + initFields(); + } + private ProtoValue(boolean noInit) {} + + private static final ProtoValue defaultInstance; + public static ProtoValue getDefaultInstance() { + return defaultInstance; + } + + public ProtoValue getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.apache.hadoop.io.ProtoTest.internal_static_org_apache_hadoop_io_ProtoValue_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.apache.hadoop.io.ProtoTest.internal_static_org_apache_hadoop_io_ProtoValue_fieldAccessorTable; + } + + // required string value = 2; + public static final int VALUE_FIELD_NUMBER = 2; + private boolean hasValue; + private java.lang.String value_ = ""; + public boolean hasValue() { return hasValue; } + public java.lang.String getValue() { return value_; } + + private void initFields() { + } + public final boolean isInitialized() { + if (!hasValue) return false; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (hasValue()) { + output.writeString(2, getValue()); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasValue()) { + size += com.google.protobuf.CodedOutputStream + .computeStringSize(2, getValue()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + public static org.apache.hadoop.io.ProtoTest.ProtoValue parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoValue parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoValue parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoValue parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoValue parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoValue parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoValue parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.hadoop.io.ProtoTest.ProtoValue parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.hadoop.io.ProtoTest.ProtoValue parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.hadoop.io.ProtoTest.ProtoValue parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.apache.hadoop.io.ProtoTest.ProtoValue prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder { + private org.apache.hadoop.io.ProtoTest.ProtoValue result; + + // Construct using org.apache.hadoop.io.ProtoTest.ProtoValue.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new org.apache.hadoop.io.ProtoTest.ProtoValue(); + return builder; + } + + protected org.apache.hadoop.io.ProtoTest.ProtoValue internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new org.apache.hadoop.io.ProtoTest.ProtoValue(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.apache.hadoop.io.ProtoTest.ProtoValue.getDescriptor(); + } + + public org.apache.hadoop.io.ProtoTest.ProtoValue getDefaultInstanceForType() { + return org.apache.hadoop.io.ProtoTest.ProtoValue.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public org.apache.hadoop.io.ProtoTest.ProtoValue build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private org.apache.hadoop.io.ProtoTest.ProtoValue buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public org.apache.hadoop.io.ProtoTest.ProtoValue buildPartial() { + if (result == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } + org.apache.hadoop.io.ProtoTest.ProtoValue returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.apache.hadoop.io.ProtoTest.ProtoValue) { + return mergeFrom((org.apache.hadoop.io.ProtoTest.ProtoValue)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.apache.hadoop.io.ProtoTest.ProtoValue other) { + if (other == org.apache.hadoop.io.ProtoTest.ProtoValue.getDefaultInstance()) return this; + if (other.hasValue()) { + setValue(other.getValue()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + return this; + } + break; + } + case 18: { + setValue(input.readString()); + break; + } + } + } + } + + + // required string value = 2; + public boolean hasValue() { + return result.hasValue(); + } + public java.lang.String getValue() { + return result.getValue(); + } + public Builder setValue(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasValue = true; + result.value_ = value; + return this; + } + public Builder clearValue() { + result.hasValue = false; + result.value_ = getDefaultInstance().getValue(); + return this; + } + + // @@protoc_insertion_point(builder_scope:org.apache.hadoop.io.ProtoValue) + } + + static { + defaultInstance = new ProtoValue(true); + org.apache.hadoop.io.ProtoTest.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:org.apache.hadoop.io.ProtoValue) + } + + private static com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_hadoop_io_ProtoKey_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_org_apache_hadoop_io_ProtoKey_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_hadoop_io_ProtoValue_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_org_apache_hadoop_io_ProtoValue_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n2src/test/core/org/apache/hadoop/io/Pro" + + "toTest.proto\022\024org.apache.hadoop.io\"\031\n\010Pr" + + "otoKey\022\r\n\005value\030\001 \002(\005\"\033\n\nProtoValue\022\r\n\005v" + + "alue\030\002 \002(\tB\002H\001" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + internal_static_org_apache_hadoop_io_ProtoKey_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_org_apache_hadoop_io_ProtoKey_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_org_apache_hadoop_io_ProtoKey_descriptor, + new java.lang.String[] { "Value", }, + org.apache.hadoop.io.ProtoTest.ProtoKey.class, + org.apache.hadoop.io.ProtoTest.ProtoKey.Builder.class); + internal_static_org_apache_hadoop_io_ProtoValue_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_org_apache_hadoop_io_ProtoValue_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_org_apache_hadoop_io_ProtoValue_descriptor, + new java.lang.String[] { "Value", }, + org.apache.hadoop.io.ProtoTest.ProtoValue.class, + org.apache.hadoop.io.ProtoTest.ProtoValue.Builder.class); + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + } + + public static void internalForceInit() {} + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/src/test/core/org/apache/hadoop/io/ProtoTest.proto b/src/test/core/org/apache/hadoop/io/ProtoTest.proto new file mode 100644 index 0000000000000..0524bab2083e9 --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/ProtoTest.proto @@ -0,0 +1,11 @@ +package org.apache.hadoop.io; + +option optimize_for = SPEED; + +message ProtoKey { + required int32 value = 1; +} + +message ProtoValue { + required string value = 2; +} diff --git a/src/test/core/org/apache/hadoop/io/RandomDatum.java b/src/test/core/org/apache/hadoop/io/RandomDatum.java index 5a4bbc0bcd1f9..558a38629a980 100644 --- a/src/test/core/org/apache/hadoop/io/RandomDatum.java +++ b/src/test/core/org/apache/hadoop/io/RandomDatum.java @@ -39,7 +39,7 @@ public int getLength() { public void write(DataOutput out) throws IOException { out.writeInt(length); - out.write(data); + out.write(data, 0, length); } public void readFields(DataInput in) throws IOException { diff --git a/src/test/core/org/apache/hadoop/io/TestDefaultStringifier.java b/src/test/core/org/apache/hadoop/io/TestDefaultStringifier.java index c96cc732938ef..0465cc101244a 100644 --- a/src/test/core/org/apache/hadoop/io/TestDefaultStringifier.java +++ b/src/test/core/org/apache/hadoop/io/TestDefaultStringifier.java @@ -26,6 +26,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.CommonConfigurationKeysPublic; +import org.apache.hadoop.io.serial.lib.JavaSerialization; +import org.apache.hadoop.io.serial.lib.WritableSerialization; public class TestDefaultStringifier extends TestCase { @@ -36,7 +39,8 @@ public class TestDefaultStringifier extends TestCase { public void testWithWritable() throws Exception { - conf.set("io.serializations", "org.apache.hadoop.io.serializer.WritableSerialization"); + conf.set(CommonConfigurationKeysPublic.HADOOP_SERIALIZATIONS_KEY, + WritableSerialization.class.getName()); LOG.info("Testing DefaultStringifier with Text"); @@ -51,7 +55,8 @@ public void testWithWritable() throws Exception { builder.append(alphabet[random.nextInt(alphabet.length)]); } Text text = new Text(builder.toString()); - DefaultStringifier stringifier = new DefaultStringifier(conf, Text.class); + DefaultStringifier stringifier = + new DefaultStringifier(conf, Text.class); String str = stringifier.toString(text); Text claimedText = stringifier.fromString(str); @@ -62,13 +67,15 @@ public void testWithWritable() throws Exception { } public void testWithJavaSerialization() throws Exception { - conf.set("io.serializations", "org.apache.hadoop.io.serializer.JavaSerialization"); + conf.set(CommonConfigurationKeysPublic.HADOOP_SERIALIZATIONS_KEY, + JavaSerialization.class.getName()); LOG.info("Testing DefaultStringifier with Serializable Integer"); //Integer implements Serializable Integer testInt = Integer.valueOf(42); - DefaultStringifier stringifier = new DefaultStringifier(conf, Integer.class); + DefaultStringifier stringifier = + new DefaultStringifier(conf, Integer.class); String str = stringifier.toString(testInt); Integer claimedInt = stringifier.fromString(str); @@ -80,7 +87,8 @@ public void testWithJavaSerialization() throws Exception { public void testStoreLoad() throws IOException { LOG.info("Testing DefaultStringifier#store() and #load()"); - conf.set("io.serializations", "org.apache.hadoop.io.serializer.WritableSerialization"); + conf.set(CommonConfigurationKeysPublic.HADOOP_SERIALIZATIONS_KEY, + WritableSerialization.class.getName()); Text text = new Text("uninteresting test string"); String keyName = "test.defaultstringifier.key1"; @@ -94,7 +102,8 @@ public void testStoreLoad() throws IOException { public void testStoreLoadArray() throws IOException { LOG.info("Testing DefaultStringifier#storeArray() and #loadArray()"); - conf.set("io.serializations", "org.apache.hadoop.io.serializer.JavaSerialization"); + conf.set(CommonConfigurationKeysPublic.HADOOP_SERIALIZATIONS_KEY, + JavaSerialization.class.getName()); String keyName = "test.defaultstringifier.key2"; diff --git a/src/test/core/org/apache/hadoop/io/TestMapFile.java b/src/test/core/org/apache/hadoop/io/TestMapFile.java index f006d4f40131d..e4cdc25393519 100644 --- a/src/test/core/org/apache/hadoop/io/TestMapFile.java +++ b/src/test/core/org/apache/hadoop/io/TestMapFile.java @@ -36,10 +36,13 @@ public void testGetClosest() throws Exception { getName() + ".mapfile"); FileSystem fs = FileSystem.getLocal(conf); Path qualifiedDirName = fs.makeQualified(dirName); + fs.delete(qualifiedDirName, true); // Make an index entry for every third insertion. MapFile.Writer.setIndexInterval(conf, 3); - MapFile.Writer writer = new MapFile.Writer(conf, fs, - qualifiedDirName.toString(), Text.class, Text.class); + MapFile.Writer writer = + new MapFile.Writer(conf, qualifiedDirName, + MapFile.Writer.keyClass(Text.class), + MapFile.Writer.valueClass(Text.class)); // Assert that the index interval is 1 assertEquals(3, writer.getIndexInterval()); // Add entries up to 100 in intervals of ten. @@ -51,8 +54,7 @@ public void testGetClosest() throws Exception { } writer.close(); // Now do getClosest on created mapfile. - MapFile.Reader reader = new MapFile.Reader(fs, qualifiedDirName.toString(), - conf); + MapFile.Reader reader = new MapFile.Reader(qualifiedDirName, conf); Text key = new Text("55"); Text value = new Text(); Text closest = (Text)reader.getClosest(key, value); @@ -94,14 +96,16 @@ public void testMidKey() throws Exception { getName() + ".mapfile"); FileSystem fs = FileSystem.getLocal(conf); Path qualifiedDirName = fs.makeQualified(dirName); + fs.delete(qualifiedDirName, true); - MapFile.Writer writer = new MapFile.Writer(conf, fs, - qualifiedDirName.toString(), IntWritable.class, IntWritable.class); + MapFile.Writer writer = + new MapFile.Writer(conf, qualifiedDirName, + MapFile.Writer.keyClass(IntWritable.class), + MapFile.Writer.valueClass(IntWritable.class)); writer.append(new IntWritable(1), new IntWritable(1)); writer.close(); // Now do getClosest on created mapfile. - MapFile.Reader reader = new MapFile.Reader(fs, qualifiedDirName.toString(), - conf); + MapFile.Reader reader = new MapFile.Reader(qualifiedDirName, conf); assertEquals(new IntWritable(1), reader.midKey()); } @@ -112,13 +116,15 @@ public void testMidKeyEmpty() throws Exception { getName() + ".mapfile"); FileSystem fs = FileSystem.getLocal(conf); Path qualifiedDirName = fs.makeQualified(dirName); + fs.delete(qualifiedDirName, true); - MapFile.Writer writer = new MapFile.Writer(conf, fs, - qualifiedDirName.toString(), IntWritable.class, IntWritable.class); + MapFile.Writer writer = + new MapFile.Writer(conf, qualifiedDirName, + MapFile.Writer.keyClass(IntWritable.class), + MapFile.Writer.valueClass(IntWritable.class)); writer.close(); // Now do getClosest on created mapfile. - MapFile.Reader reader = new MapFile.Reader(fs, qualifiedDirName.toString(), - conf); + MapFile.Reader reader = new MapFile.Reader(qualifiedDirName, conf); assertEquals(null, reader.midKey()); } } diff --git a/src/test/core/org/apache/hadoop/io/TestSecureIOUtils.java b/src/test/core/org/apache/hadoop/io/TestSecureIOUtils.java new file mode 100644 index 0000000000000..df87507adbd29 --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/TestSecureIOUtils.java @@ -0,0 +1,83 @@ +/** + * 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.io; + +import org.apache.hadoop.fs.FileStatus; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.io.nativeio.NativeIO; + +import org.junit.BeforeClass; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assume.*; +import static org.junit.Assert.*; +import java.io.IOException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; + +public class TestSecureIOUtils { + private static String realOwner, realGroup; + private static final File testFilePath = + new File(System.getProperty("test.build.data"), "TestSecureIOContext"); + + @BeforeClass + public static void makeTestFile() throws Exception { + FileOutputStream fos = new FileOutputStream(testFilePath); + fos.write("hello".getBytes("UTF-8")); + fos.close(); + + Configuration conf = new Configuration(); + FileSystem rawFS = FileSystem.getLocal(conf).getRaw(); + FileStatus stat = rawFS.getFileStatus( + new Path(testFilePath.toString())); + realOwner = stat.getOwner(); + realGroup = stat.getGroup(); + } + + @Test + public void testReadUnrestricted() throws IOException { + SecureIOUtils.openForRead(testFilePath, null, null).close(); + } + + @Test + public void testReadCorrectlyRestrictedWithSecurity() throws IOException { + SecureIOUtils + .openForRead(testFilePath, realOwner, realGroup).close(); + } + + @Test(expected=IOException.class) + public void testReadIncorrectlyRestrictedWithSecurity() throws IOException { + SecureIOUtils + .openForRead(testFilePath, "invalidUser", null).close(); + fail("Didn't throw expection for wrong ownership!"); + } + + @Test + public void testCreateForWrite() throws IOException { + try { + SecureIOUtils.createForWrite(testFilePath, 0777); + fail("Was able to create file at " + testFilePath); + } catch (SecureIOUtils.AlreadyExistsException aee) { + // expected + } + } +} diff --git a/src/test/core/org/apache/hadoop/io/TestSequenceFileSerialization.java b/src/test/core/org/apache/hadoop/io/TestSequenceFileSerialization.java index c9fc1eae4f5ae..53aec3b04d946 100644 --- a/src/test/core/org/apache/hadoop/io/TestSequenceFileSerialization.java +++ b/src/test/core/org/apache/hadoop/io/TestSequenceFileSerialization.java @@ -20,50 +20,314 @@ import junit.framework.TestCase; +import org.apache.avro.generic.GenericRecord; +import org.apache.avro.util.Utf8; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.ProtoTest.ProtoKey; +import org.apache.hadoop.io.ProtoTest.ProtoValue; +import org.apache.hadoop.io.SequenceFile.CompressionType; import org.apache.hadoop.io.SequenceFile.Reader; import org.apache.hadoop.io.SequenceFile.Writer; +import org.apache.hadoop.io.serial.Serialization; +import org.apache.hadoop.io.serial.SerializationFactory; +import org.apache.hadoop.io.serial.lib.CompatibilitySerialization; +import org.apache.hadoop.io.serial.lib.JavaSerialization; +import org.apache.hadoop.io.serial.lib.avro.AvroSerialization; +import org.apache.hadoop.io.serial.lib.avro.AvroSerialization.Kind; public class TestSequenceFileSerialization extends TestCase { private Configuration conf; private FileSystem fs; - + private Path file; + @Override protected void setUp() throws Exception { conf = new Configuration(); - conf.set("io.serializations", - "org.apache.hadoop.io.serializer.JavaSerialization"); fs = FileSystem.getLocal(conf); + file = new Path(System.getProperty("test.build.data",".") + "/test.seq"); } @Override protected void tearDown() throws Exception { fs.close(); } - - public void testJavaSerialization() throws Exception { - Path file = new Path(System.getProperty("test.build.data",".") + - "/test.seq"); + + public void writeAvroSpecificSerialization(CompressionType kind + ) throws Exception { + AvroKey key = new AvroKey(); + AvroValue value = new AvroValue(); + fs.delete(file, true); + Writer writer = + SequenceFile.createWriter(conf, + SequenceFile.Writer.file(file), + SequenceFile.Writer.compression(kind), + SequenceFile.Writer.keyClass(AvroKey.class), + SequenceFile.Writer.valueClass(AvroValue.class)); + key.value = 1; + value.value = new Utf8("one"); + writer.append(key, value); + key.value = 2; + value.value = new Utf8("two"); + writer.append(key, value); + String writerKeySerialStr = writer.getKeySerialization().toString(); + String writerValueSerialStr = writer.getValueSerialization().toString(); + writer.close(); + + assertEquals("{schema: '{\"type\":\"record\",\"name\":\"AvroKey\"," + + "\"namespace\":\"org.apache.hadoop.io\",\"fields\":[{" + + "\"name\":\"value\",\"type\":\"int\"}]}',\n" + + " kind: SPECIFIC}\n", + writerKeySerialStr); + assertEquals("{schema: '{\"type\":\"record\",\"name\":\"AvroValue\"," + + "\"namespace\":\"org.apache.hadoop.io\",\"fields\":[{" + + "\"name\":\"value\",\"type\":\"string\"}]}',\n" + + " kind: SPECIFIC}\n", + writerValueSerialStr); + SerializationFactory factory = SerializationFactory.getInstance(conf); + Serialization keySerialClone = factory.getSerialization("avro"); + keySerialClone.fromString(writerKeySerialStr); + Serialization valueSerialClone = factory.getSerialization("avro"); + valueSerialClone.fromString(writerValueSerialStr); + + Reader reader = new Reader(conf, SequenceFile.Reader.file(file)); + Serialization keySerial = reader.getKeySerialization(); + Serialization valueSerial = reader.getValueSerialization(); + assertEquals(kind, reader.getCompressionType()); + assertEquals("avro", keySerial.getName()); + assertEquals(writerKeySerialStr, keySerial.toString()); + assertEquals(keySerialClone, keySerial); + assertEquals("avro", valueSerial.getName()); + assertEquals(writerValueSerialStr, valueSerial.toString()); + assertEquals(valueSerialClone, valueSerial); + + assertEquals(1, ((AvroKey) reader.nextKey(key)).value); + assertEquals(new Utf8("one"), + ((AvroValue) reader.getCurrentValue(value)).value); + assertEquals(2, ((AvroKey) reader.nextKey(key)).value); + assertEquals(new Utf8("two"), + ((AvroValue) reader.getCurrentValue(value)).value); + assertNull(reader.nextKey(null)); + reader.close(); + } + + public void readAvroGenericSerialization() throws Exception { + Serialization serial = new AvroSerialization(Kind.GENERIC); + Reader reader = new Reader(conf, SequenceFile.Reader.file(file), + SequenceFile.Reader.keySerialization(serial), + SequenceFile.Reader.valueSerialization(serial.clone())); + + assertEquals(1, ((GenericRecord) reader.nextKey(null)).get("value")); + assertEquals(new Utf8("one"), + ((GenericRecord) reader.getCurrentValue(null)).get("value")); + assertEquals(2, ((GenericRecord) reader.nextKey(null)).get("value")); + assertEquals(new Utf8("two"), + ((GenericRecord) reader.getCurrentValue(null)).get("value")); + assertNull(reader.nextKey(null)); + reader.close(); + } + + public void writeProtobufSerialization(CompressionType kind + ) throws Exception { fs.delete(file, true); - Writer writer = SequenceFile.createWriter(fs, conf, file, Long.class, - String.class); + Writer writer = + SequenceFile.createWriter(conf, + SequenceFile.Writer.file(file), + SequenceFile.Writer.compression(kind), + SequenceFile.Writer.keyClass(ProtoKey.class), + SequenceFile.Writer.valueClass(ProtoValue.class)); + writer.append(ProtoKey.newBuilder().setValue(1).build(), + ProtoValue.newBuilder().setValue("one").build()); + writer.append(ProtoKey.newBuilder().setValue(2).build(), + ProtoValue.newBuilder().setValue("two").build()); + String keySerialStr = writer.getKeySerialization().toString(); + assertEquals("{class: org.apache.hadoop.io.ProtoTest$ProtoKey}\n", + keySerialStr); + String valueSerialStr = writer.getValueSerialization().toString(); + assertEquals("{class: org.apache.hadoop.io.ProtoTest$ProtoValue}\n", + valueSerialStr); + writer.close(); + + // build serializers from the string form + SerializationFactory factory = SerializationFactory.getInstance(conf); + Serialization keySerial = factory.getSerialization("protobuf"); + keySerial.fromString(keySerialStr); + Serialization valueSerial = factory.getSerialization("protobuf"); + valueSerial.fromString(valueSerialStr); + + Reader reader = new Reader(conf, SequenceFile.Reader.file(file)); + assertEquals(kind, reader.getCompressionType()); + Serialization readerKeySerial = reader.getKeySerialization(); + Serialization readerValueSerial = reader.getValueSerialization(); + assertEquals("protobuf", readerKeySerial.getName()); + assertEquals(keySerialStr, readerKeySerial.toString()); + assertEquals(keySerial, readerKeySerial); + assertEquals("protobuf", readerValueSerial.getName()); + assertEquals(valueSerialStr, readerValueSerial.toString()); + assertEquals(valueSerial, readerValueSerial); + + assertEquals(ProtoKey.newBuilder().setValue(1).build(), + reader.nextKey(null)); + assertEquals(ProtoValue.newBuilder().setValue("one").build(), + reader.getCurrentValue(null)); + assertEquals(ProtoKey.newBuilder().setValue(2).build(), + reader.nextKey(null)); + assertEquals(ProtoValue.newBuilder().setValue("two").build(), + reader.getCurrentValue(null)); + assertNull(reader.nextKey(null)); + reader.close(); + } + + public void writeThriftSerialization(CompressionType kind) throws Exception { + fs.delete(file, true); + Writer writer = + SequenceFile.createWriter(conf, + SequenceFile.Writer.file(file), + SequenceFile.Writer.compression(kind), + SequenceFile.Writer.keyClass(ThriftKey.class), + SequenceFile.Writer.valueClass(ThriftValue.class)); + writer.append(new ThriftKey(1), new ThriftValue("one")); + writer.append(new ThriftKey(2), new ThriftValue("two")); + writer.close(); + + Reader reader = new Reader(conf, SequenceFile.Reader.file(file)); + assertEquals(kind, reader.getCompressionType()); + assertEquals("thrift", reader.getKeySerialization().getName()); + assertEquals("thrift", reader.getValueSerialization().getName()); + assertEquals(new ThriftKey(1), reader.nextKey(null)); + assertEquals(new ThriftValue("one"), reader.getCurrentValue(null)); + assertEquals(new ThriftKey(2), reader.nextKey(null)); + assertEquals(new ThriftValue("two"), reader.getCurrentValue(null)); + assertNull(reader.nextKey(null)); + reader.close(); + } + + public void writeWritableSerialization(CompressionType kind + ) throws Exception { + fs.delete(file, true); + Writer writer = + SequenceFile.createWriter(conf, + SequenceFile.Writer.file(file), + SequenceFile.Writer.compression(kind), + SequenceFile.Writer.keyClass(IntWritable.class), + SequenceFile.Writer.valueClass(Text.class)); + writer.append(new IntWritable(1), new Text("one")); + writer.append(new IntWritable(2), new Text("two")); + writer.close(); + + Reader reader = new Reader(conf, SequenceFile.Reader.file(file)); + assertEquals(kind, reader.getCompressionType()); + assertEquals("writable", reader.getKeySerialization().getName()); + assertEquals("writable", reader.getValueSerialization().getName()); + assertEquals(new IntWritable(1), reader.nextKey(null)); + assertEquals(new Text("one"), reader.getCurrentValue(null)); + assertEquals(new IntWritable(2), reader.nextKey(null)); + assertEquals(new Text("two"), reader.getCurrentValue(null)); + assertNull(reader.nextKey(null)); + reader.close(); + } + + public void writeJavaSerialization(CompressionType kind) throws Exception { + fs.delete(file, true); + conf.set(CommonConfigurationKeysPublic.HADOOP_SERIALIZATIONS_KEY, + JavaSerialization.class.getName()); + Writer writer = + SequenceFile.createWriter(conf, + SequenceFile.Writer.file(file), + SequenceFile.Writer.compression(kind), + SequenceFile.Writer.keyClass(Long.class), + SequenceFile.Writer.valueClass(String.class)); writer.append(1L, "one"); writer.append(2L, "two"); - writer.close(); - Reader reader = new Reader(fs, file, conf); - assertEquals(1L, reader.next((Object) null)); + Reader reader = new Reader(conf, SequenceFile.Reader.file(file)); + assertEquals(kind, reader.getCompressionType()); + assertEquals("java", reader.getKeySerialization().getName()); + assertEquals("java", reader.getValueSerialization().getName()); + assertEquals(1L, reader.nextKey(null)); assertEquals("one", reader.getCurrentValue((Object) null)); - assertEquals(2L, reader.next((Object) null)); + assertEquals(2L, reader.nextKey(null)); assertEquals("two", reader.getCurrentValue((Object) null)); - assertNull(reader.next((Object) null)); + assertNull(reader.nextKey(null)); reader.close(); } + + /** + * Test the compatibility layer to load the old java serialization. + */ + public void writeOldJavaSerialization(CompressionType kind + ) throws Exception { + fs.delete(file, true); + // set the old attribute to include the java serialization + conf.set("io.serializations", + "org.apache.hadoop.io.serializer.JavaSerialization"); + SerializationFactory factory = SerializationFactory.getInstance(conf); + Serialization serial = factory.getSerializationByType(Long.class); + assertEquals(CompatibilitySerialization.class, serial.getClass()); + + Writer writer = + SequenceFile.createWriter(conf, + SequenceFile.Writer.file(file), + SequenceFile.Writer.compression(kind), + SequenceFile.Writer.keyClass(Long.class), + SequenceFile.Writer.valueClass(String.class)); + writer.append(1L, "one"); + writer.append(2L, "two"); + writer.close(); + + Reader reader = new Reader(conf, SequenceFile.Reader.file(file)); + assertEquals("compatibility", reader.getKeySerialization().getName()); + assertEquals("compatibility", reader.getValueSerialization().getName()); + assertEquals(kind, reader.getCompressionType()); + assertEquals(1L, reader.nextKey(null)); + assertEquals("one", reader.getCurrentValue((Object) null)); + assertEquals(2L, reader.nextKey(null)); + assertEquals("two", reader.getCurrentValue((Object) null)); + assertNull(reader.nextKey(null)); + reader.close(); + } + + public void testAvro() throws Exception { + writeAvroSpecificSerialization(CompressionType.NONE); + readAvroGenericSerialization(); + writeAvroSpecificSerialization(CompressionType.RECORD); + writeAvroSpecificSerialization(CompressionType.BLOCK); + } + + public void testProtobuf() throws Exception { + writeProtobufSerialization(CompressionType.NONE); + writeProtobufSerialization(CompressionType.RECORD); + writeProtobufSerialization(CompressionType.BLOCK); + } + + public void testThrift() throws Exception { + writeThriftSerialization(CompressionType.NONE); + writeThriftSerialization(CompressionType.RECORD); + writeThriftSerialization(CompressionType.BLOCK); + } + + public void testWritable() throws Exception { + writeWritableSerialization(CompressionType.NONE); + writeWritableSerialization(CompressionType.RECORD); + writeWritableSerialization(CompressionType.BLOCK); + } + + public void testJava() throws Exception { + writeJavaSerialization(CompressionType.NONE); + writeJavaSerialization(CompressionType.RECORD); + writeJavaSerialization(CompressionType.BLOCK); + } + + public void testOldJava() throws Exception { + writeOldJavaSerialization(CompressionType.NONE); + writeOldJavaSerialization(CompressionType.RECORD); + writeOldJavaSerialization(CompressionType.BLOCK); + } } diff --git a/src/test/core/org/apache/hadoop/io/ThriftKey.java b/src/test/core/org/apache/hadoop/io/ThriftKey.java new file mode 100644 index 0000000000000..b4a3fe28edf27 --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/ThriftKey.java @@ -0,0 +1,307 @@ +/** + * Autogenerated by Thrift + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + */ +package org.apache.hadoop.io; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.util.EnumMap; +import java.util.Set; +import java.util.HashSet; +import java.util.EnumSet; +import java.util.Collections; +import java.util.BitSet; +import java.nio.ByteBuffer; +import java.util.Arrays; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.thrift.*; +import org.apache.thrift.async.*; +import org.apache.thrift.meta_data.*; +import org.apache.thrift.transport.*; +import org.apache.thrift.protocol.*; + +public class ThriftKey implements TBase, java.io.Serializable, Cloneable { + private static final TStruct STRUCT_DESC = new TStruct("ThriftKey"); + + private static final TField VALUE_FIELD_DESC = new TField("value", TType.I32, (short)1); + + public int value; + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements TFieldIdEnum { + VALUE((short)1, "value"); + + private static final Map byName = new HashMap(); + + static { + for (_Fields field : EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // VALUE + return VALUE; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(String name) { + return byName.get(name); + } + + private final short _thriftId; + private final String _fieldName; + + _Fields(short thriftId, String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + private static final int __VALUE_ISSET_ID = 0; + private BitSet __isset_bit_vector = new BitSet(1); + + public static final Map<_Fields, FieldMetaData> metaDataMap; + static { + Map<_Fields, FieldMetaData> tmpMap = new EnumMap<_Fields, FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.VALUE, new FieldMetaData("value", TFieldRequirementType.DEFAULT, + new FieldValueMetaData(TType.I32))); + metaDataMap = Collections.unmodifiableMap(tmpMap); + FieldMetaData.addStructMetaDataMap(ThriftKey.class, metaDataMap); + } + + public ThriftKey() { + } + + public ThriftKey( + int value) + { + this(); + this.value = value; + setValueIsSet(true); + } + + /** + * Performs a deep copy on other. + */ + public ThriftKey(ThriftKey other) { + __isset_bit_vector.clear(); + __isset_bit_vector.or(other.__isset_bit_vector); + this.value = other.value; + } + + public ThriftKey deepCopy() { + return new ThriftKey(this); + } + + @Override + public void clear() { + setValueIsSet(false); + this.value = 0; + } + + public int getValue() { + return this.value; + } + + public ThriftKey setValue(int value) { + this.value = value; + setValueIsSet(true); + return this; + } + + public void unsetValue() { + __isset_bit_vector.clear(__VALUE_ISSET_ID); + } + + /** Returns true if field value is set (has been asigned a value) and false otherwise */ + public boolean isSetValue() { + return __isset_bit_vector.get(__VALUE_ISSET_ID); + } + + public void setValueIsSet(boolean value) { + __isset_bit_vector.set(__VALUE_ISSET_ID, value); + } + + public void setFieldValue(_Fields field, Object value) { + switch (field) { + case VALUE: + if (value == null) { + unsetValue(); + } else { + setValue((Integer)value); + } + break; + + } + } + + public Object getFieldValue(_Fields field) { + switch (field) { + case VALUE: + return new Integer(getValue()); + + } + throw new IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been asigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new IllegalArgumentException(); + } + + switch (field) { + case VALUE: + return isSetValue(); + } + throw new IllegalStateException(); + } + + @Override + public boolean equals(Object that) { + if (that == null) + return false; + if (that instanceof ThriftKey) + return this.equals((ThriftKey)that); + return false; + } + + public boolean equals(ThriftKey that) { + if (that == null) + return false; + + boolean this_present_value = true; + boolean that_present_value = true; + if (this_present_value || that_present_value) { + if (!(this_present_value && that_present_value)) + return false; + if (this.value != that.value) + return false; + } + + return true; + } + + @Override + public int hashCode() { + return 0; + } + + public int compareTo(ThriftKey other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + ThriftKey typedOther = (ThriftKey)other; + + lastComparison = Boolean.valueOf(isSetValue()).compareTo(typedOther.isSetValue()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetValue()) { + lastComparison = TBaseHelper.compareTo(this.value, typedOther.value); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(TProtocol iprot) throws TException { + TField field; + iprot.readStructBegin(); + while (true) + { + field = iprot.readFieldBegin(); + if (field.type == TType.STOP) { + break; + } + switch (field.id) { + case 1: // VALUE + if (field.type == TType.I32) { + this.value = iprot.readI32(); + setValueIsSet(true); + } else { + TProtocolUtil.skip(iprot, field.type); + } + break; + default: + TProtocolUtil.skip(iprot, field.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + validate(); + } + + public void write(TProtocol oprot) throws TException { + validate(); + + oprot.writeStructBegin(STRUCT_DESC); + oprot.writeFieldBegin(VALUE_FIELD_DESC); + oprot.writeI32(this.value); + oprot.writeFieldEnd(); + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("ThriftKey("); + boolean first = true; + + sb.append("value:"); + sb.append(this.value); + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws TException { + // check for required fields + } + +} + diff --git a/src/test/core/org/apache/hadoop/io/ThriftValue.java b/src/test/core/org/apache/hadoop/io/ThriftValue.java new file mode 100644 index 0000000000000..efb2b4ad47fc9 --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/ThriftValue.java @@ -0,0 +1,309 @@ +/** + * Autogenerated by Thrift + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + */ +package org.apache.hadoop.io; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.util.EnumMap; +import java.util.Set; +import java.util.HashSet; +import java.util.EnumSet; +import java.util.Collections; +import java.util.BitSet; +import java.nio.ByteBuffer; +import java.util.Arrays; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.thrift.*; +import org.apache.thrift.async.*; +import org.apache.thrift.meta_data.*; +import org.apache.thrift.transport.*; +import org.apache.thrift.protocol.*; + +public class ThriftValue implements TBase, java.io.Serializable, Cloneable { + private static final TStruct STRUCT_DESC = new TStruct("ThriftValue"); + + private static final TField VALUE_FIELD_DESC = new TField("value", TType.STRING, (short)1); + + public String value; + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements TFieldIdEnum { + VALUE((short)1, "value"); + + private static final Map byName = new HashMap(); + + static { + for (_Fields field : EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // VALUE + return VALUE; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(String name) { + return byName.get(name); + } + + private final short _thriftId; + private final String _fieldName; + + _Fields(short thriftId, String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + + public static final Map<_Fields, FieldMetaData> metaDataMap; + static { + Map<_Fields, FieldMetaData> tmpMap = new EnumMap<_Fields, FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.VALUE, new FieldMetaData("value", TFieldRequirementType.DEFAULT, + new FieldValueMetaData(TType.STRING))); + metaDataMap = Collections.unmodifiableMap(tmpMap); + FieldMetaData.addStructMetaDataMap(ThriftValue.class, metaDataMap); + } + + public ThriftValue() { + } + + public ThriftValue( + String value) + { + this(); + this.value = value; + } + + /** + * Performs a deep copy on other. + */ + public ThriftValue(ThriftValue other) { + if (other.isSetValue()) { + this.value = other.value; + } + } + + public ThriftValue deepCopy() { + return new ThriftValue(this); + } + + @Override + public void clear() { + this.value = null; + } + + public String getValue() { + return this.value; + } + + public ThriftValue setValue(String value) { + this.value = value; + return this; + } + + public void unsetValue() { + this.value = null; + } + + /** Returns true if field value is set (has been asigned a value) and false otherwise */ + public boolean isSetValue() { + return this.value != null; + } + + public void setValueIsSet(boolean value) { + if (!value) { + this.value = null; + } + } + + public void setFieldValue(_Fields field, Object value) { + switch (field) { + case VALUE: + if (value == null) { + unsetValue(); + } else { + setValue((String)value); + } + break; + + } + } + + public Object getFieldValue(_Fields field) { + switch (field) { + case VALUE: + return getValue(); + + } + throw new IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been asigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new IllegalArgumentException(); + } + + switch (field) { + case VALUE: + return isSetValue(); + } + throw new IllegalStateException(); + } + + @Override + public boolean equals(Object that) { + if (that == null) + return false; + if (that instanceof ThriftValue) + return this.equals((ThriftValue)that); + return false; + } + + public boolean equals(ThriftValue that) { + if (that == null) + return false; + + boolean this_present_value = true && this.isSetValue(); + boolean that_present_value = true && that.isSetValue(); + if (this_present_value || that_present_value) { + if (!(this_present_value && that_present_value)) + return false; + if (!this.value.equals(that.value)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + return 0; + } + + public int compareTo(ThriftValue other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + ThriftValue typedOther = (ThriftValue)other; + + lastComparison = Boolean.valueOf(isSetValue()).compareTo(typedOther.isSetValue()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetValue()) { + lastComparison = TBaseHelper.compareTo(this.value, typedOther.value); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(TProtocol iprot) throws TException { + TField field; + iprot.readStructBegin(); + while (true) + { + field = iprot.readFieldBegin(); + if (field.type == TType.STOP) { + break; + } + switch (field.id) { + case 1: // VALUE + if (field.type == TType.STRING) { + this.value = iprot.readString(); + } else { + TProtocolUtil.skip(iprot, field.type); + } + break; + default: + TProtocolUtil.skip(iprot, field.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + validate(); + } + + public void write(TProtocol oprot) throws TException { + validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (this.value != null) { + oprot.writeFieldBegin(VALUE_FIELD_DESC); + oprot.writeString(this.value); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("ThriftValue("); + boolean first = true; + + sb.append("value:"); + if (this.value == null) { + sb.append("null"); + } else { + sb.append(this.value); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws TException { + // check for required fields + } + +} + diff --git a/src/test/core/org/apache/hadoop/io/file/tfile/TestTFileJClassComparatorByteArrays.java b/src/test/core/org/apache/hadoop/io/file/tfile/TestTFileJClassComparatorByteArrays.java index f47ec7034c503..8c219174bdc35 100644 --- a/src/test/core/org/apache/hadoop/io/file/tfile/TestTFileJClassComparatorByteArrays.java +++ b/src/test/core/org/apache/hadoop/io/file/tfile/TestTFileJClassComparatorByteArrays.java @@ -43,6 +43,7 @@ public void setUp() throws IOException { } } +@SuppressWarnings("serial") class MyComparator implements RawComparator, Serializable { @Override @@ -54,6 +55,6 @@ public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { public int compare(byte[] o1, byte[] o2) { return WritableComparator.compareBytes(o1, 0, o1.length, o2, 0, o2.length); } - + } diff --git a/src/test/core/org/apache/hadoop/io/nativeio/TestNativeIO.java b/src/test/core/org/apache/hadoop/io/nativeio/TestNativeIO.java new file mode 100644 index 0000000000000..972c9fc25c85a --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/nativeio/TestNativeIO.java @@ -0,0 +1,137 @@ +/** + * 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.io.nativeio; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assume.*; +import static org.junit.Assert.*; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.fs.FileUtil; +import org.apache.hadoop.util.NativeCodeLoader; + +public class TestNativeIO { + static final Log LOG = LogFactory.getLog(TestNativeIO.class); + + static final File TEST_DIR = new File( + System.getProperty("test.build.data"), "testnativeio"); + + @Before + public void checkLoaded() { + assumeTrue(NativeCodeLoader.isNativeCodeLoaded()); + } + + @Before + public void setupTestDir() throws IOException { + FileUtil.fullyDelete(TEST_DIR); + TEST_DIR.mkdirs(); + } + + @Test + public void testFstat() throws Exception { + FileOutputStream fos = new FileOutputStream( + new File(TEST_DIR, "testfstat")); + NativeIO.Stat stat = NativeIO.fstat(fos.getFD()); + fos.close(); + LOG.info("Stat: " + String.valueOf(stat)); + + assertEquals(System.getProperty("user.name"), stat.getOwner()); + assertNotNull(stat.getGroup()); + assertTrue(!"".equals(stat.getGroup())); + assertEquals("Stat mode field should indicate a regular file", + NativeIO.Stat.S_IFREG, stat.getMode() & NativeIO.Stat.S_IFMT); + } + + @Test + public void testFstatClosedFd() throws Exception { + FileOutputStream fos = new FileOutputStream( + new File(TEST_DIR, "testfstat2")); + fos.close(); + try { + NativeIO.Stat stat = NativeIO.fstat(fos.getFD()); + } catch (NativeIOException nioe) { + LOG.info("Got expected exception", nioe); + assertEquals(Errno.EBADF, nioe.getErrno()); + } + } + + @Test + public void testOpenMissingWithoutCreate() throws Exception { + LOG.info("Open a missing file without O_CREAT and it should fail"); + try { + FileDescriptor fd = NativeIO.open( + new File(TEST_DIR, "doesntexist").getAbsolutePath(), + NativeIO.O_WRONLY, 0700); + fail("Able to open a new file without O_CREAT"); + } catch (NativeIOException nioe) { + LOG.info("Got expected exception", nioe); + assertEquals(Errno.ENOENT, nioe.getErrno()); + } + } + + @Test + public void testOpenWithCreate() throws Exception { + LOG.info("Test creating a file with O_CREAT"); + FileDescriptor fd = NativeIO.open( + new File(TEST_DIR, "testWorkingOpen").getAbsolutePath(), + NativeIO.O_WRONLY | NativeIO.O_CREAT, 0700); + assertNotNull(true); + assertTrue(fd.valid()); + FileOutputStream fos = new FileOutputStream(fd); + fos.write("foo".getBytes()); + fos.close(); + + assertFalse(fd.valid()); + + LOG.info("Test exclusive create"); + try { + fd = NativeIO.open( + new File(TEST_DIR, "testWorkingOpen").getAbsolutePath(), + NativeIO.O_WRONLY | NativeIO.O_CREAT | NativeIO.O_EXCL, 0700); + fail("Was able to create existing file with O_EXCL"); + } catch (NativeIOException nioe) { + LOG.info("Got expected exception for failed exclusive create", nioe); + assertEquals(Errno.EEXIST, nioe.getErrno()); + } + } + + /** + * Test that opens and closes a file 10000 times - this would crash with + * "Too many open files" if we leaked fds using this access pattern. + */ + @Test + public void testFDDoesntLeak() throws IOException { + for (int i = 0; i < 10000; i++) { + FileDescriptor fd = NativeIO.open( + new File(TEST_DIR, "testNoFdLeak").getAbsolutePath(), + NativeIO.O_WRONLY | NativeIO.O_CREAT, 0700); + assertNotNull(true); + assertTrue(fd.valid()); + FileOutputStream fos = new FileOutputStream(fd); + fos.write("foo".getBytes()); + fos.close(); + } + } + +} diff --git a/src/test/core/org/apache/hadoop/io/test.genavro b/src/test/core/org/apache/hadoop/io/test.genavro new file mode 100644 index 0000000000000..bc694d9094ab8 --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/test.genavro @@ -0,0 +1,10 @@ +@namespace("org.apache.hadoop.io") +protocol AvroTest { + record AvroKey { + int value; + } + + record AvroValue { + string value; + } +} diff --git a/src/test/core/org/apache/hadoop/io/test.thrift b/src/test/core/org/apache/hadoop/io/test.thrift new file mode 100644 index 0000000000000..5858521d5f0d6 --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/test.thrift @@ -0,0 +1,7 @@ +namespace java org.apache.hadoop.io +struct ThriftKey { + 1: i32 value +} +struct ThriftValue { + 1: string value +} diff --git a/src/test/findbugsExcludeFile.xml b/src/test/findbugsExcludeFile.xml index 615f52179c9bf..a43c17fce3e71 100644 --- a/src/test/findbugsExcludeFile.xml +++ b/src/test/findbugsExcludeFile.xml @@ -192,6 +192,16 @@ + + + + + + + + + +