diff --git a/src/main/java/org/apache/hadoop/hbase/io/HbaseObjectWritable.java b/src/main/java/org/apache/hadoop/hbase/io/HbaseObjectWritable.java index 90dfb843f38..260f982a426 100644 --- a/src/main/java/org/apache/hadoop/hbase/io/HbaseObjectWritable.java +++ b/src/main/java/org/apache/hadoop/hbase/io/HbaseObjectWritable.java @@ -123,6 +123,14 @@ public class HbaseObjectWritable implements Writable, WritableWithSize, Configur // sending of the class name using reflection, etc. private static final byte NOT_ENCODED = 0; static { + //////////////////////////////////////////////////////////////////////////// + // WARNING: Please do not insert, remove or swap any line in this static // + // block. Doing so would change or shift all the codes used to serialize // + // objects, which makes backwards compatibility very hard for clients. // + // New codes should always be added at the end. Code removal is // + // discouraged because code is a short now. // + //////////////////////////////////////////////////////////////////////////// + int code = NOT_ENCODED + 1; // Primitive types. addToMap(Boolean.TYPE, code++); @@ -165,7 +173,6 @@ public class HbaseObjectWritable implements Writable, WritableWithSize, Configur addToMap(HServerAddress.class, code++); addToMap(HServerInfo.class, code++); addToMap(HTableDescriptor.class, code++); - addToMap(HTableDescriptor[].class, code++); addToMap(MapWritable.class, code++); // @@ -222,7 +229,7 @@ public class HbaseObjectWritable implements Writable, WritableWithSize, Configur addToMap(Increment.class, code++); addToMap(KeyOnlyFilter.class, code++); - + // serializable addToMap(Serializable.class, code++); @@ -236,6 +243,8 @@ public class HbaseObjectWritable implements Writable, WritableWithSize, Configur addToMap(RegionOpeningState.class, code++); + addToMap(HTableDescriptor[].class, code++); + addToMap(Append.class, code++); addToMap(RowMutation.class, code++); @@ -593,7 +602,7 @@ public class HbaseObjectWritable implements Writable, WritableWithSize, Configur in.readFully(objectBytes); ByteArrayInputStream bis = null; ObjectInputStream ois = null; - try { + try { bis = new ByteArrayInputStream(objectBytes); ois = new ObjectInputStream(bis); instance = ois.readObject(); diff --git a/src/main/java/org/apache/hadoop/hbase/ipc/HBaseServer.java b/src/main/java/org/apache/hadoop/hbase/ipc/HBaseServer.java index c2cacd97664..e20ec4346e2 100644 --- a/src/main/java/org/apache/hadoop/hbase/ipc/HBaseServer.java +++ b/src/main/java/org/apache/hadoop/hbase/ipc/HBaseServer.java @@ -1213,9 +1213,10 @@ public abstract class HBaseServer implements RpcServer { header.readFields(in); try { String protocolClassName = header.getProtocol(); - if (protocolClassName != null) { - protocol = getProtocolClass(header.getProtocol(), conf); + if (protocolClassName == null) { + protocolClassName = "org.apache.hadoop.hbase.ipc.HRegionInterface"; } + protocol = getProtocolClass(protocolClassName, conf); } catch (ClassNotFoundException cnfe) { throw new IOException("Unknown protocol: " + header.getProtocol()); } diff --git a/src/main/java/org/apache/hadoop/hbase/ipc/Invocation.java b/src/main/java/org/apache/hadoop/hbase/ipc/Invocation.java index 39c73f53fb6..055787e560d 100644 --- a/src/main/java/org/apache/hadoop/hbase/ipc/Invocation.java +++ b/src/main/java/org/apache/hadoop/hbase/ipc/Invocation.java @@ -22,6 +22,7 @@ package org.apache.hadoop.hbase.ipc; import org.apache.hadoop.conf.Configurable; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.io.HbaseObjectWritable; +import org.apache.hadoop.io.VersionMismatchException; import org.apache.hadoop.io.VersionedWritable; import java.io.DataInput; @@ -94,10 +95,29 @@ public class Invocation extends VersionedWritable implements Configurable { } public void readFields(DataInput in) throws IOException { - super.readFields(in); - methodName = in.readUTF(); - clientVersion = in.readLong(); - clientMethodsHash = in.readInt(); + try { + super.readFields(in); + methodName = in.readUTF(); + clientVersion = in.readLong(); + clientMethodsHash = in.readInt(); + } catch (VersionMismatchException e) { + // VersionMismatchException doesn't provide an API to access + // expectedVersion and foundVersion. This is really sad. + if (e.toString().endsWith("found v0")) { + // Try to be a bit backwards compatible. In previous versions of + // HBase (before HBASE-3939 in 0.92) Invocation wasn't a + // VersionedWritable and thus the first thing on the wire was always + // the 2-byte length of the method name. Because no method name is + // longer than 255 characters, and all method names are in ASCII, + // The following code is equivalent to `in.readUTF()', which we can't + // call again here, because `super.readFields(in)' already consumed + // the first byte of input, which can't be "unread" back into `in'. + final short len = (short) (in.readByte() & 0xFF); // Unsigned byte. + final byte[] buf = new byte[len]; + in.readFully(buf, 0, len); + methodName = new String(buf); + } + } parameters = new Object[in.readInt()]; parameterClasses = new Class[parameters.length]; HbaseObjectWritable objectWritable = new HbaseObjectWritable();