fixed remove leaderboard operational transformation

This commit is contained in:
Axel Uhl
2012-03-28 18:23:10 +02:00
parent ebbd73c11e
commit 2d03493cf3
10 changed files with 106 additions and 45 deletions
@@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
/**
@@ -19,6 +20,7 @@ import java.util.concurrent.Executors;
* @param <S> type of state managed by this server to which the operations can be applied
*/
public class PeerImpl<O extends Operation<S>, S> implements Peer<O, S> {
private static final Logger logger = Logger.getLogger(PeerImpl.class.getName());
private String name;
@@ -42,20 +44,20 @@ public class PeerImpl<O extends Operation<S>, S> implements Peer<O, S> {
* confirmed, the first operation from the queue is removed because operations sent
* from this peer to the remote peer are processed in order.
*/
private Map<Peer<O, S>, UnmergedOperationsQueue<O, S>> unmergedOperationsForPeer = new HashMap<Peer<O, S>, UnmergedOperationsQueue<O, S>>();
private final Map<Peer<O, S>, UnmergedOperationsQueue<O, S>> unmergedOperationsForPeer = new HashMap<Peer<O, S>, UnmergedOperationsQueue<O, S>>();
/**
* Remembers per peer how many of that peer's operations this peer has already
* applied locally.
*/
private Map<Peer<O, S>, Integer> numberOfMergedOperations = new HashMap<Peer<O, S>, Integer>();
private final Map<Peer<O, S>, Integer> numberOfMergedOperations = new HashMap<Peer<O, S>, Integer>();
private Transformer<O> transformer;
private final Transformer<O> transformer;
/**
* The background task handler which sends out the asynchronous updates to the peers.
*/
private ExecutorService merger;
private final ExecutorService merger;
public PeerImpl(Transformer<O> transformer, S initialState, Role role) {
this.transformer = transformer;
@@ -234,6 +236,7 @@ public class PeerImpl<O extends Operation<S>, S> implements Peer<O, S> {
}
private void taskScheduled() {
logger.fine(""+this+" taskScheduled incrementing scheduleOrRunning from "+scheduledOrRunning+" to "+(scheduledOrRunning+1));
scheduledOrRunning++;
}
@@ -242,8 +245,10 @@ public class PeerImpl<O extends Operation<S>, S> implements Peer<O, S> {
* Unblocks {@link #waitForNotRunning()} if the merger's queue got empty by this.
*/
private synchronized void taskFinished() {
logger.fine(""+this+" taskFinished decrementing scheduleOrRunning from "+scheduledOrRunning+" to "+(scheduledOrRunning-1));
scheduledOrRunning--;
if (scheduledOrRunning == 0) {
logger.fine(""+this+" taskFinished notifying waiters");
notifyAll();
}
}
@@ -253,6 +258,7 @@ public class PeerImpl<O extends Operation<S>, S> implements Peer<O, S> {
while (scheduledOrRunning > 0) {
try {
wait();
logger.fine(""+this+" waitForNotRunning scheduleOrRunning: "+scheduledOrRunning);
} catch (InterruptedException e) {
// ignore interruption, try again
}
@@ -59,14 +59,14 @@ public class OperationalTransformationTest {
}
@Test
public void testAddColumnToLeaderboardOnClientAndRemoveLeaderboardOnServer() {
public void testAddColumnToLeaderboardOnClientAndRemoveLeaderboardOnServer() throws InterruptedException {
RacingEventServiceOperation addLeaderboardColumn = new AddColumnToLeaderboard(
"newColumn", DefaultLeaderboardName.DEFAULT_LEADERBOARD_NAME, /* medalRace */ true);
server.apply(addLeaderboardColumn);
RacingEventServiceOperation removeDefaultLeaderboard = new RemoveLeaderboard(DefaultLeaderboardName.DEFAULT_LEADERBOARD_NAME);
replica.apply(removeDefaultLeaderboard);
server.waitForNotRunning();
replica.waitForNotRunning();
server.waitForNotRunning();
assertEquals(0, racingEventServiceReplica.getLeaderboards().size());
assertEquals(0, racingEventServiceServer.getLeaderboards().size());
}
@@ -20,7 +20,7 @@ public abstract class AbstractLeaderboardColumnOperation extends AbstractLeaderb
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(
public RacingEventServiceOperation transformRemoveColumnFromLeaderboardServerOp(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
if (affectsSameColumn(removeColumnFromLeaderboardServerOp)) {
// skip server's remove and hence only apply the client's remove operation
@@ -31,7 +31,7 @@ public abstract class AbstractLeaderboardColumnOperation extends AbstractLeaderb
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(
public RacingEventServiceOperation transformRemoveColumnFromLeaderboardClientOp(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
if (affectsSameColumn(removeColumnFromLeaderboardClientOp)) {
// skip client's remove and hence only apply the server's remove operation
@@ -18,23 +18,4 @@ public abstract class AbstractLeaderboardOperation extends AbstractRacingEventSe
return getLeaderboardName().equals(other.getLeaderboardName());
}
@Override
public RacingEventServiceOperation transformRemoveLeaderboardClientOp(RemoveLeaderboard removeLeaderboard) {
if (affectsSameLeaderboard(removeLeaderboard)) {
return AbstractRacingEventServiceOperation.getNoOp();
} else {
return this;
}
}
@Override
public RacingEventServiceOperation transformRemoveLeaderboardServerOp(RemoveLeaderboard removeLeaderboard) {
if (affectsSameLeaderboard(removeLeaderboard)) {
return AbstractRacingEventServiceOperation.getNoOp();
} else {
return this;
}
}
}
@@ -33,27 +33,39 @@ public abstract class AbstractRacingEventServiceOperation implements RacingEvent
}
@Override
public RacingEventServiceOperation transformClientRenameLeaderboardColumnOp(
public RacingEventServiceOperation transformRenameLeaderboardColumnClientOp(
RenameLeaderboardColumn renameLeaderboardColumnClientOp) {
return renameLeaderboardColumnClientOp;
}
@Override
public RacingEventServiceOperation transformServerRenameLeaderboardColumnOp(
public RacingEventServiceOperation transformRenameLeaderboardColumnServerOp(
RenameLeaderboardColumn renameLeaderboardColumnServerOp) {
return renameLeaderboardColumnServerOp;
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
public RacingEventServiceOperation transformRemoveColumnFromLeaderboardServerOp(RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
return removeColumnFromLeaderboardServerOp;
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
public RacingEventServiceOperation transformRemoveColumnFromLeaderboardClientOp(RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
return removeColumnFromLeaderboardClientOp;
}
@Override
public RacingEventServiceOperation transformAddColumnToLeaderboardClientOp(
AddColumnToLeaderboard addColumnToLeaderboard) {
return addColumnToLeaderboard;
}
@Override
public RacingEventServiceOperation transformAddColumnToLeaderboardServerOp(
AddColumnToLeaderboard addColumnToLeaderboard) {
return addColumnToLeaderboard;
}
public static RacingEventServiceOperation getNoOp() {
return new AbstractRacingEventServiceOperation() {
@Override
@@ -63,12 +75,17 @@ public abstract class AbstractRacingEventServiceOperation implements RacingEvent
@Override
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
return serverOp;
return this;
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
return clientOp;
return this;
}
@Override
public String toString() {
return "noop";
}
};
}
@@ -25,13 +25,11 @@ public class AddColumnToLeaderboard extends AbstractLeaderboardColumnOperation {
@Override
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
// TODO Auto-generated method stub
return null;
return serverOp.transformAddColumnToLeaderboardClientOp(this);
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
// TODO Auto-generated method stub
return null;
return clientOp.transformAddColumnToLeaderboardServerOp(this);
}
}
@@ -29,13 +29,13 @@ public interface RacingEventServiceOperation extends Operation<RacingEventServic
* operation deals with the leaderboard column being removed by <code>removeColumnFromLeaderboardClientOp</code>,
* the result will be <code>null</code>, meaning that this operation cannot be applied after the column has been removed.
*/
RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp);
RacingEventServiceOperation transformRemoveColumnFromLeaderboardClientOp(RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp);
RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp);
RacingEventServiceOperation transformRemoveColumnFromLeaderboardServerOp(RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp);
RacingEventServiceOperation transformClientRenameLeaderboardColumnOp(RenameLeaderboardColumn renameLeaderboardColumnClientOp);
RacingEventServiceOperation transformRenameLeaderboardColumnClientOp(RenameLeaderboardColumn renameLeaderboardColumnClientOp);
RacingEventServiceOperation transformServerRenameLeaderboardColumnOp(RenameLeaderboardColumn renameLeaderboardColumnServerOp);
RacingEventServiceOperation transformRenameLeaderboardColumnServerOp(RenameLeaderboardColumn renameLeaderboardColumnServerOp);
RacingEventServiceOperation transformAddLeaderboardClientOp(AddLeaderboard addLeaderboard);
@@ -44,4 +44,8 @@ public interface RacingEventServiceOperation extends Operation<RacingEventServic
RacingEventServiceOperation transformRemoveLeaderboardClientOp(RemoveLeaderboard removeLeaderboard);
RacingEventServiceOperation transformRemoveLeaderboardServerOp(RemoveLeaderboard removeLeaderboard);
RacingEventServiceOperation transformAddColumnToLeaderboardClientOp(AddColumnToLeaderboard addColumnToLeaderboard);
RacingEventServiceOperation transformAddColumnToLeaderboardServerOp(AddColumnToLeaderboard addColumnToLeaderboard);
}
@@ -17,12 +17,12 @@ public class RemoveColumnFromLeaderboard extends AbstractLeaderboardColumnOperat
@Override
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
return serverOp.transformClientRemoveColumnFromLeaderboard(this);
return serverOp.transformRemoveColumnFromLeaderboardClientOp(this);
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
return clientOp.transformServerRemoveColumnFromLeaderboard(this);
return clientOp.transformRemoveColumnFromLeaderboardServerOp(this);
}
}
@@ -23,4 +23,59 @@ public class RemoveLeaderboard extends AbstractLeaderboardOperation {
return toState;
}
@Override
public RacingEventServiceOperation transformRenameLeaderboardColumnClientOp(
RenameLeaderboardColumn renameLeaderboardColumnClientOp) {
return AbstractRacingEventServiceOperation.getNoOp();
}
@Override
public RacingEventServiceOperation transformRenameLeaderboardColumnServerOp(
RenameLeaderboardColumn renameLeaderboardColumnServerOp) {
return AbstractRacingEventServiceOperation.getNoOp();
}
@Override
public RacingEventServiceOperation transformRemoveColumnFromLeaderboardServerOp(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
return AbstractRacingEventServiceOperation.getNoOp();
}
@Override
public RacingEventServiceOperation transformRemoveColumnFromLeaderboardClientOp(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
return AbstractRacingEventServiceOperation.getNoOp();
}
@Override
public RacingEventServiceOperation transformAddColumnToLeaderboardClientOp(
AddColumnToLeaderboard addColumnToLeaderboard) {
return AbstractRacingEventServiceOperation.getNoOp();
}
@Override
public RacingEventServiceOperation transformAddColumnToLeaderboardServerOp(
AddColumnToLeaderboard addColumnToLeaderboard) {
return AbstractRacingEventServiceOperation.getNoOp();
}
@Override
public RacingEventServiceOperation transformRemoveLeaderboardClientOp(RemoveLeaderboard removeLeaderboard) {
if (affectsSameLeaderboard(removeLeaderboard)) {
return AbstractRacingEventServiceOperation.getNoOp();
} else {
return this;
}
}
@Override
public RacingEventServiceOperation transformRemoveLeaderboardServerOp(RemoveLeaderboard removeLeaderboard) {
if (affectsSameLeaderboard(removeLeaderboard)) {
return AbstractRacingEventServiceOperation.getNoOp();
} else {
return this;
}
}
}
@@ -19,13 +19,13 @@ public class RenameLeaderboardColumn extends AbstractLeaderboardColumnOperation
@Override
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
return serverOp.transformClientRenameLeaderboardColumnOp(this);
return serverOp.transformRenameLeaderboardColumnClientOp(this);
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
return clientOp.transformServerRenameLeaderboardColumnOp(this);
return clientOp.transformRenameLeaderboardColumnServerOp(this);
}
}