/////////////////////////////////////////////////////////////////////////////// // // 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 counterServerRef; private TRef counterClientRef; private TRef initServerRef; #if VERSION_2 private TRef! 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(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(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(clientEp); counterServerRef = new TRef(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; } } }