All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.kv.impl.util.FastExternalizable Maven / Gradle / Ivy

Go to download

NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.

There is a newer version: 18.3.10
Show newest version
/*-
 * Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle NoSQL
 * Database made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle NoSQL Database for a copy of the license and
 * additional information.
 */

package oracle.kv.impl.util;

import java.io.DataOutput;
import java.io.IOException;

/**
 * Implemented by classes that are serialized using an optimized technique
 * that avoids the Java dependency and the performance pitfalls of the standard
 * Serializable and Externalizable approaches. The serialized form is not Java
 * dependent and can be used for transfer over RMI to Java remote recipients
 * as well as to non-Java recipients using some other (non-RMI) transport. It
 * is mainly intended for API operations, but may also be useful for high
 * frequency operations outside of the API, as well as for use with non-Java
 * applications.
 *
 * 

Standard 'Slow' Serialization

* * The simplest way to serialize objects passed and returned over RMI is to * make them Serializable. The class implements the Serializable tag interface * and a serialVersionUID field must be declared as follows: *
 *  private static final long serialVersionUID = 1;
 * 
* With standard Serialization, for every object serialized in an RMI request * or response, metadata with a complete description of its fields is included * in the request/response. The metadata is large and redundant among * requests, and it takes time to serialize and deserialize. The * deserialization process is particularly lengthy because classes must be * looked up and the class metadata compared to the metadata passed in the * request/response. *

* Because of its overhead, Serializable is not appropriate for high frequency * operations. However, it is fine and very practical for low frequency * operations. *

* The Externalizable interface is an alternative to Serializable. Like * Serializable, the class implements the Externalizable tag interface and a * serialVersionUID field must be declared. In addition, a public no-args * constructor must be declared. With Externalizable, the class must implement * the writeExternal and readExternal methods to explicitly serialize and * deserialize each field. The use of Externalizable is therefore much more * complex than with Serializable and requires maintenance. *

* Unlike Serializable, the metadata for an Externalizable object does not * include a description of its fields. Instead, only the class name and some * per-class metadata is included. It is consequently much more efficient than * Serializable. However, like with Serializable, a class lookup is performed * during deserialization. In performance tests, the class lookup was found to * be have significant overhead. *

* When using Externalizable, the class description and lookup overhead is * multiplied by the number of Externalizable classes for instances embedded in * the RMI request/response. This overhead motivated the implementation of a * faster method of serialization. * *

Optimized or 'Fast' Serialization

* * To implement fully optimized serialization for an RMI interface, the top * level objects (parameters and return value) of the remote methods should be * Externalizable. RMI calls ObjectOutput.writeObject and * ObjectInput.readObject on every non-primitive parameter and return value, so * the classes must be Serializable or Externalizable, and Externalizable is * much preferred. *

* The classes of objects contained by (embedded in) the top level parameter * and return value objects may be FastExternalizable rather than * Externalizable. This avoids writing the class name of each object, and more * importantly the class lookup during deserialization. *

* Like Externalizable, a FastExternalizable class reads and writes its * representation directly, a field at a time. Unlike Serializable, a complete * description of the class is not included in the serialized form. *

* Unlike Externalizable, a FastExternalizable class does not write a * full class name, and does not do a class lookup or use reflection to create * the instance during deserialization. Instead, a simple integer constant is * typically used to identify the class, or in some cases the class is implied * from the context, i.e., the field type. With FastExternalizable, an * instance of the class is created directly (with 'new') rather than using * reflection, or a constant instance may be used. *

* Unlike Serializable and Externalizable, a FastExternalizable instance cannot * be written using ObjectOutput.writeObject or read using * ObjectInput.readObject, since these methods are reserved for standard * serialization. * *

The FastExternalizable serialVersion parameter

* * Remote method input parameters must include a version identifying their * serialized format as well as the required serialized format of the return * value. This allows an older client to interact with a newer service. When * the serialization format changes, the service is responsible for supporting * older formats and serializing the return value in the format specified by * the client's input parameters. The client is responsible for using the * minimum of the version it supports and the version supported by the service, * which allows a newer client to interact with an older service. *

* TODO: More details to follow, as the negotiation of the version to use is not * fully implemented yet. * *

The FastExternalizable.writeFastExternal method

* * With FastExternalizable, a member method with the same signature (other than * method name) as Externalizable.writeExternal is used to write the object. * The enclosing class (whether Externalizable or FastExternalizable itself) * should call writeFastExternal directly. *

* If a class identifier field is stored for use by a factory method (more on * this below) it is written by the writeFastExternal method. * *

The FastExternalizable constructor

* * Unlike Externalizable, a constructor rather than a method is used to read * the object from a DataInput. *

* A constructor is used rather than a method so that the fields it initializes * can be declared 'final' and a no-args constructor is not needed. *

* A constructor signature similar to the following is required in all * FastExternalizable classes, by convention. When a factory method is used, * an additional parameter may be required to initialize a class identifier * field (more on this below). *

 *   ExampleClass(DataInput in, short serialVersion) throws IOException {
 *       ...
 *   }
 * 
* If a field may contain instances of only a single class, not its subclasses, * and this won't be changing in the future, the constructor can be used * directly by the enclosing class to create the instance (with 'new') and read * it from the DataInput. Otherwise, a factory method is used as described * next. * *

The FastExternalizable factory method

* * If the class is variable (for example, subtypes of the field type may be * used) then a static factory method should be defined to create the instance * of the correct class and invoke its constructor, following the constructor * convention above. *

* A factory method should also be used when the field may contain constant * values. This allows the factory method to return predefined constants * rather than creating a new instance. *

* By convention the signature of the factory method is: *

 *   static ExampleClass readFastExternal(DataInput in, short serialVersion) throws IOException {
 *       ...
 *   }
 * 
* A factory method must first read a class or constant identifier field of * some kind. After reading the identifier field, it can create a new instance * of the appropriate class, or perhaps return a constant instance. *

* A common technique for storing a class or instance identifier is to define * an Enum class with one value for each class or constant instance, and store * the Enum.ordinal() as the identifier. When reading the identifier the * matching Enum is found, and an Enum method may be used to create an instance * of the appropriate class or return a constant instance. Note that Enum * values used in this way may not be reordered, or the change in ordinals will * break serialization compatibility. *

* When the factory constructs a new instance, it may pass the class identifier * (in addition to the DataInput parameter) to the constructor, if the class * identifier will be stored in an instance field. The constructor cannot read * the class identifier from the DataInput, since it has already been read by * the factory method. * *

Null values

* * When an object may be null, by convention we use one byte to indicate this, * where 1 means non-null, and 0 means null. This logic is implemented in the * enclosing class for the object that may be null. * *

Use with non-Java applications

* * Because the FastExternalizable class does not depend on Java serialization, * data serialized in this format can be read and written by non-Java * applications. To better support this sort of interoperability, please * describe the data format in the documentation for each writeExternal method, * following the conventions found in the documentation for existing methods. * *

Detecting sequence length values

* * Although we do not enforce any limits yet (see [#25828] Data length limits), * there are security and resource auditing reasons for us to restrict the * lengths of arrays and collections during FastExternalizable serialization * and deserialization. To make this process easier in the future, please make * sure to use the methods for serializing arrays, collections, and sequence * lengths in the SerializationUtil class. * *

Combining FastExternalizable with other serialization approaches

* * FastExternalizable may be combined with DPL-persistence, Serializable, or * Externalizable in a single class. So far this has only been done for * DPL-persistence and Serializable, and this is straightforward. It is * possible to combine FastExternalizable with Externalizable, but the need for * this has not yet arisen. *

* For whatever combination is used, the most restrictive rule must be applied: *

    *
  • A serialVersionUID must be included for Serializable and Externalizable, * but not FastExternalizable or DPL-persistence. * *
  • A no-args constructor must be included for DPL-persistence and * Externalizable, but not Serializable or FastExternalizable. The no-args * constructor must be public for Externalizable, but may be private for * DPL-persistence. * *
  • Serialized fields must not be 'final' for DPL-persistence and * Externalizable, but may be 'final' for Serializable and * FastExternalizable. *
*

Examples

* *
*
{@link oracle.kv.impl.api.Request} *
* Externalizable class that contains FastExternalizable instances. Is a * top-level parameter of the RMI remote method * {@link oracle.kv.impl.api.RequestHandler#execute}. * *
{@link oracle.kv.Value} *
* FastExternalizable class that includes a constructor but not a factory * method. Simplest case. * *
{@link oracle.kv.Consistency} *
* FastExternalizable class that includes a factory method for the purpose * of returning a constant instance in some cases. * *
{@code oracle.kv.impl.api.ops.Result.ValueVersionResult} *
* Example of how null embedded objects are handled. * *
{@link oracle.kv.Operation} *
* FastExternalizable class that includes a constructor and factory method * for creating Operation subclasses. Uses an enum as the class identifier. * {@link oracle.kv.impl.api.ops.Get} is an example of a Operation subclass. * *
{@link oracle.kv.impl.topo.ResourceId} *
* Similar to Operation but is additionally Serializable. Several subclasses * are also DPL-persistent. *
*/ public interface FastExternalizable { /** * Writes the FastExternalizable object to the DataOutput. To read the * object, use a constructor or factory method as described in the class * comments. */ public void writeFastExternal(DataOutput out, short serialVersion) throws IOException; }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy