Cet exemple de code source montre comment écrire un programme de surveillance (dumper) pour gérer les mises à jour d'écriture différée ayant échoué.
//
//Cet exemple de programme est fourni TEL QUEL et peut être utilisé, exécuté, copié et
//modifiés sans acquittement de droits par le client (a) pour sa propre formation et
//analyse, (b) pour développer des applications destinées à s'exécuter avec un produit IBM
//WebSphere pour une utilisation interne par le client ou pour redistribution
//par le client, dans le cadre d'une telle application, dans les produits du client. "
//
//5724-J34 (C) COPYRIGHT International Business Machines Corp. 2009
// All Rights Reserved * Eléments sous licence - Propriété d'IBM
//
package utils;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import com.ibm.websphere.objectgrid.BackingMap;
import com.ibm.websphere.objectgrid.ObjectGrid;
import com.ibm.websphere.objectgrid.ObjectGridException;
import com.ibm.websphere.objectgrid.ObjectGridRuntimeException;
import com.ibm.websphere.objectgrid.ObjectMap;
import com.ibm.websphere.objectgrid.Session;
import com.ibm.websphere.objectgrid.UndefinedMapException;
import com.ibm.websphere.objectgrid.plugins.ObjectGridEventGroup;
import com.ibm.websphere.objectgrid.plugins.ObjectGridEventListener;
import com.ibm.websphere.objectgrid.writebehind.FailedUpdateElement;
import com.ibm.websphere.objectgrid.writebehind.WriteBehindLoaderConstants;
/**
* L'écriture différée s'attend à ce que les transactions vers le chargeur aboutissent. Si une
* transaction échoue pour une clé, elle insère une entrée dans une mappe appelée PREFIXE + nomMappe.
* L'application doit rechercher dans cette mappe les entrées de vidage des incidents de
* transaction d'écriture différée. L'application est chargée d'analyser, puis de supprimer
* ces entrées. Ces dernières peuvent être assez importantes car elles incluent la clé, les
* images avant et après de la valeur et l'exception elle-même. Les exceptions peuvent facilement
* atteindre 20k.
*
* La classe est enregistrée avec la grille et une instance est créée pour
* chaque fragment primaire d'une machine virtuelle Java. Une unique unité
* d'exécution est créée et cette dernière recherche le fragment dans chaque
* mappe d'erreurs à écriture différée, imprime le problème, puis supprime
* l'entrée.
*
* Cela signifie qu'il existera une unité d'exécution par fragment. Si le
* fragment est transféré sur une autre machine virtuelle Java, la méthode
* deactivate arrête l'unité d'exécution.
* @author bnewport
*
*/
public class WriteBehindDumper implements ObjectGridEventListener, ObjectGridEventGroup.ShardEvents,
Callable<Boolean>
{
static Logger logger = Logger.getLogger(WriteBehindDumper.class.getName());
ObjectGrid grid;
/**
* Pool d'unités d'exécution chargé de gérer les vérificateurs de table. Si l'application possède
* son propre pool, modifiez la valeur pour réutiliser le pool existant
*/
static ScheduledExecutorService pool = new ScheduledThreadPoolExecutor(2); // deux unités d'exécution pour vider les enregistrements
// futur de ce fragment
ScheduledFuture<Boolean> future;
// true si ce fragment est actif
volatile boolean isShardActive;
/**
* Durée normale entre les recherches dans les mappes d'erreurs d'écriture différée
*/
final long BLOCKTIME_SECS = 20L;
/**
* Une session allouée pour ce fragment. Il est inutile de les allouer encore et encore
*/
Session session;
/**
* Si un fragment primaire est activé, planifiez les vérifications de sorte à vérifier périodiquement
* les mappes d'erreurs d'écriture différée et imprimer les éventuels problèmes
*/
public void shardActivated(ObjectGrid grid)
{
try
{
this.grid = grid;
session = grid.getSession();
isShardActive = true;
future = pool.schedule(this, BLOCKTIME_SECS, TimeUnit.SECONDS); // vérification initiale toutes les BLOCKTIME_SECS secondes
}
catch(ObjectGridException e)
{
throw new ObjectGridRuntimeException("Exception activating write dumper", e);
}
}
/**
* Marquez le fragment comme inactif, puis annulez le vérificateur
*/
public void shardDeactivate(ObjectGrid arg0)
{
isShardActive = false;
// s'il est annulé, l'annulation renvoie la valeur true
if(future.cancel(false) == false)
{
// sinon, la tâche est bloquée jusqu'à ce que le vérificateur ait terminé son exécution
while(future.isDone() == false) // attendez que la tâche se termine d'une manière ou d'une autre
{
try
{
Thread.sleep(1000L); // vérifiez à chaque seconde
}
catch (InterruptedException e)
{
}
}
}
}
/**
* Test simple permettant de vérifier si l'écriture différée est activée
* pour la mappe ; si c'est le cas, renvoie le nom de la mappe d'erreurs
* associée.
* @param mapName Mappe à tester
* @return Nom de la mappe d'erreurs à écriture différée si elle existe ;
* sinon null
*/
static public String getWriteBehindNameIfPossible(ObjectGrid grid, String mapName)
{
BackingMap map = grid.getMap(mapName);
if(map != null && map.getWriteBehind() != null)
{
return WriteBehindLoaderConstants.WRITE_BEHIND_FAILED_UPDATES_MAP_PREFIX + mapName;
}
else
return null;
}
/**
* Exécuté pour chaque fragment. Vérifie si l'écriture différée est activée pour chaque mappe et
* si c'est le cas, imprime les éventuelles erreurs de transaction d'écriture différée
* avant de supprimer l'enregistrement.
*/
public Boolean call()
{
logger.fine("Called for " + grid.toString());
try
{
// tant que le fragment primaire est présent sur cette machine virtuelle Java,
// seules les mappes définies par l'utilisateur sont renvoyées ici ; aucune mappe système,
// telle que les mappes d'écriture différée, ne figure dans cette liste.
Iterator<String> iter = grid.getListOfMapNames().iterator();
boolean foundErrors = false;
// effectuez une itération sur toutes les mappes actuelles
while(iter.hasNext() && isShardActive)
{
String origName = iter.next();
// s'il s'agit d'une mappe d'erreurs à écriture différée
String name = getWriteBehindNameIfPossible(grid, origName);
if (name != null)
{
// essayez de supprimer des blocs de N erreurs à la fois
ObjectMap errorMap = null;
try
{
errorMap = session.getMap(name);
}
catch(UndefinedMapException e)
{
// au démarrage les mappes d'erreurs risquent de ne pas encore exister ; patience...
continue;
}
// essayez de vider jusqu'à N enregistrements à la fois
session.begin();
for(int counter = 0; counter < 100; ++counter)
{
Integer seqKey = (Integer)errorMap.getNextKey(1L);
if(seqKey != null)
{
foundErrors = true;
FailedUpdateElement elem = (FailedUpdateElement)errorMap.get(seqKey);
//
// Votre application doit consigner le problème ici
logger.info("WriteBehindDumper ( " + origName + ") for key (" + elem.getKey() + ") Exception: " +
elem.getThrowable().toString());
//
//
errorMap.remove(seqKey);
}
else
break;
}
session.commit();
}
} // passez à la mappe suivante
// bouclez plus rapidement en cas d'erreurs
if(isShardActive)
{
// replanifiez après une seconde en cas d'enregistrements incorrects ;
// sinon, attendez 20 secondes.
if(foundErrors)
future = pool.schedule(this, 1L, TimeUnit.SECONDS);
else
future = pool.schedule(this, BLOCKTIME_SECS, TimeUnit.SECONDS);
}
}
catch(ObjectGridException e)
{
logger.fine("Exception in WriteBehindDumper" + e.toString());
e.printStackTrace();
//ne laissez pas de transaction sur la session.
if(session.isTransactionActive())
{
try { session.rollback(); } catch(Exception e2) {}
}
}
return true;
}
public void destroy() {
// TODO Module de remplacement de méthode généré automatiquement
}
public void initialize(Session arg0) {
// TODO Module de remplacement de méthode généré automatiquement
}
public void transactionBegin(String arg0, boolean arg1) {
// TODO Module de remplacement de méthode généré automatiquement
}
public void transactionEnd(String arg0, boolean arg1, boolean arg2,
Collection arg3) {
// TODO Module de remplacement de méthode généré automatiquement
}
}