Add untyped transactor
This commit is contained in:
parent
4cdc46c23f
commit
db6d90df43
22 changed files with 422 additions and 39 deletions
|
|
@ -1,4 +1,4 @@
|
|||
package akka.stm.test;
|
||||
package akka.stm.example;
|
||||
|
||||
public class Address {
|
||||
private String location;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package akka.stm.test;
|
||||
package akka.stm.example;
|
||||
|
||||
import akka.stm.*;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package akka.stm.test;
|
||||
package akka.stm.example;
|
||||
|
||||
import akka.stm.*;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package akka.stm.test;
|
||||
package akka.stm.example;
|
||||
|
||||
public class StmExamples {
|
||||
public static void main(String[] args) {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package akka.stm.test;
|
||||
package akka.stm.example;
|
||||
|
||||
import akka.stm.*;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package akka.stm.test;
|
||||
package akka.stm.example;
|
||||
|
||||
import akka.stm.*;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package akka.stm.test;
|
||||
package akka.stm.example;
|
||||
|
||||
import akka.stm.*;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package akka.stm.test;
|
||||
package akka.stm.example;
|
||||
|
||||
public class User {
|
||||
private String name;
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package akka.transactor.example;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
|
||||
public class Increment {
|
||||
private ActorRef friend = null;
|
||||
|
||||
public Increment() {}
|
||||
|
||||
public Increment(ActorRef friend) {
|
||||
this.friend = friend;
|
||||
}
|
||||
|
||||
public boolean hasFriend() {
|
||||
return friend != null;
|
||||
}
|
||||
|
||||
public ActorRef getFriend() {
|
||||
return friend;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package akka.transactor.example;
|
||||
|
||||
import akka.transactor.UntypedTransactor;
|
||||
import akka.transactor.SendTo;
|
||||
import akka.stm.Ref;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class UntypedCounter extends UntypedTransactor {
|
||||
Ref<Integer> count = new Ref<Integer>(0);
|
||||
|
||||
@Override public Set<SendTo> coordinate(Object message) {
|
||||
if (message instanceof Increment) {
|
||||
Increment increment = (Increment) message;
|
||||
if (increment.hasFriend())
|
||||
return include(increment.getFriend(), new Increment());
|
||||
}
|
||||
return nobody();
|
||||
}
|
||||
|
||||
public void atomically(Object message) {
|
||||
if (message instanceof Increment) {
|
||||
count.set(count.get() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean normally(Object message) {
|
||||
if ("GetCount".equals(message)) {
|
||||
getContext().replyUnsafe(count.get());
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package akka.transactor.example;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.dispatch.Future;
|
||||
import akka.dispatch.Futures;
|
||||
|
||||
public class UntypedTransactorExample {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
System.out.println();
|
||||
System.out.println("Untyped transactor example");
|
||||
System.out.println();
|
||||
|
||||
ActorRef counter1 = UntypedActor.actorOf(UntypedCounter.class).start();
|
||||
ActorRef counter2 = UntypedActor.actorOf(UntypedCounter.class).start();
|
||||
|
||||
counter1.sendOneWay(new Increment(counter2));
|
||||
|
||||
Thread.sleep(3000);
|
||||
|
||||
Future future1 = counter1.sendRequestReplyFuture("GetCount");
|
||||
Future future2 = counter2.sendRequestReplyFuture("GetCount");
|
||||
|
||||
future1.await();
|
||||
if (future1.isCompleted()) {
|
||||
if (future1.result().isDefined()) {
|
||||
int result = (Integer) future1.result().get();
|
||||
System.out.println("counter 1: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
future2.await();
|
||||
if (future2.isCompleted()) {
|
||||
if (future2.result().isDefined()) {
|
||||
int result = (Integer) future2.result().get();
|
||||
System.out.println("counter 2: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
counter1.stop();
|
||||
counter2.stop();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,11 +5,19 @@ import java.util.List;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class Increment {
|
||||
List<ActorRef> friends;
|
||||
CountDownLatch latch;
|
||||
private List<ActorRef> friends;
|
||||
private CountDownLatch latch;
|
||||
|
||||
public Increment(List<ActorRef> friends, CountDownLatch latch) {
|
||||
this.friends = friends;
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
public List<ActorRef> getFriends() {
|
||||
return friends;
|
||||
}
|
||||
|
||||
public CountDownLatch getLatch() {
|
||||
return latch;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,14 +12,14 @@ import java.util.List;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CoordinatedCounter extends UntypedActor {
|
||||
String name;
|
||||
Ref<Integer> count = new Ref(0);
|
||||
TransactionFactory txFactory = new TransactionFactoryBuilder()
|
||||
public class UntypedCoordinatedCounter extends UntypedActor {
|
||||
private String name;
|
||||
private Ref<Integer> count = new Ref(0);
|
||||
private TransactionFactory txFactory = new TransactionFactoryBuilder()
|
||||
.setTimeout(new Duration(3, TimeUnit.SECONDS))
|
||||
.build();
|
||||
|
||||
public CoordinatedCounter(String name) {
|
||||
public UntypedCoordinatedCounter(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
|
@ -34,8 +34,8 @@ public class CoordinatedCounter extends UntypedActor {
|
|||
Object message = coordinated.getMessage();
|
||||
if (message instanceof Increment) {
|
||||
Increment increment = (Increment) message;
|
||||
List<ActorRef> friends = increment.friends;
|
||||
final CountDownLatch latch = increment.latch;
|
||||
List<ActorRef> friends = increment.getFriends();
|
||||
final CountDownLatch latch = increment.getLatch();
|
||||
if (!friends.isEmpty()) {
|
||||
Increment coordMessage = new Increment(friends.subList(1, friends.size()), latch);
|
||||
friends.get(0).sendOneWay(coordinated.coordinate(coordMessage));
|
||||
|
|
@ -17,7 +17,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import scala.Option;
|
||||
|
||||
public class CoordinatedIncrementTest {
|
||||
public class UntypedCoordinatedIncrementTest {
|
||||
List<ActorRef> counters;
|
||||
ActorRef failer;
|
||||
|
||||
|
|
@ -30,13 +30,13 @@ public class CoordinatedIncrementTest {
|
|||
final String name = "counter" + i;
|
||||
ActorRef counter = UntypedActor.actorOf(new UntypedActorFactory() {
|
||||
public UntypedActor create() {
|
||||
return new CoordinatedCounter(name);
|
||||
return new UntypedCoordinatedCounter(name);
|
||||
}
|
||||
});
|
||||
counter.start();
|
||||
counters.add(counter);
|
||||
}
|
||||
failer = UntypedActor.actorOf(CoordinatedFailer.class);
|
||||
failer = UntypedActor.actorOf(UntypedFailer.class);
|
||||
failer.start();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package akka.transactor.test;
|
||||
|
||||
import akka.transactor.UntypedTransactor;
|
||||
import akka.transactor.SendTo;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.stm.*;
|
||||
import akka.util.Duration;
|
||||
|
||||
import org.multiverse.api.StmUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UntypedCounter extends UntypedTransactor {
|
||||
private String name;
|
||||
private Ref<Integer> count = new Ref<Integer>(0);
|
||||
|
||||
public UntypedCounter(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override public TransactionFactory transactionFactory() {
|
||||
return new TransactionFactoryBuilder()
|
||||
.setTimeout(new Duration(3, TimeUnit.SECONDS))
|
||||
.build();
|
||||
}
|
||||
|
||||
private void increment() {
|
||||
System.out.println(name + ": incrementing");
|
||||
count.set(count.get() + 1);
|
||||
}
|
||||
|
||||
@Override public Set<SendTo> coordinate(Object message) {
|
||||
if (message instanceof Increment) {
|
||||
Increment increment = (Increment) message;
|
||||
List<ActorRef> friends = increment.getFriends();
|
||||
if (!friends.isEmpty()) {
|
||||
Increment coordMessage = new Increment(friends.subList(1, friends.size()), increment.getLatch());
|
||||
return include(friends.get(0), coordMessage);
|
||||
} else {
|
||||
return nobody();
|
||||
}
|
||||
} else {
|
||||
return nobody();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void before(Object message) {
|
||||
System.out.println(name + ": before transaction");
|
||||
}
|
||||
|
||||
public void atomically(Object message) {
|
||||
if (message instanceof Increment) {
|
||||
increment();
|
||||
final Increment increment = (Increment) message;
|
||||
StmUtils.scheduleDeferredTask(new Runnable() {
|
||||
public void run() { increment.getLatch().countDown(); }
|
||||
});
|
||||
StmUtils.scheduleCompensatingTask(new Runnable() {
|
||||
public void run() { increment.getLatch().countDown(); }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void after(Object message) {
|
||||
System.out.println(name + ": after transaction");
|
||||
}
|
||||
|
||||
@Override public boolean normally(Object message) {
|
||||
if ("GetCount".equals(message)) {
|
||||
getContext().replyUnsafe(count.get());
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ package akka.transactor.test;
|
|||
|
||||
import akka.actor.UntypedActor;
|
||||
|
||||
public class CoordinatedFailer extends UntypedActor {
|
||||
public class UntypedFailer extends UntypedActor {
|
||||
public void onReceive(Object incoming) throws Exception {
|
||||
throw new RuntimeException("Expected failure");
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package akka.transactor.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
import org.junit.Before;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.UntypedActorFactory;
|
||||
import akka.dispatch.Future;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import scala.Option;
|
||||
|
||||
public class UntypedTransactorTest {
|
||||
List<ActorRef> counters;
|
||||
ActorRef failer;
|
||||
|
||||
int numCounters = 5;
|
||||
int timeout = 5;
|
||||
|
||||
@Before public void initialise() {
|
||||
counters = new ArrayList<ActorRef>();
|
||||
for (int i = 1; i <= numCounters; i++) {
|
||||
final String name = "counter" + i;
|
||||
ActorRef counter = UntypedActor.actorOf(new UntypedActorFactory() {
|
||||
public UntypedActor create() {
|
||||
return new UntypedCounter(name);
|
||||
}
|
||||
});
|
||||
counter.start();
|
||||
counters.add(counter);
|
||||
}
|
||||
failer = UntypedActor.actorOf(UntypedFailer.class);
|
||||
failer.start();
|
||||
}
|
||||
|
||||
@Test public void incrementAllCountersWithSuccessfulTransaction() {
|
||||
CountDownLatch incrementLatch = new CountDownLatch(numCounters);
|
||||
Increment message = new Increment(counters.subList(1, counters.size()), incrementLatch);
|
||||
counters.get(0).sendOneWay(message);
|
||||
try {
|
||||
incrementLatch.await(timeout, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException exception) {}
|
||||
for (ActorRef counter : counters) {
|
||||
Future future = counter.sendRequestReplyFuture("GetCount");
|
||||
future.await();
|
||||
if (future.isCompleted()) {
|
||||
Option resultOption = future.result();
|
||||
if (resultOption.isDefined()) {
|
||||
Object result = resultOption.get();
|
||||
int count = (Integer) result;
|
||||
assertEquals(1, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void incrementNoCountersWithFailingTransaction() {
|
||||
CountDownLatch incrementLatch = new CountDownLatch(numCounters);
|
||||
List<ActorRef> actors = new ArrayList<ActorRef>(counters);
|
||||
actors.add(failer);
|
||||
Increment message = new Increment(actors.subList(1, actors.size()), incrementLatch);
|
||||
actors.get(0).sendOneWay(message);
|
||||
try {
|
||||
incrementLatch.await(timeout, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException exception) {}
|
||||
for (ActorRef counter : counters) {
|
||||
Future future = counter.sendRequestReplyFuture("GetCount");
|
||||
future.await();
|
||||
if (future.isCompleted()) {
|
||||
Option resultOption = future.result();
|
||||
if (resultOption.isDefined()) {
|
||||
Object result = resultOption.get();
|
||||
int count = (Integer) result;
|
||||
assertEquals(0, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue