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 4214a601bcc273f8950dfa5c5e9543be5cef8e4c Author: Udo Kohlmeyer <[email protected]> AuthorDate: Thu Sep 6 17:14:03 2018 -0700 GEODE-5705: Improve basicReadObject to use switch statement rather than if statements. --- .../geode/internal/InternalDataSerializer.java | 1671 +++++++++----------- .../apache/geode/internal/util/DscodeHelper.java | 19 + .../java/org/apache/geode/internal/DSCODETest.java | 10 + 3 files changed, 799 insertions(+), 901 deletions(-) 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 72a1bc0..fc3722a 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,6 +106,7 @@ 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; @@ -127,19 +128,24 @@ import org.apache.geode.pdx.internal.TypeRegistry; * Contains static methods for data serializing instances of internal GemFire classes. It also * contains the implementation of the distribution messaging (and shared memory management) needed * to support data serialization. - * * @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 @@ -191,27 +197,84 @@ 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 * when GemFire was open- sourced. This preserves backward-compatibility. - * * @param name the fully qualified class name * @return the name of the class in this implementation */ @@ -233,7 +296,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * For backward compatibility we must swizzle the package of some classes that had to be moved * when GemFire was open- sourced. This preserves backward-compatibility. - * * @param name the fully qualified class name * @param out the consumer of the serialized object * @return the name of the class in this implementation @@ -256,12 +318,11 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Initializes the optional serialization "accept list" if the user has requested it in the * DistributionConfig - * * @param distributionConfig the DistributedSystem configuration * @param services DistributedSystem services that might have classes to acceptlist */ public static void initialize(DistributionConfig distributionConfig, - Collection<DistributedSystemService> services) { + Collection<DistributedSystemService> services) { logger.info("initializing InternalDataSerializer with {} services", services.size()); if (distributionConfig.getValidateSerializableObjects()) { if (!ClassUtils.isClassAvailable("sun.misc.ObjectInputFilter") @@ -281,11 +342,9 @@ 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 - * {@link DistributedSystemService#getSerializationAcceptlist} + * read them from a file and then return them via {@link DistributedSystemService#getSerializationAcceptlist} */ public static Collection<String> loadClassNames(URL sanctionedSerializables) throws IOException { Collection<String> result = new ArrayList(1000); @@ -311,25 +370,6 @@ 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; @@ -343,8 +383,6 @@ public abstract class InternalDataSerializer extends DataSerializer { } } - private static final SERIALIZATION_VERSION serializationVersion = calculateSerializationVersion(); - public static boolean is662SerializationEnabled() { return serializationVersion.ordinal() >= SERIALIZATION_VERSION.v662.ordinal(); } @@ -358,10 +396,6 @@ 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 @@ -769,42 +803,6 @@ 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 */ @@ -812,17 +810,16 @@ public abstract class InternalDataSerializer extends DataSerializer { return ub & 0xFF; } - public static void setOldClientSupportService(final OldClientSupportService svc) { - oldClientSupportService = svc; - } - public static OldClientSupportService getOldClientSupportService() { return oldClientSupportService; } + public static void setOldClientSupportService(final OldClientSupportService svc) { + oldClientSupportService = svc; + } + /** * Instantiates an instance of {@code DataSerializer} - * * @throws IllegalArgumentException If the class can't be instantiated * @see DataSerializer#register(Class) */ @@ -839,11 +836,11 @@ public abstract class InternalDataSerializer extends DataSerializer { } catch (NoSuchMethodException ignored) { StringId s = LocalizedStrings.DataSerializer_CLASS_0_DOES_NOT_HAVE_A_ZEROARGUMENT_CONSTRUCTOR; - Object[] args = new Object[] {c.getName()}; + Object[] args = new Object[]{c.getName()}; if (c.getDeclaringClass() != null) { s = LocalizedStrings.DataSerializer_CLASS_0_DOES_NOT_HAVE_A_ZEROARGUMENT_CONSTRUCTOR_IT_IS_AN_INNER_CLASS_OF_1_SHOULD_IT_BE_A_STATIC_INNER_CLASS; - args = new Object[] {c.getName(), c.getDeclaringClass()}; + args = new Object[]{c.getName(), c.getDeclaringClass()}; } throw new IllegalArgumentException(s.toLocalizedString(args)); } @@ -875,7 +872,7 @@ public abstract class InternalDataSerializer extends DataSerializer { } public static DataSerializer register(Class c, boolean distribute, EventID eventId, - ClientProxyMembershipID context) { + ClientProxyMembershipID context) { DataSerializer s = newInstance(c); // This method is only called when server connection and CacheClientUpdaterThread s.setEventId(eventId); @@ -885,9 +882,8 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Registers a {@code DataSerializer} instance with the data serialization framework. - * * @param distribute Should the registered {@code DataSerializer} be distributed to other members - * of the distributed system? + * of the distributed system? * @see DataSerializer#register(Class) */ public static DataSerializer register(Class c, boolean distribute) { @@ -945,7 +941,7 @@ public abstract class InternalDataSerializer extends DataSerializer { DataSerializer other = (DataSerializer) oldSerializer; throw new IllegalStateException( LocalizedStrings.InternalDataSerializer_A_DATASERIALIZER_OF_CLASS_0_IS_ALREADY_REGISTERED_WITH_ID_1_SO_THE_DATASERIALIZER_OF_CLASS_2_COULD_NOT_BE_REGISTERED - .toLocalizedString(new Object[] {other.getClass().getName(), other.getId()})); + .toLocalizedString(new Object[]{other.getClass().getName(), other.getId()})); } } } while (retry); @@ -1018,7 +1014,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Marks a {@code DataSerializer} className for registration with the data serialization framework * if and when it is needed. Does not necessarily load the classes into this VM. - * * @param className Name of the DataSerializer class. * @param distribute If true, distribute this data serializer. * @param eventId Event id @@ -1026,7 +1021,7 @@ public abstract class InternalDataSerializer extends DataSerializer { * @see DataSerializer#register(Class) */ public static void register(String className, boolean distribute, EventID eventId, - ClientProxyMembershipID proxyId, int id) { + ClientProxyMembershipID proxyId, int id) { register(className, distribute, new SerializerAttributesHolder(className, eventId, proxyId, id)); } @@ -1034,7 +1029,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Marks a {@code DataSerializer} className for registration with the data serialization * framework. Does not necessarily load the classes into this VM. - * * @param distribute If true, distribute this data serializer. * @see DataSerializer#register(Class) */ @@ -1043,7 +1037,7 @@ public abstract class InternalDataSerializer extends DataSerializer { } private static void register(String className, boolean distribute, - SerializerAttributesHolder holder) { + SerializerAttributesHolder holder) { if (StringUtils.isBlank(className)) { throw new IllegalArgumentException("Class name cannot be null or empty."); } @@ -1053,7 +1047,7 @@ public abstract class InternalDataSerializer extends DataSerializer { if (oldValue.getId() != 0 && holder.getId() != 0 && oldValue.getId() != holder.getId()) { throw new IllegalStateException( LocalizedStrings.InternalDataSerializer_A_DATASERIALIZER_OF_CLASS_0_IS_ALREADY_REGISTERED_WITH_ID_1_SO_THE_DATASERIALIZER_OF_CLASS_2_COULD_NOT_BE_REGISTERED - .toLocalizedString(new Object[] {oldValue.getClass().getName(), oldValue.getId()})); + .toLocalizedString(new Object[]{oldValue.getClass().getName(), oldValue.getId()})); } } @@ -1076,7 +1070,6 @@ public abstract class InternalDataSerializer extends DataSerializer { * classes they support. The DataSerializers are registered as "holders" to avoid loading the * actual classes until they're needed. This method registers the names of classes supported by * the DataSerializers - * * @param map The classes returned by DataSerializer.supportedClasses() */ public static void updateSupportedClassesMap(Map<Integer, List<String>> map) { @@ -1097,53 +1090,6 @@ 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); } @@ -1178,7 +1124,7 @@ public abstract class InternalDataSerializer extends DataSerializer { new ClientDataSerializerMessage(EnumListenerEvent.AFTER_REGISTER_DATASERIALIZER, serializedDataSerializer, (ClientProxyMembershipID) dataSerializer.getContext(), (EventID) dataSerializer.getEventId(), - new Class[][] {dataSerializer.getSupportedClasses()}); + new Class[][]{dataSerializer.getSupportedClasses()}); // Deliver it to all the clients CacheClientNotifier.routeClientMessage(clientDataSerializerMessage); } @@ -1353,7 +1299,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Returns all the data serializers in this vm. This method, unlike {@link #getSerializers()}, * does not force loading of the data serializers which were not loaded in the vm earlier. - * * @return Array of {@link SerializerAttributesHolder} */ public static SerializerAttributesHolder[] getSerializersForDistribution() { @@ -1427,7 +1372,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Read the data from in and register it with this class. TODO: loadRegistrations is unused - * * @throws IllegalArgumentException if a registration fails */ public static void loadRegistrations(DataInput in) throws IOException { @@ -1471,7 +1415,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Alerts all {@code RegistrationListener}s that a new {@code DataSerializer} has been registered - * * @see InternalDataSerializer.RegistrationListener#newDataSerializer */ private static void fireNewDataSerializer(DataSerializer ds) { @@ -1483,7 +1426,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Alerts all {@code RegistrationListener}s that a new {@code Instantiator} has been registered - * * @see InternalDataSerializer.RegistrationListener#newInstantiator */ static void fireNewInstantiator(Instantiator instantiator) { @@ -1575,18 +1517,16 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Data serializes an instance of a well-known class to the given {@code DataOutput}. - * * @return {@code true} if {@code o} was actually written to {@code out} */ private static boolean writeWellKnownObject(Object o, DataOutput out, - boolean ensurePdxCompatibility) throws IOException { + boolean ensurePdxCompatibility) throws IOException { return writeUserObject(o, out, ensurePdxCompatibility); } /** * Data serializes an instance of a "user class" (that is, a class that can be handled by a * registered {@code DataSerializer}) to the given {@code DataOutput}. - * * @return {@code true} if {@code o} was written to {@code out}. */ private static boolean writeUserObject(Object o, DataOutput out, boolean ensurePdxCompatibility) @@ -1670,7 +1610,7 @@ public abstract class InternalDataSerializer extends DataSerializer { return true; } else if (is662SerializationEnabled() && (o.getClass().isEnum()/* for bug 52271 */ || (o.getClass().getSuperclass() != null - && o.getClass().getSuperclass().isEnum()))) { + && o.getClass().getSuperclass().isEnum()))) { if (isPdxSerializationInProgress()) { writePdxEnum((Enum<?>) o, out); } else { @@ -1684,7 +1624,6 @@ public abstract class InternalDataSerializer extends DataSerializer { } } - public static boolean autoSerialized(Object o, DataOutput out) throws IOException { AutoSerializableManager asm = TypeRegistry.getAutoSerializableManager(); if (asm != null) { @@ -1767,7 +1706,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Reads an object that was serialized by a customer ("user") {@code DataSerializer} from the * given {@code DataInput}. - * * @throws IOException If the serializer that can deserialize the object is not registered. */ private static Object readUserObject(DataInput in, int serializerId) @@ -1776,7 +1714,7 @@ public abstract class InternalDataSerializer extends DataSerializer { if (serializer == null) { throw new IOException(LocalizedStrings.DataSerializer_SERIALIZER_0_IS_NOT_REGISTERED - .toLocalizedString(new Object[] {serializerId})); + .toLocalizedString(new Object[]{serializerId})); } return serializer.fromData(in); @@ -1784,25 +1722,21 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Checks to make sure a {@code DataOutput} is not {@code null}. - * * @throws NullPointerException If {@code out} is {@code null} */ public static void checkOut(DataOutput out) { if (out == null) { - String s = "Null DataOutput"; - throw new NullPointerException(s); + throw new NullPointerException("Null DataOutput"); } } /** * Checks to make sure a {@code DataInput} is not {@code null}. - * * @throws NullPointerException If {@code in} is {@code null} */ public static void checkIn(DataInput in) { if (in == null) { - String s = "Null DataInput"; - throw new NullPointerException(s); + throw new NullPointerException("Null DataInput"); } } @@ -1811,7 +1745,6 @@ public abstract class InternalDataSerializer extends DataSerializer { * <P> * This method is internal because its semantics (that is, its ability to write any kind of {@code * Set}) are different from the {@code write}XXX methods of the external {@code DataSerializer}. - * * @throws IOException A problem occurs while writing to {@code out} * @see #readSet * @since GemFire 4.0 @@ -1819,29 +1752,24 @@ public abstract class InternalDataSerializer extends DataSerializer { public static void writeSet(Collection<?> set, DataOutput out) throws IOException { checkOut(out); - int size; - if (set == null) { - size = -1; - } else { + int size = -1; + if (set != null) { 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); - } + for (Object element : set) { + writeObject(element, out); } } /** * Reads a {@code Set} from a {@code DataInput}. - * * @throws IOException A problem occurs while writing to {@code out} * @throws ClassNotFoundException The class of one of the {@code HashSet}'s elements cannot be - * found. + * found. * @see #writeSet * @since GemFire 4.0 */ @@ -1852,7 +1780,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Reads a {@code Set} from a {@code DataInput} into the given non-null collection. Returns true * if collection read is non-null else returns false. TODO: readCollection is unused - * * @throws IOException A problem occurs while reading from {@code in} * @throws ClassNotFoundException The class of one of the {@code Set}'s elements cannot be found. * @see #writeSet @@ -1879,7 +1806,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * write a set of Long objects - * * @param set the set of Long objects * @param hasLongIDs if false, write only ints, not longs * @param out the output stream @@ -1922,7 +1848,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * write a set of Long objects TODO: writeListOfLongs is unused - * * @param list the set of Long objects * @param hasLongIDs if false, write only ints, not longs * @param out the output stream @@ -1963,7 +1888,6 @@ public abstract class InternalDataSerializer extends DataSerializer { } } - /** * Writes the type code for a primitive type Class to {@code DataOutput}. */ @@ -1996,48 +1920,38 @@ public abstract class InternalDataSerializer extends DataSerializer { } 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; + 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)); } - 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}. - * * @throws IOException A problem occurs while writing to {@code out} */ private static TimeUnit readTimeUnit(DataInput in) throws IOException { @@ -2146,10 +2060,6 @@ 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) { @@ -2166,7 +2076,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Writes given number of characters from array of {@code char}s to a {@code DataOutput}. - * * @throws IOException A problem occurs while writing to {@code out} * @see DataSerializer#readCharArray * @since GemFire 6.6 @@ -2190,7 +2099,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * returns true if the byte array is the serialized form of a null reference - * * @param serializedForm the serialized byte array */ public static boolean isSerializedNull(byte[] serializedForm) { @@ -2357,7 +2265,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * write an object in java Serializable form with a SERIALIZABLE DSCODE so that it can be * deserialized with DataSerializer.readObject() - * * @param o the object to serialize * @param out the data output to serialize to */ @@ -2412,7 +2319,6 @@ public abstract class InternalDataSerializer extends DataSerializer { * DataSerializable. It will invoke the correct toData method based on the class's version * information. This method does not write information about the class of the object. When * deserializing use the method invokeFromData to read the contents of the object. - * * @param ds the object to write * @param out the output stream. */ @@ -2422,7 +2328,7 @@ public abstract class InternalDataSerializer extends DataSerializer { boolean invoked = false; Version v = InternalDataSerializer.getVersionForDataStreamOrNull(out); - if (v != null && v != Version.CURRENT) { + if (Version.CURRENT != v && v != null) { // get versions where DataOutput was upgraded Version[] versions = null; if (ds instanceof SerializationVersions) { @@ -2431,12 +2337,12 @@ 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 && versions.length > 0) { + if (versions != null) { for (Version version : versions) { // if peer version is less than the greatest upgraded version if (v.compareTo(version) < 0) { ds.getClass().getMethod("toDataPre_" + version.getMethodSuffix(), - new Class[] {DataOutput.class}).invoke(ds, out); + new Class[]{DataOutput.class}).invoke(ds, out); invoked = true; break; } @@ -2486,7 +2392,6 @@ public abstract class InternalDataSerializer extends DataSerializer { * DataSerializable. It will invoke the correct fromData method based on the class's version * information. This method does not read information about the class of the object. When * serializing use the method invokeToData to write the contents of the object. - * * @param ds the object to write * @param in the input stream. */ @@ -2495,7 +2400,7 @@ public abstract class InternalDataSerializer extends DataSerializer { try { boolean invoked = false; Version v = InternalDataSerializer.getVersionForDataStreamOrNull(in); - if (v != null && v != Version.CURRENT) { + if (Version.CURRENT != v && v != null) { // get versions where DataOutput was upgraded Version[] versions = null; if (ds instanceof SerializationVersions) { @@ -2504,12 +2409,12 @@ 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 && versions.length > 0) { + if (versions != null) { for (Version version : versions) { // if peer version is less than the greatest upgraded version if (v.compareTo(version) < 0) { ds.getClass().getMethod("fromDataPre" + '_' + version.getMethodSuffix(), - new Class[] {DataInput.class}).invoke(ds, in); + new Class[]{DataInput.class}).invoke(ds, in); invoked = true; break; } @@ -2534,7 +2439,6 @@ public abstract class InternalDataSerializer extends DataSerializer { } } - private static Object readDataSerializable(final DataInput in) throws IOException, ClassNotFoundException { Class c = readClass(in); @@ -2642,25 +2546,6 @@ public abstract class InternalDataSerializer extends DataSerializer { } } - // 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); @@ -2683,9 +2568,9 @@ public abstract class InternalDataSerializer extends DataSerializer { int result = ubyteToInt(code); if (result > MAX_BYTE_ARRAY_LEN) { if (code == SHORT_ARRAY_LEN) { - result = in.readUnsignedShort(); + return in.readUnsignedShort(); } else if (code == INT_ARRAY_LEN) { - result = in.readInt(); + return in.readInt(); } else { throw new IllegalStateException("unexpected array length code=" + code); } @@ -2694,114 +2579,107 @@ public abstract class InternalDataSerializer extends DataSerializer { } } - /** - * 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)); - } + 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"); } } public static Object readDSFID(final DataInput in) throws IOException, ClassNotFoundException { checkIn(in); - 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"); + 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"); } } public static int readDSFIDHeader(final DataInput in) throws IOException { checkIn(in); - 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"); - } + return readDSFIDHeader(in, DscodeHelper.toDSCODE(in.readByte())); } /** * Reads an instance of {@code String} from a {@code DataInput} given the header byte already * being read. The return value may be {@code null}. - * * @throws IOException A problem occurs while reading from {@code in} * @since GemFire 5.7 */ - 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); - } - 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(); + 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; } - return new String(buf); - } else { - String s = "Unknown String header " + header; - throw new IOException(s); + 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 DataSerializer dvddeserializer; + 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]; + 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)); + } // TODO: registerDVDDeserializer is unused public static void registerDVDDeserializer(DataSerializer dvddeslzr) { @@ -2810,7 +2688,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Just like readObject but make sure and pdx deserialized is not a PdxInstance. - * * @since GemFire 6.6.2 */ public static <T> T readNonPdxInstanceObject(final DataInput in) @@ -2834,260 +2711,207 @@ 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 (header == DSCODE.DS_FIXED_ID_BYTE.toByte()) { - return DSFIDFactory.create(in.readByte(), 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); + + 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.SERIALIZABLE.toByte()) { - final boolean isDebugEnabled_SERIALIZER = logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE); - Object serializableResult; - if (in instanceof DSObjectInputStream) { - serializableResult = ((DSObjectInputStream) in).readObject(); + } + + 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; } else { - 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; - } + 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 (v != null && v != Version.CURRENT) { - ois = new VersionedObjectInput(ois, v); } - } - serializableResult = ois.readObject(); + }; + } - if (isDebugEnabled_SERIALIZER) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "Read Serializable object: {}", - serializableResult); + 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); } } + + serializableResult = (Serializable) ois.readObject(); + if (isDebugEnabled_SERIALIZER) { - logger.trace(LogMarker.SERIALIZER_VERBOSE, "deserialized instanceof {}", - serializableResult.getClass()); + logger.trace(LogMarker.SERIALIZER_VERBOSE, "Read Serializable object: {}", + serializableResult); } - return serializableResult; } - 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); - } - 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); + if (isDebugEnabled_SERIALIZER) { + logger.trace(LogMarker.SERIALIZER_VERBOSE, "deserialized instanceof {}", + serializableResult.getClass()); } - - String s = "Unknown header byte: " + header; - throw new IOException(s); + return serializableResult; } private static Object readUserDataSerializable(final DataInput in, int classId) @@ -3123,23 +2947,17 @@ 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 v) { - if (v) { - pdxSerializationInProgress.set(true); - } else { - pdxSerializationInProgress.set(false); - } + public static void setPdxSerializationInProgress(boolean inProgress) { + pdxSerializationInProgress.set(inProgress); } public static boolean writePdx(DataOutput out, InternalCache internalCache, Object pdx, - PdxSerializer pdxSerializer) throws IOException { + PdxSerializer pdxSerializer) throws IOException { TypeRegistry tr = null; if (internalCache != null) { tr = internalCache.getPdxRegistry(); @@ -3327,63 +3145,371 @@ public abstract class InternalDataSerializer extends DataSerializer { return supportedClassesToHolders; } - /** - * 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(); + 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); } } } /** - * 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. Made public for unit test - * access. - * - * @since GemFire 5.7 + * 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 class GetMarker extends Marker { - /** - * Number of milliseconds to wait. Also used by InternalInstantiator. Note that some tests set - * this to a small amount to speed up failures. Made public for unit test access. - */ - public static int WAIT_MS = Integer.getInteger( - DistributionConfig.GEMFIRE_PREFIX + "InternalDataSerializer.WAIT_MS", 60 * 1000); + 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); + } + } - /** - * Returns the serializer associated with this marker. If the serializer has not been registered - * yet, then this method will wait until the serializer is registered. If this method has to - * wait for too long, then {@code null} is returned. - */ - @Override - DataSerializer getSerializer() { - synchronized (this) { + /** + * 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 { + int size = -1; + if (list != null) { + size = list.size(); + } + InternalDataSerializer.writeArrayLength(size, out); + for (int i = 0; i < size; i++) { + out.writeInt(list.get(i)); + } + } + + /** + * 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(); + } + } + } + + /** + * 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. Made public for unit test + * access. + * @since GemFire 5.7 + */ + public static class GetMarker extends Marker { + /** + * Number of milliseconds to wait. Also used by InternalInstantiator. Note that some tests set + * this to a small amount to speed up failures. Made public for unit test access. + */ + public static int WAIT_MS = Integer.getInteger( + DistributionConfig.GEMFIRE_PREFIX + "InternalDataSerializer.WAIT_MS", 60 * 1000); + + /** + * Returns the serializer associated with this marker. If the serializer has not been registered + * yet, then this method will wait until the serializer is registered. If this method has to + * wait for too long, then {@code null} is returned. + */ + @Override + DataSerializer getSerializer() { + synchronized (this) { boolean firstTime = true; long endTime = 0; while (!this.hasBeenSet) { @@ -3415,7 +3541,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * A marker object for {@code DataSerializer}s that is in the process of being registered. It is * possible for getSerializer to return {@code null} - * * @since GemFire 5.7 */ static class InitMarker extends Marker { @@ -3452,29 +3577,27 @@ public abstract class InternalDataSerializer extends DataSerializer { */ public static class RegistrationMessage extends SerialDistributionMessage { /** - * The id of the {@code DataSerializer} that was registered since 5.7 an int instead of a byte + * The versions in which this message was modified */ - private int id; - + private static final Version[] dsfidVersions = new Version[]{}; /** * The eventId of the {@code DataSerializer} that was registered */ - protected EventID eventId; - + 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() {} + public RegistrationMessage() { + } /** * Creates a new {@code RegistrationMessage} that broadcasts that the given {@code @@ -3592,28 +3715,6 @@ 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. */ @@ -3685,7 +3786,6 @@ public abstract class InternalDataSerializer extends DataSerializer { /** * Used to implement serialization code for the well known classes we support in DataSerializer. - * * @since GemFire 5.7 */ protected abstract static class WellKnownDS extends DataSerializer { @@ -3716,235 +3816,4 @@ 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 new file mode 100644 index 0000000..57d7ae2 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/util/DscodeHelper.java @@ -0,0 +1,19 @@ +package org.apache.geode.internal.util; + +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) { + return dscodes[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 7bc7684..d4007bb 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 @@ -16,12 +16,15 @@ package org.apache.geode.internal; import static org.junit.Assert.assertFalse; +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}) @@ -36,4 +39,11 @@ 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 -> Assert.assertEquals(dscode, DscodeHelper.toDSCODE(dscode.toByte()))); + } }
