WebSphere eXtreme Scale realiza una copia del valor basado en los valores de CopyMode disponibles. Determine el valor que funcione mejor para sus necesidades de despliegue.
Puede utilizar el método setCopyMode(CopyMode, valueInterfaceClass) de la API BackingMap para establecer la modalidad de copia en uno de los siguientes campos estáticos finales que se definen en la clase com.ibm.websphere.objectgrid.CopyMode.
Cuando una aplicación utiliza la interfaz ObjectMap para obtener una referencia a una entrada de correlación, utilice dicha referencia sólo dentro de la transacción de cuadrícula de datos que obtuvo la referencia. El uso de la referencia en una transacción diferente puede conducir a errores. Por ejemplo, si utiliza la estrategia de bloqueo pesimista para BackingMap, una llamada de método get o getForUpdate adquiere un bloqueo S (compartido) o U (actualización), en función de la transacción. El método get devuelve la referencia al valor y el bloqueo que se obtiene se libera cuando se completa la transacción. La transacción debe llamar al método get o getForUpdate para bloquear la entrada de la correlación en una transacción diferente. Cada transacción debe obtener su propia referencia al valor llamando al método get o getForUpdate, en lugar de reutilizar la misma referencia de valor en varias transacciones.
Si se utiliza una correlación asociada con una entidad de API EntityManager, la correlación siempre devuelve los objetos tuple de entidad directamente sin realizar una copia, a menos que utilice la modalidad de copia COPY_TO_BYTES. Es importante que CopyMode se actualice o que se copie el objeto Tuple correctamente al realizar los cambios.
La modalidad COPY_ON_READ_AND_COMMIT es la modalidad predeterminada. El argumento valueInterfaceClass se pasa por alto cuando se utiliza esta modalidad. Esta modalidad garantiza que una aplicación no contenga una referencia al objeto de valor que esté en la correlación BackingMap. En su lugar, la aplicación siempre trabaja con una copia del valor que esté en la correlación BackingMap. La modalidad COPY_ON_READ_AND_COMMIT garantiza que la aplicación nunca pueda dañar accidentalmente los datos almacenados en memoria caché en BackingMap. Cuando una transacción de la aplicación llama a un método ObjectMap.get de una clave determinada, y es el primer acceso de la entrada ObjectMap de esa clave, se devuelve una copia del valor. Cuando se confirma la transacción, los cambios confirmados por la aplicación se copian en BackingMap para garantizar que la aplicación no tenga una referencia al valor confirmado en BackingMap.
La modalidad COPY_ON_READ mejora el rendimiento en comparación con la modalidad COPY_ON_READ_AND_COMMIT al eliminar la copia que se produce cuando se confirma una transacción. El argumento valueInterfaceClass se pasa por alto cuando se utiliza esta modalidad. Para conservar la integridad de los datos de BackingMap, la aplicación garantiza que todas las referencias que tiene de una entrada se destruyan una vez confirmada la transacción. Con esta modalidad, el método ObjectMap.get devuelve una copia del valor en lugar de una referencia al valor para garantizar que los cambios realizados por la aplicación en el valor no afecten al valor de BackingMap hasta que se confirme la transacción. No obstante, cuando se confirma, no se realiza una copia de los cambios. En su lugar, se almacena en BackingMap la referencia a la copia devuelta por el método ObjectMap.get. La aplicación destruye todas las referencias de la entrada de correlación una vez que se confirma la transacción. Si la aplicación no las destruye, la aplicación podría dañar los datos almacenados en memoria caché de BackingMap. Si una aplicación que utiliza esta modalidad experimenta problemas, cambie a la modalidad COPY_ON_READ_AND_COMMIT para ver si se sigue produciendo el problema. Si desaparece, significa que la aplicación no está destruyendo todas las referencias después de la confirmación de la transacción.
La modalidad COPY_ON_WRITE mejora el rendimiento en comparación con la modalidad COPY_ON_READ_AND_COMMIT al eliminar la copia que se produce cuando una transacción llama por primera vez al método ObjectMap.get para una clave determinada. El método ObjectMap.get devuelve un proxy al valor en lugar de una referencia directa al objeto de valor. El proxy garantiza que no se realice una copia del valor a no ser que la aplicación llame a un método set en la interfaz de valor especificada en el argumento valueInterfaceClass. El proxy proporciona una copia en la implementación de grabación. Cuando se confirma una transacción, BackingMap examina el proxy para determinar si se realizó una copia como resultado de haber llamado a un método set. Si se realizó un copia, la referencia a dicha copia se almacena en BackingMap. La ventaja de utilizar esta modalidad es que un valor nunca se copia en una operación de lectura o de confirmación si la transacción no ha llamado a un método set para cambiar el valor.
Las modalidades COPY_ON_READ_AND_COMMIT y COPY_ON_READ realizan una copia profunda cuando un valor se recupera de ObjectMap. Si una aplicación sólo actualiza algunos de los valores recuperados en una transacción, esta modalidad no es la ideal. La modalidad COPY_ON_WRITE admite este comportamiento de una manera eficiente, pero requiere que la aplicación utilice un patrón sencillo. Los objetos de valor son obligatorios para admitir una interfaz. La aplicación debe utilizar los métodos de esta interfaz cuando interactúe con el valor de una sesión. Si éste fuera el caso, se crean proxies para los valores devueltos a la aplicación. El proxy tiene una referencia al valor real. Si la aplicación sólo realiza operaciones de lectura, éstas siempre se ejecutan contra la copia real. Si la aplicación modifica un atributo en el objeto, el proxy realiza una copia del objeto real y después modifica la copia. A continuación, el proxy utilice la copia a partir de ese punto. El uso de la copia permite que no se realice la operación de copia para los objetos que sólo lee la aplicación. Todas las operaciones de modificación deben empezar con el prefijo set. Normalmente, los Enterprise JavaBeans se codifican para utilizar este estilo de denominación de método para los métodos que modifican los atributos de objetos. Debe seguirse este convenio. Los objetos que se modifican se copian en el momento en que los modifica la aplicación. Este escenario de lectura y escritura es el escenario más eficaz soportado por eXtreme Scale. Para configurar una correlación de modo que utilice la modalidad COPY_ON_WRITE, observe el ejemplo siguiente. En este ejemplo, la aplicación almacena objetos Person que utilizan el nombre en la correlación. El objeto person se representa en el siguiente fragmento de código.
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;
}
}
La aplicación utiliza la interfaz IPerson sólo cuando interactúa con valores recuperados de ObjectMap. Modifique el objeto para utilizar una interfaz como en el ejemplo siguiente:
interface IPerson
{
void setName(String n);
String getName();
void setAge(int a);
int getAge();
}
// Modificar Person para implementar la interfaz IPerson
class Person implements IPerson {
...
}
ObjectGrid dg = ...;
BackingMap bm = dg.defineMap("PERSON");
// usar COPY_ON_WRITE para esta correlación con
// IPerson como valueProxyInfo Class
bm.setCopyMode(CopyMode.COPY_ON_WRITE,IPerson.class);
// La aplicación debe utilizar el siguiente
// patrón al usar la correlación PERSON.
Session sess = ...;
ObjectMap person = sess.getMap("PERSON");
...
sess.begin();
// la aplicación difunde el valor devuelto a IPerson y no Person
IPerson p = (IPerson)person.get("Billy");
p.setAge(p.getAge()+1);
...
// hacer Person nuevo y añadirlo a la correlación
Person p1 = new Person();
p1.setName("Bobby");
p1.setAge(12);
person.insert(p1.getName(), p1);
sess.commit();
// el fragmento de código siguiente NO FUNCIONARÁ. Devolverá ClassCastException
sess.begin();
// el error ha sido utilizar Person en lugar de
// IPerson
Person a = (Person)person.get("Bobby");
sess.commit();
Puede difundir el proxy para dos tipos. La última parte del fragmento de código anterior muestra lo que no se permite en la modalidad COPY_ON_WRITE. La aplicación recupera el registro Bobby e intenta difundir el registro a un objeto Person. Esta acción produce una excepción de difusión de clase porque el proxy devuelto no es un objeto Person. El proxy devuelto implementa el objeto IPerson y ValueProxyInfo.
Interfaz ValueProxyInfo y soporte de actualización parcial: esta interfaz permite a una aplicación recuperar el valor confirmado de sólo lectura al que hace referencia el proxy o el conjunto de atributos modificado durante esta transacción.
public interface ValueProxyInfo {
List /**/ ibmGetDirtyAttributes();
Object ibmGetRealValue();
}
El método ibmGetRealValue devuelve una copia de sólo lectura del objeto. La aplicación no debe modificar este valor. El método ibmGetDirtyAttributes devuelve una lista de series que representan los atributos modificados por la aplicación durante esta transacción. El principal caso de uso para el método ibmGetDirtyAttributes se encuentra en una Java Database Connectivity (JDBC) o un cargador basado en CMP. Sólo deben actualizarse los atributos de la lista, ya sea en la sentencia SQL o en el objeto correlacionado con la tabla. Esta práctica permite que el cargador genere de forma más eficiente el SQL. Cuando se confirma una transacción "copy on write" y se conecta un cargador, éste puede difundir los valores de los objetos modificados a la interfaz ValueProxyInfo para obtener esta información.
Manejo del método equals al utilizar COPY_ON_WRITE o servidores proxy: por ejemplo, el código siguiente construye un objeto Person y lo inserta en un ObjectMap. A continuación, recupera el mismo objeto mediante el método ObjectMap.get. El valor se difunde a la interfaz. Si el valor se difunde a la interfaz Person, se produce una excepción ClassCastException porque el valor devuelto es un proxy que implementa la interfaz IPerson y no es un objeto Person. La comprobación de igualdad falla al utilizar la operación == porque no son el mismo objeto.
session.begin();
// objeto Person nuevo
Person p = new Person(...);
personMap.insert(p.getName, p);
// recuperarlo de nuevo, recordar usar la interfaz para la difusión
IPerson p2 = personMap.get(p.getName());
if(p2 == p) {
// son iguales
} else {
// no son iguales
}
Otra consideración a tener en cuenta es cuando debe alterarse temporalmente el método equals. El método equals debe verificar que el argumento es un objeto que implementa la interfaz IPerson y difunde el argumento para ser un objeto IPerson. Como el argumento puede ser un proxy que implementa la interfaz IPerson, debe usar los métodos getAge y getName al comparar la igualdad de las variables de instancia. Consulte el siguiente ejemplo:
{
if ( obj == null ) return false;
if ( obj instanceof IPerson ) {
IPerson x = (IPerson) obj;
return ( age.equals( x.getAge() ) && name.equals( x.getName() ) )
}
return false;
}
Requisitos de configuración de ObjectQuery y HashIndex: cuando se utiliza COPY_ON_WRITE con plug-ins ObjectQuery o HashIndex, debe configurar el esquema ObjectQuery y el plug-in HashIndex para acceder a los objetos a través de métodos de propiedades, que es el valor predeterminado. Si ha configurado el acceso a campos, el motor de consulta y el índice intentan acceder a los campos en el objeto proxy, que siempre devuelve null o 0 ya que la instancia de objeto es un proxy.
La modalidad NO_COPY permite a una aplicación obtener mejoras de rendimiento, pero requiere que dicha aplicación no modifique nunca un objeto de valor obtenido utilizando un método ObjectMap.get. El argumento valueInterfaceClass se ignora cuando se utiliza esta modalidad. Si se utiliza esta modalidad, no se produce nunca una copia del valor. Si la aplicación modifica alguna instancia de objeto de valor recuperada del ObjectMap o añadida a éste, los datos de BackingMap se dañarán. La modalidad NO_COPY es útil especialmente en el caso de correlaciones de sólo lectura en las que la aplicación nunca modifica los datos. Si la aplicación utiliza esta modalidad y experimenta problemas, cambie a la modalidad COPY_ON_READ_AND_COMMIT para ver si se sigue produciendo el problema. Si desaparece, significa que la aplicación está modificando el valor devuelto por el método ObjectMap.get, durante la transacción o una vez confirmada ésta. Todas las correlaciones asociadas a las entidades de la API EntityManager utilizan automáticamente esta modalidad, independientemente de lo que se haya especificado en la configuración de eXtreme Scale.
Todas las correlaciones asociadas a las entidades de la API EntityManager utilizan automáticamente esta modalidad, independientemente de lo que se haya especificado en la configuración de eXtreme Scale.
Puede almacenar los objetos en un formato serializado, en lugar del formato POJO. Mediante el uso del valor COPY_TO_BYTES, puede reducir la huella de la memoria que puede consumir un gráfico grande de objetos. Para obtener más información, consulte Mejora del rendimiento con correlaciones de matriz de bytes.
Con COPY_TO_BYTES_RAW, puede acceder directamente el formato serializado de los datos. Esta modalidad de copia ofrece una manera eficaz de interactuar con bytes serializados, lo que le permite evitar el proceso de deserialización para acceder a objetos en la memoria.
En el archivo XML de descriptor de ObjectGrid, puede establecer la modalidad de copia COPY_TO_BYTES, y establecer programáticamente la modalidad de copia a COPY_TO_BYTES_RAW en las instancias donde desea acceder a los datos serializados en bruto. Establezca la modalidad de copia en COPY_TO_BYTES _RAW en el archivo XML de descriptor de ObjectGrid sólo cuando la aplicación utilice el formato de datos en bruto como parte de una aplicación de proceso principal.Los errores se producen cuando la aplicación intenta mejorar el rendimiento al usar las modalidades de copia COPY_ON_READ, COPY_ON_WRITE o NO_COPY, como se ha descrito anteriormente. Los errores intermitentes no se producen al cambiar la modalidad de copia a la modalidad COPY_ON_READ_AND_COMMIT.
Problema
Los datos de la correlación ObjectGrid pueden resultar dañados como resultado de la violación por parte de la aplicación del contrato de programación de la modalidad de copia que se está utilizando. El daño en los datos puede ocasionar errores imprevisibles de forma intermitente o errores que se manifiestan de forma inexplicable o inesperada.
Solución
La aplicación debe cumplir el contrato de programación que se aplica para la modalidad de copia que se vaya a utilizar. Para las modalidades de copia COPY_ON_READ y COPY_ON_WRITE, la aplicación utiliza una referencia a un objeto de valor fuera del ámbito de la transacción del que se obtuvo la referencia del valor. Para utilizar estas modalidades, la aplicación debe eliminar la referencia al objeto de valor una vez completada la transacción, y obtener una nueva referencia al objeto de valor en cada transacción que acceda al objeto de valor. Para la modalidad de copia NO_COPY, la aplicación nunca debe modificar el objeto de valor. En este caso, escriba la aplicación de modo que no cambie el objeto de valor, o establezca la aplicación para utilizar otra modalidad de copia.