Program guide > Performance considerations



CopyMode best practices

WebSphere eXtreme Scale makes a copy of the value based on the six available CopyMode settings. Determine which setting works best for the deployment requirements.

Use the BackingMap API setCopyMode(CopyMode, valueInterfaceClass) method to set the copy mode to one of the following final static fields that are defined in the com.ibm.websphere.objectgrid.CopyMode class.

When an application uses the ObjectMap interface to obtain a reference to a map entry, use that reference only within the WebSphere eXtreme Scale transaction that obtained the reference. Using the reference in a different transaction can lead to errors. For example, if you use the pessimistic locking strategy for the BackingMap, a get or getForUpdate method call acquires an S (shared) or U (update) lock, depending on the transaction. The get method returns the reference to the value and the lock that is obtained is released when the transaction completes. The transaction must call the get or getForUpdate method to lock the map entry in a different transaction. Each transaction must obtain its own reference to the value by calling the get or getForUpdate method instead of reusing the same value reference in multiple transactions.


CopyMode for entity maps

When using a map associated with an EntityManager API entity, the map always returns the entity Tuple objects directly without making a copy unless you are using COPY_TO_BYTES copy mode. It is important that the CopyMode is updated or the Tuple is copied appropriately when making changes.


COPY_ON_READ_AND_COMMIT

The COPY_ON_READ_AND_COMMIT mode is the default mode. The valueInterfaceClass argument is ignored when this mode is used. This mode ensures that an application does not contain a reference to the value object that is in the BackingMap. Instead, the application is always working with a copy of the value that is in the BackingMap. The COPY_ON_READ_AND_COMMIT mode ensures that the application can never inadvertently corrupt the data that is cached in the BackingMap. When an application transaction calls an ObjectMap.get method for a given key, and it is the first access of the ObjectMap entry for that key, a copy of the value is returned. When the transaction is committed, any changes that are committed by the application are copied to the BackingMap to ensure that the application does not have a reference to the committed value in the BackingMap.


COPY_ON_READ

The COPY_ON_READ mode improves performance over the COPY_ON_READ_AND_COMMIT mode by eliminating the copy that occurs when a transaction is committed. The valueInterfaceClass argument is ignored when this mode is used.

To preserve the integrity of the BackingMap data, the application ensures that every reference that it has for an entry is destroyed after the transaction is committed. With this mode, the ObjectMap.get method returns a copy of the value instead of a reference to the value to ensure that changes that are made by the application to the value does not affect the BackingMap value until the transaction is committed. However, when the transaction does commit, a copy of changes is not made. Instead, the reference to the copy that was returned by the ObjectMap.get method is stored in the BackingMap. The application destroys all map entry references after the transaction is committed. If application does not destroy the map entry references, the application might cause the data cached in BackingMap to become corrupted. If an application is using this mode and is having problems, switch to COPY_ON_READ_AND_COMMIT mode to see if the problem still exists. If the problem goes away, then the application is failing to destroy all of its references after the transaction has committed.


COPY_ON_WRITE

The COPY_ON_WRITE mode improves performance over the COPY_ON_READ_AND_COMMIT mode by eliminating the copy that occurs when the ObjectMap.get method is called for the first time by a transaction for a given key. The ObjectMap.get method returns a proxy to the value instead of a direct reference to the value object. The proxy ensures that a copy of the value is not made unless the application calls a set method on the value interface that is specified by the valueInterfaceClass argument. The proxy provides a copy on write implementation. When a transaction commits, the BackingMap examines the proxy to determine if any copy was made as a result of a set method being called. If a copy was made, then the reference to that copy is stored in the BackingMap. The big advantage of this mode is that a value is never copied on a read or at a commit when the transaction never calls a set method to change the value.

