\documentclass[10pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}

\usepackage{enumerate}
\usepackage{listings}
\usepackage{url}
\usepackage{float}
\usepackage[toc,page]{appendix}

\usepackage[dutch]{babel}
\usepackage{listings}

\title{Operating Systems opdracht 5: ISAM}
\author{Sander van Veen \& Tadde\"us Kroes \\
        6167969 \& 6054129 \\
		\url{sandervv@gmail.com} \& \url{taddeuskroes@hotmail.com} }

\begin{document}

\maketitle
\tableofcontents

\pagebreak

\section{Inleiding tot ISAM}

Deze opdracht van Operating Systems gaat over het effici\"ent ophalen van
gegevens door middel van Indexed Sequential Access Method (afgekort tot ISAM).
ISAM heeft de volgende eigenschappen:

\begin{enumerate}
    \item Data wordt opgeslagen in \emph{fixed-length} datablokken (records),
    die gekenmerkt zijn door een unieke sleutel (is ook \emph{fixed-length}).
    \item Een index wordt gebruikt om de sleutels in non-lineaire tijd te
    doorzoeken. Dit maakt zoeken naar een specifiek datablok aanzienlijk
    sneller, doordat \emph{binary search} wordt toegepast.
    \item De datablokken worden sequentieel opgeslagen, gesorteerd op de waarde
    van de corresponderende sleutel. Dit maakt sequentieel zoeken aanzienlijk
    sneller.
\end{enumerate}

\noindent In een ISAM-bestand worden een vast (vooraf gedefineerd) aantal
datablokken gegroepeerd opgeslagen. De datablokken in een groep worden
gesorteerd op hun sleutel. De groepen krijgen elk de sleutel van het eerste
datablok van de groep. Een ISAM-bestand ziet er schematisch zo uit:

\begin{verbatim}
File header - describes contents and field lengths
---------------------------------------
Index records: ceil(Nblocks / 4) + ceil(Nblocks / 16) + ....
---------------------------------------
Sequential data block area (Nblocks blocks)
---------------------------------------
General overflow area
---- EOF --------
\end{verbatim}

Als een datablok wordt verwijderd, wordt het datablok niet uit het ISAM-bestand
verwijderd. In plaats van het verwijderen uit het ISAM-bestand, wordt het
datablok enkel als \emph{deleted} gemarkeerd. Op het moment dat er een nieuw
datablok op de plek van een eerder verwijderd datablok wordt geplaatst, wordt
het datablok naar de hardeschijf geschreven. Logischerwijs wordt de
\emph{deleted} markering van het weggeschreven blok dan weggehaald. De index
houdt dan bij welke blokken als \emph{deleted} zijn gemarkeerd. Dit reduceert
het aantal disk writes aanzienlijk. Het gevolg is dat veel \emph{random delete}
en \emph{random insert} acties sneller kunnen worden uitgevoerd. Want de
hardeschijf vormt het grootste bottleneck van een database.

Doordat de verwijderde datablokken niet uit het ISAM-bestand worden verwijderd,
kan het voorkomen dat een grote hoeveelheid nutteloze data in het ISAM-bestand
achterblijft. Het opschonen van het ISAM-bestand zou daarom periodiek moeten
worden uitgevoerd. Het gunstigste is om dit gedurende de daluren te doen.

De \emph{General overflow area} van een ISAM-bestand maakt het mogelijk om
(theoretish) oneindig veel datablokken op te slaan. In de praktijk is dit niet
haalbaar doordat er niet een oneindige hoeveelheid schrijfruimte bestaat. Bij
\emph{compile-time} kan niet worden gezien wat de lengte van de sleutels wordt.
Daarom wordt er gebruik gemaakt van \emph{array-indexing} en \emph{casting}.

Tot slot is er nog op te merken dat het toevoegen van een datablok met een
kleinere sleutel dan al de bestaande datablokken, wordt gedaan door de
\emph{empty string} sleutel te gebruiken. De datablokken worden immers in
groepen ingedeeld en zonder deze \emph{empty string} sleutel zou het niet
mogelijk zijn om een datablok met een lagere sleutel op te slaan aan het begin
van de eerste groep.

