Plug-ins para Versão e Comparação de Objetos de Cache

Use o plug-in OptimisticCallback para customizar as operações de versão e de comparação de objetos do cache ao usar a estratégia de bloqueio otimista.

É possível fornecer um objeto de retorno de chamada otimista conectável que implementa a interface com.ibm.websphere.objectgrid.plugins.OptimisticCallback. Para mapas de entidade, um plug-in OptimisticCallback de alto desempenho é automaticamente configurado.

Propósito

Utilize a interface OptimisticCallback para fornecer operações de comparação otimistas para os valores de um mapa. Uma implementação OptimisticCallback é necessária ao utilizar a estratégia de bloqueio otimista. O produto fornece uma implementação de OptimisticCallback padrão. No entanto, geralmente o aplicativo deve conectar sua própria implementação da interface OptimisticCallback.

Implementação Padrão

A estrutura do eXtreme Scale fornece uma implementação padrão da interface OptimisticCallback que é usada se o aplicativo não for conectado a um objeto OptimisticCallback fornecido pelo aplicativo. A implementação padrão sempre retorna o valor especial de NULL_OPTIMISTIC_VERSION como o objeto de versão para o valor e nunca atualiza o objeto de versão. Esta ação faz uma comparação otimista de uma função "no operation". Na maioria dos casos, você não deseja que a função "no operation" ocorra, quando estiver utilizando a estratégia de bloqueio otimista. Seus aplicativos devem implementar a interface OptimisticCallback e conectar suas próprias implementações de OptimisticCallback para que a implementação padrão não seja utilizada. No entanto, existe pelo menos um cenário no qual a implementação de OptimisticCallback fornecida padrão é útil. Considere a seguinte situação:
  • Um utilitário de carga é conectado para o mapa de suporte.
  • O utilitário de carga sabe como desempenhar a comparação otimista sem assistência de um plug-in OptimisticCallback.
Como o utilitário de carga pode executar a versão otimista sem assistência de um objeto OptimisticCallback? O utilitário de carga conhece o objeto de classe de valor e sabe qual campo de objeto de valor é utilizado como um valor de versão otimista. Por exemplo, suponha que a seguinte interface seja utilizada para o objeto de valor para o mapa employees:
public interface Employee
{
    // Sequential sequence number used for optimistic versioning.
    public long getSequenceNumber();
    public void setSequenceNumber(long newSequenceNumber);
    // Other get/set methods for other fields of Employee object.
}

Neste exemplo, o utilitário de carga sabe que pode utilizar o método getSequenceNumber para obter as informações de versão atuais para um objeto de valor Employee. O utilitário de carga incrementa o valor retornado para gerar um novo número de versão antes de atualizar o armazenamento persistente com o novo valor Employee. Para um utilitário de carga Java Database Connectivity (JDBC), o número de sequência atual na cláusula WHERE de uma instrução UPDATE SQL superqualificada é usado e ele usa o novo número de sequência gerado para configurar a coluna do número de sequência para o novo valor de número de sequência. Outra possibilidade é que o utilitário de carga faça uso de alguma função fornecida por backend que atualiza automaticamente uma coluna oculta que pode ser utilizada para versões otimistas.

Em alguns casos, um procedimento armazenado ou acionador possivelmente pode ser utilizado para ajudar a manter uma coluna que contém as informações de controle de versões. Se o utilitário de carga estiver utilizando uma destas técnicas para a manutenção de informações de versões otimistas, então, o aplicativo não precisa fornecer uma implementação do OptimisticCallback. A implementação OptimisticCallback padrão pode ser utilizada neste cenário porque o utilitário de carga consegue identificar versões otimistas sem nenhuma assistência de um objeto OptimisticCallback.

Implementação Padrão para Entidades

As entidades são armazenadas no ObjectGrid utilizando objetos de tupla. A implementação OptimisticCallback padrão se comporta da mesma maneira que se comporta com mapas de não-entidade. Entretanto, o campo de versão na entidade é identificado utilizando a anotação @Version ou o atributo version no arquivo XML descritor da entidade.