The COPY_ON_READ_AND_COMMIT and COPY_ON_READ modes both make a deep copy when a value is retrieved from the ObjectMap. If an application only updates some of the values that are retrieved in a transaction then this mode is not optimal. The COPY_ON_WRITE mode supports this behavior in an efficient manner but requires that the application uses a simple pattern. The value objects are required to support an interface. The application must use the methods on this interface when it is interacting with the value in an eXtreme Scale Session. If this is the case, then eXtreme Scale creates proxies for the values that are returned to the application. The proxy has a reference to be real value. If the application performs read operations only, the read operations always run against the real copy. If the application modifies an attribute on the object, the proxy makes a copy of the real object and then makes the modification on the copy. The proxy then uses the copy from that point on. Using the copy allows the copy operation to be avoided completely for objects that are only read by the application. All modify operations must start with the set prefix. Enterprise JavaBeans™ normally are coded to use this style of method naming for methods that modify the objects attributes. This convention must be followed. Any objects that are modified are copied at the time that they are modified by the application. This read and write scenario is the most efficient scenario supported by eXtreme Scale.

To configure a map to use COPY_ON_WRITE mode, use the following example. In this example, the application stores Person objects that are keyed using the name in the Map. The person object is represented in the following code snippet.

class Person {
    String name;
    int age;
    public Person() {
    }
    public void setName(String n)     {
        name = n;
    }
    public String getName() {
        return name;
    }
    public void setAge(int a) {    
        age = a;
    }
    public int getAge() {
        return age;
    }
}

The application uses the IPerson interface only when it interacts with values that are retrieved from a ObjectMap. Modify the object to use an interface as in the following example.

interface IPerson
{
    void setName(String n);
    String getName();
    void setAge(int a);
    int getAge();
}
// Modify Person to implement IPerson interface
class Person implements IPerson {
    ...
}

The application then needs to configure the BackingMap to use COPY_ON_WRITE mode, like in the following example:

ObjectGrid dg = ...;
BackingMap bm = dg.defineMap("PERSON");
// use COPY_ON_WRITE for this Map with
// IPerson as the valueProxyInfo Class
bm.setCopyMode(CopyMode.COPY_ON_WRITE,IPerson.class);
// The application should then use the following
// pattern when using the PERSON Map.
Session sess = ...;
ObjectMap person = sess.getMap("PERSON");
...
sess.begin();
// the application casts the returned value to IPerson and not Person
IPerson p = (IPerson)person.get("Billy");
p.setAge(p.getAge()+1);
...
// make a new Person and add to Map
Person p1 = new Person();
p1.setName("Bobby");
p1.setAge(12);
person.insert(p1.getName(), p1);
sess.commit();
// the following snippet WON'T WORK. Will result in ClassCastException
sess.begin();
// the mistake here is that Person is used rather than
// IPerson
Person a = (Person)person.get("Bobby");
sess.commit();

The first section shows the application retrieving a value that was named Billy in the map. The application casts the returned value to the IPerson object, not the Person object because the proxy that is returned implements two interfaces:

You can cast the proxy to two types. The last part of the preceding code snippet demonstrates what is not allowed in COPY_ON_WRITE mode. The application retrieves the Bobby record and tries to cast the record to a Person object. This action fails with a class cast exception because the proxy that is returned is not a Person object. The returned proxy implements the IPerson object and ValueProxyInfo.

ValueProxyInfo interface and partial update support: This interface allows an application to retrieve either the committed read-only value referenced by the proxy or the set of attributes that have been modified during this transaction.

public interface ValueProxyInfo {
    List /**/ ibmGetDirtyAttributes();
    Object ibmGetRealValue();
}

The ibmGetRealValue method returns a read only copy of the object. The application must not modify this value. The ibmGetDirtyAttributes method returns a list of strings representing the attributes that have been modified by the application during this transaction. The main use case for ibmGetDirtyAttributes is in a Java™ database connectivity (JDBC) or CMP based loader. Only the attributes that are named in the list need be updated on either the SQL statement or object mapped to the table, which leads to more efficient SQL generated by the Loader. When a copy on write transaction is committed and if a loader is plugged in, the the loader can cast the values of the modified objects to the ValueProxyInfo interface to obtain this information.