\section{Implementatie van \texttt{perror}}

De functie \texttt{perror()} wordt ge\"implemeteerd door een lijst met
foutbeschrijvingen te doorzoeken. De globale variabele \texttt{errno} wordt
gebruikt om de gewenste foutmelding te vinden. Het gebruik van deze lijst
(genaamd \texttt{sys\_errlist[]}) wordt afgeraden omdat deze lijst niet op alle
platformen beschikbaar is. Als alternatief wordt \texttt{strerror()} gegeven.

\subsection{\texttt{sys\_errlist[]} vs. \texttt{strerror()}}

Om een programma te kunnen compileren op diverse platformen, wordt het
aangeraden om \texttt{strerror()} te gebruiken. Dit volgt onder andere uit het
onderstaande citaat van de GCC maintainers:\footnote{Use \texttt{strerror()}:
http://www.gnu.org/software/hurd/hurd/porting/guidelines.html}

\begin{quote} If a program has only support for \texttt{sys\_errlist[]} you will
have to do some work to make it compile on GNU, which has dropped support for it
and does only provide strerror(). Steinar Hamre writes that strerror() should be
used because:

1. It is the modern, POSIX way.
2. It is localized.
3. It handles invalid signals/numbers out of range. (better
errorhandling and not a buffer-overflow-candidate/security risk)

\texttt{strerror()} should always be used if it is available. Unfortunaly there
are still some old non-POSIX systems that do not have \texttt{strerror()}, only
\texttt{sys\_errlist[]}.

Today, only supporting \texttt{strerror()} is far better than only supporting
\texttt{sys\_errlist[]}.\end{quote}

\subsection{\texttt{strerror()}}

Naast de \emph{portibility} eigenschap van \texttt{strerror()}, maakt de
function het ook mogelijk om de voorgedefineerde foutomschrijvingen van de C
library te gebruiken. Uit de opdracht kon niet worden opgemaakt of deze functie
mocht worden gebruikt, dus is er voor gekozen om een nieuwe functie genaamd
\texttt{isam\_strerror} aan te maken. Door middel van \texttt{\_user\_strerror}
kunnen er meer foutbeschrijvingen worden toegevoegd aan
\texttt{strerror()}.\footnote{Gebruik van \texttt{\_user\_strerror}:
http://www.slac.stanford.edu/comp/unix/package/rtems/doc/html/libc/\
libc.info.strerror.html} De functie \texttt{\_user\_strerror} is verder niet
gebruikt, doordat het aangeleverde framework niet de function \texttt{perror()}
aanroept.

\section{Code optimalisaties}

De oorspronkelijke functie \texttt{isam\_readByKey()} was ineffici\"ent
geprogrammeerd, doordat er onnodig werk werd gedaan. De oorspronkelijke functie
roept de functie \texttt{isam\_setKey()} aan gevolgd door de functie
\texttt{isam\_readNext()}. In plaats van direct het datablok terug te geven,
wordt er eerst achteruit gezocht naar het datablok.

De tweede optimalisatie is terug te vinden in de functie
\texttt{isam\_update()}. Deze functie was ineffici\"ent doordat er twee keer
naar een datablok werd gezocht: eerst om het blok te verwijderen en vervolgens
nog een keer om het datablok te overschrijven. Als het datablok direct wordt
overschreven (zonder dus te verwijderen), scheelt dit lezen van de hardeschijf.

Om de optimalisaties te vergelijken, is een \emph{preprocessor directive}
aangemaakt die de optimalisaties aan of uit zet. Deze directive heeft de naam
\texttt{OPTIMISED}. Door in een shell deze directive aan te maken
(\texttt{export OPTIMISED=1}) en het test programma opnieuw te compileren
(\texttt{make clean; make}), worden de optimalisaties toegepast.

\section{Resultaten}

\subsection{Resultaten zonder optimalisaties}

Allereerst (chronologisch geordend) worden de resultaten van de implementatie
zonder optimalisatie behandeld. Om de prestatie te kunnen meten, worden de
volgende instructies uitgevoerd in een shell:

\begin{verbatim}
$ unset OPTIMISED
$ rm klant.isam
$ make clean && make -s
$ ./isam_test klant.isam < tele &> /dev/null
$ ./isam_bench namen initialen titels
\end{verbatim}

\noindent De volgende resultaten worden verkregen met 6 als waarde voor de cache
grootte. Dit is de standaard waarde voor de cache grootte in deze opdracht.

\begin{verbatim}
Lees namen van namen
Lees initialen van initialen
Lees titels van titels
Failed to create file: File already exists (3)
Bestaand bestand met 488 records geopend
Stats after opening isam file...
calls: 489
reads: 42
writes: 0
hwrites: 0

Er zijn 0 records gelezen; mailings zijn verzonden aan 0
500 records gelezen, 0 mislukt
200 nieuwe klanten, 171 vertrokken
Er zijn 42 records gelezen; mailings zijn verzonden aan 42
500 records gelezen, 125 mislukt
200 nieuwe klanten, 142 vertrokken
Er zijn 78 records gelezen; mailings zijn verzonden aan 78
500 records gelezen, 173 mislukt
200 nieuwe klanten, 113 vertrokken
Er zijn 429 records gelezen; mailings zijn verzonden aan 429
Er zijn 429 records gelezen; mailings zijn verzonden aan 429
Stats after Dick Albada's benchmark...
calls: 696340
reads: 472666
writes: 8672
hwrites: 5999

Stats after benchmarking:
1000 readByKey
400 update
100 writes
100 delete

calls: 546289
reads: 356770
writes: 1994
hwrites: 1552

Stats after entire benchmark:
calls: 1243607
reads: 829520
writes: 10666
hwrites: 7551
\end{verbatim}

\noindent Daarna is de cache grootte veranderd naar 2 en is gekeken wat de
resultaten zijn:

\begin{verbatim}
Lees namen van namen
Lees initialen van initialen
Lees titels van titels
Failed to create file: File already exists (3)
Bestaand bestand met 488 records geopend
Stats after opening isam file...
calls: 489
reads: 43
writes: 0
hwrites: 0

Er zijn 0 records gelezen; mailings zijn verzonden aan 0
500 records gelezen, 0 mislukt
200 nieuwe klanten, 171 vertrokken
Er zijn 42 records gelezen; mailings zijn verzonden aan 42
500 records gelezen, 125 mislukt
200 nieuwe klanten, 142 vertrokken
Er zijn 78 records gelezen; mailings zijn verzonden aan 78
500 records gelezen, 173 mislukt
200 nieuwe klanten, 113 vertrokken
Er zijn 429 records gelezen; mailings zijn verzonden aan 429
Er zijn 429 records gelezen; mailings zijn verzonden aan 429
Stats after Dick Albada's benchmark...
calls: 696357
reads: 559525
writes: 8672
hwrites: 5999

Stats after benchmarking:
1000 readByKey
400 update
100 writes
100 delete

calls: 546290
reads: 405557
writes: 1994
hwrites: 1552
Stats after entire benchmark:
calls: 1243625
reads: 965168
writes: 10666
hwrites: 7551
\end{verbatim}

\noindent \textbf{Analyse van cache grootte 2 ipv 6:}

\begin{enumerate}

    \item Het aantal cache calls was bij cache grootte van 6 totaal uitgekomen
    op 1.243.607. Bij een cache grootte van 2 kwam er in totaal 1.243.625 cache
    calls uit. Dat is een verschil van 18 calls. Met andere woorden
    verwaarloosbaar, want Dick Albada's benchmark maakt gebruik van random
    waardes. Voor het total aantal writes en hwrites van de gehele benchmark
    valt de zelfde conclusie te trekken als bij de cache calls. Dit is niet
    afhankelijk van de cache grootte (er wordt immers gebruik gemaakt van een
    FIFO read-cache).

    \item Het grote verschil van de cache grootte is terug te zien in het aantal
    disk reads: 965.158 voor cache grootte 2 en 829.520 voor cache grootte 6.
    Dat is een verschil van 135.648 disk reads. Dat komt neer op 1.16x meer disk
    reads voor de totale benchmark met cache grootte 2 ipv 6.

\end{enumerate}

\section{Opmerkingen}



\end{document}
