mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-19 20:25:31 +00:00
ensure in-order delivery of messages from replica to master;
always pass operations to be sent to master into the queue so they cannot be delivered to the master earlier than other queued operations after connectivity has been restored Change-Id: I7b1409dc4663659039058ce2c0511a26009114b4
This commit is contained in:
+6
-6
@@ -31,7 +31,7 @@ import com.sap.sse.replication.OperationsToMasterSender;
|
||||
import com.sap.sse.replication.ReplicableWithObjectInputStream;
|
||||
import com.sap.sse.replication.ReplicationMasterDescriptor;
|
||||
import com.sap.sse.replication.ReplicationService;
|
||||
import com.sap.sse.replication.UnsentOperationsToMasterSender;
|
||||
import com.sap.sse.replication.OperationsToMasterSendingQueue;
|
||||
|
||||
/**
|
||||
* This is the main entry point of the {@link SensorFixStore} based fix tracking.
|
||||
@@ -57,10 +57,10 @@ public class RegattaLogFixTrackerRegattaListener extends AbstractTrackedRegattaA
|
||||
/**
|
||||
* This field is expected to be set by the {@link ReplicationService} once it has "adopted" this replicable.
|
||||
* The {@link ReplicationService} "injects" this service so it can be used here as a delegate for the
|
||||
* {@link UnsentOperationsToMasterSender#retrySendingLater(OperationWithResult, OperationsToMasterSender)}
|
||||
* {@link OperationsToMasterSendingQueue#scheduleForSending(OperationWithResult, OperationsToMasterSender)}
|
||||
* method.
|
||||
*/
|
||||
private UnsentOperationsToMasterSender unsentOperationsToMasterSender;
|
||||
private OperationsToMasterSendingQueue unsentOperationsToMasterSender;
|
||||
|
||||
public RegattaLogFixTrackerRegattaListener(
|
||||
ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker,
|
||||
@@ -228,15 +228,15 @@ public class RegattaLogFixTrackerRegattaListener extends AbstractTrackedRegattaA
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnsentOperationToMasterSender(UnsentOperationsToMasterSender service) {
|
||||
public void setUnsentOperationToMasterSender(OperationsToMasterSendingQueue service) {
|
||||
this.unsentOperationsToMasterSender = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void retrySendingLater(
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void scheduleForSending(
|
||||
OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender) {
|
||||
if (unsentOperationsToMasterSender != null) {
|
||||
unsentOperationsToMasterSender.retrySendingLater(operationWithResult, sender);
|
||||
unsentOperationsToMasterSender.scheduleForSending(operationWithResult, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -55,7 +55,7 @@ import com.sap.sse.replication.OperationWithResultWithIdWrapper;
|
||||
import com.sap.sse.replication.OperationsToMasterSender;
|
||||
import com.sap.sse.replication.ReplicationMasterDescriptor;
|
||||
import com.sap.sse.replication.ReplicationService;
|
||||
import com.sap.sse.replication.UnsentOperationsToMasterSender;
|
||||
import com.sap.sse.replication.OperationsToMasterSendingQueue;
|
||||
import com.sap.sse.util.ClearStateTestSupport;
|
||||
|
||||
/**
|
||||
@@ -92,10 +92,10 @@ public class PolarDataServiceImpl implements ReplicablePolarService, ClearStateT
|
||||
/**
|
||||
* This field is expected to be set by the {@link ReplicationService} once it has "adopted" this replicable.
|
||||
* The {@link ReplicationService} "injects" this service so it can be used here as a delegate for the
|
||||
* {@link UnsentOperationsToMasterSender#retrySendingLater(OperationWithResult, OperationsToMasterSender)}
|
||||
* {@link OperationsToMasterSendingQueue#scheduleForSending(OperationWithResult, OperationsToMasterSender)}
|
||||
* method.
|
||||
*/
|
||||
private UnsentOperationsToMasterSender unsentOperationsToMasterSender;
|
||||
private OperationsToMasterSendingQueue unsentOperationsToMasterSender;
|
||||
|
||||
/**
|
||||
* Constructs the polar data service with default generation settings.
|
||||
@@ -434,15 +434,15 @@ public class PolarDataServiceImpl implements ReplicablePolarService, ClearStateT
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnsentOperationToMasterSender(UnsentOperationsToMasterSender service) {
|
||||
public void setUnsentOperationToMasterSender(OperationsToMasterSendingQueue service) {
|
||||
this.unsentOperationsToMasterSender = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void retrySendingLater(
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void scheduleForSending(
|
||||
OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender) {
|
||||
if (unsentOperationsToMasterSender != null) {
|
||||
unsentOperationsToMasterSender.retrySendingLater(operationWithResult, sender);
|
||||
unsentOperationsToMasterSender.scheduleForSending(operationWithResult, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-6
@@ -7,9 +7,12 @@ import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.Timeout;
|
||||
|
||||
import com.sap.sailing.server.interfaces.RacingEventService;
|
||||
import com.sap.sse.replication.OperationWithResult;
|
||||
@@ -19,11 +22,12 @@ import com.sap.sse.replication.ReplicationMasterDescriptor;
|
||||
import com.sap.sse.replication.impl.UnsentOperationsSenderJob;
|
||||
|
||||
public class UnsentOperationSenderJobTest implements OperationsToMasterSender<RacingEventService, OperationWithResult<RacingEventService, String>> {
|
||||
private static final int MAX_RESEND_COUNT = 10;
|
||||
private UnsentOperationsSenderJob job;
|
||||
private int resendCount;
|
||||
private CountDownLatch latch;
|
||||
|
||||
// @Rule public Timeout timeout = new Timeout(10, TimeUnit.SECONDS);
|
||||
@Rule public Timeout timeout = new Timeout(10, TimeUnit.SECONDS);
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -36,14 +40,14 @@ public class UnsentOperationSenderJobTest implements OperationsToMasterSender<Ra
|
||||
public void testResendThatFailsAtLeastOnce() throws InterruptedException, BrokenBarrierException {
|
||||
final OperationWithResult<RacingEventService, String> operationWithResult = null;
|
||||
final OperationsToMasterSender<RacingEventService, OperationWithResult<RacingEventService, String>> sender = this;
|
||||
job.retrySendingLater(operationWithResult, sender);
|
||||
job.scheduleForSending(operationWithResult, sender);
|
||||
latch.await();
|
||||
assertEquals(2, resendCount);
|
||||
assertEquals(MAX_RESEND_COUNT+1, resendCount);
|
||||
}
|
||||
|
||||
public <T> void sendReplicaInitiatedOperationToMaster(OperationWithResult<RacingEventService, T> operation) throws IOException {
|
||||
logger.info("resending at count "+resendCount);
|
||||
if (resendCount++ == 0) {
|
||||
if (resendCount++ < MAX_RESEND_COUNT) {
|
||||
throw new IOException("First resend failed");
|
||||
} else {
|
||||
latch.countDown();
|
||||
@@ -51,9 +55,9 @@ public class UnsentOperationSenderJobTest implements OperationsToMasterSender<Ra
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void retrySendingLater(
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void scheduleForSending(
|
||||
OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender) {
|
||||
job.retrySendingLater(operationWithResult, sender);
|
||||
job.scheduleForSending(operationWithResult, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,4 +75,7 @@ public class UnsentOperationSenderJobTest implements OperationsToMasterSender<Ra
|
||||
|
||||
@Override
|
||||
public void addOperationSentToMasterForReplication(OperationWithResultWithIdWrapper<RacingEventService, ?> operationWithResultWithIdWrapper) {}
|
||||
|
||||
@Override
|
||||
public boolean hasSentOperationToMaster(OperationWithResult<RacingEventService, ?> operation) { return false; }
|
||||
}
|
||||
|
||||
+6
-6
@@ -288,7 +288,7 @@ import com.sap.sse.replication.OperationWithResultWithIdWrapper;
|
||||
import com.sap.sse.replication.OperationsToMasterSender;
|
||||
import com.sap.sse.replication.ReplicationMasterDescriptor;
|
||||
import com.sap.sse.replication.ReplicationService;
|
||||
import com.sap.sse.replication.UnsentOperationsToMasterSender;
|
||||
import com.sap.sse.replication.OperationsToMasterSendingQueue;
|
||||
import com.sap.sse.shared.media.ImageDescriptor;
|
||||
import com.sap.sse.shared.media.VideoDescriptor;
|
||||
import com.sap.sse.util.ClearStateTestSupport;
|
||||
@@ -516,10 +516,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
/**
|
||||
* This field is expected to be set by the {@link ReplicationService} once it has "adopted" this replicable.
|
||||
* The {@link ReplicationService} "injects" this service so it can be used here as a delegate for the
|
||||
* {@link UnsentOperationsToMasterSender#retrySendingLater(OperationWithResult, OperationsToMasterSender)}
|
||||
* {@link OperationsToMasterSendingQueue#scheduleForSending(OperationWithResult, OperationsToMasterSender)}
|
||||
* method.
|
||||
*/
|
||||
private UnsentOperationsToMasterSender unsentOperationsToMasterSender;
|
||||
private OperationsToMasterSendingQueue unsentOperationsToMasterSender;
|
||||
|
||||
/**
|
||||
* Providing the constructor parameters for a new {@link RacingEventServiceImpl} instance is a bit tricky
|
||||
@@ -4365,15 +4365,15 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnsentOperationToMasterSender(UnsentOperationsToMasterSender service) {
|
||||
public void setUnsentOperationToMasterSender(OperationsToMasterSendingQueue service) {
|
||||
this.unsentOperationsToMasterSender = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void retrySendingLater(
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void scheduleForSending(
|
||||
OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender) {
|
||||
if (unsentOperationsToMasterSender != null) {
|
||||
unsentOperationsToMasterSender.retrySendingLater(operationWithResult, sender);
|
||||
unsentOperationsToMasterSender.scheduleForSending(operationWithResult, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.sap.sse.common.impl.MillisecondsDurationImpl;
|
||||
public interface Duration extends Serializable, Comparable<Duration> {
|
||||
|
||||
static final Duration NULL = new MillisecondsDurationImpl(0);
|
||||
static final Duration ONE_MILLISECOND = new MillisecondsDurationImpl(1);
|
||||
static final Duration ONE_SECOND = new MillisecondsDurationImpl(1000);
|
||||
static final Duration ONE_MINUTE = ONE_SECOND.times(60);
|
||||
static final Duration ONE_HOUR = ONE_MINUTE.times(60);
|
||||
|
||||
+6
-6
@@ -29,7 +29,7 @@ import com.sap.sse.replication.OperationWithResultWithIdWrapper;
|
||||
import com.sap.sse.replication.OperationsToMasterSender;
|
||||
import com.sap.sse.replication.ReplicationMasterDescriptor;
|
||||
import com.sap.sse.replication.ReplicationService;
|
||||
import com.sap.sse.replication.UnsentOperationsToMasterSender;
|
||||
import com.sap.sse.replication.OperationsToMasterSendingQueue;
|
||||
|
||||
/**
|
||||
* Implements {@link ServiceTrackerCustomizer} so that all {@link FileStorageServices} announced in the registry can
|
||||
@@ -61,10 +61,10 @@ public class FileStorageManagementServiceImpl implements ReplicableFileStorageMa
|
||||
/**
|
||||
* This field is expected to be set by the {@link ReplicationService} once it has "adopted" this replicable.
|
||||
* The {@link ReplicationService} "injects" this service so it can be used here as a delegate for the
|
||||
* {@link UnsentOperationsToMasterSender#retrySendingLater(OperationWithResult, OperationsToMasterSender)}
|
||||
* {@link OperationsToMasterSendingQueue#scheduleForSending(OperationWithResult, OperationsToMasterSender)}
|
||||
* method.
|
||||
*/
|
||||
private UnsentOperationsToMasterSender unsentOperationForMasterQueue;
|
||||
private OperationsToMasterSendingQueue unsentOperationForMasterQueue;
|
||||
|
||||
public FileStorageManagementServiceImpl(TypeBasedServiceFinder<FileStorageService> serviceFinder,
|
||||
FileStorageServicePropertyStore propertyStore) {
|
||||
@@ -248,15 +248,15 @@ public class FileStorageManagementServiceImpl implements ReplicableFileStorageMa
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnsentOperationToMasterSender(UnsentOperationsToMasterSender service) {
|
||||
public void setUnsentOperationToMasterSender(OperationsToMasterSendingQueue service) {
|
||||
this.unsentOperationForMasterQueue = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void retrySendingLater(
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void scheduleForSending(
|
||||
OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender) {
|
||||
if (unsentOperationForMasterQueue != null) {
|
||||
unsentOperationForMasterQueue.retrySendingLater(operationWithResult, sender);
|
||||
unsentOperationForMasterQueue.scheduleForSending(operationWithResult, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import com.sap.sse.replication.OperationWithResult;
|
||||
import com.sap.sse.replication.OperationWithResultWithIdWrapper;
|
||||
import com.sap.sse.replication.OperationsToMasterSender;
|
||||
import com.sap.sse.replication.ReplicationMasterDescriptor;
|
||||
import com.sap.sse.replication.UnsentOperationsToMasterSender;
|
||||
import com.sap.sse.replication.OperationsToMasterSendingQueue;
|
||||
import com.sap.sse.util.ObjectInputStreamResolvingAgainstCache;
|
||||
|
||||
public class MailServiceImpl implements ReplicableMailService {
|
||||
@@ -57,10 +57,10 @@ public class MailServiceImpl implements ReplicableMailService {
|
||||
/**
|
||||
* This field is expected to be set by the {@link ReplicationService} once it has "adopted" this replicable.
|
||||
* The {@link ReplicationService} "injects" this service so it can be used here as a delegate for the
|
||||
* {@link UnsentOperationsToMasterSender#retrySendingLater(OperationWithResult, OperationsToMasterSender)}
|
||||
* {@link OperationsToMasterSendingQueue#scheduleForSending(OperationWithResult, OperationsToMasterSender)}
|
||||
* method.
|
||||
*/
|
||||
private UnsentOperationsToMasterSender unsentOperationForMasterQueue;
|
||||
private OperationsToMasterSendingQueue unsentOperationForMasterQueue;
|
||||
|
||||
public MailServiceImpl(Properties mailProperties, MailServiceResolver mailServiceResolver) {
|
||||
this.mailProperties = mailProperties;
|
||||
@@ -256,15 +256,15 @@ public class MailServiceImpl implements ReplicableMailService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnsentOperationToMasterSender(UnsentOperationsToMasterSender service) {
|
||||
public void setUnsentOperationToMasterSender(OperationsToMasterSendingQueue service) {
|
||||
this.unsentOperationForMasterQueue = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void retrySendingLater(
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void scheduleForSending(
|
||||
OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender) {
|
||||
if (unsentOperationForMasterQueue != null) {
|
||||
unsentOperationForMasterQueue.retrySendingLater(operationWithResult, sender);
|
||||
unsentOperationForMasterQueue.scheduleForSending(operationWithResult, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -11,7 +11,7 @@ import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sse.common.WithID;
|
||||
|
||||
public interface OperationsToMasterSender<S, O extends OperationWithResult<S, ?>> extends UnsentOperationsToMasterSender, WithID {
|
||||
public interface OperationsToMasterSender<S, O extends OperationWithResult<S, ?>> extends OperationsToMasterSendingQueue, WithID {
|
||||
final Logger logger = Logger.getLogger(OperationsToMasterSender.class.getName());
|
||||
|
||||
/**
|
||||
@@ -63,4 +63,11 @@ public interface OperationsToMasterSender<S, O extends OperationWithResult<S, ?>
|
||||
* {@code operationWithResultWithIdWrapper} exactly once after this method has returned.
|
||||
*/
|
||||
void addOperationSentToMasterForReplication(OperationWithResultWithIdWrapper<S, ?> operationWithResultWithIdWrapper);
|
||||
|
||||
/**
|
||||
* If an operation equal to <code>operationWithResultWithIdWrapper</code> has previously been passed to a call to
|
||||
* {@link OperationsToMasterSender#addOperationSentToMasterForReplication(OperationWithResultWithIdWrapper)}, the call returns <code>true</code>
|
||||
* exactly once.
|
||||
*/
|
||||
boolean hasSentOperationToMaster(OperationWithResult<S, ?> operation);
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sse.replication;
|
||||
|
||||
/**
|
||||
* Objects of this type can queue operations whose delivery to the master server has failed temporarily.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface OperationsToMasterSendingQueue {
|
||||
/**
|
||||
* Adds the operation to the queue. A sending task is scheduled after the current send delay if none has been
|
||||
* scheduled yet. When this replica was unable to send an operation to the master, e.g., for connectivity issues or
|
||||
* the master currently not being available, passing the operation to this method will enqueue the operation for
|
||||
* later re-send attempts. Implementations have to make sure that operations are queued and sent in the order in
|
||||
* which they are passed to this method. Therefore, implementations should {@code synchronize} on this object.
|
||||
*
|
||||
* @param sender
|
||||
* the object to use to try to send the operation to the master server upon the next attempt
|
||||
*/
|
||||
<S, O extends OperationWithResult<S, ?>, T> void scheduleForSending(OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender);
|
||||
}
|
||||
+3
-11
@@ -242,18 +242,10 @@ extends OperationsToMasterSender<S, OperationWithResult<S, ?>>, Replicator<S, O>
|
||||
}
|
||||
|
||||
/**
|
||||
* If an operation equal to <code>operationWithResultWithIdWrapper</code> has previously been passed to a call to
|
||||
* {@link OperationsToMasterSender#addOperationSentToMasterForReplication(OperationWithResultWithIdWrapper)}, the call returns <code>true</code>
|
||||
* exactly once.
|
||||
*/
|
||||
boolean hasSentOperationToMaster(OperationWithResult<S, ?> operation);
|
||||
|
||||
|
||||
/**
|
||||
* Injects a service into this replicable that this instance of {@link UnsentOperationsToMasterSender} can use
|
||||
* as a delegate to implement the {@link UnsentOperationsToMasterSender#retrySendingLater(OperationWithResult, OperationsToMasterSender)}
|
||||
* Injects a service into this replicable that this instance of {@link OperationsToMasterSendingQueue} can use
|
||||
* as a delegate to implement the {@link OperationsToMasterSendingQueue#scheduleForSending(OperationWithResult, OperationsToMasterSender)}
|
||||
* method. This replicable may not be able to enqueue operations for re-trying sending to master after
|
||||
* an error occurred unless this method has been used to announce the service.
|
||||
*/
|
||||
void setUnsentOperationToMasterSender(UnsentOperationsToMasterSender service);
|
||||
void setUnsentOperationToMasterSender(OperationsToMasterSendingQueue service);
|
||||
}
|
||||
|
||||
+7
-24
@@ -120,15 +120,7 @@ public interface ReplicableWithObjectInputStream<S, O extends OperationWithResul
|
||||
// if this is a replica and this replicable is not currently in the process of handling replication data (either an operation
|
||||
// or the initial load) coming from the master, send the operation back to the master
|
||||
if (getMasterDescriptor() != null && !isCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster()) {
|
||||
try {
|
||||
sendReplicaInitiatedOperationToMaster(castOperation);
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.INFO, "Error sending operation "+operation+" to master "+getMasterDescriptor()+
|
||||
". Queueing for later delivery.");
|
||||
// remove the operation that failed to arrive on the master server from those marked as sent to master for now:
|
||||
hasSentOperationToMaster(operation);
|
||||
retrySendingLater(castOperation, this);
|
||||
}
|
||||
scheduleForSending(castOperation, this);
|
||||
}
|
||||
replicateReplicated(operation); // this anticipates receiving the operation back from master; then, the operation will be ignored;
|
||||
// see also addOperationSentToMasterForReplication
|
||||
@@ -173,7 +165,7 @@ public interface ReplicableWithObjectInputStream<S, O extends OperationWithResul
|
||||
* Checks whether this replicable is a replica. If yes, the operation is executed locally and sent to the master
|
||||
* server for execution. If sending the operation fails with an {@link IOException}, the operation will be enqueued
|
||||
* for a later re-try using the
|
||||
* {@link #retrySendingLater(OperationWithResultWithIdWrapper, OperationsToMasterSender)} method. Note that this may
|
||||
* {@link #scheduleForSending(OperationWithResultWithIdWrapper, OperationsToMasterSender)} method. Note that this may
|
||||
* also happen while in a resend attempt. Otherwise, {@link #applyReplicated(OperationWithResult)} is invoked which
|
||||
* executes and replicates the operation immediately.
|
||||
*/
|
||||
@@ -185,20 +177,11 @@ public interface ReplicableWithObjectInputStream<S, O extends OperationWithResul
|
||||
}
|
||||
final T result = applyReplicated(operation);
|
||||
ReplicationMasterDescriptor masterDescriptor = getMasterDescriptor();
|
||||
try {
|
||||
if (masterDescriptor != null) {
|
||||
sendReplicaInitiatedOperationToMaster(operation);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.INFO, "Error sending operation "+operation+" to master "+masterDescriptor+
|
||||
". Queueing for later delivery.");
|
||||
// remove the operation that failed to arrive on the master server from those marked as sent to master for now:
|
||||
hasSentOperationToMaster(operation);
|
||||
retrySendingLater(operation, this);
|
||||
} finally {
|
||||
if (needToRemoveThreadLocal) {
|
||||
idOfOperationBeingExecuted.remove();
|
||||
}
|
||||
if (masterDescriptor != null) {
|
||||
scheduleForSending(operation, this);
|
||||
}
|
||||
if (needToRemoveThreadLocal) {
|
||||
idOfOperationBeingExecuted.remove();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package com.sap.sse.replication;
|
||||
|
||||
/**
|
||||
* Objects of this type can queue operations whose delivery to the master server has failed temporarily.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface UnsentOperationsToMasterSender {
|
||||
/**
|
||||
* When this replica was unable to send an operation to the master, e.g., for connectivity issues or the
|
||||
* master currently not being available, passing the operation to this method will enqueue the operation
|
||||
* for later re-send attempts. Implementations have to make sure that operations are queued and sent in the
|
||||
* order in which they are passed to this method. Therefore, implementations should {@code synchronize} on this
|
||||
* object.
|
||||
*
|
||||
* @param sender the object to use to try to send the operation to the master server upon the next attempt
|
||||
*/
|
||||
<S, O extends OperationWithResult<S, ?>, T> void retrySendingLater(OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender);
|
||||
}
|
||||
+4
-4
@@ -43,7 +43,7 @@ import com.sap.sse.replication.ReplicablesProvider.ReplicableLifeCycleListener;
|
||||
import com.sap.sse.replication.ReplicationMasterDescriptor;
|
||||
import com.sap.sse.replication.ReplicationReceiver;
|
||||
import com.sap.sse.replication.ReplicationService;
|
||||
import com.sap.sse.replication.UnsentOperationsToMasterSender;
|
||||
import com.sap.sse.replication.OperationsToMasterSendingQueue;
|
||||
import com.sap.sse.util.HttpUrlConnectionHelper;
|
||||
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
@@ -76,7 +76,7 @@ import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||
* @author Frank Mittag, Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class ReplicationServiceImpl implements ReplicationService, UnsentOperationsToMasterSender {
|
||||
public class ReplicationServiceImpl implements ReplicationService, OperationsToMasterSendingQueue {
|
||||
private static final Logger logger = Logger.getLogger(ReplicationServiceImpl.class.getName());
|
||||
|
||||
private final ReplicationInstancesManager replicationInstancesManager;
|
||||
@@ -831,7 +831,7 @@ public class ReplicationServiceImpl implements ReplicationService, UnsentOperati
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void retrySendingLater(OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender) {
|
||||
unsentOperationsSenderJob.retrySendingLater(operationWithResult, sender);
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void scheduleForSending(OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender) {
|
||||
unsentOperationsSenderJob.scheduleForSending(operationWithResult, sender);
|
||||
}
|
||||
}
|
||||
|
||||
+30
-14
@@ -11,7 +11,7 @@ import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.replication.OperationWithResult;
|
||||
import com.sap.sse.replication.OperationsToMasterSender;
|
||||
import com.sap.sse.replication.UnsentOperationsToMasterSender;
|
||||
import com.sap.sse.replication.OperationsToMasterSendingQueue;
|
||||
import com.sap.sse.util.ThreadPoolUtil;
|
||||
|
||||
/**
|
||||
@@ -29,7 +29,7 @@ import com.sap.sse.util.ThreadPoolUtil;
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class UnsentOperationsSenderJob implements UnsentOperationsToMasterSender, Runnable {
|
||||
public class UnsentOperationsSenderJob implements OperationsToMasterSendingQueue, Runnable {
|
||||
private static final Logger logger = Logger.getLogger(UnsentOperationsSenderJob.class.getName());
|
||||
private final static Duration MAX_WAIT_TIME_BETWEEN_ATTEMPTS = Duration.ONE_MINUTE;
|
||||
|
||||
@@ -49,11 +49,11 @@ public class UnsentOperationsSenderJob implements UnsentOperationsToMasterSender
|
||||
}
|
||||
|
||||
private void resetWaitDuration() {
|
||||
nextWaitDuration = Duration.ONE_SECOND;
|
||||
nextWaitDuration = Duration.ONE_MILLISECOND;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <S, O extends OperationWithResult<S, ?>, T> void retrySendingLater(
|
||||
public synchronized <S, O extends OperationWithResult<S, ?>, T> void scheduleForSending(
|
||||
OperationWithResult<S, T> operationWithResult,
|
||||
OperationsToMasterSender<S, O> sender) {
|
||||
queue.addLast(new Pair<>(operationWithResult, sender));
|
||||
@@ -74,14 +74,29 @@ public class UnsentOperationsSenderJob implements UnsentOperationsToMasterSender
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (this) { // FIXME synchronization too coarse-grained
|
||||
while (!queue.isEmpty() && tryToSend(queue.getFirst())) {
|
||||
queue.removeFirst();
|
||||
resetWaitDuration();
|
||||
boolean empty = false;
|
||||
Pair<OperationWithResult<?, ?>, OperationsToMasterSender<?, ?>> first = null;
|
||||
boolean sendOk = true;
|
||||
while (!empty && sendOk) {
|
||||
first = queue.peekFirst();
|
||||
if (first != null) {
|
||||
sendOk = tryToSend(first);
|
||||
} else {
|
||||
sendOk = false;
|
||||
}
|
||||
scheduled = false;
|
||||
if (!queue.isEmpty()) {
|
||||
ensureScheduled();
|
||||
synchronized (this) { // FIXME synchronization too coarse-grained
|
||||
if (sendOk) {
|
||||
resetWaitDuration();
|
||||
queue.removeFirst();
|
||||
} else {
|
||||
incrementWaitDuration();
|
||||
// stop this loop (because sendOk==false) and re-schedule
|
||||
scheduled = false;
|
||||
ensureScheduled();
|
||||
}
|
||||
empty = queue.isEmpty();
|
||||
assert empty || !sendOk;
|
||||
assert empty || scheduled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,8 +119,9 @@ public class UnsentOperationsSenderJob implements UnsentOperationsToMasterSender
|
||||
result = true;
|
||||
} catch (IOException e) {
|
||||
result = false;
|
||||
incrementWaitTime();
|
||||
logger.log(Level.INFO, "Error re-sending operation "+operation+" to master "+sender.getMasterDescriptor()+
|
||||
// remove the operation that failed to arrive on the master server from those marked as sent to master for now:
|
||||
sender.hasSentOperationToMaster(operation);
|
||||
logger.log(Level.INFO, "Error (re-)sending operation "+operation+" to master "+sender.getMasterDescriptor()+
|
||||
". Will try again in "+nextWaitDuration);
|
||||
}
|
||||
return result;
|
||||
@@ -114,7 +130,7 @@ public class UnsentOperationsSenderJob implements UnsentOperationsToMasterSender
|
||||
/**
|
||||
* Doubles the wait duration, capping at {@link #MAX_WAIT_TIME_BETWEEN_ATTEMPTS}.
|
||||
*/
|
||||
private void incrementWaitTime() {
|
||||
private void incrementWaitDuration() {
|
||||
if (nextWaitDuration.compareTo(MAX_WAIT_TIME_BETWEEN_ATTEMPTS) < 0) {
|
||||
nextWaitDuration = nextWaitDuration.times(2);
|
||||
if (nextWaitDuration.compareTo(MAX_WAIT_TIME_BETWEEN_ATTEMPTS) > 0) {
|
||||
|
||||
@@ -75,7 +75,7 @@ import com.sap.sse.replication.OperationWithResultWithIdWrapper;
|
||||
import com.sap.sse.replication.OperationsToMasterSender;
|
||||
import com.sap.sse.replication.ReplicationMasterDescriptor;
|
||||
import com.sap.sse.replication.ReplicationService;
|
||||
import com.sap.sse.replication.UnsentOperationsToMasterSender;
|
||||
import com.sap.sse.replication.OperationsToMasterSendingQueue;
|
||||
import com.sap.sse.security.BearerAuthenticationToken;
|
||||
import com.sap.sse.security.ClientUtils;
|
||||
import com.sap.sse.security.Credential;
|
||||
@@ -128,10 +128,10 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
|
||||
/**
|
||||
* This field is expected to be set by the {@link ReplicationService} once it has "adopted" this replicable.
|
||||
* The {@link ReplicationService} "injects" this service so it can be used here as a delegate for the
|
||||
* {@link UnsentOperationsToMasterSender#retrySendingLater(OperationWithResult, OperationsToMasterSender)}
|
||||
* {@link OperationsToMasterSendingQueue#scheduleForSending(OperationWithResult, OperationsToMasterSender)}
|
||||
* method.
|
||||
*/
|
||||
private UnsentOperationsToMasterSender unsentOperationsToMasterSender;
|
||||
private OperationsToMasterSendingQueue unsentOperationsToMasterSender;
|
||||
|
||||
private static Ini shiroConfiguration;
|
||||
static {
|
||||
@@ -1160,15 +1160,15 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnsentOperationToMasterSender(UnsentOperationsToMasterSender service) {
|
||||
public void setUnsentOperationToMasterSender(OperationsToMasterSendingQueue service) {
|
||||
this.unsentOperationsToMasterSender = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void retrySendingLater(
|
||||
public <S, O extends OperationWithResult<S, ?>, T> void scheduleForSending(
|
||||
OperationWithResult<S, T> operationWithResult, OperationsToMasterSender<S, O> sender) {
|
||||
if (unsentOperationsToMasterSender != null) {
|
||||
unsentOperationsToMasterSender.retrySendingLater(operationWithResult, sender);
|
||||
unsentOperationsToMasterSender.scheduleForSending(operationWithResult, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user