/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Libraries\Resiliency\DirectoryServiceProxy.sg // // Note: Intermediary of DirectoryServiceContract // using System; using System.Collections; using System.Threading; using Microsoft.SingSharp; using Microsoft.Singularity; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Directory; using Microsoft.Singularity.ServiceManager; using Microsoft.Singularity.Services; namespace Microsoft.Singularity.Resiliency { internal sealed class DirectoryServiceProxy : IRunnable, IRecoveryAware { private bool recovery; private Object! recoveryLock; private ServiceProxy! manager; private IList! providerList; private JournaletFactory! factory; private PersistentMemory! objectStore; private TRef rootDsRef; private TRef myDsRef; private TRef proxyRef; private TRef signalRef; private TRef senderRef; private TRef receiverRef; /// dep Channel to the (root) directory service. This channel is /// necessary to intercept the connection request from a client /// to the server. /// fep Channel from the target server. This channel acts as the /// directory service for the server. internal DirectoryServiceProxy(ServiceProxy! proxy, JournaletFactory! factory, [Claims]DirectoryServiceContract.Imp:Ready! dep, [Claims]DirectoryServiceContract.Exp:Ready! fep, [Claims]ServiceProxyContract.Exp:Ready! xep) { SignalContract.Imp! imp; SignalContract.Exp! exp; this.manager = proxy; this.factory = factory; this.providerList = new ArrayList(); this.objectStore = new PersistentMemory(); this.recoveryLock = new Object(); this.myDsRef = new TRef(fep); this.proxyRef = new TRef(xep); this.rootDsRef = new TRef(dep); SignalContract.NewChannel(out imp, out exp); senderRef = new TRef(imp); receiverRef = new TRef(exp); } public void Signal([Claims]ThreadTerminationContract.Exp:Start! ep) { signalRef = new TRef(ep); } // Proxy recovers from server failure by itself. public void Run() { DirectoryServiceContract.Exp:Ready newEP; ServiceProxyContract.Exp:Ready newPx; SignalContract.Imp:Start! signal; for (;;) { DebugStub.Print("DPx: HandleProxyService\n"); if (!HandleProxyService()) { break; } manager.RecoverService(out newEP, out newPx); if (newEP == null || newPx == null) { delete newEP; delete newPx; break; } DebugStub.Print("DPx: Replace DS\n"); // replace with the new endpoint delete myDsRef.Acquire(); myDsRef.Release(newEP); DebugStub.Print("DPx: Replace proxy\n"); delete proxyRef.Acquire(); proxyRef.Release(newPx); } delete signalRef.Acquire(); } /// /// Handles DirectoryService and ServiceProvider /// private bool HandleProxyService() { DirectoryServiceContract.Exp:Ready! myDS; ServiceProxyContract.Exp:Ready! proxy; DirectoryServiceContract.Imp:Ready! rootDS; ThreadTerminationContract.Exp:Start! signalFromManager; SignalContract.Exp:Start! signalInternal; int currentGeneration = -1; int previousGeneration = 0; Random random = new Random(); if (signalRef == null) { DebugStub.Print("DPx: signal is not set!\n"); return recovery; } myDS = myDsRef.Acquire(); rootDS = rootDsRef.Acquire(); proxy = proxyRef.Acquire(); signalFromManager = signalRef.Acquire(); signalInternal = receiverRef.Acquire(); recovery = false; for (;;) { switch receive { // BEGIN SWR LEVEL0 // From the service process case myDS.Register(path, imp): { string! pathName; ServiceProviderProxy provider; ServiceProviderContract.Imp! client; ServiceProviderContract.Exp! server; ServiceProviderContract.Imp:Start! oldEp; pathName = Bitter.ToString2(path); DebugStub.Print("DPx: Register '{0}'\n", __arglist(pathName)); provider = LookupProviderProxy(pathName); if (provider != null) { // We already have the one. provider.Stop(out oldEp); delete oldEp; provider.Start(imp); myDS.SendAckRegister(); delete path; break; } // Register the JP's endpoint to the NS. ServiceProviderContract.NewChannel(out client, out server); rootDS.SendRegister(path, client); // BEGIN SWR LEVEL1 switch receive { // From the root DS case rootDS.AckRegister(): { myDS.SendAckRegister(); CreateProviderProxy(pathName, imp, server); break; } // From the root DS case rootDS.NakRegister(rejected, error): { myDS.SendNakRegister(imp, error); delete rejected; delete server; break; } // From the root DS case rootDS.NakRegisterReparse(npath, rest, link, rejected): { DebugStub.Print("DPx: NakRegisterReparse\n"); myDS.SendNakRegisterReparse(npath, rest, link, imp); delete rejected; delete server; break; } // internal communication case signalFromManager.Stop(): { signalFromManager.SendAckStop(); delete server; delete imp; goto exit; break; } // internal communication case signalFromManager.ChannelClosed(): { delete server; delete imp; goto exit; break; } case unsatisfiable: { // protocol mismatch delete server; delete imp; break; } } // END SWR LEVEL1 break; } // From the service process case myDS.Deregister(path): { string! pathName; ServiceProviderProxy provider; pathName = Bitter.ToString2(path); DebugStub.Print("DPx: Deregister '{0}'\n", __arglist(pathName)); rootDS.SendDeregister(path); switch receive { // From the root DS case rootDS.AckDeregister(ep): { provider = LookupProviderProxy(pathName); if (provider != null) { ServiceProviderContract.Imp:Start! endpoint; provider.Terminate(out endpoint); myDS.SendAckDeregister(endpoint); RemoveProviderProxy(provider); } else { myDS.SendNakDeregister(ErrorCode.NotFound); } delete ep; break; } // From the root DS case rootDS.NakDeregister(error): { myDS.SendNakDeregister(error); break; } case rootDS.NakDeregisterReparse(npath, rest, link): { myDS.SendNakDeregisterReparse(npath, rest, link); break; } } // END SWR LEVEL1 break; } // // PRef style //NOTE: Not tested yet case proxy.Allocate(obj): { proxy.SendNakAllocate(obj); break; } case proxy.Deallocate(id): { proxy.SendNakDeallocate(); break; } case proxy.AcquireObject(id): { proxy.SendNakAcquireObject(); break; } case proxy.ReleaseObject(obj): { proxy.SendNakReleaseObject(); break; } // // Serialization style // case proxy.Upload(data): { proxy.SendAckUpload(); objectStore.Store(data); break; } case proxy.Download(): { byte[] in ExHeap buffer = objectStore.Restore(); if (buffer != null) { proxy.SendAckDownload(buffer); } else { proxy.SendNakDownload(); } break; } // // Checkpoint update protocol //NOTE: not tested yet case proxy.Suspend(/* journalet id */): { proxy.SendAckSuspend(currentGeneration); SuspendProviderProxies(); break; } case proxy.Resume(generation): { proxy.SendAckResume(); if (generation == currentGeneration) { ResumeProviderProxies(); } break; } case proxy.Update(generation): { proxy.SendAckUpdate(); if (generation == currentGeneration) { objectStore.Flush(); UpdateProviderProxies(); previousGeneration = currentGeneration; do { currentGeneration = random.Next(); } while (currentGeneration == previousGeneration); } break; } case proxy.ChannelClosed(): { DebugStub.Print("DPx: Server channel closed. " + "Recover.\n"); objectStore.Undo(); recovery = true; goto exit; break; } // From the service process case myDS.ChannelClosed(): { DebugStub.Print("DPx: Server channel closed. " + "Recover.\n"); objectStore.Undo(); recovery = true; goto exit; break; } // From the root DS case rootDS.ChannelClosed(): { DebugStub.Print("DPx: DS channel closed. Exit.\n"); goto exit; break; } case signalFromManager.Stop(): { TerminateProviderProxies(); signalFromManager.SendAckStop(); goto exit; break; } case signalFromManager.ChannelClosed(): { TerminateProviderProxies(); goto exit; break; } case signalInternal.Stop(): { recovery = true; signalInternal.SendAckStop(); goto exit; break; } // this works with the proxy initiation style case signalInternal.Update(): { DebugStub.Print("DPx: Update Master\n"); objectStore.Flush(); signalInternal.SendAckUpdate(); break; } case signalInternal.ChannelClosed(): { TerminateProviderProxies(); goto exit; break; } } // END SWR LEVEL0 } // END OF LOOP exit: signalRef.Release(signalFromManager); receiverRef.Release(signalInternal); myDsRef.Release(myDS); rootDsRef.Release(rootDS); proxyRef.Release(proxy); return recovery; } // HandleDirectoryService private void CreateProviderProxy(string! path, [Claims]ServiceProviderContract.Imp:Start! provider, [Claims]ServiceProviderContract.Exp:Start! myProvider) { ServiceProviderProxy pp = new ServiceProviderProxy(this, path, factory, myProvider); lock (providerList) { providerList.Add(pp); } pp.Start(provider); } private ServiceProviderProxy LookupProviderProxy(string! path) { ServiceProviderProxy pp; lock (providerList) { foreach (Object obj in providerList) { if (obj == null) { break; } pp = obj as ServiceProviderProxy; if (pp == null) { continue; } if (pp.Path == path) { return pp; } } } return null; } private void RemoveProviderProxy(ServiceProviderProxy! sp) { lock (providerList) { providerList.Remove(sp); } } private void TerminateProviderProxies() { ServiceProviderProxy pp; ServiceProviderContract.Imp:Start! ep; //DebugStub.Print("DPx: Enter TerminateProviderProxies\n"); lock (providerList) { foreach (Object obj in providerList) { if (obj == null) { break; } pp = obj as ServiceProviderProxy; if (pp == null) { continue; } pp.Terminate(out ep); delete ep; } } //DebugStub.Print("DPx: Exit TerminateProviderProxies\n"); } private void SuspendProviderProxies() { ServiceProviderProxy pp; lock (providerList) { foreach (Object obj in providerList) { if (obj == null) { break; } pp = obj as ServiceProviderProxy; if (pp == null) { continue; } pp.Suspend(); } } } private void ResumeProviderProxies() { ServiceProviderProxy pp; lock (providerList) { foreach (Object obj in providerList) { if (obj == null) { break; } pp = obj as ServiceProviderProxy; if (pp == null) { break; } pp.Resume(); } } } private void UpdateProviderProxies() { ServiceProviderProxy pp; lock (providerList) { foreach (Object obj in providerList) { if (obj == null) { break; } pp = obj as ServiceProviderProxy; if (pp == null) { break; } pp.Flush(); } } } /// /// Signal to the main loop for recovering the server. /// Invoked by ServiceProviderProxy. /// public void NotifyRecovery() { SignalContract.Imp:Start! signal; if (!Monitor.TryEnter(recoveryLock)) { return; } if (!recovery) { signal = senderRef.Acquire(); signal.SendStop(); switch receive { case signal.AckStop(): break; case unsatisfiable: break; } senderRef.Release(signal); } Monitor.Exit(recoveryLock); } public void UpdateCheckpoint() { SignalContract.Imp:Start! signal; //DebugStub.Print("DPx: Enter UpdateCheckpoint\n"); signal = senderRef.Acquire(); SuspendProviderProxies(); signal.SendUpdate(); switch receive { case signal.AckUpdate(): break; } UpdateProviderProxies(); ResumeProviderProxies(); senderRef.Release(signal); //DebugStub.Print("DPx: Exit UpdateCheckpoint\n"); } } }