412 lines
14 KiB
Plaintext
412 lines
14 KiB
Plaintext
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: Services\Tests\CounterProxy\CounterJournalet.sg
|
||
|
//
|
||
|
// Note:
|
||
|
//
|
||
|
#define VERSION_2
|
||
|
using System;
|
||
|
using System.Threading;
|
||
|
using System.Collections;
|
||
|
using Microsoft.SingSharp;
|
||
|
using Microsoft.Singularity;
|
||
|
using Microsoft.Singularity.Channels;
|
||
|
using Microsoft.Singularity.Directory;
|
||
|
using Microsoft.Singularity.Resiliency;
|
||
|
|
||
|
namespace Microsoft.Singularity.Services.CounterProxy
|
||
|
{
|
||
|
internal enum MessageType : uint
|
||
|
{
|
||
|
Unknown,
|
||
|
Success,
|
||
|
Increment,
|
||
|
BeginCount,
|
||
|
Next,
|
||
|
End,
|
||
|
AckIncrement,
|
||
|
NakIncrement,
|
||
|
Current,
|
||
|
Terminated,
|
||
|
}
|
||
|
#if VERSION_2
|
||
|
internal sealed class CounterJournalet : Journalet2
|
||
|
#else
|
||
|
internal sealed class CounterJournalet : Journalet
|
||
|
#endif
|
||
|
{
|
||
|
private Log! incoming;
|
||
|
private Log! outgoing;
|
||
|
private TRef<CounterContract.Imp:Ready> counterServerRef;
|
||
|
private TRef<CounterContract.Exp:Ready> counterClientRef;
|
||
|
private TRef<CounterContract.Imp:Start> initServerRef;
|
||
|
#if VERSION_2
|
||
|
private TRef<CounterContract.Exp:Start>! initClientRef;
|
||
|
#endif
|
||
|
|
||
|
#if VERSION_2
|
||
|
internal CounterJournalet([Claims]ServiceContract.Exp:Start! ep)
|
||
|
: base()
|
||
|
{
|
||
|
CounterContract.Exp:Start counterEp;
|
||
|
counterEp = ep as CounterContract.Exp:Start;
|
||
|
if (counterEp == null) {
|
||
|
throw new ArgumentException();
|
||
|
}
|
||
|
|
||
|
this.incoming = new Log();
|
||
|
this.outgoing = new Log();
|
||
|
this.initClientRef = new TRef<CounterContract.Exp:Start>(counterEp);
|
||
|
}
|
||
|
#else
|
||
|
internal CounterJournalet(JournalProducer! producer,
|
||
|
[Claims]ServiceContract.Exp:Start! ep)
|
||
|
{
|
||
|
base(producer, ep);
|
||
|
this.incoming = new Log();
|
||
|
this.outgoing = new Log();
|
||
|
this.state = ProxyState.Waiting;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if VERSION_2
|
||
|
public override void CreateEndpoint(out ServiceContract.Exp! ep)
|
||
|
#else
|
||
|
public override void CreateServerEndpoint(out ServiceContract.Exp:Start! ep)
|
||
|
#endif
|
||
|
{
|
||
|
CounterContract.Imp! imp;
|
||
|
CounterContract.Exp! exp;
|
||
|
|
||
|
//DebugStub.Print("CJ: ENTER CreateServerEndpoint\n");
|
||
|
CounterContract.NewChannel(out imp, out exp);
|
||
|
initServerRef = new TRef<CounterContract.Imp:Start>(imp);
|
||
|
ep = exp;
|
||
|
//DebugStub.Print("CJ: EXIT CreateServerEndpoint\n");
|
||
|
}
|
||
|
|
||
|
#if VERSION_2
|
||
|
public override void Flush()
|
||
|
{
|
||
|
incoming.Flush();
|
||
|
outgoing.Flush();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
protected override bool Initialize()
|
||
|
{
|
||
|
bool success = false;
|
||
|
CounterContract.Exp:Start clientEp;
|
||
|
CounterContract.Imp:Start! serverEp;
|
||
|
|
||
|
#if VERSION_2
|
||
|
clientEp = initClientRef.Acquire();
|
||
|
#else
|
||
|
ServiceContract.Exp:Start! ep;
|
||
|
ep = clientRef.Acquire();
|
||
|
clientEp = ep as CounterContract.Exp:Start;
|
||
|
if (clientEp == null) {
|
||
|
clientRef.Release(ep);
|
||
|
return false;
|
||
|
}
|
||
|
#endif
|
||
|
assume initServerRef != null;
|
||
|
serverEp = initServerRef.Acquire();
|
||
|
switch receive {
|
||
|
case serverEp.Success():
|
||
|
clientEp.SendSuccess();
|
||
|
success = true;
|
||
|
break;
|
||
|
case serverEp.ChannelClosed():
|
||
|
success = false;
|
||
|
break;
|
||
|
case unsatisfiable:
|
||
|
DebugStub.Break();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (success) {
|
||
|
counterClientRef = new TRef<CounterContract.Exp:Ready>(clientEp);
|
||
|
counterServerRef = new TRef<CounterContract.Imp:Ready>(serverEp);
|
||
|
return true;
|
||
|
}
|
||
|
else {
|
||
|
delete clientEp;
|
||
|
delete serverEp;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected override bool HandleMessages()
|
||
|
{
|
||
|
bool recovery = false;
|
||
|
CounterContract.Exp:Ready! clientEp;
|
||
|
CounterContract.Imp:Ready! serverEp;
|
||
|
|
||
|
assume counterClientRef != null;
|
||
|
assume counterServerRef != null;
|
||
|
clientEp = counterClientRef.Acquire();
|
||
|
serverEp = counterServerRef.Acquire();
|
||
|
|
||
|
for (;;) {
|
||
|
switch receive {
|
||
|
case clientEp.Increment():
|
||
|
State = ProxyState.Running;
|
||
|
#if VERSION_2
|
||
|
Sync();
|
||
|
#endif
|
||
|
serverEp.SendIncrement();
|
||
|
incoming.Record((uint)MessageType.Increment, null);
|
||
|
break;
|
||
|
case clientEp.BeginCount():
|
||
|
State = ProxyState.Running;
|
||
|
DebugStub.Print("CJ: BeginCount\n");
|
||
|
#if VERSION_2
|
||
|
Sync();
|
||
|
#endif
|
||
|
serverEp.SendBeginCount();
|
||
|
incoming.Record((uint)MessageType.BeginCount, null);
|
||
|
break;
|
||
|
case clientEp.Next():
|
||
|
State = ProxyState.Running;
|
||
|
DebugStub.Print("CJ: Next\n");
|
||
|
#if VERSION_2
|
||
|
Sync();
|
||
|
#endif
|
||
|
serverEp.SendNext();
|
||
|
incoming.Record((uint)MessageType.Next, null);
|
||
|
break;
|
||
|
case clientEp.End():
|
||
|
State = ProxyState.Running;
|
||
|
serverEp.SendEnd();
|
||
|
#if VERSION_2
|
||
|
Sync();
|
||
|
#endif
|
||
|
incoming.Record((uint)MessageType.End, null);
|
||
|
break;
|
||
|
case clientEp.ChannelClosed():
|
||
|
State = ProxyState.Running;
|
||
|
// Lost client. Journalet also goes away.
|
||
|
DebugStub.Print("CJ: Client disconnected.\n");
|
||
|
recovery = false;
|
||
|
goto exit;
|
||
|
break;
|
||
|
|
||
|
case serverEp.AckIncrement(number):
|
||
|
#if VERSION_2
|
||
|
Sync();
|
||
|
#endif
|
||
|
State = ProxyState.Running;
|
||
|
clientEp.SendAckIncrement(number);
|
||
|
ArrayList al = new ArrayList(1);
|
||
|
al.Add(number);
|
||
|
outgoing.Record((uint)MessageType.AckIncrement, al);
|
||
|
break;
|
||
|
case serverEp.Current(number):
|
||
|
#if VERSION_2
|
||
|
Sync();
|
||
|
#endif
|
||
|
State = ProxyState.Running;
|
||
|
DebugStub.Print("CJ: Current\n");
|
||
|
clientEp.SendCurrent(number);
|
||
|
ArrayList al = new ArrayList(1);
|
||
|
al.Add(number);
|
||
|
outgoing.Record((uint)MessageType.Current, al);
|
||
|
break;
|
||
|
case serverEp.Terminated():
|
||
|
#if VERSION_2
|
||
|
Sync();
|
||
|
#endif
|
||
|
State = ProxyState.Running;
|
||
|
clientEp.SendTerminated();
|
||
|
outgoing.Record((uint)MessageType.Terminated, null);
|
||
|
break;
|
||
|
case serverEp.ChannelClosed():
|
||
|
State = ProxyState.Running;
|
||
|
DebugStub.Print("CJ: Server disconnected.\n");
|
||
|
recovery = true;
|
||
|
goto exit;
|
||
|
break;
|
||
|
}
|
||
|
State = ProxyState.Waiting;
|
||
|
}
|
||
|
exit:
|
||
|
if (recovery) {
|
||
|
counterClientRef.Release(clientEp);
|
||
|
counterServerRef.Release(serverEp);
|
||
|
}
|
||
|
else {
|
||
|
delete clientEp;
|
||
|
delete serverEp;
|
||
|
}
|
||
|
|
||
|
return recovery;
|
||
|
}
|
||
|
|
||
|
protected override bool Recover()
|
||
|
{
|
||
|
bool success = false;
|
||
|
uint msg;
|
||
|
IList args;
|
||
|
Object tmp;
|
||
|
MessageType op;
|
||
|
CounterContract.Imp:Start serverEp;
|
||
|
|
||
|
DebugStub.Print("-- Incoming Log Length: {0}\n",
|
||
|
__arglist(incoming.Count));
|
||
|
DebugStub.Print("-- Outgoing Log Length: {0}\n",
|
||
|
__arglist(outgoing.Count));
|
||
|
|
||
|
//
|
||
|
// Channel initialization
|
||
|
//
|
||
|
assume initServerRef != null;
|
||
|
DebugStub.Print("CJ: Getting an endpoint...");
|
||
|
serverEp = initServerRef.Acquire();
|
||
|
switch receive {
|
||
|
case serverEp.Success():
|
||
|
break;
|
||
|
case serverEp.ChannelClosed():
|
||
|
delete serverEp;
|
||
|
throw new ChannelClosedException();
|
||
|
break;
|
||
|
}
|
||
|
DebugStub.Print("done.\n");
|
||
|
|
||
|
//
|
||
|
// Channel State Recovery Main Loop
|
||
|
//
|
||
|
while (incoming.Playback(out msg, out args)) {
|
||
|
//
|
||
|
// Playback the incoming message
|
||
|
//
|
||
|
op = (MessageType)msg;
|
||
|
switch (op) {
|
||
|
case MessageType.Increment:
|
||
|
serverEp.SendIncrement();
|
||
|
break;
|
||
|
case MessageType.BeginCount:
|
||
|
serverEp.SendBeginCount();
|
||
|
break;
|
||
|
case MessageType.Next:
|
||
|
serverEp.SendNext();
|
||
|
break;
|
||
|
case MessageType.End:
|
||
|
serverEp.SendEnd();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Playback the outgoing message
|
||
|
//
|
||
|
bool res = true;
|
||
|
res = outgoing.Playback(out msg, out args);
|
||
|
op = (MessageType)msg;
|
||
|
|
||
|
if (!res) {
|
||
|
DebugStub.Print("Playback: End of log. Break.\n");
|
||
|
success = true;
|
||
|
break;
|
||
|
}
|
||
|
switch receive {
|
||
|
case serverEp.AckIncrement(number):
|
||
|
if (op != MessageType.AckIncrement || args == null) {
|
||
|
// make a decision
|
||
|
// 1. ignore
|
||
|
// 2. notify
|
||
|
success = false;
|
||
|
}
|
||
|
else {
|
||
|
tmp = args[0];
|
||
|
if (tmp == null) {
|
||
|
// make a decision
|
||
|
// 1. ignore
|
||
|
// 2. notify
|
||
|
success = false;
|
||
|
}
|
||
|
else {
|
||
|
int lognum = (int)tmp;
|
||
|
if (number != lognum) {
|
||
|
// make a decision
|
||
|
// 1. ignore
|
||
|
// 2. notify
|
||
|
success = false;
|
||
|
}
|
||
|
else {
|
||
|
success = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case serverEp.NakIncrement():
|
||
|
if (op != MessageType.NakIncrement) {
|
||
|
// make a decision
|
||
|
// 1. ignore
|
||
|
// 2. notify
|
||
|
success = false;
|
||
|
}
|
||
|
else {
|
||
|
success = true;
|
||
|
}
|
||
|
break;
|
||
|
case serverEp.Current(number):
|
||
|
if (op != MessageType.Current ||
|
||
|
args == null) {
|
||
|
// make a decision
|
||
|
// 1. ignore
|
||
|
// 2. notify
|
||
|
success = false;
|
||
|
}
|
||
|
else {
|
||
|
tmp = args[0];
|
||
|
if (tmp == null) {
|
||
|
// make a decision
|
||
|
// 1. ignore
|
||
|
// 2. notify
|
||
|
success = false;
|
||
|
}
|
||
|
else {
|
||
|
int lognum = (int)tmp;
|
||
|
if (number != lognum) {
|
||
|
// make a decision
|
||
|
// 1. ignore
|
||
|
// 2. notify
|
||
|
success = false;
|
||
|
}
|
||
|
else {
|
||
|
success = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case serverEp.Terminated():
|
||
|
if (op != MessageType.Terminated) {
|
||
|
// make a decision
|
||
|
// 1. ignore
|
||
|
// 2. notify
|
||
|
success = false;
|
||
|
}
|
||
|
else {
|
||
|
success = true;
|
||
|
}
|
||
|
break;
|
||
|
case serverEp.ChannelClosed():
|
||
|
delete serverEp;
|
||
|
throw new ChannelClosedException();
|
||
|
break;
|
||
|
}
|
||
|
} // end of loop
|
||
|
|
||
|
assume counterServerRef != null;
|
||
|
delete counterServerRef.Acquire();
|
||
|
counterServerRef.Release(serverEp);
|
||
|
return success;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|