This is an automated email from the ASF dual-hosted git repository. udo pushed a commit to branch feature/GEODE-5705 in repository https://gitbox.apache.org/repos/asf/geode.git
commit 6b7827305df6db2701f105e7157dcb4b22434622 Author: Udo Kohlmeyer <[email protected]> AuthorDate: Thu Dec 6 13:05:01 2018 -0800 Revert "GEODE-5705: Improve basicReadObject to use switch statement rather than if statements." This reverts commit c699e46e --- .../main/java/org/apache/geode/DataSerializer.java | 3 +- .../geode/internal/InternalDataSerializer.java | 1620 ++++++++++---------- .../apache/geode/internal/util/DscodeHelper.java | 38 - .../java/org/apache/geode/internal/DSCODETest.java | 18 - 4 files changed, 853 insertions(+), 826 deletions(-) diff --git a/geode-core/src/main/java/org/apache/geode/DataSerializer.java b/geode-core/src/main/java/org/apache/geode/DataSerializer.java index 430e2f9..45a757a 100644 --- a/geode-core/src/main/java/org/apache/geode/DataSerializer.java +++ b/geode-core/src/main/java/org/apache/geode/DataSerializer.java @@ -1481,7 +1481,8 @@ public abstract class DataSerializer { * @since GemFire 5.7 */ public static void writeCharArray(char[] array, DataOutput out) throws IOException { - InternalDataSerializer.writeCharArray(array, out); + + InternalDataSerializer.writeCharArray(array, array != null ? array.length : -1, out); } /** diff --git a/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java b/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java index 66a9754..72a1bc0 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java +++ b/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java @@ -106,7 +106,6 @@ import org.apache.geode.internal.lang.ClassUtils; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.log4j.LocalizedMessage; import org.apache.geode.internal.logging.log4j.LogMarker; -import org.apache.geode.internal.util.DscodeHelper; import org.apache.geode.internal.util.concurrent.CopyOnWriteHashMap; import org.apache.geode.pdx.NonPortableClassException; import org.apache.geode.pdx.PdxInstance; @@ -132,22 +131,15 @@ import org.apache.geode.pdx.internal.TypeRegistry; * @since GemFire 3.5 */ public abstract class InternalDataSerializer extends DataSerializer { - // array is null - public static final byte NULL_ARRAY = -1; - /** - * array len encoded as int in next 4 bytes - * - * @since GemFire 5.7 - */ - public static final byte INT_ARRAY_LEN = -3; - public static final boolean LOAD_CLASS_EACH_TIME = - Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "loadClassOnEveryDeserialization"); private static final Logger logger = LogService.getLogger(); + /** * Maps Class names to their DataSerializer. This is used to find a DataSerializer during * serialization. */ private static final Map<String, DataSerializer> classesToSerializers = new ConcurrentHashMap<>(); + + /** * This list contains classes that Geode's classes subclass, such as antlr AST classes which are * used by our Object Query Language. It also contains certain classes that are DataSerializable @@ -199,80 +191,22 @@ public abstract class InternalDataSerializer extends DataSerializer { // geode-modules + ";org.apache.geode.modules.util.SessionCustomExpiry" + ";"; - private static final String serializationVersionTxt = - System.getProperty(DistributionConfig.GEMFIRE_PREFIX + "serializationVersion"); - /** - * Change this constant to be the last one in SERIALIZATION_VERSION - */ - private static final SERIALIZATION_VERSION latestVersion = SERIALIZATION_VERSION.v662; - private static final SERIALIZATION_VERSION serializationVersion = calculateSerializationVersion(); - /** - * Maps the id of a serializer to its {@code DataSerializer}. - */ - private static final ConcurrentMap/* <Integer, DataSerializer|Marker> */ idsToSerializers = - new ConcurrentHashMap(); - /** - * Contains the classnames of the data serializers (and not the supported classes) not yet loaded - * into the vm as keys and their corresponding holder instances as values. - */ - private static final ConcurrentHashMap<String, SerializerAttributesHolder> dsClassesToHolders = - new ConcurrentHashMap<>(); - /** - * Contains the id of the data serializers not yet loaded into the vm as keys and their - * corresponding holder instances as values. - */ - private static final ConcurrentHashMap<Integer, SerializerAttributesHolder> idsToHolders = - new ConcurrentHashMap<>(); - /** - * Contains the classnames of supported classes as keys and their corresponding - * SerializerAttributesHolder instances as values. This applies only to the data serializers which - * have not been loaded into the vm. - */ - private static final ConcurrentHashMap<String, SerializerAttributesHolder> supportedClassesToHolders = - new ConcurrentHashMap<>(); - private static final Object listenersSync = new Object(); - private static final byte TIME_UNIT_NANOSECONDS = -1; - private static final byte TIME_UNIT_MICROSECONDS = -2; - private static final byte TIME_UNIT_MILLISECONDS = -3; - private static final byte TIME_UNIT_SECONDS = -4; - private static final ConcurrentMap dsfidToClassMap = - logger.isTraceEnabled(LogMarker.SERIALIZER_WRITE_DSFID_VERBOSE) ? new ConcurrentHashMap() - : null; - /** - * array len encoded as unsigned short in next 2 bytes - * - * @since GemFire 5.7 - */ - private static final byte SHORT_ARRAY_LEN = -2; - private static final int MAX_BYTE_ARRAY_LEN = (byte) -4 & 0xFF; - private static final ThreadLocal<Boolean> pdxSerializationInProgress = new ThreadLocal<>(); - // Variable Length long encoded as int in next 4 bytes - private static final byte INT_VL = 126; - // Variable Length long encoded as long in next 8 bytes - private static final byte LONG_VL = 127; - private static final int MAX_BYTE_VL = 125; - private static final CopyOnWriteHashMap<String, WeakReference<Class<?>>> classCache = - LOAD_CLASS_EACH_TIME ? null : new CopyOnWriteHashMap<>(); - private static final Object cacheAccessLock = new Object(); + + private static InputStreamFilter defaultSerializationFilter = new EmptyInputStreamFilter(); + /** * A deserialization filter for ObjectInputStreams */ private static InputStreamFilter serializationFilter = defaultSerializationFilter; + + private static final String serializationVersionTxt = + System.getProperty(DistributionConfig.GEMFIRE_PREFIX + "serializationVersion"); + /** * support for old GemFire clients and WAN sites - needed to enable moving from GemFire to Geode */ private static OldClientSupportService oldClientSupportService; - /** - * {@code RegistrationListener}s that receive callbacks when {@code DataSerializer}s and {@code - * Instantiator}s are registered. Note: copy-on-write access used for this set - */ - private static volatile Set listeners = new HashSet(); - private static DataSerializer dvddeserializer; - - static { - initializeWellKnownSerializers(); - } /** * For backward compatibility we must swizzle the package of some classes that had to be moved @@ -347,6 +281,7 @@ public abstract class InternalDataSerializer extends DataSerializer { serializationFilter = defaultSerializationFilter; } + /** * {@link DistributedSystemService}s that need to acceptlist Serializable objects can use this to * read them from a file and then return them via @@ -376,6 +311,25 @@ public abstract class InternalDataSerializer extends DataSerializer { } + + /** + * Any time new serialization format is added then a new enum needs to be added here. + * + * @since GemFire 6.6.2 + */ + private enum SERIALIZATION_VERSION { + vINVALID, + // includes 6.6.0.x and 6.6.1.x. Note that no serialization changes were made in 6.6 until 6.6.2 + v660, + // 6.6.2.x or later NOTE if you add a new constant make sure and update "latestVersion". + v662 + } + + /** + * Change this constant to be the last one in SERIALIZATION_VERSION + */ + private static final SERIALIZATION_VERSION latestVersion = SERIALIZATION_VERSION.v662; + private static SERIALIZATION_VERSION calculateSerializationVersion() { if (serializationVersionTxt == null || serializationVersionTxt.isEmpty()) { return latestVersion; @@ -389,6 +343,8 @@ public abstract class InternalDataSerializer extends DataSerializer { } } + private static final SERIALIZATION_VERSION serializationVersion = calculateSerializationVersion(); + public static boolean is662SerializationEnabled() { return serializationVersion.ordinal() >= SERIALIZATION_VERSION.v662.ordinal(); } @@ -402,6 +358,10 @@ public abstract class InternalDataSerializer extends DataSerializer { } } + static { + initializeWellKnownSerializers(); + } + private static void initializeWellKnownSerializers() { // ArrayBlockingQueue does not have zero-arg constructor // LinkedBlockingQueue does have zero-arg constructor but no way to get capacity @@ -809,6 +769,42 @@ public abstract class InternalDataSerializer extends DataSerializer { } /** + * Maps the id of a serializer to its {@code DataSerializer}. + */ + private static final ConcurrentMap/* <Integer, DataSerializer|Marker> */ idsToSerializers = + new ConcurrentHashMap(); + + /** + * Contains the classnames of the data serializers (and not the supported classes) not yet loaded + * into the vm as keys and their corresponding holder instances as values. + */ + private static final ConcurrentHashMap<String, SerializerAttributesHolder> dsClassesToHolders = + new ConcurrentHashMap<>(); + + /** + * Contains the id of the data serializers not yet loaded into the vm as keys and their + * corresponding holder instances as values. + */ + private static final ConcurrentHashMap<Integer, SerializerAttributesHolder> idsToHolders = + new ConcurrentHashMap<>(); + + /** + * Contains the classnames of supported classes as keys and their corresponding + * SerializerAttributesHolder instances as values. This applies only to the data serializers which + * have not been loaded into the vm. + */ + private static final ConcurrentHashMap<String, SerializerAttributesHolder> supportedClassesToHolders = + new ConcurrentHashMap<>(); + + /** + * {@code RegistrationListener}s that receive callbacks when {@code DataSerializer}s and {@code + * Instantiator}s are registered. Note: copy-on-write access used for this set + */ + private static volatile Set listeners = new HashSet(); + + private static final Object listenersSync = new Object(); + + /** * Convert the given unsigned byte to an int. The returned value will be in the range [0..255] * inclusive */ @@ -816,14 +812,14 @@ public abstract class InternalDataSerializer extends DataSerializer { return ub & 0xFF; } - public static OldClientSupportService getOldClientSupportService() { - return oldClientSupportService; - } - public static void setOldClientSupportService(final OldClientSupportService svc) { oldClientSupportService = svc; } + public static OldClientSupportService getOldClientSupportService() { + return oldClientSupportService; + } + /** * Instantiates an instance of {@code DataSerializer} * @@ -1101,6 +1097,53 @@ public abstract class InternalDataSerializer extends DataSerializer { } } + /** + * A SerializerAttributesHolder holds information required to load a DataSerializer and exists to + * allow client/server connections to be created more quickly than they would if the + * DataSerializer information downloaded from the server were used to immediately load the + * corresponding classes. + */ + public static class SerializerAttributesHolder { + private String className = ""; + private EventID eventId = null; + private ClientProxyMembershipID proxyId = null; + private int id = 0; + + SerializerAttributesHolder() {} + + SerializerAttributesHolder(String name, EventID event, ClientProxyMembershipID proxy, int id) { + this.className = name; + this.eventId = event; + this.proxyId = proxy; + this.id = id; + } + + /** + * @return String the classname of the data serializer this instance represents. + */ + public String getClassName() { + return this.className; + } + + public EventID getEventId() { + return this.eventId; + } + + public ClientProxyMembershipID getProxyId() { + return this.proxyId; + } + + public int getId() { + return this.id; + } + + @Override + public String toString() { + return "SerializerAttributesHolder[name=" + this.className + ",id=" + this.id + ",eventId=" + + this.eventId + ']'; + } + } + private static void sendRegistrationMessageToServers(DataSerializer dataSerializer) { PoolManagerImpl.allPoolsRegisterDataSerializers(dataSerializer); } @@ -1641,6 +1684,7 @@ public abstract class InternalDataSerializer extends DataSerializer { } } + public static boolean autoSerialized(Object o, DataOutput out) throws IOException { AutoSerializableManager asm = TypeRegistry.getAutoSerializableManager(); if (asm != null) { @@ -1745,7 +1789,8 @@ public abstract class InternalDataSerializer extends DataSerializer { */ public static void checkOut(DataOutput out) { if (out == null) { - throw new NullPointerException("Null DataOutput"); + String s = "Null DataOutput"; + throw new NullPointerException(s); } } @@ -1756,7 +1801,8 @@ public abstract class InternalDataSerializer extends DataSerializer { */ public static void checkIn(DataInput in) { if (in == null) { - throw new NullPointerException("Null DataInput"); + String s = "Null DataInput"; + throw new NullPointerException(s); } } @@ -1773,22 +1819,20 @@ public abstract class InternalDataSerializer extends DataSerializer { public static void writeSet(Collection<?> set, DataOutput out) throws IOException { checkOut(out); - if (set != null) { - final int size = set.size(); - writeArrayLength(size, out); - if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { - logger - .trace(LogMarker.SERIALIZER_VERBOSE, "Writing HashSet with {} elements: {}", size, set); - } + int size; + if (set == null) { + size = -1; + } else { + size = set.size(); + } + writeArrayLength(size, out); + if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "Writing HashSet with {} elements: {}", size, set); + } + if (size > 0) { for (Object element : set) { writeObject(element, out); } - } else { - writeArrayLength(-1, out); - if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { - logger - .trace(LogMarker.SERIALIZER_VERBOSE, "Writing HashSet with {} elements: {}", -1, set); - } } } @@ -1919,6 +1963,7 @@ public abstract class InternalDataSerializer extends DataSerializer { } } + /** * Writes the type code for a primitive type Class to {@code DataOutput}. */ @@ -1950,37 +1995,46 @@ public abstract class InternalDataSerializer extends DataSerializer { } } - public static Class decodePrimitiveClass(byte typeCode) throws IOException { - DSCODE dscode = DscodeHelper.toDSCODE(typeCode); - switch (dscode) { - case BOOLEAN_TYPE: - return Boolean.TYPE; - case CHARACTER_TYPE: - return Character.TYPE; - case BYTE_TYPE: - return Byte.TYPE; - case SHORT_TYPE: - return Short.TYPE; - case INTEGER_TYPE: - return Integer.TYPE; - case LONG_TYPE: - return Long.TYPE; - case FLOAT_TYPE: - return Float.TYPE; - case DOUBLE_TYPE: - return Double.TYPE; - case VOID_TYPE: - return Void.TYPE; - case NULL: - return null; - default: - throw new InternalGemFireError( - LocalizedStrings.InternalDataSerializer_UNEXPECTED_TYPECODE_0 - .toLocalizedString(typeCode)); + public static Class decodePrimitiveClass(byte typeCode) { + if (typeCode == DSCODE.BOOLEAN_TYPE.toByte()) { + return Boolean.TYPE; } - + if (typeCode == DSCODE.CHARACTER_TYPE.toByte()) { + return Character.TYPE; + } + if (typeCode == DSCODE.BYTE_TYPE.toByte()) { + return Byte.TYPE; + } + if (typeCode == DSCODE.SHORT_TYPE.toByte()) { + return Short.TYPE; + } + if (typeCode == DSCODE.INTEGER_TYPE.toByte()) { + return Integer.TYPE; + } + if (typeCode == DSCODE.LONG_TYPE.toByte()) { + return Long.TYPE; + } + if (typeCode == DSCODE.FLOAT_TYPE.toByte()) { + return Float.TYPE; + } + if (typeCode == DSCODE.DOUBLE_TYPE.toByte()) { + return Double.TYPE; + } + if (typeCode == DSCODE.VOID_TYPE.toByte()) { + return Void.TYPE; + } + if (typeCode == DSCODE.NULL.toByte()) { + return null; + } + throw new InternalGemFireError( + LocalizedStrings.InternalDataSerializer_UNEXPECTED_TYPECODE_0.toLocalizedString(typeCode)); } + private static final byte TIME_UNIT_NANOSECONDS = -1; + private static final byte TIME_UNIT_MICROSECONDS = -2; + private static final byte TIME_UNIT_MILLISECONDS = -3; + private static final byte TIME_UNIT_SECONDS = -4; + /** * Reads a {@code TimeUnit} from a {@code DataInput}. * @@ -2092,6 +2146,10 @@ public abstract class InternalDataSerializer extends DataSerializer { return result; } + private static final ConcurrentMap dsfidToClassMap = + logger.isTraceEnabled(LogMarker.SERIALIZER_WRITE_DSFID_VERBOSE) ? new ConcurrentHashMap() + : null; + public static void writeUserDataSerializableHeader(int classId, DataOutput out) throws IOException { if (classId <= Byte.MAX_VALUE && classId >= Byte.MIN_VALUE) { @@ -2113,19 +2171,19 @@ public abstract class InternalDataSerializer extends DataSerializer { * @see DataSerializer#readCharArray * @since GemFire 6.6 */ - public static void writeCharArray(char[] array, DataOutput out) throws IOException { + public static void writeCharArray(char[] array, int length, DataOutput out) throws IOException { checkOut(out); if (array == null) { - writeArrayLength(-1, out); - } else { - final int length = array.length; - if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "Writing char array of length {}", length); - } - writeArrayLength(length, out); - for (char character : array) { - out.writeChar(character); + length = -1; + } + writeArrayLength(length, out); + if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "Writing char array of length {}", length); + } + if (length > 0) { + for (int i = 0; i < length; i++) { + out.writeChar(array[i]); } } } @@ -2364,7 +2422,7 @@ public abstract class InternalDataSerializer extends DataSerializer { boolean invoked = false; Version v = InternalDataSerializer.getVersionForDataStreamOrNull(out); - if (Version.CURRENT != v && v != null) { + if (v != null && v != Version.CURRENT) { // get versions where DataOutput was upgraded Version[] versions = null; if (ds instanceof SerializationVersions) { @@ -2373,7 +2431,7 @@ public abstract class InternalDataSerializer extends DataSerializer { } // check if the version of the peer or diskstore is different and // there has been a change in the message - if (versions != null) { + if (versions != null && versions.length > 0) { for (Version version : versions) { // if peer version is less than the greatest upgraded version if (v.compareTo(version) < 0) { @@ -2437,7 +2495,7 @@ public abstract class InternalDataSerializer extends DataSerializer { try { boolean invoked = false; Version v = InternalDataSerializer.getVersionForDataStreamOrNull(in); - if (Version.CURRENT != v && v != null) { + if (v != null && v != Version.CURRENT) { // get versions where DataOutput was upgraded Version[] versions = null; if (ds instanceof SerializationVersions) { @@ -2446,7 +2504,7 @@ public abstract class InternalDataSerializer extends DataSerializer { } // check if the version of the peer or diskstore is different and // there has been a change in the message - if (versions != null) { + if (versions != null && versions.length > 0) { for (Version version : versions) { // if peer version is less than the greatest upgraded version if (v.compareTo(version) < 0) { @@ -2476,6 +2534,7 @@ public abstract class InternalDataSerializer extends DataSerializer { } } + private static Object readDataSerializable(final DataInput in) throws IOException, ClassNotFoundException { Class c = readClass(in); @@ -2583,19 +2642,38 @@ public abstract class InternalDataSerializer extends DataSerializer { } } - public static void writeArrayLength(int len, DataOutput out) throws IOException { - if (len == -1) { - out.writeByte(NULL_ARRAY); - } else if (len <= MAX_BYTE_ARRAY_LEN) { - out.writeByte(len); - } else if (len <= 0xFFFF) { - out.writeByte(SHORT_ARRAY_LEN); - out.writeShort(len); - } else { - out.writeByte(INT_ARRAY_LEN); - out.writeInt(len); - } - } + // array is null + public static final byte NULL_ARRAY = -1; + + /** + * array len encoded as unsigned short in next 2 bytes + * + * @since GemFire 5.7 + */ + private static final byte SHORT_ARRAY_LEN = -2; + + /** + * array len encoded as int in next 4 bytes + * + * @since GemFire 5.7 + */ + public static final byte INT_ARRAY_LEN = -3; + + private static final int MAX_BYTE_ARRAY_LEN = (byte) -4 & 0xFF; + + public static void writeArrayLength(int len, DataOutput out) throws IOException { + if (len == -1) { + out.writeByte(NULL_ARRAY); + } else if (len <= MAX_BYTE_ARRAY_LEN) { + out.writeByte(len); + } else if (len <= 0xFFFF) { + out.writeByte(SHORT_ARRAY_LEN); + out.writeShort(len); + } else { + out.writeByte(INT_ARRAY_LEN); + out.writeInt(len); + } + } public static int readArrayLength(DataInput in) throws IOException { byte code = in.readByte(); @@ -2605,9 +2683,9 @@ public abstract class InternalDataSerializer extends DataSerializer { int result = ubyteToInt(code); if (result > MAX_BYTE_ARRAY_LEN) { if (code == SHORT_ARRAY_LEN) { - return in.readUnsignedShort(); + result = in.readUnsignedShort(); } else if (code == INT_ARRAY_LEN) { - return in.readInt(); + result = in.readInt(); } else { throw new IllegalStateException("unexpected array length code=" + code); } @@ -2616,46 +2694,61 @@ public abstract class InternalDataSerializer extends DataSerializer { } } - private static Object readDSFID(final DataInput in, DSCODE dscode) - throws IOException, ClassNotFoundException { - if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "readDSFID: header={}", dscode); - } - switch (dscode) { - case DS_FIXED_ID_BYTE: - return DSFIDFactory.create(in.readByte(), in); - case DS_FIXED_ID_SHORT: - return DSFIDFactory.create(in.readShort(), in); - case DS_NO_FIXED_ID: - return readDataSerializableFixedID(in); - case DS_FIXED_ID_INT: - return DSFIDFactory.create(in.readInt(), in); - default: - throw new IllegalStateException("unexpected byte: " + dscode + " while reading dsfid"); + /** + * Serializes a list of Integers. The argument may be null. Deserialize with + * readListOfIntegers(). + * + * TODO: writeListOfIntegers is unused + */ + public void writeListOfIntegers(List<Integer> list, DataOutput out) throws IOException { + int size; + if (list == null) { + size = -1; + } else { + size = list.size(); + } + InternalDataSerializer.writeArrayLength(size, out); + if (size > 0) { + for (int i = 0; i < size; i++) { + out.writeInt(list.get(i)); + } } } public static Object readDSFID(final DataInput in) throws IOException, ClassNotFoundException { checkIn(in); - return readDSFID(in, DscodeHelper.toDSCODE(in.readByte())); - } - - private static int readDSFIDHeader(final DataInput in, DSCODE dscode) throws IOException { - switch (dscode) { - case DS_FIXED_ID_BYTE: - return in.readByte(); - case DS_FIXED_ID_SHORT: - return in.readShort(); - case DS_FIXED_ID_INT: - return in.readInt(); - default: - throw new IllegalStateException("unexpected byte: " + dscode + " while reading dsfid"); + byte header = in.readByte(); + if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "readDSFID: header={}", header); + } + if (header == DSCODE.DS_FIXED_ID_BYTE.toByte()) { + return DSFIDFactory.create(in.readByte(), in); + } else if (header == DSCODE.DS_FIXED_ID_SHORT.toByte()) { + return DSFIDFactory.create(in.readShort(), in); + } else if (header == DSCODE.DS_NO_FIXED_ID.toByte()) { + return readDataSerializableFixedID(in); + } else if (header == DSCODE.DS_FIXED_ID_INT.toByte()) { + return DSFIDFactory.create(in.readInt(), in); + } else { + throw new IllegalStateException("unexpected byte: " + header + " while reading dsfid"); } } public static int readDSFIDHeader(final DataInput in) throws IOException { checkIn(in); - return readDSFIDHeader(in, DscodeHelper.toDSCODE(in.readByte())); + byte header = in.readByte(); + if (header == DSCODE.DS_FIXED_ID_BYTE.toByte()) { + return in.readByte(); + } else if (header == DSCODE.DS_FIXED_ID_SHORT.toByte()) { + return in.readShort(); + } else if (header == DSCODE.DS_NO_FIXED_ID.toByte()) { + // is that correct?? + return Integer.MAX_VALUE; + } else if (header == DSCODE.DS_FIXED_ID_INT.toByte()) { + return in.readInt(); + } else { + throw new IllegalStateException("unexpected byte: " + header + " while reading dsfid"); + } } /** @@ -2665,59 +2758,50 @@ public abstract class InternalDataSerializer extends DataSerializer { * @throws IOException A problem occurs while reading from {@code in} * @since GemFire 5.7 */ - private static String readString(DataInput in, DSCODE dscode) throws IOException { - switch (dscode) { - case STRING_BYTES: - return readStringBytesFromDataInput(in, in.readUnsignedShort()); - case STRING: - return readStringUTFFromDataInput(in); - case NULL_STRING: { - if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading NULL_STRING"); - } - return null; + public static String readString(DataInput in, byte header) throws IOException { + if (header == DSCODE.STRING_BYTES.toByte()) { + int len = in.readUnsignedShort(); + if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading STRING_BYTES of len={}", len); } - case HUGE_STRING_BYTES: - return readStringBytesFromDataInput(in, in.readInt()); - case HUGE_STRING: - return readHugeStringFromDataInput(in); - default: - throw new IOException("Unknown String header " + dscode); - } - } - - private static String readHugeStringFromDataInput(DataInput in) throws IOException { - int len = in.readInt(); - if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading HUGE_STRING of len={}", len); - } - char[] buf = new char[len]; - for (int i = 0; i < len; i++) { - buf[i] = in.readChar(); - } - return new String(buf); - } - - private static String readStringUTFFromDataInput(DataInput in) throws IOException { - if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading utf STRING"); - } - return in.readUTF(); - } - - private static String readStringBytesFromDataInput(DataInput dataInput, int len) - throws IOException { - if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading STRING_BYTES of len={}", len); + byte[] buf = new byte[len]; + in.readFully(buf, 0, len); + return new String(buf, 0); // intentionally using deprecated constructor + } else if (header == DSCODE.STRING.toByte()) { + if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading utf STRING"); + } + return in.readUTF(); + } else if (header == DSCODE.NULL_STRING.toByte()) { + if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading NULL_STRING"); + } + return null; + } else if (header == DSCODE.HUGE_STRING_BYTES.toByte()) { + int len = in.readInt(); + if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading HUGE_STRING_BYTES of len={}", len); + } + byte[] buf = new byte[len]; + in.readFully(buf, 0, len); + return new String(buf, 0); // intentionally using deprecated constructor + } else if (header == DSCODE.HUGE_STRING.toByte()) { + int len = in.readInt(); + if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading HUGE_STRING of len={}", len); + } + char[] buf = new char[len]; + for (int i = 0; i < len; i++) { + buf[i] = in.readChar(); + } + return new String(buf); + } else { + String s = "Unknown String header " + header; + throw new IOException(s); } - byte[] buf = new byte[len]; - dataInput.readFully(buf, 0, len); - return new String(buf, 0); // intentionally using deprecated constructor } - public static String readString(DataInput in, byte header) throws IOException { - return readString(in, DscodeHelper.toDSCODE(header)); - } + private static DataSerializer dvddeserializer; // TODO: registerDVDDeserializer is unused public static void registerDVDDeserializer(DataSerializer dvddeslzr) { @@ -2750,212 +2834,260 @@ public abstract class InternalDataSerializer extends DataSerializer { // Read the header byte byte header = in.readByte(); - DSCODE headerDSCode = DscodeHelper.toDSCODE(header); - if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { logger.trace(LogMarker.SERIALIZER_VERBOSE, "basicReadObject: header={}", header); } - - if (headerDSCode == null) { - throw new IOException("Unknown header byte: " + header); - } - - switch (headerDSCode) { - case DS_FIXED_ID_BYTE: - return DSFIDFactory.create(in.readByte(), in); - case DS_FIXED_ID_SHORT: - return DSFIDFactory.create(in.readShort(), in); - case DS_FIXED_ID_INT: - return DSFIDFactory.create(in.readInt(), in); - case DS_NO_FIXED_ID: - return readDataSerializableFixedID(in); - case NULL: - return null; - case NULL_STRING: - return null; - case STRING: - return readStringUTFFromDataInput(in); - case HUGE_STRING: - return readHugeStringFromDataInput(in); - case STRING_BYTES: - return readStringBytesFromDataInput(in, in.readUnsignedShort()); - case HUGE_STRING_BYTES: - return readStringBytesFromDataInput(in, in.readInt()); - case CLASS: - return readClass(in); - case DATE: - return readDate(in); - case FILE: - return readFile(in); - case INET_ADDRESS: - return readInetAddress(in); - case BOOLEAN: - return readBoolean(in); - case CHARACTER: - return readCharacter(in); - case BYTE: - return readByte(in); - case SHORT: - return readShort(in); - case INTEGER: - return readInteger(in); - case LONG: - return readLong(in); - case FLOAT: - return readFloat(in); - case DOUBLE: - return readDouble(in); - case BYTE_ARRAY: - return readByteArray(in); - case ARRAY_OF_BYTE_ARRAYS: - return readArrayOfByteArrays(in); - case SHORT_ARRAY: - return readShortArray(in); - case STRING_ARRAY: - return readStringArray(in); - case INT_ARRAY: - return readIntArray(in); - case LONG_ARRAY: - return readLongArray(in); - case FLOAT_ARRAY: - return readFloatArray(in); - case DOUBLE_ARRAY: - return readDoubleArray(in); - case BOOLEAN_ARRAY: - return readBooleanArray(in); - case CHAR_ARRAY: - return readCharArray(in); - case OBJECT_ARRAY: - return readObjectArray(in); - case ARRAY_LIST: - return readArrayList(in); - case LINKED_LIST: - return readLinkedList(in); - case HASH_SET: - return readHashSet(in); - case LINKED_HASH_SET: - return readLinkedHashSet(in); - case HASH_MAP: - return readHashMap(in); - case IDENTITY_HASH_MAP: - return readIdentityHashMap(in); - case HASH_TABLE: - return readHashtable(in); - case CONCURRENT_HASH_MAP: - return readConcurrentHashMap(in); - case PROPERTIES: - return readProperties(in); - case TIME_UNIT: - return readTimeUnit(in); - case USER_CLASS: - return readUserObject(in, in.readByte()); - case USER_CLASS_2: - return readUserObject(in, in.readShort()); - case USER_CLASS_4: - return readUserObject(in, in.readInt()); - case VECTOR: - return readVector(in); - case STACK: - return readStack(in); - case TREE_MAP: - return readTreeMap(in); - case TREE_SET: - return readTreeSet(in); - case BOOLEAN_TYPE: - return Boolean.TYPE; - case CHARACTER_TYPE: - return Character.TYPE; - case BYTE_TYPE: - return Byte.TYPE; - case SHORT_TYPE: - return Short.TYPE; - case INTEGER_TYPE: - return Integer.TYPE; - case LONG_TYPE: - return Long.TYPE; - case FLOAT_TYPE: - return Float.TYPE; - case DOUBLE_TYPE: - return Double.TYPE; - case VOID_TYPE: - return Void.TYPE; - case USER_DATA_SERIALIZABLE: - return readUserDataSerializable(in, in.readByte()); - case USER_DATA_SERIALIZABLE_2: - return readUserDataSerializable(in, in.readShort()); - case USER_DATA_SERIALIZABLE_4: - return readUserDataSerializable(in, in.readInt()); - case DATA_SERIALIZABLE: - return readDataSerializable(in); - case SERIALIZABLE: - return readSerializable(in); - case PDX: - return readPdxSerializable(in); - case PDX_ENUM: - return readPdxEnum(in); - case GEMFIRE_ENUM: - return readGemFireEnum(in); - case PDX_INLINE_ENUM: - return readPdxInlineEnum(in); - case BIG_INTEGER: - return readBigInteger(in); - case BIG_DECIMAL: - return readBigDecimal(in); - case UUID: - return readUUID(in); - case TIMESTAMP: - return readTimestamp(in); - default: - throw new IOException("Unknown header byte: " + header); + if (header == DSCODE.DS_FIXED_ID_BYTE.toByte()) { + return DSFIDFactory.create(in.readByte(), in); } - - } - - private static Serializable readSerializable(DataInput in) - throws IOException, ClassNotFoundException { - final boolean isDebugEnabled_SERIALIZER = logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE); - Serializable serializableResult; - if (in instanceof DSObjectInputStream) { - serializableResult = (Serializable) ((DSObjectInputStream) in).readObject(); - } else { - InputStream stream; - if (in instanceof InputStream) { - stream = (InputStream) in; + if (header == DSCODE.DS_FIXED_ID_SHORT.toByte()) { + return DSFIDFactory.create(in.readShort(), in); + } + if (header == DSCODE.DS_FIXED_ID_INT.toByte()) { + return DSFIDFactory.create(in.readInt(), in); + } + if (header == DSCODE.DS_NO_FIXED_ID.toByte()) { + return readDataSerializableFixedID(in); + } + if (header == DSCODE.NULL.toByte()) { + return null; + } + if (header == DSCODE.NULL_STRING.toByte() || header == DSCODE.STRING.toByte() + || header == DSCODE.HUGE_STRING.toByte() || header == DSCODE.STRING_BYTES.toByte() + || header == DSCODE.HUGE_STRING_BYTES.toByte()) { + return readString(in, header); + } + if (header == DSCODE.CLASS.toByte()) { + return readClass(in); + } + if (header == DSCODE.DATE.toByte()) { + return readDate(in); + } + if (header == DSCODE.FILE.toByte()) { + return readFile(in); + } + if (header == DSCODE.INET_ADDRESS.toByte()) { + return readInetAddress(in); + } + if (header == DSCODE.BOOLEAN.toByte()) { + return readBoolean(in); + } + if (header == DSCODE.CHARACTER.toByte()) { + return readCharacter(in); + } + if (header == DSCODE.BYTE.toByte()) { + return readByte(in); + } + if (header == DSCODE.SHORT.toByte()) { + return readShort(in); + } + if (header == DSCODE.INTEGER.toByte()) { + return readInteger(in); + } + if (header == DSCODE.LONG.toByte()) { + return readLong(in); + } + if (header == DSCODE.FLOAT.toByte()) { + return readFloat(in); + } + if (header == DSCODE.DOUBLE.toByte()) { + return readDouble(in); + } + if (header == DSCODE.BYTE_ARRAY.toByte()) { + return readByteArray(in); + } + if (header == DSCODE.ARRAY_OF_BYTE_ARRAYS.toByte()) { + return readArrayOfByteArrays(in); + } + if (header == DSCODE.SHORT_ARRAY.toByte()) { + return readShortArray(in); + } + if (header == DSCODE.STRING_ARRAY.toByte()) { + return readStringArray(in); + } + if (header == DSCODE.INT_ARRAY.toByte()) { + return readIntArray(in); + } + if (header == DSCODE.LONG_ARRAY.toByte()) { + return readLongArray(in); + } + if (header == DSCODE.FLOAT_ARRAY.toByte()) { + return readFloatArray(in); + } + if (header == DSCODE.DOUBLE_ARRAY.toByte()) { + return readDoubleArray(in); + } + if (header == DSCODE.BOOLEAN_ARRAY.toByte()) { + return readBooleanArray(in); + } + if (header == DSCODE.CHAR_ARRAY.toByte()) { + return readCharArray(in); + } + if (header == DSCODE.OBJECT_ARRAY.toByte()) { + return readObjectArray(in); + } + if (header == DSCODE.ARRAY_LIST.toByte()) { + return readArrayList(in); + } + if (header == DSCODE.LINKED_LIST.toByte()) { + return readLinkedList(in); + } + if (header == DSCODE.HASH_SET.toByte()) { + return readHashSet(in); + } + if (header == DSCODE.LINKED_HASH_SET.toByte()) { + return readLinkedHashSet(in); + } + if (header == DSCODE.HASH_MAP.toByte()) { + return readHashMap(in); + } + if (header == DSCODE.IDENTITY_HASH_MAP.toByte()) { + return readIdentityHashMap(in); + } + if (header == DSCODE.HASH_TABLE.toByte()) { + return readHashtable(in); + } + if (header == DSCODE.CONCURRENT_HASH_MAP.toByte()) { + return readConcurrentHashMap(in); + } + if (header == DSCODE.PROPERTIES.toByte()) { + return readProperties(in); + } + if (header == DSCODE.TIME_UNIT.toByte()) { + return readTimeUnit(in); + } + if (header == DSCODE.USER_CLASS.toByte()) { + return readUserObject(in, in.readByte()); + } + if (header == DSCODE.USER_CLASS_2.toByte()) { + return readUserObject(in, in.readShort()); + } + if (header == DSCODE.USER_CLASS_4.toByte()) { + return readUserObject(in, in.readInt()); + } + if (header == DSCODE.VECTOR.toByte()) { + return readVector(in); + } + if (header == DSCODE.STACK.toByte()) { + return readStack(in); + } + if (header == DSCODE.TREE_MAP.toByte()) { + return readTreeMap(in); + } + if (header == DSCODE.TREE_SET.toByte()) { + return readTreeSet(in); + } + if (header == DSCODE.BOOLEAN_TYPE.toByte()) { + return Boolean.TYPE; + } + if (header == DSCODE.CHARACTER_TYPE.toByte()) { + return Character.TYPE; + } + if (header == DSCODE.BYTE_TYPE.toByte()) { + return Byte.TYPE; + } + if (header == DSCODE.SHORT_TYPE.toByte()) { + return Short.TYPE; + } + if (header == DSCODE.INTEGER_TYPE.toByte()) { + return Integer.TYPE; + } + if (header == DSCODE.LONG_TYPE.toByte()) { + return Long.TYPE; + } + if (header == DSCODE.FLOAT_TYPE.toByte()) { + return Float.TYPE; + } + if (header == DSCODE.DOUBLE_TYPE.toByte()) { + return Double.TYPE; + } + if (header == DSCODE.VOID_TYPE.toByte()) { + return Void.TYPE; + } + if (header == DSCODE.USER_DATA_SERIALIZABLE.toByte()) { + return readUserDataSerializable(in, in.readByte()); + } + if (header == DSCODE.USER_DATA_SERIALIZABLE_2.toByte()) { + return readUserDataSerializable(in, in.readShort()); + } + if (header == DSCODE.USER_DATA_SERIALIZABLE_4.toByte()) { + return readUserDataSerializable(in, in.readInt()); + } + if (header == DSCODE.DATA_SERIALIZABLE.toByte()) { + return readDataSerializable(in); + } + if (header == DSCODE.SERIALIZABLE.toByte()) { + final boolean isDebugEnabled_SERIALIZER = logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE); + Object serializableResult; + if (in instanceof DSObjectInputStream) { + serializableResult = ((DSObjectInputStream) in).readObject(); } else { - stream = new InputStream() { - @Override - public int read() throws IOException { - try { - return in.readUnsignedByte(); // fix for bug 47249 - } catch (EOFException ignored) { - return -1; + InputStream stream; + if (in instanceof InputStream) { + stream = (InputStream) in; + } else { + stream = new InputStream() { + @Override + public int read() throws IOException { + try { + return in.readUnsignedByte(); // fix for bug 47249 + } catch (EOFException ignored) { + return -1; + } } - } - }; - } + }; + } - ObjectInput ois = new DSObjectInputStream(stream); - serializationFilter.setFilterOn((ObjectInputStream) ois); - if (stream instanceof VersionedDataStream) { - Version v = ((VersionedDataStream) stream).getVersion(); - if (Version.CURRENT != v && v != null) { - ois = new VersionedObjectInput(ois, v); + ObjectInput ois = new DSObjectInputStream(stream); + serializationFilter.setFilterOn((ObjectInputStream) ois); + if (stream instanceof VersionedDataStream) { + Version v = ((VersionedDataStream) stream).getVersion(); + if (v != null && v != Version.CURRENT) { + ois = new VersionedObjectInput(ois, v); + } } - } - serializableResult = (Serializable) ois.readObject(); + serializableResult = ois.readObject(); + if (isDebugEnabled_SERIALIZER) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "Read Serializable object: {}", + serializableResult); + } + } if (isDebugEnabled_SERIALIZER) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "Read Serializable object: {}", - serializableResult); + logger.trace(LogMarker.SERIALIZER_VERBOSE, "deserialized instanceof {}", + serializableResult.getClass()); } + return serializableResult; } - if (isDebugEnabled_SERIALIZER) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "deserialized instanceof {}", - serializableResult.getClass()); + if (header == DSCODE.PDX.toByte()) { + return readPdxSerializable(in); + } + if (header == DSCODE.PDX_ENUM.toByte()) { + return readPdxEnum(in); + } + if (header == DSCODE.GEMFIRE_ENUM.toByte()) { + return readGemFireEnum(in); } - return serializableResult; + if (header == DSCODE.PDX_INLINE_ENUM.toByte()) { + return readPdxInlineEnum(in); + } + if (header == DSCODE.BIG_INTEGER.toByte()) { + return readBigInteger(in); + } + if (header == DSCODE.BIG_DECIMAL.toByte()) { + return readBigDecimal(in); + } + if (header == DSCODE.UUID.toByte()) { + return readUUID(in); + } + if (header == DSCODE.TIMESTAMP.toByte()) { + return readTimestamp(in); + } + + String s = "Unknown header byte: " + header; + throw new IOException(s); } private static Object readUserDataSerializable(final DataInput in, int classId) @@ -2991,13 +3123,19 @@ public abstract class InternalDataSerializer extends DataSerializer { } } + private static final ThreadLocal<Boolean> pdxSerializationInProgress = new ThreadLocal<>(); + public static boolean isPdxSerializationInProgress() { Boolean v = pdxSerializationInProgress.get(); return v != null && v; } - public static void setPdxSerializationInProgress(boolean inProgress) { - pdxSerializationInProgress.set(inProgress); + public static void setPdxSerializationInProgress(boolean v) { + if (v) { + pdxSerializationInProgress.set(true); + } else { + pdxSerializationInProgress.set(false); + } } public static boolean writePdx(DataOutput out, InternalCache internalCache, Object pdx, @@ -3189,347 +3327,35 @@ public abstract class InternalDataSerializer extends DataSerializer { return supportedClassesToHolders; } - public static void writeObjectArray(Object[] array, DataOutput out, boolean ensureCompatibility) - throws IOException { - InternalDataSerializer.checkOut(out); - int length = -1; - if (array != null) { - length = array.length; - } - InternalDataSerializer.writeArrayLength(length, out); - if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "Writing Object array of length {}", length); - } - if (length >= 0) { - writeClass(array.getClass().getComponentType(), out); - for (int i = 0; i < length; i++) { - basicWriteObject(array[i], out, ensureCompatibility); - } - } - } - /** - * Write a variable length long the old way (pre 7.0). Use this only in contexts where you might - * need to communicate with pre 7.0 members or files. + * A marker object for {@code DataSerializer}s that have not been registered. Using this marker + * object allows us to asynchronously send {@code DataSerializer} registration updates. If the + * serialized bytes arrive at a VM before the registration message does, the deserializer will + * wait an amount of time for the registration message to arrive. */ - public static void writeVLOld(long data, DataOutput out) throws IOException { - if (data < 0) { - Assert.fail("Data expected to be >=0 is " + data); - } - if (data <= MAX_BYTE_VL) { - out.writeByte((byte) data); - } else if (data <= 0x7FFF) { - // set the sign bit to indicate a short - out.write(((int) data >>> 8 | 0x80) & 0xFF); - out.write((int) data >>> 0 & 0xFF); - } else if (data <= Integer.MAX_VALUE) { - out.writeByte(INT_VL); - out.writeInt((int) data); - } else { - out.writeByte(LONG_VL); - out.writeLong(data); - } - } - - /** - * Write a variable length long the old way (pre 7.0). Use this only in contexts where you might - * need to communicate with pre 7.0 members or files. - */ - public static long readVLOld(DataInput in) throws IOException { - byte code = in.readByte(); - long result; - if (code < 0) { - // mask off sign bit - result = code & 0x7F; - result <<= 8; - result |= in.readByte() & 0xFF; - } else if (code <= MAX_BYTE_VL) { - result = code; - } else if (code == INT_VL) { - result = in.readInt(); - } else if (code == LONG_VL) { - result = in.readLong(); - } else { - throw new IllegalStateException("unexpected variable length code=" + code); - } - return result; - } - - /** - * Encode a long as a variable length array. - * - * This method is appropriate for unsigned integers. For signed integers, negative values will - * always consume 10 bytes, so it is recommended to use writeSignedVL instead. - * - * This is taken from the varint encoding in protobufs (BSD licensed). See - * https://developers.google.com/protocol-buffers/docs/encoding - */ - public static void writeUnsignedVL(long data, DataOutput out) throws IOException { - while (true) { - if ((data & ~0x7FL) == 0) { - out.writeByte((int) data); - return; - } else { - out.writeByte((int) data & 0x7F | 0x80); - data >>>= 7; - } - } - } - - /** - * Decode a long as a variable length array. - * - * This is taken from the varint encoding in protobufs (BSD licensed). See - * https://developers.google.com/protocol-buffers/docs/encoding - */ - public static long readUnsignedVL(DataInput in) throws IOException { - int shift = 0; - long result = 0; - while (shift < 64) { - final byte b = in.readByte(); - result |= (long) (b & 0x7F) << shift; - if ((b & 0x80) == 0) { - return result; - } - shift += 7; - } - throw new GemFireIOException("Malformed variable length integer"); - } - - /** - * Encode a signed long as a variable length array. - * - * This method is appropriate for signed integers. It uses zig zag encoding to so that negative - * numbers will be represented more compactly. For unsigned values, writeUnsignedVL will be more - * efficient. - */ - public static void writeSignedVL(long data, DataOutput out) throws IOException { - writeUnsignedVL(encodeZigZag64(data), out); - } - - /** - * Decode a signed long as a variable length array. - * - * This method is appropriate for signed integers. It uses zig zag encoding to so that negative - * numbers will be represented more compactly. For unsigned values, writeUnsignedVL will be more - * efficient. - */ - public static long readSignedVL(DataInput in) throws IOException { - return decodeZigZag64(readUnsignedVL(in)); - } - - /** - * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into values that can be - * efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits - * to be varint encoded, thus always taking 10 bytes on the wire.) - * - * @param n An unsigned 64-bit integer, stored in a signed int because Java has no explicit - * unsigned support. - * @return A signed 64-bit integer. - * - * This is taken from the varint encoding in protobufs (BSD licensed). See - * https://developers.google.com/protocol-buffers/docs/encoding - */ - private static long decodeZigZag64(final long n) { - return n >>> 1 ^ -(n & 1); - } - - /** - * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into values that can be - * efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits - * to be varint encoded, thus always taking 10 bytes on the wire.) - * - * @param n A signed 64-bit integer. - * @return An unsigned 64-bit integer, stored in a signed int because Java has no explicit - * unsigned support. - * - * This is taken from the varint encoding in protobufs (BSD licensed). See - * https://developers.google.com/protocol-buffers/docs/encoding - */ - private static long encodeZigZag64(final long n) { - // Note: the right-shift must be arithmetic - return n << 1 ^ n >> 63; - } - - /* test only method */ - public static int calculateBytesForTSandDSID(int dsid) { - HeapDataOutputStream out = new HeapDataOutputStream(4 + 8, Version.CURRENT); - long now = System.currentTimeMillis(); - try { - writeUnsignedVL(now, out); - writeUnsignedVL(InternalDataSerializer.encodeZigZag64(dsid), out); - } catch (IOException ignored) { - return 0; - } - return out.size(); - } - - public static Class<?> getCachedClass(String p_className) throws ClassNotFoundException { - String className = processIncomingClassName(p_className); - if (LOAD_CLASS_EACH_TIME) { - return ClassPathLoader.getLatest().forName(className); - } else { - Class<?> result = getExistingCachedClass(className); - if (result == null) { - // Do the forName call outside the sync to fix bug 46172 - result = ClassPathLoader.getLatest().forName(className); - synchronized (cacheAccessLock) { - Class<?> cachedClass = getExistingCachedClass(className); - if (cachedClass == null) { - classCache.put(className, new WeakReference<>(result)); - } else { - result = cachedClass; - } - } - } - return result; - } - } - - private static Class<?> getExistingCachedClass(String className) { - WeakReference<Class<?>> wr = classCache.get(className); - Class<?> result = null; - if (wr != null) { - result = wr.get(); - } - return result; - } - - public static void flushClassCache() { - if (classCache != null) { - // Not locking classCache during clear as doing so causes a deadlock in the DeployedJar - classCache.clear(); - } - } - - /** - * Serializes a list of Integers. The argument may be null. Deserialize with - * readListOfIntegers(). - * - * TODO: writeListOfIntegers is unused - */ - public void writeListOfIntegers(List<Integer> list, DataOutput out) throws IOException { - if (list != null) { - InternalDataSerializer.writeArrayLength(list.size(), out); - for (Integer entry : list) { - out.writeInt(entry); - } - } else { - InternalDataSerializer.writeArrayLength(-1, out); - } - } - - /** - * Any time new serialization format is added then a new enum needs to be added here. - * - * @since GemFire 6.6.2 - */ - private enum SERIALIZATION_VERSION { - vINVALID, - // includes 6.6.0.x and 6.6.1.x. Note that no serialization changes were made in 6.6 until 6.6.2 - v660, - // 6.6.2.x or later NOTE if you add a new constant make sure and update "latestVersion". - v662 - } - - /** - * A listener whose listener methods are invoked when {@link DataSerializer}s and {@link - * Instantiator}s are registered. This is part of the fix for bug 31422. - * - * @see InternalDataSerializer#addRegistrationListener - * @see InternalDataSerializer#removeRegistrationListener - */ - public interface RegistrationListener { - - /** - * Invoked when a new {@code Instantiator} is {@linkplain Instantiator#register(Instantiator) - * registered}. - */ - void newInstantiator(Instantiator instantiator); - - /** - * Invoked when a new {@code DataSerializer} is {@linkplain DataSerializer#register(Class) - * registered}. - */ - void newDataSerializer(DataSerializer ds); - } - - /** - * A SerializerAttributesHolder holds information required to load a DataSerializer and exists to - * allow client/server connections to be created more quickly than they would if the - * DataSerializer information downloaded from the server were used to immediately load the - * corresponding classes. - */ - public static class SerializerAttributesHolder { - private String className = ""; - private EventID eventId = null; - private ClientProxyMembershipID proxyId = null; - private int id = 0; - - SerializerAttributesHolder() {} - - SerializerAttributesHolder(String name, EventID event, ClientProxyMembershipID proxy, int id) { - this.className = name; - this.eventId = event; - this.proxyId = proxy; - this.id = id; - } - - /** - * @return String the classname of the data serializer this instance represents. - */ - public String getClassName() { - return this.className; - } - - public EventID getEventId() { - return this.eventId; - } - - public ClientProxyMembershipID getProxyId() { - return this.proxyId; - } - - public int getId() { - return this.id; - } - - @Override - public String toString() { - return "SerializerAttributesHolder[name=" + this.className + ",id=" + this.id + ",eventId=" - + this.eventId + ']'; - } - } - - /** - * A marker object for {@code DataSerializer}s that have not been registered. Using this marker - * object allows us to asynchronously send {@code DataSerializer} registration updates. If the - * serialized bytes arrive at a VM before the registration message does, the deserializer will - * wait an amount of time for the registration message to arrive. - */ - abstract static class Marker { - /** - * The DataSerializer that is filled in upon registration - */ - protected DataSerializer serializer = null; - - /** - * set to true once setSerializer is called. - */ - boolean hasBeenSet = false; - - abstract DataSerializer getSerializer(); - - /** - * Sets the serializer associated with this marker. It will notify any threads that are waiting - * for the serializer to be registered. - */ - void setSerializer(DataSerializer serializer) { - synchronized (this) { - this.hasBeenSet = true; - this.serializer = serializer; - this.notifyAll(); - } + abstract static class Marker { + /** + * The DataSerializer that is filled in upon registration + */ + protected DataSerializer serializer = null; + + /** + * set to true once setSerializer is called. + */ + boolean hasBeenSet = false; + + abstract DataSerializer getSerializer(); + + /** + * Sets the serializer associated with this marker. It will notify any threads that are waiting + * for the serializer to be registered. + */ + void setSerializer(DataSerializer serializer) { + synchronized (this) { + this.hasBeenSet = true; + this.serializer = serializer; + this.notifyAll(); + } } } @@ -3626,23 +3452,26 @@ public abstract class InternalDataSerializer extends DataSerializer { */ public static class RegistrationMessage extends SerialDistributionMessage { /** - * The versions in which this message was modified + * The id of the {@code DataSerializer} that was registered since 5.7 an int instead of a byte */ - private static final Version[] dsfidVersions = new Version[] {}; + private int id; + /** * The eventId of the {@code DataSerializer} that was registered */ protected EventID eventId; - /** - * The id of the {@code DataSerializer} that was registered since 5.7 an int instead of a byte - */ - private int id; + /** * The name of the {@code DataSerializer} class */ private String className; /** + * The versions in which this message was modified + */ + private static final Version[] dsfidVersions = new Version[] {}; + + /** * Constructor for {@code DataSerializable} */ public RegistrationMessage() {} @@ -3763,6 +3592,28 @@ public abstract class InternalDataSerializer extends DataSerializer { } /** + * A listener whose listener methods are invoked when {@link DataSerializer}s and {@link + * Instantiator}s are registered. This is part of the fix for bug 31422. + * + * @see InternalDataSerializer#addRegistrationListener + * @see InternalDataSerializer#removeRegistrationListener + */ + public interface RegistrationListener { + + /** + * Invoked when a new {@code Instantiator} is {@linkplain Instantiator#register(Instantiator) + * registered}. + */ + void newInstantiator(Instantiator instantiator); + + /** + * Invoked when a new {@code DataSerializer} is {@linkplain DataSerializer#register(Class) + * registered}. + */ + void newDataSerializer(DataSerializer ds); + } + + /** * An {@code ObjectInputStream} whose {@link #resolveClass} method loads classes from the current * context class loader. */ @@ -3865,4 +3716,235 @@ public abstract class InternalDataSerializer extends DataSerializer { protected abstract static class WellKnownPdxDS extends WellKnownDS { // subclasses need to implement toData } + + public static void writeObjectArray(Object[] array, DataOutput out, boolean ensureCompatibility) + throws IOException { + InternalDataSerializer.checkOut(out); + int length; + if (array == null) { + length = -1; + } else { + length = array.length; + } + InternalDataSerializer.writeArrayLength(length, out); + if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "Writing Object array of length {}", length); + } + if (length >= 0) { + writeClass(array.getClass().getComponentType(), out); + for (int i = 0; i < length; i++) { + basicWriteObject(array[i], out, ensureCompatibility); + } + } + } + + // Variable Length long encoded as int in next 4 bytes + private static final byte INT_VL = 126; + + // Variable Length long encoded as long in next 8 bytes + private static final byte LONG_VL = 127; + + private static final int MAX_BYTE_VL = 125; + + /** + * Write a variable length long the old way (pre 7.0). Use this only in contexts where you might + * need to communicate with pre 7.0 members or files. + */ + public static void writeVLOld(long data, DataOutput out) throws IOException { + if (data < 0) { + Assert.fail("Data expected to be >=0 is " + data); + } + if (data <= MAX_BYTE_VL) { + out.writeByte((byte) data); + } else if (data <= 0x7FFF) { + // set the sign bit to indicate a short + out.write(((int) data >>> 8 | 0x80) & 0xFF); + out.write((int) data >>> 0 & 0xFF); + } else if (data <= Integer.MAX_VALUE) { + out.writeByte(INT_VL); + out.writeInt((int) data); + } else { + out.writeByte(LONG_VL); + out.writeLong(data); + } + } + + /** + * Write a variable length long the old way (pre 7.0). Use this only in contexts where you might + * need to communicate with pre 7.0 members or files. + */ + public static long readVLOld(DataInput in) throws IOException { + byte code = in.readByte(); + long result; + if (code < 0) { + // mask off sign bit + result = code & 0x7F; + result <<= 8; + result |= in.readByte() & 0xFF; + } else if (code <= MAX_BYTE_VL) { + result = code; + } else if (code == INT_VL) { + result = in.readInt(); + } else if (code == LONG_VL) { + result = in.readLong(); + } else { + throw new IllegalStateException("unexpected variable length code=" + code); + } + return result; + } + + /** + * Encode a long as a variable length array. + * + * This method is appropriate for unsigned integers. For signed integers, negative values will + * always consume 10 bytes, so it is recommended to use writeSignedVL instead. + * + * This is taken from the varint encoding in protobufs (BSD licensed). See + * https://developers.google.com/protocol-buffers/docs/encoding + */ + public static void writeUnsignedVL(long data, DataOutput out) throws IOException { + while (true) { + if ((data & ~0x7FL) == 0) { + out.writeByte((int) data); + return; + } else { + out.writeByte((int) data & 0x7F | 0x80); + data >>>= 7; + } + } + } + + /** + * Decode a long as a variable length array. + * + * This is taken from the varint encoding in protobufs (BSD licensed). See + * https://developers.google.com/protocol-buffers/docs/encoding + */ + public static long readUnsignedVL(DataInput in) throws IOException { + int shift = 0; + long result = 0; + while (shift < 64) { + final byte b = in.readByte(); + result |= (long) (b & 0x7F) << shift; + if ((b & 0x80) == 0) { + return result; + } + shift += 7; + } + throw new GemFireIOException("Malformed variable length integer"); + } + + /** + * Encode a signed long as a variable length array. + * + * This method is appropriate for signed integers. It uses zig zag encoding to so that negative + * numbers will be represented more compactly. For unsigned values, writeUnsignedVL will be more + * efficient. + */ + public static void writeSignedVL(long data, DataOutput out) throws IOException { + writeUnsignedVL(encodeZigZag64(data), out); + } + + /** + * Decode a signed long as a variable length array. + * + * This method is appropriate for signed integers. It uses zig zag encoding to so that negative + * numbers will be represented more compactly. For unsigned values, writeUnsignedVL will be more + * efficient. + */ + public static long readSignedVL(DataInput in) throws IOException { + return decodeZigZag64(readUnsignedVL(in)); + } + + /** + * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into values that can be + * efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits + * to be varint encoded, thus always taking 10 bytes on the wire.) + * + * @param n An unsigned 64-bit integer, stored in a signed int because Java has no explicit + * unsigned support. + * @return A signed 64-bit integer. + * + * This is taken from the varint encoding in protobufs (BSD licensed). See + * https://developers.google.com/protocol-buffers/docs/encoding + */ + private static long decodeZigZag64(final long n) { + return n >>> 1 ^ -(n & 1); + } + + /** + * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into values that can be + * efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits + * to be varint encoded, thus always taking 10 bytes on the wire.) + * + * @param n A signed 64-bit integer. + * @return An unsigned 64-bit integer, stored in a signed int because Java has no explicit + * unsigned support. + * + * This is taken from the varint encoding in protobufs (BSD licensed). See + * https://developers.google.com/protocol-buffers/docs/encoding + */ + private static long encodeZigZag64(final long n) { + // Note: the right-shift must be arithmetic + return n << 1 ^ n >> 63; + } + + /* test only method */ + public static int calculateBytesForTSandDSID(int dsid) { + HeapDataOutputStream out = new HeapDataOutputStream(4 + 8, Version.CURRENT); + long now = System.currentTimeMillis(); + try { + writeUnsignedVL(now, out); + writeUnsignedVL(InternalDataSerializer.encodeZigZag64(dsid), out); + } catch (IOException ignored) { + return 0; + } + return out.size(); + } + + public static final boolean LOAD_CLASS_EACH_TIME = + Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "loadClassOnEveryDeserialization"); + + private static final CopyOnWriteHashMap<String, WeakReference<Class<?>>> classCache = + LOAD_CLASS_EACH_TIME ? null : new CopyOnWriteHashMap<>(); + + private static final Object cacheAccessLock = new Object(); + + public static Class<?> getCachedClass(String p_className) throws ClassNotFoundException { + String className = processIncomingClassName(p_className); + if (LOAD_CLASS_EACH_TIME) { + return ClassPathLoader.getLatest().forName(className); + } else { + Class<?> result = getExistingCachedClass(className); + if (result == null) { + // Do the forName call outside the sync to fix bug 46172 + result = ClassPathLoader.getLatest().forName(className); + synchronized (cacheAccessLock) { + Class<?> cachedClass = getExistingCachedClass(className); + if (cachedClass == null) { + classCache.put(className, new WeakReference<>(result)); + } else { + result = cachedClass; + } + } + } + return result; + } + } + + private static Class<?> getExistingCachedClass(String className) { + WeakReference<Class<?>> wr = classCache.get(className); + Class<?> result = null; + if (wr != null) { + result = wr.get(); + } + return result; + } + + public static void flushClassCache() { + if (classCache != null) { + // Not locking classCache during clear as doing so causes a deadlock in the DeployedJar + classCache.clear(); + } + } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/util/DscodeHelper.java b/geode-core/src/main/java/org/apache/geode/internal/util/DscodeHelper.java deleted file mode 100644 index 30a9f9b..0000000 --- a/geode-core/src/main/java/org/apache/geode/internal/util/DscodeHelper.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.geode.internal.util; - -import java.io.IOException; -import java.util.Arrays; - -import org.apache.geode.internal.DSCODE; - -public class DscodeHelper { - - private static final DSCODE[] dscodes = new DSCODE[128]; - - static { - Arrays.stream(DSCODE.values()).filter(dscode -> dscode.toByte() >= 0) - .forEach(dscode -> dscodes[dscode.toByte()] = dscode); - } - - public static DSCODE toDSCODE(final byte value) throws IOException { - try { - return dscodes[value]; - } catch (ArrayIndexOutOfBoundsException e) { - throw new IOException("Unknown header byte: " + value); - } - } -} diff --git a/geode-core/src/test/java/org/apache/geode/internal/DSCODETest.java b/geode-core/src/test/java/org/apache/geode/internal/DSCODETest.java index 7240825..7bc7684 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/DSCODETest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/DSCODETest.java @@ -15,18 +15,13 @@ package org.apache.geode.internal; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; -import java.io.IOException; -import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.apache.geode.internal.util.DscodeHelper; import org.apache.geode.test.junit.categories.SerializationTest; @Category({SerializationTest.class}) @@ -41,17 +36,4 @@ public class DSCODETest { previouslySeen.add(integerValue); } } - - @Test - public void testGetEnumFromByte() { - Arrays.stream(DSCODE.values()) - .filter(dscode -> dscode != DSCODE.RESERVED_FOR_FUTURE_USE && dscode != DSCODE.ILLEGAL) - .forEach(dscode -> { - try { - Assert.assertEquals(dscode, DscodeHelper.toDSCODE(dscode.toByte())); - } catch (IOException e) { - fail("No exception should have been caught, as the \"error\" codes are filtered out."); - } - }); - } }
