package org.infinispan.query.affinity; import java.io.Serializable; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.lucene.document.Document; import org.hibernate.search.backend.LuceneWork; import org.hibernate.search.indexes.spi.IndexManager; import org.infinispan.query.backend.KeyTransformationHandler; import org.infinispan.query.impl.ModuleCommandIds; import org.infinispan.query.indexmanager.AbstractUpdateCommand; import org.infinispan.query.indexmanager.LuceneWorkConverter; import org.infinispan.query.logging.Log; import org.infinispan.remoting.responses.ExceptionResponse; import org.infinispan.remoting.responses.SuccessfulResponse; import org.infinispan.util.ByteString; import org.infinispan.util.logging.LogFactory; /** * Handle index updates forwarded by the {@link AffinityIndexManager}, in exceptional cases where * an index work ceases to be local to a node due to transient ownership changes. * * @since 9.0 */ public class AffinityUpdateCommand extends AbstractUpdateCommand { private static final Log log = LogFactory.getLog(AffinityUpdateCommand.class, Log.class); public static final byte COMMAND_ID = ModuleCommandIds.UPDATE_INDEX_AFFINITY; public AffinityUpdateCommand(ByteString cacheName) { super(cacheName); } @Override public void setSerializedWorkList(byte[] serializedModel) { super.setSerializedWorkList(serializedModel); } @Override public CompletableFuture<Object> invokeAsync() throws Throwable { if (queryInterceptor.isStopping()) { throw log.cacheIsStoppingNoCommandAllowed(cacheName.toString()); } List<LuceneWork> luceneWorks = searchFactory.getWorkSerializer().toLuceneWorks(serializedModel); KeyTransformationHandler handler = queryInterceptor.getKeyTransformationHandler(); List<LuceneWork> workToApply = LuceneWorkConverter.transformKeysToString(luceneWorks, handler); for (LuceneWork luceneWork : workToApply) { List<IndexManager> indexManagers = getIndexManagerForModifications(luceneWork); try { for (IndexManager im : indexManagers) { if (log.isDebugEnabled()) log.debugf("Performing remote affinity work %s command on index %s", workToApply, im.getIndexName()); AffinityIndexManager affinityIndexManager = (AffinityIndexManager) im; affinityIndexManager.performOperations(Collections.singletonList(luceneWork), null, false, false); } } catch (Exception e) { return CompletableFuture.completedFuture(new ExceptionResponse(e)); } } return CompletableFuture.completedFuture(SuccessfulResponse.create(Boolean.TRUE)); } private List<IndexManager> getIndexManagerForModifications(LuceneWork luceneWork) { Class<?> entityClass = luceneWork.getEntityClass(); Serializable id = luceneWork.getId(); if (id != null) { String idInString = luceneWork.getIdInString(); Document document = luceneWork.getDocument(); return Arrays.asList(searchFactory.getIndexBinding(entityClass).getSelectionStrategy() .getIndexManagerForAddition(entityClass, id, idInString, document)); } else { return Arrays.asList(searchFactory.getIndexBinding(entityClass) .getSelectionStrategy().getIndexManagersForDeletion(entityClass, null, null)); } } @Override public byte getCommandId() { return ModuleCommandIds.UPDATE_INDEX_AFFINITY; } @Override public boolean isReturnValueExpected() { return true; } }