mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-19 20:25:31 +00:00
uncompileable interims commit for bug4018: started with an operation re-send queue
Change-Id: I20acb4bd2d10226911055b8b92efa64bd56272a4
This commit is contained in:
Executable
+46
@@ -0,0 +1,46 @@
|
||||
package com.sap.sse.replication;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import com.sap.sse.util.HttpUrlConnectionHelper;
|
||||
|
||||
public interface OperationsToMasterSender<S, O extends OperationWithResult<S, ?>> extends Replicable<S, O>, UnsentOperationsForMasterQueue {
|
||||
/**
|
||||
* When a replica has initiated (not received through replication) an operation, this operation needs to be sent to
|
||||
* the master for execution from where it will replicate across the replication tree. This method uses the
|
||||
* {@link ReplicationMasterDescriptor#getSendReplicaInitiatedOperationToMasterURL(String) URL for sending an
|
||||
* operation to the replication servlet on the master} and through the POST request's output stream first sends the
|
||||
* target replicable's ID as a string using a {@link DataOutputStream}, then
|
||||
* {@link #writeOperation(OperationWithResult, OutputStream, boolean) serializes the operation}.<p>
|
||||
*/
|
||||
default <T> void sendReplicaInitiatedOperationToMaster(OperationWithResult<S, T> operation) throws IOException {
|
||||
ReplicationMasterDescriptor masterDescriptor = getMasterDescriptor();
|
||||
assert masterDescriptor != null;
|
||||
final OperationWithResultWithIdWrapper<S, T> operationWithResultWithIdWrapper = new OperationWithResultWithIdWrapper<S, T>(operation);
|
||||
// TODO bug4018: if sending the operation fails, e.g., because of an HTTP response code != 2xx, enqueue the operation for retry
|
||||
addOperationSentToMasterForReplication(operationWithResultWithIdWrapper);
|
||||
URL url = masterDescriptor.getSendReplicaInitiatedOperationToMasterURL(this.getId().toString());
|
||||
final HttpURLConnection connection = (HttpURLConnection) HttpUrlConnectionHelper.redirectConnection(url, "POST"); // sets doOutput to true
|
||||
logger.info("Sending operation "+operation+" to master "+masterDescriptor+"'s replicable with ID "+this+" for initial execution and replication");
|
||||
connection.connect();
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(outputStream);
|
||||
dos.writeUTF(getId().toString());
|
||||
this.writeOperation(operationWithResultWithIdWrapper, outputStream, /* closeStream */ true);
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
bufferedReader.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the {@code operationWithResultWithIdWrapper} was sent to master for further processing and replication.
|
||||
* The {@link #hasSentOperationToMaster(OperationWithResult)} will return {@code true} for an operation equal to
|
||||
* {@code operationWithResultWithIdWrapper} exactly once after this method has returned.
|
||||
*/
|
||||
void addOperationSentToMasterForReplication(OperationWithResultWithIdWrapper<S, ?> operationWithResultWithIdWrapper);
|
||||
}
|
||||
@@ -260,7 +260,7 @@ public interface Replicable<S, O extends OperationWithResult<S, ?>> extends Repl
|
||||
|
||||
/**
|
||||
* If an operation equal to <code>operationWithResultWithIdWrapper</code> has previously been passed to a call to
|
||||
* {@link #addOperationSentToMasterForReplication(OperationWithResultWithIdWrapper)}, the call returns <code>true</code>
|
||||
* {@link OperationsToMasterSender#addOperationSentToMasterForReplication(OperationWithResultWithIdWrapper)}, the call returns <code>true</code>
|
||||
* exactly once.
|
||||
*/
|
||||
boolean hasSentOperationToMaster(OperationWithResult<S, ?> operation);
|
||||
|
||||
+12
-39
@@ -1,25 +1,19 @@
|
||||
package com.sap.sse.replication;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sse.common.WithID;
|
||||
import com.sap.sse.operationaltransformation.Operation;
|
||||
import com.sap.sse.util.HttpUrlConnectionHelper;
|
||||
|
||||
public interface ReplicableWithObjectInputStream<S, O extends OperationWithResult<S, ?>> extends Replicable<S, O> {
|
||||
public interface ReplicableWithObjectInputStream<S, O extends OperationWithResult<S, ?>> extends OperationsToMasterSender<S, O> {
|
||||
static final Logger logger = Logger.getLogger(ReplicableWithObjectInputStream.class.getName());
|
||||
|
||||
/**
|
||||
@@ -171,36 +165,13 @@ public interface ReplicableWithObjectInputStream<S, O extends OperationWithResul
|
||||
|
||||
Iterable<OperationExecutionListener<S>> getOperationExecutionListeners();
|
||||
|
||||
/**
|
||||
* When a replica has initiated (not received through replication) an operation, this operation needs to be sent to
|
||||
* the master for execution from where it will replicate across the replication tree. This method uses the
|
||||
* {@link ReplicationMasterDescriptor#getSendReplicaInitiatedOperationToMasterURL(String) URL for sending an
|
||||
* operation to the replication servlet on the master} and through the POST request's output stream first sends the
|
||||
* target replicable's ID as a string using a {@link DataOutputStream}, then
|
||||
* {@link #writeOperation(OperationWithResult, OutputStream, boolean) serializes the operation}.
|
||||
*/
|
||||
default <T> void sendReplicaInitiatedOperationToMaster(OperationWithResult<S, T> operation) throws IOException {
|
||||
ReplicationMasterDescriptor masterDescriptor = getMasterDescriptor();
|
||||
assert masterDescriptor != null;
|
||||
final OperationWithResultWithIdWrapper<S, T> operationWithResultWithIdWrapper = new OperationWithResultWithIdWrapper<S, T>(operation);
|
||||
// TODO bug4018: if sending the operation fails, e.g., because of an HTTP response code != 2xx, enqueue the operation for retry
|
||||
addOperationSentToMasterForReplication(operationWithResultWithIdWrapper);
|
||||
URL url = masterDescriptor.getSendReplicaInitiatedOperationToMasterURL(this.getId().toString());
|
||||
final HttpURLConnection connection = (HttpURLConnection) HttpUrlConnectionHelper.redirectConnection(url, "POST"); // sets doOutput to true
|
||||
logger.info("Sending operation "+operation+" to master "+masterDescriptor+"'s replicable with ID "+this+" for initial execution and replication");
|
||||
connection.connect();
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(outputStream);
|
||||
dos.writeUTF(getId().toString());
|
||||
this.writeOperation(operationWithResultWithIdWrapper, outputStream, /* closeStream */ true);
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
bufferedReader.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this replicable is a replica. If yes, the operation is executed locally and sent to the master
|
||||
* server for execution. Otherwise, {@link #applyReplicated(OperationWithResult)} is invoked which executes and
|
||||
* replicates the operation immediately.
|
||||
* 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
|
||||
* also happen while in a resend attempt. Otherwise, {@link #applyReplicated(OperationWithResult)} is invoked which
|
||||
* executes and replicates the operation immediately.
|
||||
*/
|
||||
default <T> T apply(OperationWithResult<S, T> operation) {
|
||||
boolean needToRemoveThreadLocal = false;
|
||||
@@ -214,8 +185,12 @@ public interface ReplicableWithObjectInputStream<S, O extends OperationWithResul
|
||||
if (masterDescriptor != null) {
|
||||
sendReplicaInitiatedOperationToMaster(operation);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Exception trying to send operation "+operation+" to master for replication", e);
|
||||
} 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();
|
||||
@@ -224,8 +199,6 @@ public interface ReplicableWithObjectInputStream<S, O extends OperationWithResul
|
||||
return result;
|
||||
}
|
||||
|
||||
void addOperationSentToMasterForReplication(OperationWithResultWithIdWrapper<S, ?> operationWithResultWithIdWrapper);
|
||||
|
||||
/**
|
||||
* The operation is executed by immediately {@link Operation#internalApplyTo(Object) applying} it to this
|
||||
* service object. It is then replicated to all replicas if and only if the operation is marked as
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
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 UnsentOperationsForMasterQueue {
|
||||
/**
|
||||
* 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> operationWithResultWithIdWrapper, OperationsToMasterSender<S, O> sender);
|
||||
}
|
||||
Reference in New Issue
Block a user