Un chargeur avec un contrôleur de préchargement de fragments réplique est un chargeur qui implémente l'interface ReplicaPreloadController en plus de l'interface Loader.
L'interface ReplicaPreloadController est conçue pour permettre à une réplique qui devient un fragment primaire de savoir si le fragment primaire précédent a effectué le processus de préchargement. Si le préchargement est partiellement effectué, les informations permettant de reprendre le fragment primaire précédent là où il s'est arrêté sont fournies. Avec l'implémentation de l'interfaceReplicaPreloadController, une réplique qui devient un fragment primaire continue le processus de préchargement là où s'est arrêté le fragment primaire précédent et termine le préchargement complet.
Dans un environnement WebSphere eXtreme Scale réparti, une mappe peut comporter des fragments réplique et peut précharger un volume important de données pendant l'initialisation. Le préchargement est une activité du chargeur et a lieu uniquement dans la mappe principale lors de l'initialisation. Le préchargement peut prendre un certain temps si un volume important de données sont préchargées. Si la mappe principale a terminé une grande partie des données de préchargement mais si elle s'interrompt pour une raison inconnue pendant l'initialisation, une réplique devient un fragment primaire. Dans ce cas, les données de préchargement qui ont été traitées par le fragment primaire précédent sont perdues car le nouveau fragment primaire effectue normalement un préchargement inconditionnel. Avec un préchargement inconditionnel, le nouveau fragment primaire redémarre le processus de préchargement depuis le début et les données de préchargement précédentes sont ignorées. Si vous voulez que le nouveau fragment primaire reprenne là où le fragment primaire précédent s'est arrêté lors du préchargement, utilisez un chargeur qui implémente l'interface ReplicaPreloadController. Pour plus d'informations, consultez la documentation d'API.
Pour plus d'informations sur les chargeurs, voir les Chargeurs. Si l'écriture d'un plug-in Loader traditionnel vous intéresse, reportez-vous à la rubrique Ecriture d'un chargeur.
public interface ReplicaPreloadController
{
public static final class Status
{
static public final Status PRELOADED_ALREADY = new Status(K_PRELOADED_ALREADY);
static public final Status FULL_PRELOAD_NEEDED = new Status(K_FULL_PRELOAD_NEEDED);
static public final Status PARTIAL_PRELOAD_NEEDED = new Status(K_PARTIAL_PRELOAD_NEEDED);
}
Status checkPreloadStatus(Session session, BackingMap bmap);
}
Les sections suivantes traitent de certaines des méthodes des interfaces Loader et ReplicaPreloadController.
Lorsqu'un chargeur implémente l'interface ReplicaPreloadController, la méthode checkPreloadStatus est appelée avant la méthode preloadMap pendant l'initialisation de la mappe. L'état de retour de cette méthode détermine si la méthode preloadMap est appelée. Si cette méthode renvoieStatus#PRELOADED_ALREADY, la méthode de préchargement n'est pas appelée. Dans le cas contraire, la méthode preload est exécutée. En raison de ce comportement, cette méthode doit servir de méthode d'initialisation du chargeur. Vous devez initialiser les propriétés du chargeur dans cette méthode. Celle-ci doit renvoyer l'état correct ou le préchargement risque de ne pas se dérouler comme prévu.
public Status checkPreloadStatus(Session session,
BackingMap backingMap) {
// Lorsqu'un chargeur implémente l'interface ReplicaPreloadController,
// cette méthode est appelée avant la méthode preloadMap
// pendant l'initialisation de la mappe. Que la méthode preloadMap soit ou non appelée
// dépend du statut retourné par cette méthode. Cette méthode
// sert donc également de méthode d'initialisation du chargeur. Elle doit
// retourner le statut exact sous peine de compromettre le préchargement.
// Remarque : doit initialiser cette instance de chargeur ici.
ivOptimisticCallback = backingMap.getOptimisticCallback();
ivBackingMapName = backingMap.getName();
ivPartitionId = backingMap.getPartitionId();
ivPartitionManager = backingMap.getPartitionManager();
ivTransformer = backingMap.getObjectTransformer();
preloadStatusKey = ivBackingMapName + "_" + ivPartitionId;
try {
// l'on obtient la preloadStatusMap pour enregistrer le statut du préchargement
// qui a pu être défini par d'autres machines virtuelles Java.
ObjectMap preloadStatusMap = session.getMap(ivPreloadStatusMapName);
// extrayez le dernier index de bloc de données de préchargement enregistré.
Integer lastPreloadedDataChunk = (Integer) preloadStatusMap.get(preloadStatusKey);
if (lastPreloadedDataChunk == null) {
preloadStatus = Status.FULL_PRELOAD_NEEDED;
} else {
preloadedLastDataChunkIndex = lastPreloadedDataChunk.intValue();
if (preloadedLastDataChunkIndex == preloadCompleteMark) {
preloadStatus = Status.PRELOADED_ALREADY;
} else {
preloadStatus = Status.PARTIAL_PRELOAD_NEEDED;
}
}
System.out.println("TupleHeapCacheWithReplicaPreloadControllerLoader.
checkPreloadStatus()
-> map = " + ivBackingMapName + ", preloadStatusKey = " + preloadStatusKey
+ ", retrieved lastPreloadedDataChunk =" + lastPreloadedDataChunk + ",
determined preloadStatus = "
+ getStatusString(preloadStatus));
} catch (Throwable t) {
t.printStackTrace();
}
return preloadStatus;
}
L'exécution de la méthode preloadMap dépend des résultats renvoyés par la méthode checkPreloadStatus. Si la méthode preloadMap est appelée, elle doit généralement extraire les informations sur l'état du préchargement de la mappe d'état de préchargement spécifiée et déterminer la procédure à suivre. Idéalement, la méthode preloadMap doit savoir si le préchargement est partiellement effectué et exactement où il doit démarrer. Pendant le préchargement des données, la méthode preloadMap doit mettre à jour l'état de préchargement dans la mappe d'état de préchargement spécifiée. L'état de préchargement stocké dans la mappe d'état de préchargement est extrait par la méthode checkPreloadStatus lorsqu'elle doit vérifier l'état de préchargement.
public void preloadMap(Session session, BackingMap backingMap)
throws LoaderException {
EntityMetadata emd = backingMap.getEntityMetadata();
if (emd != null && tupleHeapPreloadData != null) {
// La méthode getPreLoadData est similaire à l'extraction des données
// depuis la base de données. Ces données sont envoyées dans le cache dans le cadre
// du préchargement.
ivPreloadData = tupleHeapPreloadData.getPreLoadData(emd);
ivOptimisticCallback = backingMap.getOptimisticCallback();
ivBackingMapName = backingMap.getName();
ivPartitionId = backingMap.getPartitionId();
ivPartitionManager = backingMap.getPartitionManager();
ivTransformer = backingMap.getObjectTransformer();
Map preloadMap;
if (ivPreloadData != null) {
try {
ObjectMap map = session.getMap(ivBackingMapName);
// obtenez la preloadStatusMap pour enregistrer l'état de préchargement.
ObjectMap preloadStatusMap = session.getMap(ivPreloadStatusMapName);
// Remarque : lorsque cette méthode preloadMap est appelée,
// checkPreloadStatus a été appelé, Both preloadStatus
// et preloadedLastDataChunkIndex ont tous les deux été définis. Et
// preloadStatus doit être soit PARTIAL_PRELOAD_NEEDED,
// soit FULL_PRELOAD_NEEDED qui requiert à nouveau un préchargement.
// En cas de volume important de données à précharger, les données sont généralement
// divisés en blocs et le préchargement
// traite chacun de ces blocs au sein de son propre service de transaction répartie. Ici,
// nous nous contentons de précharger quelques entrées censées représenter un bloc.
// de sorte que le préchargement traite une entrée dans un service de transaction répartie pour simuler
// le préchargement par blocs.
Set entrySet = ivPreloadData.entrySet();
preloadMap = new HashMap();
ivMap = preloadMap;
// dataChunkIndex représente le bloc de données
// en cours de traitement
int dataChunkIndex = -1;
boolean shouldRecordPreloadStatus = false;
int numberOfDataChunk = entrySet.size();
System.out.println(" numberOfDataChunk to be preloaded = "
+ numberOfDataChunk);
Iterator it = entrySet.iterator();
int whileCounter = 0;
while (it.hasNext()) {
whileCounter++;
System.out.println("preloadStatusKey = " + preloadStatusKey
+ " ,
whileCounter = " + whileCounter);
dataChunkIndex++;
// si dataChunkIndex <= preloadedLastDataChunkIndex
// pas besoin de traiter car il a été préchargé auparavant
// par une autre machine virtuelle Java. Uniquement besoin de traiter dataChunkIndex
// > preloadedLastDataChunkIndex
if (dataChunkIndex <= preloadedLastDataChunkIndex) {
System.out.println("ignore current dataChunkIndex =
" + dataChunkIndex + " that has been previously
preloaded.");
continue;
}
// Remarque : cet exemple simule un bloc de données comme entrée.
// chaque clé représente un bloc de données à des fins de clarté.
// Si le serveur primaire ou le fragment primaire s'arrête pour une raison inconnue, l'état du préchargement qui
// le statut du préchargement qui indique l'avancement
// du préchargement doit être disponible dans preloadStatusMap. Un
// fragment réplique qui devient un fragment primaire peut obtenir le statut du préchargement et déterminer comment relancer le
// et déterminer comment faire à nouveau pour précharger.
// Remarque : l'enregistrement du statut du préchargement doit être dans le même
// service de transaction répartie que le positionnement des données dans le cache, ce qui fait que si ce service
// est annulé ou échoue, le statut enregistré est
// le statut réel.
Map.Entry entry = (Entry) it.next();
Object key = entry.getKey();
Object value = entry.getValue();
boolean tranActive = false;
System.out.println("processing data chunk. map = " +
this.ivBackingMapName + ", current dataChunkIndex = " +
dataChunkIndex + ", key = " + key);
try {
shouldRecordPreloadStatus = false; // redéfinir sur false
session.beginNoWriteThrough();
tranActive = true;
if (ivPartitionManager.getNumOfPartitions() == 1) {
// si uniquement 1 partition, pas besoin de s'occuper
// de la partition.
// simplement envoyer les données dans le cache
map.put(key, value);
preloadMap.put(key, value);
shouldRecordPreloadStatus = true;
} else if (ivPartitionManager.getPartition(key) == ivPartitionId) {
// si la mappe est partitionnée, il faut prendre en compte
// la clé de partition ne télécharger que les données appartenant
// à cette partition.
map.put(key, value);
preloadMap.put(key, value);
shouldRecordPreloadStatus = true;
} else {
// ignorer cette entrée car elle n'appartient pas
// à cette partition.
}
if (shouldRecordPreloadStatus) {
System.out.println("record preload status. map = " +
this.ivBackingMapName + ", preloadStatusKey = " +
preloadStatusKey + ", current dataChunkIndex ="
+ dataChunkIndex);
if (dataChunkIndex == numberOfDataChunk) {
System.out.println("record preload status. map = " +
this.ivBackingMapName + ", preloadStatusKey = " +
preloadStatusKey + ", mark complete =" +
preloadCompleteMark);
// signifie qu'il s'agit du dernier bloc de données, si validation
// réussie, le préchargement de l'enregistrement est effectué.
// à ce stade, le préchargement est considéré comme effectué
// utilisez -99 comme marque spéciale pour l'état de préchargement terminé.
preloadStatusMap.get(preloadStatusKey);
// a put follow a get devient un update si le get
// renvoie un objet, sinon, il devient insert.
preloadStatusMap.put(preloadStatusKey, new
Integer(preloadCompleteMark));
} else {
// enregistre le dataChunkIndex préchargé actuel
// dans preloadStatusMap a put follow a get devient un update si le get
// renvoie un objet, sinon, devient
// insert.
preloadStatusMap.get(preloadStatusKey);
preloadStatusMap.put(preloadStatusKey, new
Integer(dataChunkIndex));
}
}
session.commit();
tranActive = false;
// pour simuler le préchargement d'une grande quantité de données
// mettez cette unité d'exécution en veille pour 30 sec.
// L'app réelle ne doit PAS mettre cette unité d'exécution en veille
Thread.sleep(10000);
} catch (Throwable e) {
e.printStackTrace();
throw new LoaderException("preload failed with exception: " + e, e);
} finally {
if (tranActive && session != null) {
try {
session.rollback();
} catch (Throwable e1) {
// préchargement ignorant l'exception de l'annulation
}
}
}
}
// à ce stade, le préchargement est considéré comme devant être impérativement effectué
// utilisez -99 comme marque spéciale pour l'état de préchargement terminé.
// cela garantit que la marque complète est définie.
// en outre, lors du partitionnement, chaque partition ne sait pas
// quand il s'agit de son dernier bloc de données. Le bloc suivant sert donc
// de rapport de statut terminé pour l'ensemble du chargement.
System.out.println("Overall preload status complete -> record preload status. map = " + this.ivBackingMapName + ",
preloadStatusKey = " + preloadStatusKey + ", mark complete =" +
preloadCompleteMark);
session.begin();
preloadStatusMap.get(preloadStatusKey);
// a put follow a get devient une mise à jour si le get renvoie un objet,
// autrement, il devient insert.
preloadStatusMap.put(preloadStatusKey, new Integer(preloadCompleteMark));
session.commit();
ivMap = preloadMap;
} catch (Throwable e) {
e.printStackTrace();
throw new LoaderException("preload failed with exception: " + e, e);
}
}
}
}
Vous devez utiliser une mappe d'état de préchargement pour prendre en charge l'implémentation de l'interface ReplicaPreloadController. La méthode preloadMap doit toujours commencer par vérifier l'état du préchargement stocké dans la mappe d'état de préchargement et le mettre à jour dès qu'elle envoie des données dans le cache. La méthode checkPreloadStatus peut extraire l'état de préchargement de la mappe d'état de préchargement, déterminer l'état de préchargement et renvoyer l'état à son demandeur. La mappe d'état de préchargement doit se situer dans le même groupe de mappaes que les autres mappes dotées de chargeurs de contrôleur de préchargement de fragments réplique.