Rastreando Atualizações de Mapas por um Aplicativo

Quando um aplicativo está fazendo alterações em um Mapa durante uma transação, um objeto LogSequence rastreia estas alterações. Se o aplicativo alterar uma entrada no mapa, um objeto LogElement correspondente fornecerá os detalhes da mudança.

Os Loaders recebem um objeto LogSequence para um mapa específico sempre que um aplicativo solicita uma limpeza ou confirmação da transação. O Utilitário de Carga é repetido pelos objetos LogElement, no objeto LogSequence, e aplica cada objeto LogElement ao backend.

Os listeners ObjectGridEventListener registrados com um ObjectGrid também utilizam os objetos LogSequence. Estes listeners recebem um objeto LogSequence para cada mapa em uma transação confirmada. Os aplicativos podem utilizar estes listeners para esperar alterações de algumas entradas, como um acionador em um banco de dados convencional.

As seguintes interfaces ou classes relacionadas ao log são fornecidas pela estrutura do eXtreme Scale:

Interface LogElement

Um LogElement representa uma operação em uma entrada durante uma transação. Um objeto LogElement possui vários métodos para obter os vários atributos. Os atributos mais usados são de tipo e os atributos de valor atual procurados por getType() e getCurrentValue().

O tipo é representado por uma das seguintes constantes definidas na interface LogElement: INSERT, UPDATE, DELETE, EVICT, FETCH ou TOUCH.

O valor atual representa o novo valor para a operação INSERT, UPDATE ou FETCH. Se a operação for TOUCH, DELETE ou EVICT, o valor atual será nulo. Este valor pode ser lançado no ValueProxyInfo quando um ValueInterface estiver sendo utilizado.

Consulte a documentação da API para obter mais detalhes sobre a interface LogElement.

Interface LogSequence

Na maioria das transações, ocorrem operações em mais de uma entrada em um mapa, portanto, são criados vários objetos LogElement. É necessário criar um objeto que atue como uma composição de vários objetos LogElement. A interface LogSequence atende esta finalidade contendo uma lista de objetos LogElement.

Consulte a documentação da API para obter mais detalhes sobre a interface LogSequence.

Usando o LogElement e o LogSequence

O LogElement e o LogSequence são amplamente utilizados no eXtreme Scale e por plug-ins do ObjectGrid que são gravados por usuários quando operações são propagadas de um componente ou servidor para outro componente ou servidor. Por exemplo, um objeto LogSequence pode ser utilizado pela função de propagação de transação do ObjectGrid distribuído para propagar as alterações para outros servidores ou pode ser aplicado ao armazenamento de persistência pelo loader. LogSequence é utilizado principalmente pelas seguintes interfaces.

  • com.ibm.websphere.objectgrid.plugins.ObjectGridEventListener
  • com.ibm.websphere.objectgrid.plugins.Loader
  • com.ibm.websphere.objectgrid.plugins.Evictor
  • com.ibm.websphere.objectgrid.Session

Exemplo de Utilitário de Carga

Esta seção demonstra como os objetos LogSequence e LogElement são utilizados em um Utilitário de Carga. Um Utilitário de Carga é utilizado para fins de carregamento ou persistência de dados num armazenamento persistente. O método batchUpdate da interface do Utilitário de Carga utiliza o objeto LogSequence:

void batchUpdate(TxID txid, LogSequence sequence) throws LoaderException, OptimisticCollisionException;

O método batchUpdate é chamado quando um ObjectGrid precisa aplicar todas as alterações atuais no Utilitário de Carga. O Utilitário de Carga recebe uma lista de objetos LogElement para o mapa, encapsulados em um objeto LogSequence. A implementação do método batchUpdate deve ser repetida nas alterações e aplicada ao backend. O trecho de código a seguir demonstra como um Utilitário de Carga utiliza um objeto LogSequence. O fragmento é repetido no conjunto de mudanças e constrói três instruções de Java Database Connectivity (JDBC) em lote: inserts, updates e deletes:

