org.infinispan.query.indexmanager.RemoteIndexingBackend Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of infinispan-embedded-query
Show all versions of infinispan-embedded-query
Infinispan Embedded Query All-in-One module
The newest version!
package org.infinispan.query.indexmanager;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.hibernate.search.backend.FlushLuceneWork;
import org.hibernate.search.backend.IndexingMonitor;
import org.hibernate.search.backend.LuceneWork;
import org.hibernate.search.backend.PurgeAllLuceneWork;
import org.hibernate.search.indexes.spi.IndexManager;
import org.infinispan.commands.ReplicableCommand;
import org.infinispan.commons.util.Util;
import org.infinispan.query.logging.Log;
import org.infinispan.remoting.rpc.RpcManager;
import org.infinispan.remoting.transport.Address;
import org.infinispan.util.ByteString;
import org.infinispan.util.logging.LogFactory;
/**
* The IndexingBackend which forwards all operations to a different node
* using Infinispan's custom commands.
*
* @author Sanne Grinovero (C) 2014 Red Hat Inc.
* @since 7.0
*/
final class RemoteIndexingBackend implements IndexingBackend {
private static final Log log = LogFactory.getLog(RemoteIndexingBackend.class, Log.class);
private final int GRACE_MILLISECONDS_FOR_REPLACEMENT = 4000;
private final int POLLING_MILLISECONDS_FOR_REPLACEMENT = 4000;
protected static final Set> SYNC_ONLY_WORKS =
Util.asSet(PurgeAllLuceneWork.class, FlushLuceneWork.class);
private final String cacheName;
private final String indexName;
private final Collection recipients;
private final RpcManager rpcManager;
private final Address masterAddress;
private final boolean async;
private volatile IndexingBackend replacement;
public RemoteIndexingBackend(String cacheName, RpcManager rpcManager, String indexName, Address masterAddress, boolean async) {
this.cacheName = cacheName;
this.rpcManager = rpcManager;
this.indexName = indexName;
this.masterAddress = masterAddress;
this.recipients = Collections.singleton(masterAddress);
this.async = async;
}
@Override
public void flushAndClose(IndexingBackend replacement) {
if (replacement != null) {
this.replacement = replacement;
}
}
@Override
public void applyWork(List workList, IndexingMonitor monitor, IndexManager indexManager) {
IndexUpdateCommand command = new IndexUpdateCommand(ByteString.fromString(cacheName));
//Use Search's custom Avro based serializer as it includes support for back/future compatibility
byte[] serializedModel = indexManager.getSerializer().toSerializedModel(workList);
command.setSerializedWorkList(serializedModel);
command.setIndexName(this.indexName);
try {
log.applyingChangeListRemotely(workList);
sendCommand(command, workList, shouldSendSync(workList));
} catch (Exception e) {
waitForReplacementBackend();
if (replacement != null) {
replacement.applyWork(workList, monitor, indexManager);
} else {
throw e;
}
}
}
/**
* Decides whether a command should be sent sync or async
*/
private boolean shouldSendSync(LuceneWork operation) {
return !async || SYNC_ONLY_WORKS.contains(operation.getClass());
}
private boolean shouldSendSync(List operations) {
return !async || (operations.size() == 1 && shouldSendSync(operations.get(0)));
}
@Override
public void applyStreamWork(LuceneWork singleOperation, IndexingMonitor monitor, IndexManager indexManager) {
final IndexUpdateStreamCommand streamCommand = new IndexUpdateStreamCommand(ByteString.fromString(cacheName));
final List operations = Collections.singletonList(singleOperation);
final byte[] serializedModel = indexManager.getSerializer().toSerializedModel(operations);
streamCommand.setSerializedWorkList(serializedModel);
streamCommand.setIndexName(this.indexName);
try {
sendCommand(streamCommand, operations, shouldSendSync(singleOperation));
} catch (Exception e) {
waitForReplacementBackend();
if (replacement != null) {
replacement.applyStreamWork(singleOperation, monitor, indexManager);
} else {
throw e;
}
}
}
/**
* If some error happened, and a new IndexingBackend was provided, it is safe to
* assume the error relates with the fact the current backend is no longer valid.
* At this point we can still forward the work from the current stack to the next
* backend, creating a linked list of forwards to the right backend:
*/
private void waitForReplacementBackend() {
int waitedMilliseconds = 0;
try {
while (replacement != null) {
if (waitedMilliseconds >= GRACE_MILLISECONDS_FOR_REPLACEMENT) {
return;
}
Thread.sleep(POLLING_MILLISECONDS_FOR_REPLACEMENT);
waitedMilliseconds += POLLING_MILLISECONDS_FOR_REPLACEMENT;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void sendCommand(ReplicableCommand command, List workList, boolean sync) {
rpcManager.invokeRemotely(recipients, command, rpcManager.getDefaultRpcOptions(sync));
log.workListRemotedTo(workList, masterAddress);
}
@Override
public boolean isMasterLocal() {
return false;
}
public String toString() {
return "RemoteIndexingBackend(" + masterAddress + ")";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy