Home | Papers | Reports | Projects | Code Fragments | Dissertations | Presentations | Posters | Proposals | Lectures given | Course notes |
<< 17. Examination Questions 1999-2000 | 19. Examination Questions 2001-2002 >> |
18. Examination Questions 2000-2001Werner Van Belle1 - werner@yellowcouch.org, werner.van.belle@gmail.com Abstract : A variety of examination questions, includes a grtaphical whiteboard in all possible variants: synchronous, asynchronous fault tolerant and so on. These were used in 2000-2001
Reference:
Werner Van Belle; Examination Questions 2000-2001; |
import java.rmi.*; public interface FacCalcer extends Remote { public int fac(int n, FacCalcer fc) throws RemoteException; }
import java.rmi.*; import java.rmi.server.*; public class FacApp extends UnicastRemoteObject implements FacCalcer { public FacApp() throws RemoteException { } public int fac(int n, FacCalcer fc) throws RemoteException { System.out.println("fac("+n+")"); if (n==0) return 1; return n*fc.fac(n-1,this); } public static void main(String args[]) { FacCalcer fc; FacApp self=null; try { int answer; self=new FacApp(); try { fc=(FacCalcer)Naming.lookup("faccalcer"); answer=fc.fac(0,self); System.out.println("The answer my friend ... "+answer); } catch (NotBoundException e) { System.out.println("faccalcer bound"); Naming.bind("faccalcer",self); } } catch (Exception e) { System.out.println(e); } } }
Dit programma werkt en heeft indien het twee maal gestart wordt de onderstaande uitvoer.
> rmiregistry
&
> Java FacApp &
faccalcer bound
> Java FacApp
fac(4)
fac(3)
fac(2)
fac(1)
fac(0)
The answer my friend ... 24
>
Opgave: Teken de control flow van het volledige programma in detail.
We willen een gedistribueerd agent systeem gebruiken om online scheduling van personen hun agenda te doen. De idee hierbij is dat elke persoon een agent op het netwerk heeft rondhuppelen die zijn schedule bewaakt. De schedule-agents kunnen met elkaar communiceren om gaatjes op elkaars agenda te vinden en meetings vast te leggen.
-Beschrijf het protocol dat u zou gebruiken tussen de verschillende schedule-agents om een meeting te plannen met een aantal mensen. Hierbij zal de schedule-agent opgeroepen worden vanuit een user interface met het bericht scheduleMeeting(partners[],time). Partners[] is een array die de namen van de andere schedule-agents bevat. Time is het ogenblik waarop de meeting geplaatst kan worden. Het resultaat van deze call moet zijn dat de eigenaar ingelicht wordt met 'meeting Scheduled', of 'scheduling failed'.
- Hou terdege rekening met concurrentieproblemen !
We willen in staat zijn 2 processen te synchroniseren op een bepaald moment in tijd. We willen dit doen door een synchronisatieprimitieve te introduceren (sync genaamd). Deze synchronisatie-primitieve zal 2 argumenten nemen. Het eerste argument is de naam van de andere partner, het tweede argument is de conditie die we gebruiken als synchronisatie. Bv:
agent ikel: ...
sync(agent("test"),580) en
agent test: ... sync(agent("ikel"),580)
Deze twee agents zullen beiden synchroniseren en true weergeven als ze beide de sync operatie bereiken. Beide agents zullen zullen daarentegen niet synchroniseren als de expressies (580 en 580) niet overeen komen.
Hetgeen we zullen trachten te doen is unificatie te gebruiken om beide expressie te synchroniseren: zodoende, de synchronisatieoperator mag enkel verder gaan als de 2 expressie unifieren. Bv:
agent ikel:
sync(agent("test"),[?r,100]) en
agent test: sync(agent("ikel"),[?x,?x])
zullen synchroniseren omdat [?r, 100] ~ [?x, ?x]. (De oplossing is r = 100, x = 100).
Om deze synchronistatie-operatie te kunnen ontwikkelen hebben we beschikking tot een unificatiealgoritme dat als input twee expressies pakt, een reeks bindingen en als antwoord een incomplete (met nieuwe bindingen), een complete of een fail geeft.
unify(exp,with)
-> incomplete expression zolang er nog vrije variabelen zijn. Dit kan gechecked worden met incomplete?(exp)
-> fail expression. Dit kan gechecked worden met fail?(exp)
-> success expression. Dit kan gechecked worden met success?(exp)
Bv:
unify([?r,?r],[?x,?x])
=> incomplete
unify([?r,?r],[?x,100]) => success
unify([?a,10],[10,20]) => fail
unify(unify([?r,?r],[?x,?x]),[10,?t])) =>
success
Verder hebben we beschikking over een TCP/IP protocol. Dus we kunnen send's en receive's van expressies doen.
Opgave: Geef het synchronistatie-protocol dat u zou willen gebruiken. Illustreer en bespreek een aantal 'moeilijkere' gevallen.
De synchronistatie hierboven is relatief eenvoudig te schrijven, maar is alleen niet in staat te synchroniseren met meer dan 1 partner. We willen nu een synchronisatie operator die meerdere agents als eerste argument neemt. Bijvoorbeeld: de agents
agent s: ...
sync([agent("test"),agent("ikel")],[10,?b,?c])
agent test: ...
sync([agent("s"),agent("ikel"),[?a,20,?c])
agent ikel: ...
sync([agent("s"),agent("test"),[?a,?b,30])
zullen synchroniseren.
Opgave: Bespreek hoe u synchronisatie met meerdere partners zou ontwerpen. Geef het protocol, bespreek een aantal 'moeilijkere' gevallen.
Onderstaand is een interface die gebruikt kan worden om een host te vinden.
import java.rmi.*; import java.rmi.server.*; interface HopInterface extends Remote { public void Find(String tofind, HopInterface answerto) throws RemoteException; public void Answer(String text) throws RemoteException; }
Het onderstaande
programma maakt hier
gebruik van:
import java.rmi.*; import java.rmi.server.*; public class Hop extends UnicastRemoteObject implements HopInterface { static String ownName=null; static String nextName=null; static HopInterface next=null; public Hop() throws RemoteException { } public void Find(String tofind, HopInterface answerto) throws RemoteException { System.out.println("Looking for "+tofind); if (tofind.compareTo(ownName)==0) answerto.Answer("---"); else { if (next==null) try {next=(HopInterface)Naming.lookup(nextName);} catch (Exception e) {} next.Find(tofind,answerto); } } public void Answer(String text) throws RemoteException { System.out.println(text); } public static void main(String args[]) { try { Hop hop=new Hop(); ownName=args[0]; Naming.bind(ownName,hop); nextName=args[1]; if (args.length==3) hop.Find(args[2],hop); } catch (Exception e) { e.printStackTrace(); } } }
Na compilatie van stub- en skeleton code, starten we dit programma 4 maal opdezelfde computer met de volgende commandos:
> rmiregistry
&
> Java Hop D E &
> Java Hop C rmi://127.0.0.1/D &
> Java Hop B rmi://127.0.0.1/C &
> Java Hop A rmi://127.0.0.1/B D &
---
>
Opgave: Teken de control flow van het volledige programma in detail. Teken ook de name lookups naar de rmiregistry.
Onderstaande programma is geschreven in Borg. Clone maakt een object van de huidige scope. De agentclone functie maakt van het gegeven object een agent met de naam name. Dus agentclone(clone(),name) zal van het huidige Hop-object een agent maken met de gegeven naam. De '..' operator is de asynchrone send.
{ createHop(name,next):: { Find(tofind,answerto):: { if (tofind=name, answerto->Answer("---"), next->Find(tofind,answerto)) }; Answer(text)::display(text); agentclone(clone(),name) }; d:createHop("D",void); c:createHop("C",d); b:createHop("B",c); a:createHop("A",b); a->Find("D",a) }
Opgave: Beschrijf wat dit programma doet. Teken een control flow diagram.
Stel dat java rmi een beetje anders werkt en de standaard library geen serialiseerbare Strings aanbied, maar wel Strings die doorgegeven worden by reference. Teken in dit geval opnieuw de Control Flow van opgave 1.
We hebben proces A dat data bewerkt en uitstuur naar proces B. Proces B bewerkt de data op zijn manier en stuurt de data verder naar proces C. Deze vorm van parallellisatie word pipelining genoemd. Het is natuurlijk zo dat als proces A rapper data bewerkt dan proces B, proces B langzaam maar zeker gaat verzuipen in zijn backlog.
- Bespreek hoe we er kunnen voor zorgen in een parallel werkende pipeline dat geen enkel proces meer moet verwerken dan hij kan verwerken.
- Schrijf een java framework voor dergelijke pipelines. Dit framework moet een abstracte calculate methode aanroepen die afhaneklijke van het proces anders ingevuld kan worden. Begin met het geven van het protocol. Schrijf nadien de java code zo correct mogelijk neer.
We willen een netwerk file system ontwikkelen dat de volgende eigenschappen heeft.
Eindgebruikers moeten kunnen connecteren aan het netwerk en moeten allen dezelfde centraal beheerde directorystructuur zien.
Vanuit deze directorystructuur moeten ze data kunnen copieren.
Ze moeten data kunnen inbrengen in de directorystructuur.
Ze moeten in staat zijn data te verplaatsen doorheen de directorystructuur op een optimale wijze.
Data moet automatisch lokaal gerepliceerd worden indien ze veel gelezen doch weinig geschreven wordt.
1. Bespreek hoe u dergelijk systeem zou laten werken
Geef een uitgebreid overzicht van de protocollen die u ervoor zou ontwikkelen
De repeater die we gezien hebben in de oefeningenreeks tot nu toe bied, indien correct geimplementeerd, een eenvoudige repeating service aan die garandeert dat alle berichten in dezelfde volgorde toekomen bij alle geconnecteerde clients en dat er geen berichten verloren gaan. We maken gebruik van deze transportlaag die bestaat uit de volgende interface. Alle messages zijn synchroon zoals in Java RMI:
client -> repeater: join(<name>)
wordt gebruikt door een client om te connecteren aan de whiteboard. De whiteboard zal hierbij een message joined terugsturen naar de client en een hasjoined message naar alle andere partners.
repeater -> client: hasjoined(<naam>,<ref>)
hasjoined wordt verstuurd naar alle clients op het ogenblik een nieuwe client is geconnecteerd aan de whiteboard. <ref> is de referentie naar de pas geconnecteerde client. Naam is de naam van de pas geconnecteerde client.
repeater -> client: updateclients(<clientnameslist>)
wordt vesrtuurd vanuit de repeater als de client-list geupdate is. Dit gebeurt na een join en (forced) disconnect.
client -> repeater: putmessage(<msg>)
putmessage kan naar het whiteboard gestuurd worden door elke geconnecteerde client. De whiteboard zal een putmessage sturen naar alle clients, met vermelding van originator en uniek message id. Message returned op het ogenblik iedereen de gegeven message ontvangen heeft en beantwoord of alle errors opgelost zijn.
repeater -> client: putmessage(<msg>)
wordt ontvangen door een client vanuit de whiteboard. Originator is de referentie naar de client die het bericht gepost heeft.
We willen aan de hand van deze repeating service een grafische whiteboard maken. We willen grafische objecten kunnen visualiseren en editeren zodat we met een aantal mensen tegelijk aan dezelfde objecten verandering kan brengen. Het eerste wat we hiervoor nodig hebben is de definitie van een grafisch object binnen het systeem. Het is duidelijk dat deze objecten door iedereen aangemaakt, verandert en vernietigd moeten kunnen worden. We zullen er vanuit gaan dat alle objecten aanwezig op het whiteboard slechts aanwezig zijn op 1 van de clients; namelijk de client die het object gemaakt heeft. Alle grafische objecten worden bijgevolg doorgegeven 'by reference'.
Welke functionaliteit zou u afschuiven op de repeater, welke functionaliteit zou u leggen bij de client application en welke functionaliteit legt u binnen de grafische objecten zelf.
Beschrijf de interface van grafische objecten en de interface van de clientapplication
Teken de control flow hoe u een dergelijk object aanmaakt.
Teken de control flow hoe u een dergelijk object verwijdert.
Teken de control flow hoe u een zelf gecreerd object verandert.
Teken de control flow hoe iemand anders een object verandert.
Bespreek de concurrentieproblemen die u ziet.
We gaan nu kijken hoe we de whiteboard uit de vorige opgave kunnen implementeren als we alle objecten repliceren. Elke client zal in dit design alle objecten lokaal hebben. Dit wil zeggen dat we nu alle grafische objecten doorgeven 'by value'.
De whiteboard die we gezien hebben in de oefeningenreeks tot nu toe bied, indien correct geimplementeerd, een eenvoudige repeating service aan die garandeert dat alle berichten in dezelfde volgorde toekomen bij alle geconnecteerde clients en dat er geen berichten verloren gaan zolang de clients geconnecteerd blijven. We maken gebruik van deze transportlaag die bestaat uit de volgende interface. Alle messages zijn asynchroon:
client -> repeater: join(<name>)
wordt gebruikt door een client om te connecteren aan de whiteboard. De whiteboard zal hierbij een message joined terugsturen naar de client en een hasjoined message naar alle andere partners.
repeater -> client: joinok()
wordt verstuurd door de whiteboard naar een client die wou connecteren om hem te melden dat hij geconnecteerd is. Vanaf nu mag de client putmessages verwachten. Na de join message zal normaliter nog een hasjoined volgen.
repeater -> client: hasjoined(<naam>,<ref>)
hasjoined wordt verstuurd naar alle clients op het ogenblik een nieuwe client is geconnecteerd aan de whiteboard. <ref> is de referentie naar de pas geconnecteerde client. Naam is de naam van de pas geconnecteerde client.
repeater -> client: updateclients(<clientnameslist>)
wordt vesrtuurd vanuit de repeater als de client-list geupdate is. Dit gebeurt na een join en (forced) disconnect.
client -> repeater: putmessage(<msg>)
putmessage kan naar het whiteboard gestuurd worden door elke geconnecteerde client. De whiteboard zal een putmessage sturen naar alle clients, met vermelding van originator en uniek message id.
repeater -> client: putmessage(<originator>,<id>,<msg>)
wordt ontvangen door een client vanuit de whiteboard. Originator is de referentie naar de client die het bericht gepost heeft. Id is een uniek messageid en Msg is de eigenlijke message. Als de client het bericht ontvangen heeft is hij verplicht een messageok terug te sturen naar de whiteboard, met de id als vermelding.
client -> repeater: messageok(<id>)
Bericht dat teruggestuurd moet worden vanuit de client na de server, na ontvangen van een putmessage.
repeater -> client: votefor(<wtf>)
Er is een client die blijkbaar weigert te antwoorden. Of we wachten op een reconnect van die client of niet is iets waar al de andere clients moeten over voten. Dit wordt gevraagd door een votefor message te sturen. <wtf> is een referentie naar de gedisconnecteerde client. Al diegene die moeten voten moeten een voteresult message terugsturen.
client -> repeater: voteresult(<wtf>,<continueornot>)
wordt terug gestuurd naar de server in antwoord op een votefor message. Als <continueornot> true is stemt de zender voor het verder doen zonder te wachten op de gedisconnecteerde, als <continueornot> false is stemt de zender voor het wachten op de gedisconnecteerde. Zolang de gedisconnecteerde niet geconnecteerd is en niet alle geconnecteerde continue gevote hebben wacht de repeater. Berichten gaan niet verloren en zullen nadien in 1 trek doorgestuurd worden. Desalnietemin wordt wel verwacht dat clients geen berichten meer sturen eens we aan het voten zijn. We kunnen weer berichten sturen na het ontvangen van een continue message
repeater -> client: continue()
wordt opgeroepen vanuit de whiteboard op het ogenblik hij weer in repeating mode gaat en de vote geresolved is.
repeater -> client: disconnected()
wordt opgeroepen vanuit de whiteboard naar een client toe die geen messageok-message heeft gestuurd, of deze te traag heeft gestuurd.
client -> repeater: disconnect()
wordt opgeroepen naar de whiteboard toe om te disconnecteren
repeater -> client: hasdisconnected(<wtf>)
wordt verstuurd vanuit de whiteboard als melding dat de gegeven client uit de running ligt.
Deze eenvoudige repeatingservice is heel tof, maar heeft het grote nadeel dat late joiners niet weten wat er reeds op de whiteboard aanwezig is. Bespreek hoe we dit toch kunnen verwezenlijken -zonder de repeaterservice aan te passen-.
http://werner.yellowcouch.org/ werner@yellowcouch.org |