public void batchUpdate(TxID tx, LogSequence sequence) throws LoaderException {
    // Obter uma conexão SQL para utilizar.
    Connection conn = getConnection(tx);
    try
    {
    // Processar a lista de alterações e construir um conjunto de instruções preparadas
    // para executar uma operação SQL update, insert ou delete
    // . As instruções são armazenadas em cache em stmtCache.
    Iterator iter = sequence.getPendingChanges();
    while(iter.hasNext())
    {
        LogElement logElement = (LogElement)iter.next();
        Object key = logElement.getCacheEntry().getKey();
        Object value = logElement.getCurrentValue();
        switch ( logElement.getType().getCode() )
        {
            case LogElement.CODE_INSERT:
                buildBatchSQLInsert( key, value, conn );
                break;
            case LogElement.CODE_UPDATE:
                buildBatchSQLUpdate( key, value, conn );
                break;
            case LogElement.CODE_DELETE:
                buildBatchSQLDelete( key, conn );
                break;
        }
    }
    // Executar as instruções de lote que foram construídas pelo loop acima.
    Collection statements = getPreparedStatementCollection( tx, conn );
    iter = statements.iterator();
    while(iter.hasNext())
    {
        PreparedStatement pstmt = (PreparedStatement) iter.next();
        pstmt.executeBatch();
    }
} catch (SQLException e) {
    LoaderException ex = new LoaderException(e);
    throw ex;
}
}

O exemplo anterior mostra a lógica de alto nível de processamento do argumento LogSequence. Entretanto, o exemplo não mostra os detalhes de como construir uma instrução SQL insert, update ou delete. O método getPendingChanges é chamado no argumento LogSequence para obter um iterador dos objetos LogElement que o Utilitário de Carga precisa para processar e o método LogElement.getType().getCode() é usado para determinar se um LogElement destina-se para uma operação SQL insert, update ou delete.

Amostra de Evictor

Também é possível usar os objetos LogSequence e LogElement com um Evictor. Um Evictor é utilizado para liberar as entradas do mapa de suporte com base em alguns critérios. O método apply da interface do Evictor utiliza LogSequence.

/**
* É chamado durante a confirmação de cache para permitir que o 
evictor rastreie o uso de objetos
* em um mapa de apoio. Também relatará as entradas que foram liberadas com
* êxito.
*
* Sequência @param LogSequence de alterações no mapa
*/
void apply(LogSequence sequence);

Para obter informações sobre como o método apply utiliza o objeto LogSequence, consulte a amostra de código no tópico Gravando um Evictor Customizado.

Interfaces LogSequenceFilter e LogSequenceTransformer

Às vezes, é necessário filtrar os objetos LogElement para que apenas os objetos LogElement com alguns critérios sejam aceitos e rejeitar outros objetos. Por exemplo, você pode serializar um determinado LogElement com base em algum critério.

LogSequenceFilter resolve este problema com o seguinte método:

public boolean accept (LogElement logElement);

Este método retorna true se o LogElement especificado tiver que ser utilizado na operação e retorna false se o LogElement especificado não tiver que ser utilizado.

LogSequenceTransformer é uma classe que utiliza a função LogSequenceFilter. Utiliza LogSequenceFilter para filtrar alguns objetos LogElement e, em seguida, serializar os objetos LogElement aceitos. Esta classe possui dois métodos. O primeiro método é o seguinte:

public static void serialize(Collection logSequences, ObjectOutputStream stream,
			LogSequenceFilter filter, DistributionMode mode) throws IOException

Este método permite que o responsável pela chamada forneça um filtro para determinar quais LogElements incluir no processo de serialização. O parâmetro DistributionMode permite que o responsável pela chamada controle o processo de serialização. Por exemplo, se o modo de distribuição for apenas de invalidação, não será necessário serializar o valor. O segundo método desta classe é o método inflate, da seguinte forma:

public static Collection inflate(ObjectInputStream stream, ObjectGrid
			objectGrid) throws IOException, ClassNotFoundException

Esse método lê o formulário serializado de sequência de log, que foi criado pelo método serialize a partir do fluxo de entrada de objetos fornecido.