O atributo version pode ser de um dos seguintes tipos: int, Integer, short, Short, long, Long ou java.sql.Timestamp. Uma entidade deve ter apenas um atributo version definido. O atributo version deve ser configurado apenas durante a construção. Depois de a entidade ser persistida, o valor do atributo de versão não deve ser modificado.

Se um atributo version não estiver configurado e a estratégia de bloqueio otimista for utilizada, então, a tupla inteira será implicitamente versionada utilizando o estado inteiro da tupla, o que é mais custoso

No exemplo a seguir, a entidade Employee possui um atributo de versão longa denominado SequenceNumber:
@Entity
public class Employee {
private long sequence;
    // Sequential sequence number used for optimistic versioning.
    @Version
    public long getSequenceNumber() {
        return sequence;
    }
    public void setSequenceNumber(long newSequenceNumber) {
        this.sequence = newSequenceNumber;
    }
    // Other get/set methods for other fields of Employee object.
}

Gravando um Plug-in OptimisticCallback

Um plug-in OptimisticCallback precisa implementar a interface OptimisticCallback e seguir as convenções comuns do plug-in ObjectGrid. Consulte a Interface OptimisticCallback para obter mais informações.

A lista a seguir fornece uma descrição ou consideração para cada um dos métodos na interface OptimisticCallback:

NULL_OPTIMISTIC_VERSION

Este valor especial será retornado pelo método getVersionedObjectForValue se a implementação OptimisticCallback não requerer uma verificação de versão. A implementação de plug-in integrada da classe com.ibm.websphere.objectgrid.plugins.builtins.NoVersioningOptimisticCallback usa esse valor porque a versão é desativada ao especificar essa implementação de plug-in.

Método getVersionedObjectForValue

O método getVersionedObjectForValue pode retornar uma cópia do valor ou um atributo do valor que pode ser utilizado para fins de versão. Este método é chamado sempre que um objeto é associado a uma transação. Quando nenhum Utilitário de Carga estiver conectado a um mapa de suporte, o mapa de suporte utilizará este valor no tempo de confirmação para desempenhar uma comparação de versão otimista. A comparação de versão otimista é utilizada pelo mapa de apoio para assegurar que a versão não tenha sido alterada depois que a primeira transação acessou pela primeira vez a entrada do mapa que foi modificada por esta transação. Se outra transação já tiver modificado a versão desta entrada do mapa, a comparação de versão falhará e o mapa de apoio exibirá uma exceção OptimisticCollisionException para forçar o retrocesso da transação. Se um Utilitário de Carga estiver conectado, o mapa de suporte não utilizará as informações de controle de versões otimista. Em vez disso, o Utilitário de Carga é responsável por desempenhar a comparação de controle de versões otimista e por atualizar as informações de controle de versões quando necessário. O Utilitário de Carga geralmente obtém o objeto de versão inicial do LogElement transmitido para o método batchUpdate no utilitário de carga, que é chamado quando ocorre uma operação de limpeza ou quando uma transação é confirmada.

O código a seguir mostra a implementação utilizada pelo objeto EmployeeOptimisticCallbackImpl:
public Object getVersionedObjectForValue(Object value)
{
    if (value == null)
    {
        return null;
    }
    else
    {
        Employee emp = (Employee) value;
        return new Long( emp.getSequenceNumber() );
    }
}

Conforme demonstrado no exemplo anterior, o atributo sequenceNumber é retornado em um objeto java.lang.Long conforme esperado pelo Utilitário de Carga, que significa que a mesma pessoa que gravou o Utilitário de Carga gravou a implementação de EmployeeOptimisticCallbackImpl ou trabalhou junto com a pessoa que implementou o EmployeeOptimisticCallbackImpl - por exemplo, concordou com o valor retornado pelo método getVersionedObjectForValue. O plug-in OptimisticCallback padrão retorna o valor especial NULL_OPTIMISTIC_VERSION como o objeto de versão.

Método updateVersionedObjectForValue