Handle the equals method when using COPY_ON_WRITE or proxies: For example, the following code constructs a Person object and then inserts it to a an ObjectMap. Next, it retrieves the same object using the ObjectMap.get method. The value is cast to the interface. If the value is cast to the Person interface, a ClassCastException exception results because the returned value is a proxy that implements the IPerson interface and is not a Person object. The equality check fails when using the == operation because they are not the same object.

session.begin();
// new the Person object
Person p = new Person(...);
personMap.insert(p.getName, p);
// retrieve it again, remember to use the interface for the cast
IPerson p2 = personMap.get(p.getName());
if(p2 == p) {
    // they are the same
} else {
    // they are not
}

Another consideration is when override the equals method. As illustrated in the following snippet of code, the equals method must verify that the argument is an object that implements IPerson interface and cast the argument to be a IPerson. Because the argument might be a proxy that implements the IPerson interface, use the getAge and getName methods when comparing instance variables for equality.

{
    if ( obj == null ) return false;
    if ( obj instanceof IPerson ) {
        IPerson x = (IPerson) obj;
        return ( age.equals( x.getAge() ) && name.equals( x.getName() ) )
    }
    return false;
}

ObjectQuery and HashIndex configuration requirements: When using COPY_ON_WRITE with ObjectQuery or a HashIndex plug-in, it's important to configure the ObjectQuery schema and HashIndex plug-in to access the objects using property methods, which is the default. If configured to use field access, the query engine and index will attempt to access the fields in the proxy object, which will always return null or 0 since the object instance will be a proxy.


NO_COPY

The NO_COPY mode allows an application to ensure that it never modifies a value object that is obtained using an ObjectMap.get method in exchange for performance improvements. The valueInterfaceClass argument is ignored when this mode is used. If this mode is used, no copy of the value is ever made. If the application modifies values, then the data in the BackingMap is corrupted. The NO_COPY mode is primarily useful for read-only maps where data is never modified by the application. If the application is using this mode and it is having problems, then switch to the COPY_ON_READ_AND_COMMIT mode to see if the problem still exists. If the problem goes away, then the application is modifying the value returned by ObjectMap.get method, either during transaction or after transaction has committed. All maps associated with EntityManager API entities automatically use this mode regardless of what is specified in the eXtreme Scale configuration.

All maps associated with EntityManager API entities automatically use this mode regardless of what is specified in the eXtreme Scale configuration.


COPY_TO_BYTES

You can store objects in a serialized format instead of POJO format. By using the COPY_TO_BYTES setting, you can reduce the memory footprint that a large graph of Objects can consume. See Byte array maps for additional information.


Incorrect use of CopyMode

Errors occur when an application attempts to improve performance by using the COPY_ON_READ, COPY_ON_WRITE, or NO_COPY copy mode, as described above. The intermittent errors do not occur when you change the copy mode to the COPY_ON_READ_AND_COMMIT mode.


Problem

The problem might be due to corrupted data in the ObjectGrid map, which is a result of the application violating the programming contract of the copy mode that is being used. Data corruption can cause unpredictable errors to occur intermittently or in an unexplained or unexpected fashion.


Solution

The application must comply with the programming contract that is stated for the copy mode being used. For the COPY_ON_READ and COPY_ON_WRITE copy modes, the application uses a reference to a value object outside of the transaction scope from which the value reference was obtained. To use these modes, the application must delete the reference to the value object after the transaction completes, and obtain a new reference to the value object in each transaction that accesses the value object. For the NO_COPY copy mode, the application must never change the value object. In this case, either write the application so that it does not change the value object, or set the application to use a different copy mode.


Parent topic:

Access data in WebSphere eXtreme Scale


Parent topic:

Performance considerations for application developers


Related concepts

Byte array maps

JVM tuning

Plug-in evictor performance best practices

Locking performance best practices

Serialization performance

ObjectTransformer interface best practices

Query performance tuning