Home Papers Reports Projects Code Fragments Dissertations Presentations Posters Proposals Lectures given Course notes
<< 17. Examination Questions 1999-200019. Examination Questions 2001-2002 >>

18. Examination Questions 2000-2001

Werner Van Belle1 - werner@yellowcouch.org, werner.van.belle@gmail.com

1- Programming Technology Lab (PROG) Department of Computer Science (DINF) Vrije Universiteit Brussel (VUB); Pleinlaan 2; 1050 Brussel; Belgium

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;


Java RMI & The Factorial Recursive Call

Onderstaand is een interface die gebruikt kan worden om een faculteit te berekenen.
import java.rmi.*;
public interface FacCalcer extends Remote
{
   public int fac(int n, FacCalcer fc) throws RemoteException;
}

Het onderstaande programma maakt hier gebruik van:
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.

Avatar: Guarding van een Schedule

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 !

Synchronisatie

Unificatie tussen 2 partijen

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.

Unificatie tussen meerdere partijen

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.

HopAlong

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.

Borg Control Flow

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.

Argument Passing

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.

Pipelining

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.

Network File System

Design

We willen een netwerk file system ontwikkelen dat de volgende eigenschappen heeft.

1. Bespreek hoe u dergelijk systeem zou laten werken

  1. Geef een uitgebreid overzicht van de protocollen die u ervoor zou ontwikkelen

Concurrentieprobelem

Bespreek de concurrentieproblemen in uw voorstel aangaande uw netwerk filesysteem

Partial Failure

- Hoe reageert uw netwerk filesysteem op het uitvallen van machines ?
- Is er een single point of failure ?
- Waar is uw netwerk niet tegen bestand ?

A Graphical Whiteboard

Synchronous Variant

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:

Joining

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.




Repeating

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.



Variante Opgave 1: pass by reference

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'.


  1. 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.

  2. Beschrijf de interface van grafische objecten en de interface van de clientapplication

  3. Teken de control flow hoe u een dergelijk object aanmaakt.

  4. Teken de control flow hoe u een dergelijk object verwijdert.

  5. Teken de control flow hoe u een zelf gecreerd object verandert.

  6. Teken de control flow hoe iemand anders een object verandert.

  7. Bespreek de concurrentieproblemen die u ziet.

Variante Opgave 2: Pass by value

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'.

1. Welke functionaliteit zou u nu afschuiven op de repeater, welke functionaliteit bij de client application en welke functionaliteit binnen de grafische objecten zelf.
2. Beschrijf de interface van grafische objecten en de interface van de clientapplication
3. Teken de control flow hoe u een grafisch object aanmaakt.
4. Teken de control flow hoe u een grafisch object verwijdert.
5. Teken de control flow hoe u een zelf gecreerd grafisch object verandert.
6. Teken de control flow hoe iemand anders een object verandert.
7.Bespreek de concurrentieproblemen die u ziet.

Asynchronous Variant

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:

Joining

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.


Joining

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.


Voting

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.




Disconnecting

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.




Opgave

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-.

1. Bespreek de algemene algoritmiek en waar u welke data bijhoud.
2. Beschrijf de verschillende states waarin uw programmatuur zich kan bevinden (state machine)
3. Teken control flow diagrams (zoals gezien in de lessen)
4. Bespreek concurrentie-problemen (illustreer met sequence chart en bespreek hoe u ze opgelost hebt)
5. Bespreek error-handling (illustreer met sequence chart en bespreek hoe u ze opgelost hebt)

http://werner.yellowcouch.org/
werner@yellowcouch.org