Este método é chamado sempre que uma transação tiver atualizado um valor e um novo objeto de versão for requerido. Se o método getVersionedObjectForValue retornar um atributo do valor, este método geralmente atualizará o valor de atributo com um novo objeto de versão. Se o método getVersionedObjectForValue retornar uma cópia do valor, este método normalmente não executa nenhuma ação. O plug-in OptimisticCallback padrão não executa nenhuma ação com esse método pois a implementação padrão de getVersionedObjectForValue sempre retorna o valor especial NULL_OPTIMISTIC_VERSION como o objeto de versão. O seguinte exemplo mostra a implementação usada pelo objeto EmployeeOptimisticCallbackImpl que é usado na seção OptimisticCallback:
public void updateVersionedObjectForValue(Object value)
{
    if ( value != null )
    {
        Employee emp = (Employee) value;
        long next = emp.getSequenceNumber() + 1;
        emp.updateSequenceNumber( next );
    }
}

Conforme demonstrado no exemplo anterior, o atributo sequenceNumber é incrementado em um para que na próxima vez em que o método getVersionedObjectForValue for chamado, o valor java.lang.Long retornado tenha um valor longo que é o valor do número de sequência original mais um, por exemplo, é o próximo valor de versão para esta instância employee. Este exemplo significa que a pessoa que gravou o Utilitário de Carga gravou o EmployeeOptimisticCallbackImpl ou trabalhou junto com a pessoa que implementou o EmployeeOptimisticCallbackImpl.

Método serializeVersionedValue

Este método grava o valor com versão no fluxo especificado. Dependendo da implementação, o valor com versão pode ser utilizado para identificar colisões de atualização otimistas. Em algumas implementações, o valor com versão é uma cópia do valor original. Outras implementações podem ter um número de sequência ou algum outro objeto para indicar a versão do valor. Como a implementação real é desconhecida, este método é fornecido para executar a serialização apropriada. A implementação padrão faz uma chamada writeObject.

Método inflateVersionedValue

Este método utiliza a versão serializada do valor com versão e retorna o objeto de valor com versão real. Dependendo da implementação, o valor com versão pode ser utilizado para identificar colisões de atualização otimistas. Em algumas implementações, o valor com versão é uma cópia do valor original. Outras implementações podem ter um número de sequência ou algum outro objeto para indicar a versão do valor. Como a implementação real é desconhecida, este método é fornecido para executar a desserialização apropriada. A implementação padrão chama o método readObject.

Utilizando o Objeto OptimisticCallback Fornecido pelo Aplicativo

Há duas abordagens para incluir um objeto OptimisticCallback fornecido pelo aplicativo na configuração de BackingMap: configuração programática e configuração XML.

Conectar Programaticamente um Objeto OptimisticCallback

O exemplo a seguir demonstra como um aplicativo pode conectar programaticamente um objeto OptimisticCallback para o mapa de apoio de funcionários na instância grid1 do ObjectGrid local:
import com.ibm.websphere.objectgrid.ObjectGridManagerFactory;
import com.ibm.websphere.objectgrid.ObjectGridManager;
import com.ibm.websphere.objectgrid.ObjectGrid;
import com.ibm.websphere.objectgrid.BackingMap;
ObjectGridManager ogManager = ObjectGridManagerFactory.getObjectGridManager();
ObjectGrid og = ogManager.createObjectGrid( "grid1" );
BackingMap bm = dg.defineMap("employees");
EmployeeOptimisticCallbackImpl cb = new EmployeeOptimisticCallbackImpl();
bm.setOptimisticCallback( cb );

Abordagem de configuração XML para conectar um objeto OptimisticCallback

O aplicativo pode utilizar um arquivo XML para conectar seu objeto OptimisticCallback, conforme mostrado no seguinte exemplo:
<?xml version="1.0" encoding="UTF-8"?>
<objectGridConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://ibm.com/ws/objectgrid/config ../objectGrid.xsd"
 xmlns="http://ibm.com/ws/objectgrid/config">
<objectGrids>
    <objectGrid name="grid1">
        <backingMap name="employees" pluginCollectionRef="employees" lockStrategy="OPTIMISTIC" />
    </objectGrid>
</objectGrids>

<backingMapPluginCollections>
    <backingMapPluginCollection id="employees">
        <bean id="OptimisticCallback" className="com.xyz.EmployeeOptimisticCallbackImpl" />
    </backingMapPluginCollection>
</backingMapPluginCollections>
</objectGridConfig>