Finished code assignment 5 of Operating Systems.

parent 9d4a71b3
CC = gcc
CFLAGS = -Wall -W -Wstrict-prototypes -O2 -ansi -g -D_XOPEN_SOURCE=500
ifdef OPTIMISED
CFLAGS +=-DOPTIMISED
endif
LIBS = -lm
all: isam_bench isam_test
isam_bench: isam_bench.o isam.o index.o
$(CC) $(CFLAGS) -o isam_bench isam_bench.o isam.o index.o $(LIBS)
isam_test: isam_test.o isam.o index.o
$(CC) $(CFLAGS) -o isam_test isam_test.o isam.o index.o $(LIBS)
isam_bench.o: isam_bench.c isam.h
$(CC) $(CFLAGS) -c isam_bench.c
isam_test.o: isam_test.c isam.h
$(CC) $(CFLAGS) -c isam_test.c
isam.o: isam.c isam.h index.h
$(CC) $(CFLAGS) -c isam.c
index.o: index.c index.h
$(CC) $(CFLAGS) -c index.c
clean:
rm -f *.o *~ isam_bench isam_test
CC = gcc
CFLAGS = -Wall -Wstrict-prototypes -ansi -O2
LIBS = -lm
isam_bench: isam_bench.o isam.o index.o
$(CC) $(CFLAGS) -o isam_bench isam_bench.o isam.o index.o $(LIBS)
isam_test: isam_test.o isam.o index.o
$(CC) $(CFLAGS) -o isam_test isam_test.o isam.o index.o $(LIBS)
isam_bench.o: isam_bench.c isam.h
$(CC) $(CFLAGS) -c isam_bench.c
isam_test.o: isam_test.c isam.h
$(CC) $(CFLAGS) -c isam_test.c
isam.o: isam.c isam.h index.h
$(CC) $(CFLAGS) -c isam.c
index.o: index.c index.h
$(CC) $(CFLAGS) -c index.c
clean:
rm -f *.o *~ isam_bench isam_test core
CC = cc
CFLAGS = -fast
LIBS = -lm
isam_bench: isam_bench.o isam.o index.o
$(CC) $(CFLAGS) -o isam_bench isam_bench.o isam.o index.o $(LIBS)
isam_test: isam_test.o isam.o index.o
$(CC) $(CFLAGS) -o isam_test isam_test.o isam.o index.o $(LIBS)
isam_bench.o: isam_bench.c isam.h
$(CC) $(CFLAGS) -c isam_bench.c
isam_test.o: isam_test.c isam.h
$(CC) $(CFLAGS) -c isam_test.c
isam.o: isam.c isam.h index.h
$(CC) $(CFLAGS) -c isam.c
index.o: index.c index.h
$(CC) $(CFLAGS) -c index.c
clean:
rm -f *.o *~ isam_bench isam_test core
Een korte beschrijving van de beschikbare bestanden:
README - dit readme bestand
isam.c - de sources voor de isam bibliotheek routines
isam.h - de bijbehorende header file
index.c - de sources voor de routines die de index voor de isam file
verzorgen.
index.h - de bijbehorende header file.
isam_bench.c - een testprogramma voor de isam routines, ook bedoeld als
benchmark.
namen, initialen, titles - drie invoerfiles voor gebruik met isam_bench
Gebruik:
isam_bench namen initialen titels
isam_bench namen initialen titels debug
isam_test.c - een ander testprogramma
tele - invoer voor isam_test, te gebruiken als
isam_test tele.isam < tele
hiermee kan een eerste vulling voor tele.isam worden aangemaakt.
Makefile.GCC Makefile voor gebruik met de GNU C compiler. Gebruik b.v.:
make -f Makefile.GCC isam_bench
Makefile.SUN Makefile voor gebruik met de SUN C compiler. Gebruik b.v.:
make -f Makefile.SUN isam_bench
/*
* These routines will be used to create the index for the isam file system.
* -------------------------------------------------------------------------
* Author: G.D. van Albada
* University of Amsterdam
* Faculty of Science
* Informatics Institute
* Copyright (C) Universiteit van Amsterdam
* dick at science.uva.nl
* Version: 0.1
* Date: December 2001 / January 2002 / November 2004
* Goal: Part of an assignment on file system structure for the operating
* systems course.
* -------------------------------------------------------------------------
* The strucure/implementation of this index is not very efficient.
* We use an N-ary tree with a fixed branching factor of 4; it might
* have been more logical to make this variable, depending on the
* key length and an appropriate record/block size. This also depends on
* whether the index blocks are retained in memory, or read when
* needed.
* The choice for a small number of elements per record also was
* made to obtain a multi-level tree structure for a limited
* number of elements.
*
* Will we keep the index in memory?
* Well - that greatly simplifies matters - so let's do it
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stddef.h>
/*
* Use assert to pinpoint fatal errors - should be removed later
*/
#include <assert.h>
#include "index.h"
/*
* C is not very helpful when you have to define structures with elements
* of which the size is not known at compile time. In this case, we will
* make full use of another weakness of C - the lack of array-boundary
* checking. The structure that we define contains the first few fixed
* length entries, followed by the first elements of the array that will
* contain the actual variable part. When allocating memory for this
* structure, we will allocate the actual required size, and use higher
* index values to access that part of the array. Also notice that the
* array (keys) will eventually contain four key strings. We have to
* compute the starting points of the first, second and third element when
* we actually need them. Macros can be very helpful to keep the code
* readable in such cases
*/
typedef struct
{
unsigned long Nkeys; /* The number of valid keys in this record */
unsigned long index[4]; /* Data/index record nrs for the keys */
char keys[8]; /* Store 4 keys here; actual size will be larger */
} indexRecord;
/*
* The index will contain a number of index records (defined above) and a
* structure describing the actual size of the index (element size, number
* of elements, number of levels, degree of filling). On disk this index
* header will, of course, precede the index records.
*/
typedef struct
{
unsigned long Nlevels;
unsigned long KeyLength;
unsigned long Nkeys; /* The number of valid keys in the index */
unsigned long iRecordLength; /* The actual size of an index record */
unsigned long NperLevel[8]; /* The number of index records per level */
indexRecord root; /* The root index */
} indexheader;
/* This structure will describe the index elements when stored in memory */
typedef struct INDEX_IN_CORE
{
indexRecord *levels[8]; /* Arrays with index records */
indexheader to_disk; /* This goes to disk */
} in_core;
#define KeyInRec(key,rec,len) (&((rec).keys[(key) * (len)]))
int index_error = 0;
/*
* index_makeNew will construct a new index (in memory only),
* characterised by Nblocks (the maximum number of entries in the index)
* and KeyLength (the length of the key strings).
*/
in_core *
index_makeNew(unsigned long Nblocks, unsigned long KeyLength)
{
unsigned long iRecordLength = sizeof(indexRecord) - sizeof(char[8]) +
4 * KeyLength;
in_core *in = calloc(1, sizeof(in_core) - sizeof(indexRecord) +
iRecordLength);
int i;
int levs;
int n;
/*
* We will have NBlocks entries in the deepest level of nodes (the
* leaf nodes). These will be contained in Nrec = (NBlocks + 3) / 4
* index records. These, in turn will need (Nrec + 3) / 4 index
* records, etc.
*/
#ifdef DEBUG
printf("iRecordLength = %d\n", iRecordLength);
#endif
if (!in) {
index_error = INDEX_ALLOCATION_FAILURE;
return in;
}
if (KeyLength == 0) {
index_error = INDEX_BAD_KEYLENGTH;
free(in);
return NULL;
}
#ifdef DEBUG
printf("-------> 1\n");
#endif
for (levs = 0, i = Nblocks; i > 1; levs++, i = (i + 3) >> 2) ;
if (!levs) {
levs = 1;
}
#ifdef DEBUG
printf("-------> 2\n");
#endif
/*
* levs == 1 -> root only; otherwise (levs - 1) additional levels
*/
in->to_disk.iRecordLength = iRecordLength;
in->to_disk.KeyLength = KeyLength;
in->to_disk.Nkeys = 1; /* The single empty key for record 0! */
in->to_disk.root.Nkeys = 1;
in->to_disk.Nlevels = levs - 1;
n = (Nblocks + 3) >> 2;
for (i = levs - 2; i >= 0; i--) {
in->levels[i] = calloc(n, iRecordLength);
assert(in->levels[i] != NULL);
in->levels[i]->Nkeys = 1;
in->to_disk.NperLevel[i] = n;
#ifdef DEBUG
printf("%d index records at level %d\n", n, i);
#endif
n = (n + 3) >> 2;
}
#ifdef DEBUG
printf("-------> 3\n");
#endif
return in;
}
/*
* The following routine writes the index to disk. It assumes that the
* file is already correctly positioned. It returns the file position
* after the write
*/
long index_writeToDisk(in_core * in, int fid)
{
unsigned int i;
int rv;
if ((!in) || (!(in->to_disk.Nkeys)) || (!(in->to_disk.KeyLength))) {
index_error = INDEX_INVALID_HANDLE;
return -1;
}
rv = write(fid, &(in->to_disk),
sizeof(indexheader) - sizeof(indexRecord) + in->to_disk.iRecordLength);
if (rv != (int)(sizeof(indexheader) - sizeof(indexRecord) +
in->to_disk.iRecordLength)) {
index_error = INDEX_WRITE_FAIL;
return -1;
}
#ifdef DEBUG
printf("Wrote %d bytes\n", rv);
#endif
for (i = 0; i < in->to_disk.Nlevels; i++) {
rv = write(fid, in->levels[i], in->to_disk.NperLevel[i] *
in->to_disk.iRecordLength);
if (rv != (int)(in->to_disk.NperLevel[i]
* in->to_disk.iRecordLength)) {
index_error = INDEX_WRITE_FAIL;
return -1;
}
#ifdef DEBUG
printf("Wrote %d bytes\n", rv);
#endif
}
return lseek(fid, 0, SEEK_CUR);
}
/*
* index_readFromDisk will read an index from disk. This is a three step
* process. First the header is read to determine the size of the index,
* then index_makeNew is called to reserve and initialise the required
* memory, and finally, the actual index records are retrieved.
*/
in_core *index_readFromDisk(int fid)
{
unsigned int i;
int rv;
int NBlocks;
indexheader head;
in_core *in;
rv = read(fid, &(head), offsetof(indexheader, root));
if (rv != offsetof(indexheader, root)) {
index_error = INDEX_READ_ERROR;
return NULL;
}
NBlocks = 4 * head.NperLevel[head.Nlevels - 1];
in = index_makeNew(NBlocks, head.KeyLength);
if (!in) {
return NULL;
}
assert(head.iRecordLength == in->to_disk.iRecordLength);
assert(head.Nlevels == in->to_disk.Nlevels);
assert(head.NperLevel[head.Nlevels - 1] ==
in->to_disk.NperLevel[head.Nlevels - 1]);
in->to_disk = head;
rv = read(fid, &(in->to_disk.root), head.iRecordLength);
if (rv != (int)head.iRecordLength) {
index_error = INDEX_READ_ERROR;
return NULL;
}
#ifdef DEBUG
printf("Read %d bytes\n", rv);
printf("Nlevels = %d\n", in->to_disk.Nlevels);
#endif
for (i = 0; i < in->to_disk.Nlevels; i++) {
#ifdef DEBUG
printf("NperLevel[%d] = %d\n", i, in->to_disk.NperLevel[i]);
#endif
if (read(fid, in->levels[i],
in->to_disk.NperLevel[i] * in->to_disk.iRecordLength)
!= (int)(in->to_disk.NperLevel[i] * in->to_disk.iRecordLength))
{
index_error = INDEX_READ_ERROR;
return NULL;
}
}
return in;
}
/*
* The following function will seek for a key in an index record. It will
* return the index entry corresponding to the largest valid key in the
* record that is not larger than the key sought. If no such key exists,
* it will return -1. (Zero is a valid index value) It needs as input: The
* sought key The index record The length of the keys.
*/
static long
key_to_index(indexRecord * rec, const char *key, unsigned long KeyLength)
{
int rv;
long index = -1;
unsigned int i;
for (i = 0; i < rec->Nkeys; i++) {
rv = strncmp(key, KeyInRec(i, *rec, KeyLength), KeyLength);
if (rv < 0) {
break;
}
index = rec->index[i];
if (rv == 0) {
break;
}
}
#ifdef DEBUG
printf("index = %d ", index);
#endif
return index;
}
/*
* The following routine will use a complete index to look for a given
* key. The value it should return is the number of the data block where
* the key-search should continue. It needs as input: The key sought A
* pointer to the in-core structure The key length
*/
long index_keyToBlock(in_core * in, const char *key)
{
long index = 0;
unsigned int i;
int KeyLength = in->to_disk.KeyLength;
indexRecord *rec;
if ((!in) || (!(in->to_disk.Nkeys)) || (!(in->to_disk.KeyLength))) {
index_error = INDEX_INVALID_HANDLE;
return -1;
}
rec = &(in->to_disk.root);
index = key_to_index(rec, key, KeyLength);
if (index < 0) {
index_error = INDEX_INDEXING_ERROR;
return index;
}
for (i = 0; i < in->to_disk.Nlevels; i++) {
rec = (indexRecord *) (index * in->to_disk.iRecordLength +
(char *)in->levels[i]);
index = key_to_index(rec, key, KeyLength);
if (index < 0) {
index_error = INDEX_INDEXING_ERROR;
return index;
}
}
return index;
}
/*
* The following routine must add a key at the end of an index. Now this
* is a complex operation. 1) We must ensure that the key is indeed larger
* than the last key. 2) We must check that we are not exceeding the
* maximum capacity of the index. 3) At every level, we may have to insert
* extra keys and activate extra records.
*/
int index_addKey(in_core * in, const char *key, int index)
{
unsigned int maxKeys =
4 * in->to_disk.NperLevel[in->to_disk.Nlevels - 1];
int lev = in->to_disk.Nlevels - 1;
int KeyLength = in->to_disk.KeyLength;
int nrec;
int nkey;
int keyno = in->to_disk.Nkeys;
int do_prev;
indexRecord *rec;
int rv;
if ((!in) || (!(in->to_disk.Nkeys)) || (!(in->to_disk.KeyLength))) {
index_error = INDEX_INVALID_HANDLE;
return -1;
}
/*
* See if we can accommodate more keys
*/
if (in->to_disk.Nkeys >= maxKeys) {
index_error = INDEX_FULL;
return -1;
}
/*
* Find highest key and compare
*/
nrec = (keyno - 1) / 4;
nkey = (keyno - 1) & 0x0003;
rec = (indexRecord *) (nrec * in->to_disk.iRecordLength +
(char *)in->levels[lev]);
rv = strncmp(key, KeyInRec(nkey, *rec, KeyLength), KeyLength);
if (rv <= 0) {
index_error = INDEX_KEY_NOT_LARGER;
return -1;
}
/*
* Find insertion point at leaf level and insert
*/
nrec = keyno / 4;
nkey = keyno & 0x0003;
rec = (indexRecord *) (nrec * in->to_disk.iRecordLength +
(char *)in->levels[lev]);
#ifdef DEBUG
printf("nrec = %d, nkey = %d, lev = %d, NperLevel = %d\n",
nrec, nkey, lev, in->to_disk.NperLevel[lev]);
#endif
strncpy(KeyInRec(nkey, *rec, KeyLength), key, KeyLength);
do_prev = !nkey;
rec->index[nkey] = index;
rec->Nkeys++;
in->to_disk.Nkeys++;
/*
* If we have just initiated a new record (do_prev is true), we have
* to add the key also to the previous level in the index. nrec
* actually points to the number of the key at that level
*/
for (; do_prev && (lev--);) {
keyno = nrec;
nrec = keyno / 4;
nkey = keyno & 0x0003;
#ifdef DEBUG
printf("nrec = %d, nkey = %d, lev = %d, NperLevel = %d\n",
nrec, nkey, lev, in->to_disk.NperLevel[lev]);
#endif
rec = (indexRecord *) (nrec * in->to_disk.iRecordLength +
(char *)in->levels[lev]);
strncpy(KeyInRec(nkey, *rec, KeyLength), key, KeyLength);
do_prev = !nkey;
rec->index[nkey] = keyno;
rec->Nkeys++;
}
if (do_prev) {
/*
* Add key to root as well
*/
if (nrec >= 4) {
index_error = INDEX_WEIRD_ERROR;
return -1;
}
nkey = nrec;
rec = &(in->to_disk.root);
strncpy(KeyInRec(nkey, *rec, KeyLength), key, KeyLength);
rec->index[nkey] = nkey;
rec->Nkeys++;
}
return in->to_disk.Nkeys;
}
/*
* Call this function to free the memory used by the index
*/
int index_free(in_core * in)
{
unsigned int i;
/*
* Heap memory can remain accessible, even after it is freed, as long
* as you retain the pointer. However, its contents have become
* invalid, so we set a few values to mark it as invalid (this is not
* fool-proof, as new values may be set after a new allocation...
*/
if ((!in) || (!(in->to_disk.Nkeys)) || (!(in->to_disk.KeyLength))) {
index_error = INDEX_INVALID_HANDLE;
return -1;
}
for (i = 0; i < in->to_disk.Nlevels; i++) {
free(in->levels[i]);
in->levels[i] = NULL;
}
in->to_disk.Nkeys = 0;
in->to_disk.KeyLength = 0;
free(in);
return 0;
}
#ifndef INDEX_H
#define INDEX_H
/* -------------------------------------------------------------------------
Author: G.D. van Albada
University of Amsterdam
Faculty of Science
Informatics Institute
Copyright (C) Universiteit van Amsterdam
dick at science.uva.nl
Version: 0.1
Date: December 2001 / January 2002 / November 2004
Goal: Part of an assignment on file system structure for the operating
systems course. It demonstrates many of the administrative and
layering structures that are also used in normal file systems.
----------------------------------------------------------------------------*/
extern int index_error;
#define INDEX_FULL (100)
#define INDEX_ALLOCATION_FAILURE (101)
#define INDEX_INDEXING_ERROR (102)
#define INDEX_KEY_NOT_LARGER (103)
#define INDEX_WEIRD_ERROR (104)
#define INDEX_READ_ERROR (105)
#define INDEX_INVALID_HANDLE (106)
#define INDEX_BAD_KEYLENGTH (107)
#define INDEX_WRITE_FAIL (108)
typedef struct INDEX_IN_CORE *index_handle;
/*
* index_makeNew will construct a new index (in memory only),
* characterised by Nblocks (the maximum number if entries in the index)
* and KeyLength (the length of the key strings).
*/
index_handle index_makeNew(unsigned long Nblocks, unsigned long KeyLength);
/*
* The following routine writes the index to disk. It assumes that the
* file is already correctly positioned. It returns the file position
* after the write. Required input: The index handle, The file handle.
*/
long index_writeToDisk(index_handle in, int fid);
/*
* index_readFromDisk will read an index from disk. This is a three step
* process. First the header is read to determine the size of the index,
* then index_makeNew is called to reserve and initialise the required
* memory, and finally, the actual index records are retrieved. The
* required input is the integer identifier of the (correctly positioned)
* file.
*/
index_handle index_readFromDisk(int fid);
/*
* The following routine will use a complete index to look for a given
* key. The value it should return is the number of the data block where
* the key-search should continue. It needs as input: The index handle for
* the index. The key sought
*/
long index_keyToBlock(index_handle in, const char *key);
/*
* The following routine must add a key at the end of an index. It needs
* as input: The index handle for the index. A poiner to the key string
* The integer index value to be associated with this key
*/
int index_addKey(index_handle in, const char *key, int index);
/*
* Call this function to free the memory used by the index
*/
int index_free(index_handle in);
#endif
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.
A.A.
A.D.
A.G.
A.G.
A.H.
A.H.L.
A.H.M.
A.J.
A.M.
A.M.M.
A.P.
A.S.
A.S.Z.
A.W.
B.
B.
B.
B.
B.
B.
B.A.
B.A.A.
B.D.
B.G.
B.J.
B.J.A.
B.M.
C.
C.
C.A.
C.E.
C.E.
C.G.
C.J.H.
C.J.K.
C.P.
C.W.J.
D.
D.
D.
D.
D.
D.
D.
D.
D.
D.
D.C.
D.E.
D.H.J.
D.J.M.
D.L.
D.S.
E.
E.
E.
E.
E.
E.
E.
E.
E.
E.
E.
E.-J.
E.-J.
E.H.M.
E.J.
E.J.
E.J.H.
E.P.J.
F.
F.
F.
F.
F.
F.
F.
F.
F.
F.
F.C.A.
F.F.M.
G.
G.
G.
G.
G.
G.
G.
G.
G.
G.
G.
G.
G.
G.
G.A.
G.D.
G.G.
G.J.
G.J.L.
G.R.
H-.M.
H-.P.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.
H.A.
H.E.
H.G.
H.J.
H.J.
H.J.
H.U.
H.V.
H.Z.
I.
I.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.
J.-B.
J.A.
J.A.
J.A.
J.B.
J.C.
J.C.
J.E.
J.E.
J.E.J.
J.F.
J.F.
J.F.M.
J.G.
J.I.
J.J.
J.J.
J.J.B.
J.J.J.
J.L.
J.L.
J.M.
J.M.
J.M.
J.M.
J.M.
J.M.
J.M.
J.M.
J.M.M.
J.P.
J.P.
J.R.
J.W.
J.W.
J.W.J.
Jr.
K.
K.
K.
K.
K.
K.
K.
K.
K.
K.
K.
K.
K.
K.A.
K.E.I.
L.
L.
L.
L.
L.
L.
L.
L.
L.B.F.M.
L.D.
L.H.
L.J.
L.M.
L.O.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.
M.A.
M.A.
M.D.
M.G.
M.H.
M.H.
M.H.F.
M.I.
M.J.
M.J.
M.J.
M.M.
M.O.
M.O.
M.O.
M.T.
M.W.
M.Y.
N.
N.
N.
N.
N.C.
O.
O.J.G.
P.
P.
P.
P.
P.
P.
P.
P.
P.
P.
P.
P.
P.
P.
P.
P.C.
P.D.
P.F.
P.J.
P.J.H.
P.K.A.
P.M.A.
P.M.G.
P.M.W.
P.P.
P.R.
P.U.
P.V.
Q.
Q.
R.
R.
R.
R.
R.
R.
R.
R.
R.
R.
R.
R.
R.
R.
R.
R.
R.
R.
R.A.
R.A.
R.A.F.
R.D.
R.D.
R.F.H.
R.G.
R.H.
R.L.
R.M.
R.M.H.
R.M.P.
R.N.
R.S.
R.W.M.
S.
S.
S.
S.
S.
S.
S.
S.
S.
S.G.
S.L.
T.
T.
T.
T.
T.
T.
T.
T.
T.
T.
T.G.B.W.
T.J.
Th.M.G.
Tj.R.
U.
U.
V.
V.
V.
V.
V.N.
W.
W.
W.
W.
W.
W.
W.
W.
W.
W.
W.J.
W.J.
W.J.A.
W.W.
Z.
Z.
Z.W.
/* In this file, a library for a simple ISAM (indexed sequential access method)
* file structure is defined.
* -------------------------------------------------------------------------
* Author: G.D. van Albada
* University of Amsterdam
* Faculty of Science
* Informatics Institute
* dick at science.uva.nl
* Version: 0.0
* Date: December 2001 / January 2002
* Goal: Part of an assignment on file system structure for the operating
* systems course.
* It demonstrates many of the administrative and layering structures
* that are also used in normal file systems.
*
* The basic assumptions are the following:
*
* 1. The file structure should be flexible and allow for different
* key lengths (but keys have to be character strings)
* data field lengths (we allow for only one data field; the user of
* the library can put any (fixed length) data structure in here).
* key and data fields will be stored together in a record. The record
* will contain additional administrative fields:
*
* state: free, used, deleted
* next: index of next record in sequence
* previous: index of previous record in sequence
* padding: to make the basic record length a multiple of 8 bytes
*
* The initial file structure will contain Nblocks blocks, each containing
* maximum of NrecPB records, of which at most (NrecPB - 1) are initially
* filled. The key of the first record in each block is also used in the
* (fixed) index at the start of the file. The index will be a N-ary tree
* (N = 4), organised in records. It will precede the area with the data
* blocks and will in turn be preceded by the information area for the file.
* The last part of the file is the general overflow area, which can
* grow idefinitely, in principle.
*
* Because the record length is not known at compile time, we have to use an
* approach based on array-indexing and casting etc. To help getting this
* right, we'll define some suitable macros.
*
* File structure:
* 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 --------
*
* Regarding the search procedure:
* The file is provided with an incomplete index, i.e. not all keys
* that occur in the file will occur in the index. As we will
* (for the sake of simplicity) not update the index, actually no record
* need correspond to the keys in the index (the record may have been
* deleted).
*
* The index will return the number of the record with the largest index
* not larger than the searched key. Such a record will always be the
* first record of a "block". Now this record may have been deleted
* from the file. There is a large number of ways to handle this so
* that the organisation remains consistent. The simplest way appears
* to just mark this record as deleted, but retain it otherwise. I.e.
* the first record in a block can be deleted, but cannot be overwritten
* with a record with a different key.
*
* A case in point is the very first record in the file. In order to
* allow for the insertion of records with low key values, this record
* necessarily must have the minimum key value. Luckily, this is well
* defined: it is the empty string "". This record will be created and
* marked "reserved" right at the start.
*
* When creating the file, every Nth (N = NrecPB - 1) record's key will
* be inserted into the index.
*
* The index will be a tree where every node has up to four children.
* The leaf nodes point to the records. The reason for not using a more
* sophisticated tree structure are that not all keys searched for need
* appear in the tree.
*
* So the structure will be:
* 1 17 33 49
* 1 5 9 13 17 ..
* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ....
*
* The depth of the tree will be determined by Nblocks
* (D = ceil(log4(Nblocks)))
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
/*
* Use assert to pinpoint fatal errors - should be removed later
*/
#include <assert.h>
#include "isam.h"
#include "index.h"
/*
* Compile a static structure to store cache statistics
*/
static struct ISAM_CACHE_STATS cstat;
/*
* Just one flag value describing the state of the file for now
*/
#define ISAM_STATE_UPDATING (1024)
/*
* Catch any calls to debugRecord, so we don't have any warnings :)
*/
#ifndef DEBUG
# define debugRecord(alpha, beta, gamma) __placeholder()
static void __placeholder(void) {return;}
#endif
/*
* An isam file will start with an information block that is described in
* the following typedef.
*/
typedef struct
{
unsigned long magic; /* Make sure this is an isam file */
unsigned long version; /* Allow for later versions */
unsigned long Nblocks; /* Number of regular data blocks */
unsigned long NrecPB; /* Number of records per data block */
unsigned long KeyLen; /* Maximum key field length */
unsigned long DataLen; /* Data field length */
unsigned long Nrecords; /* Current number of valid records */
unsigned long DataStart; /* Byte offset of first data record */
unsigned long RecordLen; /* Total record length */
unsigned long CurBlocks; /* Current number of data blocks */
unsigned long MaxKeyRec; /* The location of the MaxKey rec. */
unsigned long FileState; /* Flags to indicate file state */
} fileHead;
/*
* Occupied record positions come in three tastes, for now
*/
#define ISAM_VALID (1)
#define ISAM_DELETED (2)
#define ISAM_SPECIAL (4)
/*
* A record will start with a small header linking it sequentially to
* other records in the file. Next and previous will contain record
* numbers. Records are numbered sequentially throughout the file,
* starting at zero
*/
typedef struct
{
unsigned long next;
unsigned long previous;
unsigned long statusFlags;
} recordHead;
/*
* When a file is opened some additional information will be stored in
* memory, besides the file header. This includes, e.g. a cache for
* recently used blocks.
*/
#define CACHE_SIZE (6)
typedef struct ISAM
{
fileHead fHead; /* The file header */
unsigned long blockSize; /* The file datablock size */
int mayWrite; /* Unused - opened for read/write */
int fileId; /* The file-id for the file */
int errorState; /* Unused */
int cur_id; /* The cache-slot containing the current
* record */
int cur_recno; /* The position in the cache of the
* current record */
int last_in; /* For a FIFO cache */
int blockInCache[CACHE_SIZE]; /* block number per cache
* slot */
index_handle index; /* The handle for the index */
char *cache[CACHE_SIZE]; /* Pointers to cache blocks */
char *maxKey; /* The highest key in the file */
} isam;
/*
* Starting a file with a magic number provides a simple validity test
* when opening the file (avoid some accidents)
*/
#define isamMagic (0x15a8f17e)
/*
* The following macros should simplify the access to the various parts of
* the variable length records in blocks as stored in the cache.
* Apparently the use of key() as a macro does not interfere with the use
* of key as a variable name
*/
#define head(isam,id,Nrec) ((recordHead *)((isam).cache[(id)]+\
(Nrec)*((isam).fHead.RecordLen)))
#define cur_head(isam) head((isam), (isam).cur_id, (isam).cur_recno)
#define key(isam,id,Nrec) (((isam).cache[(id)])+\
(Nrec)*((isam).fHead.RecordLen)+sizeof(recordHead))
#define cur_key(isam) key((isam), (isam).cur_id, (isam).cur_recno)
#define data(isam,id,Nrec) ((void *)((isam).cache[(id)]+\
(Nrec)*((isam).fHead.RecordLen)+sizeof(recordHead)+\
(isam).fHead.KeyLen))
#define cur_data(isam) data((isam), (isam).cur_id, (isam).cur_recno)
enum isam_error isam_error = ISAM_NO_ERROR;
/*
* makeIsamPtr creates an isamPtr given a file header, fills in some data
* and initialises the cache
*/
static isamPtr
makeIsamPtr(fileHead * fHead)
{
isamPtr ipt = (isamPtr) calloc(1, sizeof(isam));
int blockSize;
int i;
assert(ipt != NULL);
ipt->fHead = *fHead;
ipt->blockSize = blockSize = fHead->NrecPB * fHead->RecordLen;
ipt->cache[0] = calloc(CACHE_SIZE, blockSize);
assert(ipt->cache[0] != NULL);
ipt->blockInCache[0] = -1;
for (i = 1; i < CACHE_SIZE; i++) {
ipt->cache[i] = blockSize + ipt->cache[i - 1];
ipt->blockInCache[i] = -1;
}
return ipt;
}
static void
dumpMaxKey(isamPtr f)
{
unsigned int i;
fprintf(stderr, "Maxkey ='");
for (i = 0; (i < f->fHead.KeyLen) && (f->maxKey[i]); i++) {
fprintf(stderr, "%c", f->maxKey[i]);
}
fprintf(stderr, "'\n");
}
/*
* Write the file header to disk (again)
*/
static int
writeHead(isamPtr f)
{
#ifdef DEBUG
fprintf(stderr,
"writeHead: Nrecords = %lu DataStart = %lu CurBlocks = %lu FileState = %lu\n",
f->fHead.Nrecords, f->fHead.DataStart,
f->fHead.CurBlocks, f->fHead.FileState);
#endif
if (lseek(f->fileId, 0, SEEK_SET)) {
isam_error = ISAM_SEEK_ERROR;
return -1;
}
if (sizeof(fileHead) != write(f->fileId, &(f->fHead), sizeof(fileHead))) {
isam_error = ISAM_WRITE_FAIL;
return -1;
}
/*
* STEP 2 INF: This is a good place to record the number of header writes.
*/
cstat.hwrites++;
return 0;
}
/*
* You never can predict what junk you get as a file pointer...
*/
static int
testPtr(isamPtr f)
{
if ((!f) || (f->fHead.magic != isamMagic)) {
isam_error = ISAM_IDENT_INVALID;
return -1;
}
return 0;
}
/*
* In the remainder of the code, we should not need to worry about how and
* where to write a given block from the cache
*/
static int
write_cache_block(isamPtr isam_ident, int iCache)
{
unsigned long block_no = isam_ident->blockInCache[iCache];
int rv;
if (lseek(isam_ident->fileId, isam_ident->fHead.DataStart +
block_no * isam_ident->blockSize, SEEK_SET) == (off_t) - 1) {
isam_error = ISAM_SEEK_ERROR;
return -1;
}
rv = write(isam_ident->fileId, isam_ident->cache[iCache],
isam_ident->blockSize);
if (rv != (int) isam_ident->blockSize) {
isam_error = ISAM_WRITE_FAIL;
return -1;
}
/*
* STEP 2 INF: This is a good place to record the number of block writes.
*/
cstat.writes++;
return 0;
}
/*
* See if the requested block is in the cache (could be a data block, or a
* block in the overflow area). If not, load the block. We will assume
* that there are no "dirty" blocks - every block that is modified is
* written to disk right away. If the block lies beyond the last block in
* the file, there is no need to read from the file (which should result
* in an EOF error anyway); we just zero the cache block (corresponding to
* an empty record).
*/
static int
isam_cache_block(isamPtr isam_ident, unsigned long block_no)
{
int iCache;
int rv;
#ifdef DEBUG
fprintf(stderr, "isam_cache_block(..., %lu)\n", block_no);
#endif
/*
* A block beyond the current end of the file. Write it to extend the file
* right away.
*/
/*
* STEP 2: this function needs to be instrumented to record the number of
* times it has been called (this is a good place to do that) and the
* number of times it needs to read from disk (see read() call below).
*/
cstat.calls++;
if (block_no >= isam_ident->fHead.CurBlocks) {
iCache = isam_ident->last_in + 1;
if (iCache >= CACHE_SIZE) {
iCache = 0;
}
memset(isam_ident->cache[iCache], 0, isam_ident->blockSize);
isam_ident->last_in = iCache;
isam_ident->blockInCache[iCache] = block_no;
if (write_cache_block(isam_ident, iCache)) {
return -1;
}
isam_ident->fHead.CurBlocks = block_no + 1;
if (writeHead(isam_ident)) {
return -1;
}
return iCache;
}
/*
* A block within the current file bounds. First see if it is in the cache
* already
*/
for (iCache = 0; iCache < CACHE_SIZE; iCache++) {
if ((int) block_no == isam_ident->blockInCache[iCache]) {
break;
}
}
if (iCache >= CACHE_SIZE) {
/*
* The block is not in the cache. Fill the slot after the last slot
* filled.
*/
iCache = isam_ident->last_in + 1;
if (iCache >= CACHE_SIZE) {
iCache = 0;
}
if (lseek(isam_ident->fileId, isam_ident->fHead.DataStart +
block_no * isam_ident->blockSize,
SEEK_SET) == (off_t) - 1) {
isam_error = ISAM_SEEK_ERROR;
return -1;
}
rv = read(isam_ident->fileId, isam_ident->cache[iCache],
isam_ident->blockSize);
if (rv != (int) isam_ident->blockSize) {
isam_error = ISAM_READ_ERROR;
return -1;
}
isam_ident->last_in = iCache;
isam_ident->blockInCache[iCache] = block_no;
/*
* STEP 2: This is a good place to record the number of disk reads.
*/
cstat.reads++;
}
return iCache;
}
/*
* We look for the first free record in a given block. We have a number of
* options to do this - by block number (in which case we have to make
* sure that the block is in the cache), or by cached block number
* (putting the responsability for the blocknumber on the calling
* function) We'll use the latter approach - it also has the advantage
* that we only need to return a single value.
*/
static int
free_record_in_block(isamPtr isam_ident, int iCache)
{
unsigned int iFree;
if ((iCache < 0) || (iCache >= CACHE_SIZE)) {
#ifdef DEBUG
fprintf(stderr, "free_record iCache = %d\n", iCache);
#endif
return -1;
}
if (isam_ident->blockInCache[iCache] < 0) {
#ifdef DEBUG
fprintf(stderr, "free_record blockInCache = %d\n",
isam_ident->blockInCache[iCache]);
#endif
return -1;
}
for (iFree = 0; iFree < isam_ident->fHead.NrecPB; iFree++) {
/*
* We cannot use a deleted record either. Records are only marked
* deleted rather than unused (free) if 1. they are the first record
* of a block and have been deleted. (otherwise this plays havoc with
* the index). 2. temporarily, while pointers in the preceding and
* following records are being updated after deletion.
*/
if (!(head(*isam_ident, iCache, iFree)->statusFlags)) {
return iFree;
}
}
return -1;
}
/*
* Strictly for debugging - print some information about a record
*/
#ifdef DEBUG
static void
debugRecord(isamPtr f, unsigned long n, char *from)
{
int ib = n / f->fHead.NrecPB;
int ic = isam_cache_block(f, ib);
int ir = n % f->fHead.NrecPB;
if (ic < 0) {
return;
}
fprintf(stderr, "%s: key = %s\n", from, key(*f, ic, ir));
}
#endif
/*
* The following function will create an empty isam file, with the
* specified parameters. It will return an isamPtr when succesful, NULL if
* not. The empty file should initially be written sequentially (i.e. with
* increasing key numbers). Now, how long can that continue and what
* happens when you write a non-sequential entry? That is for somewhere
* else... Requirements here: no file with the specified name should exist
* yet.
*/
isamPtr
isam_create(const char *name, unsigned long KeyLen,
unsigned long DataLen, unsigned long NrecPB,
unsigned long Nblocks)
{
struct stat buf;
int i, l;
long rv;
isamPtr fp;
fileHead fHead;
memset(&fHead, 0, sizeof(fHead));
isam_error = ISAM_NO_ERROR;
if ((8 > KeyLen) || (40 < KeyLen)) {
isam_error = ISAM_KEY_LEN;
return NULL;
}
/*
* First check if name points to an existing file. If it does, stat will
* return 0, and our routine should return NULL
*/
if (!stat(name, &buf)) {
isam_error = ISAM_FILE_EXISTS;
return NULL;
}
/*
* Now stat may fail when the pointer is an existing, but invalid
* symbolic link. We do not want that either.
*/
if (!lstat(name, &buf)) {
isam_error = ISAM_LINK_EXISTS;
return NULL;
}
/*
* Now create and initialize the file header and descriptor
*/
fHead.magic = isamMagic;
fHead.KeyLen = KeyLen;
fHead.DataLen = DataLen;
fHead.NrecPB = NrecPB;
fHead.Nblocks = Nblocks;
i = KeyLen + DataLen + sizeof(recordHead);
l = (i + 7) / 8;
fHead.RecordLen = 8 * l;
fp = makeIsamPtr(&fHead);
/*
* At last - create a file
*/
fp->fileId = open(name, O_RDWR | O_CREAT | O_EXCL, 0660);
if (fp->fileId < 0) {
isam_error = ISAM_OPEN_FAIL;
goto error_open;
}
/*
* Write an initial header
*/
if (writeHead(fp))
goto error_head;
fp->mayWrite = 1;
/*
* Initialise the file index and write it to disk.
* The data blocks will start immediately after the index.
*/
fp->index = index_makeNew(Nblocks, KeyLen);
fp->fHead.DataStart = rv = index_writeToDisk(fp->index, fp->fileId);
if (rv < 0)
goto error_write;
/*
* Initialise the first data block with the dummy first record. Store in
* cache and write to disk.
*/
fp->blockInCache[0] = 0;
fp->cur_id = 0;
fp->cur_recno = 0;
cur_head((*fp))->statusFlags = ISAM_SPECIAL;
l = write(fp->fileId, fp->cache[0], fp->blockSize);
if (l != (int) fp->blockSize)
goto error_write;
/*
* The file header can now be further updated.
*/
fp->fHead.CurBlocks = 1;
if (writeHead(fp))
goto error_write;
fp->maxKey = calloc(1, KeyLen);
assert(fp->maxKey != NULL);
return fp;
error_write:
isam_error = ISAM_WRITE_FAIL;
index_free(fp->index);
error_head:
close(fp->fileId);
error_open:
free(fp->cache[0]);
free(fp);
return NULL;
}
isamPtr
isam_open(const char *name, int update)
{
struct stat buf;
isamPtr fp;
fileHead fh;
int fid;
int block_no, rec_no;
int iCache;
memset(&fh, 0, sizeof(fh));
isam_error = ISAM_NO_ERROR;
/*
* First check if name points to an existing file. If it does, stat will
* return 0, and our routine can continue
*/
if (stat(name, &buf)) {
isam_error = ISAM_NO_SUCH_FILE;
return NULL;
}
/*
* And then, there were none.
* (Warnings that is ;)
*/
if (!update) {}
/*
* At last - open a file
*/
fid = open(name, O_RDWR);
if (fid < 0) {
isam_error = ISAM_OPEN_FAIL;
return NULL;
}
/*
* read header and test amount of data read
*/
if (sizeof(fileHead) != read(fid, &fh, sizeof(fileHead))) {
isam_error = ISAM_READ_ERROR;
goto error_file;
}
/*
* test if it could be an isam file
*/
if (fh.magic != isamMagic) {
isam_error = ISAM_BAD_MAGIC;
goto error_file;
}
/*
* We can only handle version 0
*/
if (fh.version > 0) {
isam_error = ISAM_BAD_VERSION;
goto error_file;
}
/*
* Now create and initialise the isamPtr
*/
fp = makeIsamPtr(&fh);
isam_error = ISAM_NO_ERROR;
if (!(fp->index = index_readFromDisk(fid)))
{
isam_error = ISAM_INDEX_ERROR;
goto error_index;
}
fp->fileId = fid;
fp->mayWrite = 1;
fp->blockInCache[0] = 0;
fp->cur_id = 0;
fp->cur_recno = 0;
if (read(fp->fileId, fp->cache[0], fp->blockSize) != (int) fp->blockSize) {
isam_error = ISAM_READ_ERROR;
goto error_cache;
}
fp->maxKey = calloc(1, fp->fHead.KeyLen);
assert(fp->maxKey != NULL);
block_no = fp->fHead.MaxKeyRec / fp->fHead.NrecPB;
rec_no = fp->fHead.MaxKeyRec % fp->fHead.NrecPB;
iCache = isam_cache_block(fp, block_no);
if (iCache < 0)
goto error_cache;
memcpy(fp->maxKey, key(*fp, iCache, rec_no), fp->fHead.KeyLen);
return fp;
error_cache:
index_free(fp->index);
error_index:
free(fp->cache[0]);
free(fp);
error_file:
close(fid);
return NULL;
}
/*
* Close an isam file and release the memory used
*/
int
isam_close(isamPtr f)
{
int i;
/*
* Before closing the file, we should actually make sure it has been
* "sync-ed" to disk. We'll make sure that any modifications are written
* immediately by the function making the modification. So we'll need not
* do any saving here
*/
isam_error = ISAM_NO_ERROR;
if (testPtr(f)) {
return -1;
}
free(f->cache[0]);
free(f->maxKey);
for (i = 0; i < CACHE_SIZE; i++) {
f->cache[i] = NULL;
}
index_free(f->index);
f->fHead.magic = 0;
close(f->fileId);
free(f);
return 0;
}
/*
* Set the current pointer to the last valid record (if that exists) with
* a key less than the requested key. isam_readNext will then read the
* record with that key (if it exists), or the next higher key (if that
* exists)
*/
int
isam_setKey(isamPtr isam_ident, const char *key)
{
int block_no;
int rec_no;
unsigned long next, prev;
int iCache;
int rv;
if (testPtr(isam_ident)) {
return -1;
}
if (key[0] == 0) {
/*
* "rewind" the file to the dummy first record.
*/
iCache = isam_cache_block(isam_ident, 0);
if (iCache < 0) {
return -1;
}
isam_ident->cur_id = iCache;
isam_ident->cur_recno = 0;
return 0;
}
/*
* First find block number from index
*/
block_no = index_keyToBlock(isam_ident->index, key);
rec_no = 0;
/*
* Now make sure the block is in cache
*/
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
/*
* Skip all records with smaller keys
*/
while ((rv = strncmp(key, key((*isam_ident), iCache, rec_no),
isam_ident->fHead.KeyLen)) > 0) {
next = head((*isam_ident), iCache, rec_no)->next;
debugRecord(isam_ident, next, "setkey #1");
if (!next) {
/*
* There is no next record
*/
break;
}
block_no = next / isam_ident->fHead.NrecPB;
rec_no = next % isam_ident->fHead.NrecPB;
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
}
/*
* Now we have found / may have found a record with a key larger than or
* equal to the given key - but then we promised to position at the
* previous valid record - so look for that. There may be no record with a
* larger key - in that case (rv < 0) && (next == 0) A valid record is a
* record that has the valid flag set.
*/
while (((rv = strncmp(key, key((*isam_ident), iCache, rec_no),
isam_ident->fHead.KeyLen)) <= 0) ||
(!(head((*isam_ident), iCache, rec_no)->
statusFlags & ISAM_VALID))) {
prev = head((*isam_ident), iCache, rec_no)->previous;
debugRecord(isam_ident, prev, "setkey #2");
/* prev may be 0 - that is OK; we are then pointing to the dummy
* first record. However, that is not a valid record, but we
* have no choice.
* This means that a call to isam_prev must return an invalid result
*/
block_no = prev / isam_ident->fHead.NrecPB;
rec_no = prev % isam_ident->fHead.NrecPB;
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
if (!prev) {
/*
* The "current" record is not "it", and the previous is the dummy
* first record. We have gone there already. This is completely
* normal
*/
isam_ident->cur_id = iCache;
isam_ident->cur_recno = 0;
return 0;
}
}
isam_ident->cur_id = iCache;
isam_ident->cur_recno = rec_no;
return 0;
}
/*
* isam_readNext will read the next valid record (from cur_recno and
* cur_id), if such a record exists
*/
int
isam_readNext(isamPtr isam_ident, char *key, void *data)
{
int block_no;
int rec_no;
int iCache;
int next;
if (testPtr(isam_ident)) {
return -1;
}
/*
* First we have to look for the next valid record (that is the way we
* decided to make all this work!
*/
rec_no = isam_ident->cur_recno;
iCache = isam_ident->cur_id;
do {
next = head((*isam_ident), iCache, rec_no)->next;
debugRecord(isam_ident, next, "next #1");
if (!next) {
isam_error = ISAM_EOF;
return -1;
}
block_no = next / isam_ident->fHead.NrecPB;
rec_no = next % isam_ident->fHead.NrecPB;
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
}
while (!(head((*isam_ident),iCache,rec_no)->statusFlags & ISAM_VALID));
isam_ident->cur_id = iCache;
isam_ident->cur_recno = rec_no;
memcpy(key, cur_key(*isam_ident), isam_ident->fHead.KeyLen);
memcpy(data, cur_data(*isam_ident), isam_ident->fHead.DataLen);
isam_error = ISAM_NO_ERROR;
return 0;
}
/*
* isam_readPrev will read the current record, if it is valid, and then
* reposition the file to the preceding valid record (if that exists).
*/
int
isam_readPrev(isamPtr isam_ident, char *key, void *data)
{
int block_no;
int rec_no = 0;
int iCache = 0;
int prev;
if (testPtr(isam_ident)) {
return -1;
}
/*
* We should now be at the correct valid record (unless we are at the very
* first record). So we check, copy the data, and try to find the
* preceding valid record.
*/
isam_error = ISAM_NO_ERROR;
if (cur_head(*isam_ident)->statusFlags & ISAM_VALID) {
memcpy(key, cur_key(*isam_ident), isam_ident->fHead.KeyLen);
memcpy(data, cur_data(*isam_ident), isam_ident->fHead.DataLen);
rec_no = isam_ident->cur_recno;
iCache = isam_ident->cur_id;
do {
prev = head((*isam_ident), iCache, rec_no)->previous;
block_no = prev / isam_ident->fHead.NrecPB;
rec_no = prev % isam_ident->fHead.NrecPB;
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
if (!prev) {
break;
}
}
while (!(head((*isam_ident), iCache, rec_no)->statusFlags
& ISAM_VALID));
isam_ident->cur_id = iCache;
isam_ident->cur_recno = rec_no;
return 0;
}
isam_error = ISAM_SOF;
return -1;
}
/*
* isam_readByKey will attempt to read a record with the requested key
*/
int
isam_readByKey(isamPtr isam_ident, const char *key, void *data)
{
#ifdef OPTIMISED
int block_no;
int rec_no;
unsigned long next;
int iCache;
if (testPtr(isam_ident)) {
return -1;
}
else if (!key[0]) {
isam_error = ISAM_NULL_KEY;
return -1;
}
/*
* First find block number from index
*/
block_no = index_keyToBlock(isam_ident->index, key);
rec_no = 0;
/*
* Now make sure the block is in cache
*/
if ((iCache = isam_cache_block(isam_ident, block_no)) < 0)
return -1;
/*
* Skip all records with smaller keys
*/
while (strncmp(key, key((*isam_ident),iCache,rec_no),
isam_ident->fHead.KeyLen) > 0) {
/*
* There is no next record
*/
if (!(next = head((*isam_ident),iCache,rec_no)->next))
break;
block_no = next / isam_ident->fHead.NrecPB;
rec_no = next % isam_ident->fHead.NrecPB;
if ((iCache = isam_cache_block(isam_ident, block_no)) < 0)
return -1;
}
/*
* Current key is not exact match
*/
if (strncmp(key, key((*isam_ident),iCache,rec_no),
isam_ident->fHead.KeyLen) != 0) {
isam_error = ISAM_NO_SUCH_KEY;
return -1;
}
/*
* Deleted?
*/
else if (!(head((*isam_ident),iCache,rec_no)->statusFlags & ISAM_VALID)) {
isam_error = ISAM_NO_SUCH_KEY;
return -1;
}
/*
* Found it!
*/
isam_error = ISAM_NO_ERROR;
isam_ident->cur_id = iCache;
isam_ident->cur_recno = rec_no;
memcpy(data, data((*isam_ident),iCache,rec_no), isam_ident->fHead.DataLen);
return 0;
#else
/*
* STEP 5: This implementation is inefficient, and I have not verified
* that it really works according to its specification For one thing, it
* does not test for a valid isam_ident before use. It is probably better
* to include tempData and tempKey as part of the structure pointed to by
* isam_ident. That also saves some mallocs and frees
*/
void *tempData = malloc(isam_ident->fHead.DataLen);
char *tempKey = malloc(isam_ident->fHead.KeyLen);
int rv = isam_setKey(isam_ident, key);
assert(tempData != NULL && tempKey != NULL);
if (rv || isam_readNext(isam_ident, tempKey, tempData) ) {
goto key_error;
}
if (strncmp(key, tempKey, isam_ident->fHead.KeyLen)) {
isam_error = ISAM_NO_SUCH_KEY;
goto key_error;
}
memcpy(data, tempData, isam_ident->fHead.DataLen);
free(tempKey);
free(tempData);
return 0;
key_error:
free(tempKey);
free(tempData);
return -1;
#endif
}
/*
* isam_append implements part of the functionality of isam_writeNew. It
* is only used when the key is larger than or equal to the largest key so
* far (this can be a key in a regular record, in a deleted first record
* of a block, or in an overflow record. The latter can happen if a record
* was inserted before the then last record, after which the record was
* deleted). We must find the last record (store that in the file header)
* and an appropriate place to store the new record. The appropriate
* place will be defined as: 1. The place of a deleted first record, if
* the key matches the key of the deleted record. 2. The first free slot
* in the block returned by an index search for the maximum key, as long
* as that is not the last slot in that block. 3. The first slot in a new
* block if that still fits in with the regular data blocks. In this case
* the key must be added to the index and the index rewritten. 4. An
* overflow record position (last block in a record, or a free slot in an
* overflow block)
*/
static int
isam_append(isamPtr isam_ident, const char *key, const void *data)
{
int block_no;
int rec_no;
int new_block_no, new_rec_no;
unsigned long next;
int iCache, nCache;
int rv;
/*
* First find block number from index
*/
block_no = index_keyToBlock(isam_ident->index, key);
rec_no = 0;
/*
* Now make sure the block is in cache
*/
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
/* First see if this is a deleted first record.
* There are a lot of properties that we could check.
* 1. The first record must have been deleted (but it may still have a
* smaller key)
* 2. The first record has the same key as the requested key (and as
* maxKey).
* 3. The next pointer of the first record is zero (this appears to be
* the most sensible test anyway).
*/
next = head((*isam_ident), iCache, rec_no)->next;
if (next == 0) {
/*
* I think this must be a deleted first record. It still may have a
* smaller key than the new record. This actually is a bit a doubtful
* case for append - let it be for now
*/
if ((rv = strncmp(key, key((*isam_ident), iCache, rec_no),
isam_ident->fHead.KeyLen))) {
assert(rv > 0);
/*
* This now implies an otherwise normal append
*/
}
else {
/*
* Keys are indeed equal - but, have we checked anywhere else
* if the key did not yet exist by chance? So let's check that
* here. Next check maxKey for added security
*/
if (ISAM_VALID & head((*isam_ident),iCache,rec_no)->statusFlags) {
isam_error = ISAM_RECORD_EXISTS;
return -1;
}
assert(0 == strncmp(key, isam_ident->maxKey,
isam_ident->fHead.KeyLen));
/*
* Assert deleted state
*/
assert(ISAM_DELETED ==
head((*isam_ident), iCache, rec_no)->statusFlags);
/*
* We only need to copy the data and mark the record as valid
*/
memcpy(data(*isam_ident, iCache, rec_no), data,
isam_ident->fHead.DataLen);
head(*isam_ident, iCache, rec_no)->statusFlags = ISAM_VALID;
isam_ident->fHead.Nrecords++;
/*
* Now what do we write first? - writing the header twice is extra
* work, but at least makes it easy to identify an inconsistent
* file. Writing intentions would be even more secure
*/
isam_ident->fHead.FileState |= ISAM_STATE_UPDATING;
writeHead(isam_ident);
if (write_cache_block(isam_ident, iCache)) {
return -1;
}
isam_ident->fHead.FileState &= ~ISAM_STATE_UPDATING;
return writeHead(isam_ident);
}
}
/*
* So there is a next, follow it to the bitter end
*/
while (next) {
block_no = next / isam_ident->fHead.NrecPB;
rec_no = next % isam_ident->fHead.NrecPB;
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
next = head((*isam_ident), iCache, rec_no)->next;
}
/*
* Now we should have a record with a smaller key, equal to maxKey
*/
rv = strncmp(key, key((*isam_ident), iCache, rec_no),
isam_ident->fHead.KeyLen);
if (rv <= 0) {
unsigned int i;
dumpMaxKey(isam_ident);
fprintf(stderr, "key = '%s', found key ='", key);
for (i = 0; i <= isam_ident->fHead.KeyLen; i++) {
fprintf(stderr, "%c", key((*isam_ident), iCache, rec_no)[i]);
}
fprintf(stderr, "'\n");
}
assert(rv > 0);
new_block_no = block_no;
nCache = iCache;
new_rec_no = free_record_in_block(isam_ident, iCache);
while (new_rec_no < 0 || new_rec_no >= (int) isam_ident->fHead.NrecPB) {
/*
* We'll leave the last slot free for inserts
*/
new_block_no++;
if (new_block_no >= (int) isam_ident->fHead.Nblocks) {
/*
* Insertion in an overflow block obeys slightly different rules -
* e.g. we do not add to the index, and we do not leave a free
* slot
*/
break;
}
nCache = isam_cache_block(isam_ident, new_block_no);
if (nCache < 0) {
return -1;
}
new_rec_no = free_record_in_block(isam_ident, nCache);
}
while (new_rec_no < 0) {
new_block_no++;
nCache = isam_cache_block(isam_ident, new_block_no);
if (nCache < 0) {
return -1;
}
new_rec_no = free_record_in_block(isam_ident, nCache);
}
memcpy(isam_ident->maxKey, key, isam_ident->fHead.KeyLen);
isam_ident->cur_id = nCache;
isam_ident->cur_recno = new_rec_no;
memcpy(cur_key(*isam_ident), key, isam_ident->fHead.KeyLen);
memcpy(cur_data(*isam_ident), data, isam_ident->fHead.DataLen);
cur_head(*isam_ident)->statusFlags = ISAM_VALID;
cur_head(*isam_ident)->previous = block_no * isam_ident->fHead.NrecPB +
rec_no;
cur_head(*isam_ident)->next = 0;
/*
* Beware - the previous record may have been deleted from the cache, but
* re-reading it may remove the current record. We'll first update the
* file header
*/
isam_ident->fHead.FileState |= ISAM_STATE_UPDATING;
isam_ident->fHead.Nrecords++;
isam_ident->fHead.MaxKeyRec = new_rec_no +
new_block_no * isam_ident->fHead.NrecPB;
writeHead(isam_ident);
/*
* We'll now update the index - if needed and as long as the file pointer
* is correct
*/
if (new_rec_no == 0 && new_block_no < (int) isam_ident->fHead.Nblocks) {
index_addKey(isam_ident->index, key, new_block_no);
index_writeToDisk(isam_ident->index, isam_ident->fileId);
}
if (new_block_no == block_no) {
/*
* Update the "next" pointer here and now
*/
assert(iCache == nCache);
head(*isam_ident, iCache, rec_no)->next =
isam_ident->fHead.MaxKeyRec;
}
if (write_cache_block(isam_ident, nCache)) {
return -1;
}
if (new_block_no != block_no) {
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
head(*isam_ident, iCache, rec_no)->next =
isam_ident->fHead.MaxKeyRec;
if (write_cache_block(isam_ident, iCache)) {
return -1;
}
}
isam_ident->fHead.FileState &= ~ISAM_STATE_UPDATING;
return writeHead(isam_ident);
}
int
isam_writeNew(isamPtr isam_ident, const char *key, const void *data)
{
int block_no;
int rec_no;
int new_block_no, new_rec_no;
int prev_block_no, prev_rec_no;
unsigned long next, prev;
int iCache, nCache, pCache;
int rv;
if (testPtr(isam_ident)) {
return -1;
}
if (!key[0]) {
isam_error = ISAM_NULL_KEY;
return -1;
}
rv = strncmp(key, isam_ident->maxKey, isam_ident->fHead.KeyLen);
if (rv >= 0) {
return isam_append(isam_ident, key, data);
}
/*
* Now look for the record with the highest key less than key The
* successor will be the one with the lowest greater than... Beware of
* equal keys, unless for deleted records. We might be tempted to use
* setkey, but setkey selects the last valid record - and we are not
* interested in that now. Copy some code, though.
*/
block_no = index_keyToBlock(isam_ident->index, key);
rec_no = 0;
/*
* Now make sure the block is in cache
*/
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
next = block_no * isam_ident->fHead.NrecPB;
while ((rv = strncmp(key, key((*isam_ident), iCache, rec_no),
isam_ident->fHead.KeyLen)) > 0) {
next = head((*isam_ident), iCache, rec_no)->next;
assert(next);
block_no = next / isam_ident->fHead.NrecPB;
rec_no = next % isam_ident->fHead.NrecPB;
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
}
/*
* As we (should have) avoided the last record by going to append when
* needed - and by doing this "assert(next)" stuff, we can now proceed on
* the assumption that the record found really has an equal or larger key
*
* Is the key equal ?
*/
if (rv == 0) {
if (head((*isam_ident), iCache, rec_no)->
statusFlags & ISAM_DELETED) {
/*
* Should be simple and OK.
* We only need to copy the data and mark the record as valid
*/
memcpy(data(*isam_ident, iCache, rec_no), data,
isam_ident->fHead.DataLen);
head(*isam_ident, iCache, rec_no)->statusFlags = ISAM_VALID;
isam_ident->fHead.Nrecords++;
/*
* No what do we write first? - writing the header twice is extra
* work, but at least makes it easy to identify an inconsistent
* file. Writing intentions would be even more secure
*/
isam_ident->fHead.FileState |= ISAM_STATE_UPDATING;
writeHead(isam_ident);
if (write_cache_block(isam_ident, iCache)) {
return -1;
}
isam_ident->fHead.FileState &= ~ISAM_STATE_UPDATING;
isam_ident->cur_id = iCache;
isam_ident->cur_recno = rec_no;
return writeHead(isam_ident);
}
else {
/*
* Someone is trying to update a record with isam_writeNew, we are
* not going to allow that
*/
isam_error = ISAM_RECORD_EXISTS;
return -1;
}
}
/*
* So, now we know that the key of the record pointed to by "next" is
* larger, and its predecessor must be smaller (possibly the empty key "")
* We first look for the previous record (bearing in mind that we may lose
* the current in doing so), then look for a free slot from that point
* forward. Here we have the choice to only use last slots, or any free
* slot. Let's keep it simple....
*/
prev = head(*isam_ident, iCache, rec_no)->previous;
prev_block_no = prev / isam_ident->fHead.NrecPB;
prev_rec_no = prev % isam_ident->fHead.NrecPB;
pCache = isam_cache_block(isam_ident, prev_block_no);
if (pCache < 0) {
return -1;
}
nCache = pCache;
new_block_no = prev_block_no;
new_rec_no = free_record_in_block(isam_ident, nCache);
if (new_rec_no < 0) {
new_block_no = isam_ident->fHead.Nblocks - 1;
while (new_rec_no < 0) {
new_block_no++;
nCache = isam_cache_block(isam_ident, new_block_no);
if (nCache < 0) {
return -1;
}
new_rec_no = free_record_in_block(isam_ident, nCache);
}
}
/*
* Set new record as current (isam_readPrev should allow you to re-read
* it) and store all necessary information (key, data, prev and next
* pointers and set to VALID
*/
isam_ident->cur_id = nCache;
isam_ident->cur_recno = new_rec_no;
memcpy(cur_key(*isam_ident), key, isam_ident->fHead.KeyLen);
memcpy(cur_data(*isam_ident), data, isam_ident->fHead.DataLen);
cur_head(*isam_ident)->statusFlags = ISAM_VALID;
cur_head(*isam_ident)->previous = prev;
cur_head(*isam_ident)->next = next;
/*
* Update file header and prepare for writing.
*/
isam_ident->fHead.Nrecords++;
isam_ident->fHead.FileState |= ISAM_STATE_UPDATING;
writeHead(isam_ident);
/*
* Now we have three records that may or may not lie in the same block.
* We'll not explore all possibilities, but check at least this:
* prev_block_no == new_block_no prev_block_no == new_block_no
* && new_block_no == block_no
*/
if (prev_block_no == new_block_no) {
/*
* Also update pointer in preceding record when writing block
*/
assert(pCache == nCache);
head(*isam_ident, pCache, prev_rec_no)->next = new_rec_no +
new_block_no * isam_ident->fHead.NrecPB;
if (new_block_no == block_no) {
/*
* And also that in the next record
*/
assert(iCache == nCache);
head(*isam_ident, iCache, rec_no)->previous = new_rec_no +
new_block_no * isam_ident->fHead.NrecPB;
if (write_cache_block(isam_ident, nCache)) {
return -1;
}
/*
* Complete update and return
*/
isam_ident->fHead.FileState &= ~ISAM_STATE_UPDATING;
return writeHead(isam_ident);
}
/*
* Update pointer in next record separately, start with new
*/
if (write_cache_block(isam_ident, nCache)) {
return -1;
}
/*
* Make sure next record is in cache, update and write
*/
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
head(*isam_ident, iCache, rec_no)->previous = new_rec_no +
new_block_no * isam_ident->fHead.NrecPB;
if (write_cache_block(isam_ident, iCache)) {
return -1;
}
/*
* Finish update and return
*/
nCache = isam_cache_block(isam_ident, new_block_no);
if (nCache < 0) {
return -1;
}
isam_ident->cur_id = nCache;
isam_ident->cur_recno = new_rec_no;
isam_ident->fHead.FileState &= ~ISAM_STATE_UPDATING;
return writeHead(isam_ident);
}
/*
* Process all three records separately
*/
if (write_cache_block(isam_ident, nCache)) {
return -1;
}
/*
* Preceding record
*/
pCache = isam_cache_block(isam_ident, prev_block_no);
if (pCache < 0) {
return -1;
}
head(*isam_ident, pCache, prev_rec_no)->next = new_rec_no +
new_block_no * isam_ident->fHead.NrecPB;
if (write_cache_block(isam_ident, pCache)) {
return -1;
}
/*
* Next record
*/
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
head(*isam_ident, iCache, rec_no)->previous = new_rec_no +
new_block_no * isam_ident->fHead.NrecPB;
if (write_cache_block(isam_ident, iCache)) {
return -1;
}
/*
* Finish and return
*/
nCache = isam_cache_block(isam_ident, new_block_no);
if (nCache < 0) {
return -1;
}
isam_ident->cur_id = nCache;
isam_ident->cur_recno = new_rec_no;
isam_ident->fHead.FileState &= ~ISAM_STATE_UPDATING;
return writeHead(isam_ident);
}
/*
* The implementation of `strerror' provides user-defined extensibility.
* `errno.h' defines __ELASTERROR, which can be used as a base for user-defined
* error values. If the user supplies a routine named `_user_strerror', and
* ERRNUM passed to `strerror' does not match any of the supported values,
* `_user_strerror' is called with ERRNUM as its argument.
*
* For this assignment, we add the prefix "isam_" instead of implementing the
* `_user_strerror' function.
*/
const char * isam_strerror(int errno)
{
switch( errno ) {
case ISAM_NO_ERROR: return "No error occured"; break;
case ISAM_WRITE_FAIL: return "Writing to file failed"; break;
case ISAM_KEY_LEN: return "Invalid key length"; break;
case ISAM_FILE_EXISTS: return "File already exists"; break;
case ISAM_LINK_EXISTS: return "Link already exists"; break;
case ISAM_OPEN_FAIL: return "Opening file failed"; break;
case ISAM_NO_SUCH_FILE: return "There is no such file"; break;
case ISAM_OPEN_COUNT: return "Too many files are open"; break;
case ISAM_INDEX_ERROR: return "Index entry is invalid"; break;
case ISAM_READ_ERROR: return "Reading from file failed"; break;
case ISAM_BAD_MAGIC: return "Invalid magic number"; break;
case ISAM_BAD_VERSION: return "Invalid isam version number"; break;
case ISAM_HEADER_ERROR: return "Invalid isam header"; break;
case ISAM_OPEN_FOR_UPDATE: return "Opening file for update"; break;
case ISAM_IDENT_INVALID: return "Invalid file identifier"; break;
case ISAM_NO_SUCH_KEY: return "No such key found"; break;
case ISAM_NULL_KEY: return "Null key not supported"; break;
case ISAM_DATA_MISMATCH: return "Malformed data found"; break;
case ISAM_RECORD_EXISTS: return "Record already exists"; break;
case ISAM_SEEK_ERROR: return "File seek operation failed"; break;
case ISAM_SOF: return "Start of file reached"; break;
case ISAM_EOF: return "End of file reached"; break;
default: return NULL; break;
}
}
/*
* The following routine should give a lot more explanation of the nature
* of the error than it does now.
*/
int isam_perror(const char *str)
{
/*
* STEP 1: instead of printing an error number, print textual
* representation for every possible error.
*/
if( str ) {
fprintf(stderr, "%s: %s (%d)", str, isam_strerror(isam_error),
isam_error);
}
else {
fprintf(stderr, "isam_perror: %s (%d)",
isam_strerror(isam_error), isam_error);
}
fprintf(stderr, "\n");
return 0;
}
/*
* isam_delete will delete a record if - it exists, - is valid - key and
* data match
*/
int
isam_delete(isamPtr isam_ident, const char *key, const void *data)
{
unsigned long block_no;
int rec_no;
unsigned long next, prev, prev_valid;
int iCache;
int rv;
int keep_link = 0;
int prev_block_no, prev_rec_no, pCache;
int next_block_no, next_rec_no, nCache;
int prev_valid_block_no, prev_valid_rec_no, pvCache;
if (testPtr(isam_ident)) {
return -1;
}
if (key[0] == 0) {
isam_error = ISAM_NULL_KEY;
return -1;
}
/*
* First find block number from index
*/
block_no = index_keyToBlock(isam_ident->index, key);
rec_no = 0;
/*
* Now make sure the block is in cache
*/
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
/*
* Skip all records with smaller keys
*/
while ((rv = strncmp(key, key((*isam_ident), iCache, rec_no),
isam_ident->fHead.KeyLen)) > 0) {
next = head((*isam_ident), iCache, rec_no)->next;
debugRecord(isam_ident, next, "delete #1");
if (!next) {
/*
* There is no next record
*/
break;
}
block_no = next / isam_ident->fHead.NrecPB;
rec_no = next % isam_ident->fHead.NrecPB;
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
}
/*
* Now either rv != 0 - in which case there is no matching key,
* independent of next being zero or not, or rv == 0, in which case at
* least the key matches
*/
if (rv || !(head(*isam_ident, iCache, rec_no)->statusFlags & ISAM_VALID)) {
isam_error = ISAM_NO_SUCH_KEY;
return -1;
}
/*
* So the key matches and the record is valid, now see if the data match.
* The data may not be strings - so compare the full length. So the user
* must beware to include the same junk in the remainder of a data field,
* if it happens to be a string (isam_readByKey will take care of that)
*/
if (memcmp(data, data(*isam_ident, iCache, rec_no),
isam_ident->fHead.DataLen)) {
isam_error = ISAM_DATA_MISMATCH;
return -1;
}
/*
* So we can now delete the record. Begin by marking it "deleted"
*/
head(*isam_ident, iCache, rec_no)->statusFlags = ISAM_DELETED;
isam_ident->fHead.FileState |= ISAM_STATE_UPDATING;
isam_ident->fHead.Nrecords--;
if (writeHead(isam_ident)) {
return -1;
}
if ((rec_no == 0) && (block_no < isam_ident->fHead.Nblocks)) {
/*
* This record occurs in the index, so we only mark it as deleted, but
* keep it in the linked list
*/
keep_link = 1;
if (write_cache_block(isam_ident, iCache)) {
return -1;
}
}
/*
* We'll need two kinds of preceding record - the immediately preceding
* (which will always exist), and the preceding valid (which may exist).
* The latter is needed to reposition the cur_id and the cur_block_no.
* Let's begin with the preceding. The record cannot be the dummy first,
* so there must be a previous record.
*/
next = head(*isam_ident, iCache, rec_no)->next;
prev = head(*isam_ident, iCache, rec_no)->previous;
prev_block_no = prev / isam_ident->fHead.NrecPB;
prev_rec_no = prev % isam_ident->fHead.NrecPB;
pCache = isam_cache_block(isam_ident, prev_block_no);
if (pCache < 0) {
return -1;
}
prev_valid = prev;
prev_valid_block_no = prev_block_no;
prev_valid_rec_no = prev_rec_no;
pvCache = pCache;
isam_ident->cur_id = pvCache;
isam_ident->cur_recno = prev_valid_rec_no;
if (!keep_link) {
cur_head(*isam_ident)->next = next;
if (write_cache_block(isam_ident, pCache)) {
return -1;
}
/*
* The next record need not exist (we may have deleted the last)
*/
if (next) {
next_block_no = next / isam_ident->fHead.NrecPB;
next_rec_no = next % isam_ident->fHead.NrecPB;
nCache = isam_cache_block(isam_ident, next_block_no);
if (nCache < 0) {
return -1;
}
head(*isam_ident, nCache, next_rec_no)->previous = prev;
if (write_cache_block(isam_ident, nCache)) {
return -1;
}
}
else {
/*
* This is likely to be the record with the maxKey; if it is,
* maxKey must be set to that of the preceding record.
*/
if (!strncmp
(key, isam_ident->maxKey, isam_ident->fHead.KeyLen)) {
memcpy(isam_ident->maxKey,
key(*isam_ident, pCache, prev_rec_no),
isam_ident->fHead.KeyLen);
isam_ident->fHead.MaxKeyRec = prev;
}
}
/*
* Now clear all status flags, but first ensure that the record
* still/again is cached.
*/
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
head(*isam_ident, iCache, rec_no)->statusFlags = 0;
if (write_cache_block(isam_ident, iCache)) {
return -1;
}
}
isam_ident->fHead.FileState &= ~ISAM_STATE_UPDATING;
if (writeHead(isam_ident)) {
return -1;
}
/*
* Now make sure the previous valid record is found and cached
*/
pvCache = isam_cache_block(isam_ident, prev_valid_block_no);
if (pvCache < 0) {
return -1;
}
while (prev_valid
&& (!(cur_head(*isam_ident)->statusFlags & ISAM_VALID))) {
prev_valid = cur_head(*isam_ident)->previous;
prev_valid_block_no = prev_valid / isam_ident->fHead.NrecPB;
prev_valid_rec_no = prev_valid % isam_ident->fHead.NrecPB;
pvCache = isam_cache_block(isam_ident, prev_valid_block_no);
if (pvCache < 0) {
return -1;
}
isam_ident->cur_id = pvCache;
isam_ident->cur_recno = prev_valid_rec_no;
}
return 0;
}
/*
* STEP 5: Updating a record effectively has the same effect as first
* deleting it, and the rewriting it again (though the resulting file
* structure may be different). Here we choose the quick-and-dirty
* implementation, deleting and writing. The correct and more efficient
* implementation, where far fewer records need to be written, is left as
* an exercise.
*/
int
isam_update(isamPtr isam_ident, const char *key, const void *old_data,
const void *new_data)
{
#ifdef OPTIMISED
int block_no;
int rec_no;
unsigned long next;
int iCache;
if (testPtr(isam_ident)) {
return -1;
}
else if (!key[0]) {
isam_error = ISAM_NULL_KEY;
return -1;
}
/*
* Find key
*/
/*
* First find block number from index
*/
block_no = index_keyToBlock(isam_ident->index, key);
rec_no = 0;
/*
* Now make sure the block is in cache
*/
if ((iCache = isam_cache_block(isam_ident, block_no)) < 0)
return -1;
/*
* Skip all records with smaller keys
*/
while (strncmp(key, key((*isam_ident),iCache,rec_no),
isam_ident->fHead.KeyLen) > 0) {
/*
* There is no next record
*/
if (!(next = head((*isam_ident),iCache,rec_no)->next))
break;
block_no = next / isam_ident->fHead.NrecPB;
rec_no = next % isam_ident->fHead.NrecPB;
if ((iCache = isam_cache_block(isam_ident, block_no)) < 0)
return -1;
}
/*
* Current key is not exact match
*/
if (strncmp(key, key((*isam_ident),iCache,rec_no),
isam_ident->fHead.KeyLen) != 0) {
isam_error = ISAM_NO_SUCH_KEY;
return -1;
}
/*
* Deleted -- We *could* allow this
*/
else if (!(head((*isam_ident),iCache,rec_no)->statusFlags & ISAM_VALID)) {
isam_error = ISAM_NO_SUCH_KEY;
return -1;
}
/*
* 2. Update record
*/
/*
* Verify that data matches
*/
if (memcmp(data(*isam_ident, iCache, rec_no), old_data,
isam_ident->fHead.DataLen)) {
isam_error = ISAM_DATA_MISMATCH;
return -1;
}
isam_error = ISAM_NO_ERROR;
/*
* We only need to copy the data and mark the record as valid
*/
memcpy(data(*isam_ident, iCache, rec_no), new_data,
isam_ident->fHead.DataLen);
head(*isam_ident, iCache, rec_no)->statusFlags = ISAM_VALID;
/*
* 3. Write to disk
*/
isam_ident->fHead.FileState |= ISAM_STATE_UPDATING;
if (writeHead(isam_ident) ||
write_cache_block(isam_ident, iCache)) {
return -1;
}
isam_ident->fHead.FileState &= ~ISAM_STATE_UPDATING;
isam_ident->cur_id = iCache;
isam_ident->cur_recno = rec_no;
return writeHead(isam_ident);
#else
if (isam_delete(isam_ident, key, old_data)) {
return -1;
}
return isam_writeNew(isam_ident, key, new_data);
#endif
}
/*
* Like strlen, but with a maximum length allowed. There is "strnlen" in
* GNU libc, but it's non-standard, hence we provide our own version.
*/
static long
my_strnlen(const char *str, int maxLen)
{
const char *s = str;
while (maxLen-- > 0 && *s) {
s++;
}
return s - str;
}
/*
* Go through the file and collect statistics on the filling of records
* and complete blocks, separately for sequential part and for overflow
* part. Also collect statistics on the key length used.
*/
int
isam_fileStats(isamPtr isam_ident, struct ISAM_FILE_STATS *stats)
{
int iCache;
unsigned long block_no;
unsigned long keySum = 0;
unsigned long keyNo = 0;
unsigned long blocksRegularUsedSum = 0;
unsigned long blocksOverflowUsedSum = 0;
if (testPtr(isam_ident)) {
return -1;
}
/*
* Initialise statistics.
*/
stats->blocksRegularNEmpty = 0;
stats->blocksRegularNPartial = 0;
stats->blocksRegularNFull = 0;
stats->blocksRegularUsedMin = 0xffffffff;
stats->blocksRegularUsedMax = 0;
stats->blocksRegularUsedAverage = 0;
stats->recordsRegularNEmpty = 0;
stats->recordsRegularNUsed = 0;
stats->blocksOverflowNEmpty = 0;
stats->blocksOverflowNPartial = 0;
stats->blocksOverflowNFull = 0;
stats->blocksOverflowUsedMin = 0xffffffff;
stats->blocksOverflowUsedMax = 0;
stats->blocksOverflowUsedAverage = 0;
stats->recordsOverflowNEmpty = 0;
stats->recordsOverflowNUsed = 0;
stats->keyMin = -1;
stats->keyMax = 0;
stats->keyAverage = 0;
/*
* Iterate through all the blocks.
*/
for (block_no = 0; block_no < isam_ident->fHead.CurBlocks; block_no++) {
unsigned long rec_no;
unsigned long empty = 0;
unsigned long used = 0;
iCache = isam_cache_block(isam_ident, block_no);
if (iCache < 0) {
return -1;
}
/*
* Iterate through all the records in each block.
*/
for (rec_no = 0; rec_no < isam_ident->fHead.NrecPB; rec_no++) {
recordHead *rec = head(*isam_ident, iCache, rec_no);
if (rec->statusFlags & ISAM_VALID) {
/*
* Record is used. Collect key length statistics.
*/
int keyLen = my_strnlen(key(*isam_ident, iCache, rec_no),
isam_ident->fHead.KeyLen);
used++;
if (stats->keyMin == -1 || keyLen < stats->keyMin) {
stats->keyMin = keyLen;
}
if (keyLen > stats->keyMax) {
stats->keyMax = keyLen;
}
keySum += keyLen;
keyNo++;
}
else if (rec->statusFlags & ISAM_SPECIAL) {
/*
* Special null start record.
*/
used++;
}
else {
/*
* The record is empty. Either it's ISAM_DELETED (being the
* index record), or it doesn't serve any function.
*/
empty++;
}
}
/*
* Collect statistics after iterating through all the records of a
* block.
*/
if (block_no < isam_ident->fHead.Nblocks) {
/*
* Ordinary, sequential block.
*/
stats->recordsRegularNEmpty += empty;
stats->recordsRegularNUsed += used;
if (empty == isam_ident->fHead.NrecPB) {
stats->blocksRegularNEmpty++;
}
else if (used == isam_ident->fHead.NrecPB) {
stats->blocksRegularNFull++;
}
else {
stats->blocksRegularNPartial++;
}
if (stats->blocksRegularUsedMin == 0xffffffff
|| used < stats->blocksRegularUsedMin) {
stats->blocksRegularUsedMin = used;
}
if (used > stats->blocksRegularUsedMax) {
stats->blocksRegularUsedMax = used;
}
blocksRegularUsedSum += used;
}
else {
/*
* Overflow block.
*/
stats->recordsOverflowNEmpty += empty;
stats->recordsOverflowNUsed += used;
if (empty == isam_ident->fHead.NrecPB) {
stats->blocksOverflowNEmpty++;
}
else if (used == isam_ident->fHead.NrecPB) {
stats->blocksOverflowNFull++;
}
else {
stats->blocksOverflowNPartial++;
}
if (stats->blocksOverflowUsedMin == 0xffffffff
|| used < stats->blocksOverflowUsedMin) {
stats->blocksOverflowUsedMin = used;
}
if (used > stats->blocksOverflowUsedMax) {
stats->blocksOverflowUsedMax = used;
}
blocksOverflowUsedSum += used;
}
}
/*
* Collect statistics after iterating through all the records of all
* blocks. Take into account the possibility that no statistics could
* have been collected.
*/
if (stats->blocksRegularNEmpty + stats->blocksRegularNFull
+ stats->blocksRegularNPartial > 0) {
stats->blocksRegularUsedAverage = blocksRegularUsedSum /
(stats->blocksRegularNEmpty + stats->blocksRegularNFull +
stats->blocksRegularNPartial);
}
if (stats->blocksOverflowNEmpty + stats->blocksOverflowNFull
+ stats->blocksOverflowNPartial) {
stats->blocksOverflowUsedAverage = blocksOverflowUsedSum /
(stats->blocksOverflowNEmpty + stats->blocksOverflowNFull +
stats->blocksOverflowNPartial);
}
if (keyNo > 0) {
stats->keyAverage = keySum / keyNo;
}
if (stats->blocksRegularUsedMin == 0xffffffff) {
stats->blocksRegularUsedMin = 0;
}
if (stats->blocksOverflowUsedMin == 0xffffffff) {
stats->blocksOverflowUsedMin = 0;
}
/*
* Leave the ISAM file in a well defined state.
*/
iCache = isam_cache_block(isam_ident, 0);
if (iCache < 0) {
return -1;
}
isam_ident->cur_id = iCache;
isam_ident->cur_recno = 0;
return 0;
}
/*
* Return collected statistics about cache performance
* stored in the static cstat structure
*/
int isam_cacheStats(struct ISAM_CACHE_STATS *stats)
{
assert(stats);
(*stats) = cstat;
return 0;
}
#ifndef ISAM_H
#define ISAM_H
/* -------------------------------------------------------------------------
Author: G.D. van Albada
University of Amsterdam
Faculty of Science
Informatics Institute
Copyright (C) Universiteit van Amsterdam
dick at science.uva.nl
Version: 0.1
Date: December 2001 / January 2002 / November 2004
Goal: Part of an assignment on file system structure for the operating
systems course. It demonstrates many of the administrative and layering
structures that are also used in normal file systems.
--------------------------------------------------------------------------*/
typedef struct ISAM *isamPtr;
struct ISAM_FILE_STATS;
struct ISAM_CACHE_STATS;
/* isam_create will create an isam_file, but only if a file of that name
does not yet exist.
The parameters are:
name: name of the file, possibly including directory information
key_len: maximum length of the (character string) key.
data_len: length of the data field
NrecPB: number of records that should be put into one block (including
one overflow record per block).
Nblocks: The number of regular data blocks = number of entries in the
index
isam_create will return an isamPtr on success, NULL on failure
*/
isamPtr isam_create(const char *name, unsigned long key_len,
unsigned long data_len, unsigned long NrecPB, unsigned long Nblocks);
/* isam_open will open an existing isam file.
The parameters are:
name: name of the file, possibly including directory information
update: (not used) when != 0 the file is opened for reading and writing
(it actually always is).
isam_open will return an isamPtr on success, NULL on failure
*/
isamPtr isam_open(const char *name, int update);
/* isam_close will close a previously opened/created isam_file
The parameters are:
isam_ident: the isamPtr for the file.
isam_close will return 0 on success, -1 on failure.
*/
int isam_close(isamPtr isam_ident);
/* isam_setKey will position an isam file on the last valid record with
a key smaller than the requested key, such that the next call to
isam_readNext will return the record with the given key, if it exists.
If no such record exists, the first record with a larger key will
be returned, if that exists.
The parameters are:
isam_ident: the isamPtr for the file.
key: a string containing the requested key.
isam_setKey will return 0 on success, -1 on failure.
*/
int isam_setKey(isamPtr isam_ident, const char *key);
/* isam_readNext will read the next valid record, if that exists.
The parameters are:
isam_ident: the isamPtr for the file.
key: a character array where the key will be stored.
data: pointer to the location where the data are to be stored.
isam_readNext will return 0 on success, -1 on failure.
*/
int isam_readNext(isamPtr isam_ident, char *key, void *data);
/* isam_readPrev will read the current record, if that exists and is valid and
afterwards position the file at the preceding valid record, if that exists.
The parameters are:
isam_ident: the isamPtr for the file.
key: a character array where the key will be stored.
data: pointer to the location where the data are to be stored.
isam_readPrev will return 0 on success, -1 on failure.
*/
int isam_readPrev(isamPtr isam_ident, char *key, void *data);
/* isam_readByKey will try to read a record with the requested key. It behaves
like an isam_setKey followed by an isam_readNext plus a check that the
requested key and the retrieved key are the same.
The parameters are:
isam_ident: the isamPtr for the file.
key: a string containing the requested key.
data: pointer to the location where the data are to be stored.
isam_readByKey will return 0 on success, -1 on failure.
*/
int isam_readByKey(isamPtr isam_ident, const char *key, void *data);
/* isam_update will replace the data field for a record with the given key,
if such a record exists. As a security measure, it will verify that the
user has the correct original data.
The parameters are:
isam_ident: the isamPtr for the file.
key: a string containing the requested key.
old_data: a pointer to a location containing a copy of the data that
the record should contain before modification.
new_data: the new data to be stored in the record.
isam_update will return 0 on success, -1 on failure.
*/
int isam_update(isamPtr isam_ident, const char *key, const void *old_data,
const void *new_data);
/* isam_writeNew will write a new record to the file, but only if the key is
not yet in use.
The parameters are:
isam_ident: the isamPtr for the file.
key: a string containing the new key.
data: the data to be stored in the new record.
isam_writeNew will return 0 on success, -1 on failure.
*/
int isam_writeNew(isamPtr isam_ident, const char *key, const void *data);
/* isam_delete will delete the record with the given key. As a security
measure, it will verify that the user has the correct original data.
The parameters are:
isam_ident: the isamPtr for the file.
key: a string containing the key of the record to be deleted.
data: a pointer to a location containing a copy of the data that
the record should contain before deletion.
isam_delete will return 0 on success, -1 on failure.
*/
int isam_delete(isamPtr isam_ident, const char *key, const void *data);
/* isam_fileStats will collect statistics about a given ISAM file.
The parameters are:
isam_ident: the isamPtr for the file.
stats: the structure to fill in with statistics.
isam_fileStats will return 0 on success, -1 on failure.
*/
int isam_fileStats(isamPtr isam_ident, struct ISAM_FILE_STATS* stats);
/*
* isam_cacheStats will return statistics collected throughout the usage
* of the ISAM library. These statistics are not collected per file, but
* rather give you a summary of the overall performance of the ISAM library
* cache. All statistics are per process and start at zero at process start
* time
*
* The parameters are:
* stats: A pointer to an ISAM_CACHE_STATS structure to receive the
* collected statistics.
*/
int isam_cacheStats(struct ISAM_CACHE_STATS *stats);
/* All above routines will set the global variable isam_error when an
error occurs. Like the standard routine perror, isam_perror should
print a suitable error message to stderr, optionally preceded by the
message mess provided by the user */
int isam_perror(const char *mess);
/*
* Not all of the following errors are actually used ....
*/
enum isam_error
{
ISAM_NO_ERROR = (0),
ISAM_WRITE_FAIL,
ISAM_KEY_LEN,
ISAM_FILE_EXISTS,
ISAM_LINK_EXISTS,
ISAM_OPEN_FAIL,
ISAM_NO_SUCH_FILE,
ISAM_OPEN_COUNT,
ISAM_INDEX_ERROR,
ISAM_READ_ERROR,
ISAM_BAD_MAGIC,
ISAM_BAD_VERSION,
ISAM_HEADER_ERROR,
ISAM_OPEN_FOR_UPDATE,
ISAM_IDENT_INVALID,
ISAM_NO_SUCH_KEY,
ISAM_NULL_KEY,
ISAM_DATA_MISMATCH,
ISAM_RECORD_EXISTS,
ISAM_SEEK_ERROR,
ISAM_SOF,
ISAM_EOF
};
extern enum isam_error isam_error;
/*
* Statistics obtained using isam_fileStats.
*/
struct ISAM_FILE_STATS
{
/* Statistics for regular (sequential) blocks. */
unsigned long blocksRegularNEmpty; /* # of totally empty blocks */
unsigned long blocksRegularNPartial; /* # of partially occupied blocks. */
unsigned long blocksRegularNFull; /* # of fully occupied blocks. */
unsigned long blocksRegularUsedMin; /* Smallest observed number of
used records in a block. */
unsigned long blocksRegularUsedMax; /* Largest observed number of
used records in a block. */
unsigned long blocksRegularUsedAverage; /* Average number of used records
in a block (floor). */
unsigned long recordsRegularNEmpty; /* # of empty records. */
unsigned long recordsRegularNUsed; /* # of used records. */
/* Same as above, but for overflow blocks. */
unsigned long blocksOverflowNEmpty;
unsigned long blocksOverflowNPartial;
unsigned long blocksOverflowNFull;
unsigned long blocksOverflowUsedMin;
unsigned long blocksOverflowUsedMax;
unsigned long blocksOverflowUsedAverage;
unsigned long recordsOverflowNEmpty;
unsigned long recordsOverflowNUsed;
/* Statistics for key length. */
int keyMin; /* Smallest observed key length */
int keyMax; /* Largest observed key length */
int keyAverage; /* Average key length (floor) */
};
/*
* Cache statistics obtained through isam_cacheStats()
*/
struct ISAM_CACHE_STATS
{
int
calls, /* Times the cache got called */
reads, /* Times we needed to read from disk */
writes, /* Times we wrote to it */
hwrites; /* Times we wrote a header */
};
#endif
/* A simple program to benchmark an isam file system
-------------------------------------------------
Author: G.D. van Albada
University of Amsterdam
Faculty of Science
Informatics Institute
dick at science.uva.nl
Version: 0.0
Date: January 2002 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "isam.h"
typedef struct KLANT
{
char naam[64];
char voorvoegsel[16];
char initialen[16];
char titel[16];
unsigned long klantSinds; /* Dag na 1/1/1900 */
unsigned long laatsteMailing; /* Dag na 1/1/1900 */
unsigned long laatsteBestelling;
unsigned long nummerBestelling;
} klant;
static char initialen[500][16];
static int Ninit = 0;
typedef struct NAAM
{
char naam[64];
char voorvoegsel[16];
} naam;
static naam namen[500];
static int Nnamen = 0;
static char titels[64][16];
static int Ntitels = 0;
static char sleutels[9000][20];
static int Nsleutels = 0;
static int report = 0;
/*
* Bereken dagnummer met 1/1/1900 == 1
* Routine faalt op en na 1/3/2100
*/
static long
berekenDag(int dag, int maand, int jaar)
{
long dagen;
dagen = dag;
dagen += 365 * (jaar - 1900) + (jaar - 1901) / 4;
switch (maand) {
case 12:
dagen += 30;
case 11:
dagen += 31;
case 10:
dagen += 30;
case 9:
dagen += 31;
case 8:
dagen += 31;
case 7:
dagen += 30;
case 6:
dagen += 31;
case 5:
dagen += 30;
case 4:
dagen += 31;
case 3:
dagen += ((0 == jaar % 4) && jaar > 1900) ? 29 : 28;
case 2:
dagen += 31;
case 1:
break;
default:
return -1;
}
return dagen;
}
/*
* Print klant-informatie
*/
static void
printKlant(FILE * log, char *kop, char *sleutel, klant * Klant)
{
if (kop) {
fprintf(log, "%s\n", kop);
}
fprintf(log, "%s \t||%s %s %s %s\t%lu\t%lu\t%lu\t%lu\n",
sleutel, Klant->titel, Klant->initialen,
Klant->voorvoegsel, Klant->naam,
Klant->klantSinds, Klant->laatsteMailing,
Klant->laatsteBestelling, Klant->nummerBestelling);
}
/*
* Maak een random klant
*/
static void
maakKlant(klant *nieuweKlant)
{
int i, dag, maand, jaar;
if (Nnamen) {
i = lrand48() % Nnamen;
strncpy(nieuweKlant->naam, namen[i].naam, 64);
strncpy(nieuweKlant->voorvoegsel, namen[i].voorvoegsel, 16);
}
if (Ninit) {
i = lrand48() % Ninit;
strncpy(nieuweKlant->initialen, initialen[i], 16);
}
if (Ntitels) {
i = lrand48() % Ntitels;
strncpy(nieuweKlant->titel, titels[i], 16);
}
jaar = 1950 + lrand48() % 52;
dag = lrand48() % 29;
maand = 1 + lrand48() % 12;
nieuweKlant->klantSinds = berekenDag(dag, maand, jaar);
jaar = 2001;
nieuweKlant->laatsteMailing = berekenDag(dag, maand, jaar);
jaar = 1998 + lrand48() % 4;
nieuweKlant->laatsteBestelling = berekenDag(dag, maand, jaar);
nieuweKlant->nummerBestelling = 100 * nieuweKlant->laatsteBestelling
+ lrand48() % 95;
return;
}
static int code = 1000;
/*
* Maak een random sleutel, dichtbij de postcode in "code". Verhoog code.
* Sleutel is een postcode plus huisnummer.
*/
static int
maakSleutel(char *sleutel)
{
int huisnummer;
code += lrand48() % 8;
/*
* maak een huisnummer tot 53, met een voorkeur voor lage nummers.
*/
huisnummer = lrand48() % 30 + lrand48() % 25;
huisnummer -= lrand48() % 30 + lrand48() % 25;
huisnummer = (huisnummer <= 0) ? (1 - huisnummer) : huisnummer;
sprintf(sleutel, "%4d %c%c - %4d", code, (char) ('A' + lrand48 () % 26),
(char) ('A' + lrand48 () % 26), huisnummer);
return (code < 9999);
}
/*
* Schrijf een nieuw record op een willekeurige plek in het bestand
*/
static int
randomNieuwRecord(isamPtr ip)
{
char sleutel[20];
klant nieuweKlant;
int rv;
memset(&nieuweKlant, 0, sizeof(nieuweKlant));
memset(sleutel, 0, sizeof(sleutel));
do {
code = 1000 + lrand48() % 8990;
maakSleutel(sleutel);
}
while (0 == isam_readByKey(ip, sleutel, &nieuweKlant));
maakKlant(&nieuweKlant);
rv = isam_writeNew(ip, sleutel, &nieuweKlant);
if (rv && report) {
isam_perror("write new client record");
}
else {
strncpy(sleutels[Nsleutels], sleutel, 20);
}
Nsleutels++;
return Nsleutels;
}
/*
* Lees sequentieel alle records in bepaald sleutelbereik, en pleeg een
* bewerking
*/
static int
leesBereik(isamPtr ip, char *minSleutel, char *maxSleutel, int datum)
{
char sleutel[20];
char vorigeSleutel[20] = "";
int i = 0;
int j = 0;
int rv;
klant klantRecordOud;
klant klantRecordNieuw;
/*
* Net als bij het plegen van een mailing
*/
isam_setKey(ip, minSleutel);
do {
rv = isam_readNext(ip, sleutel, &klantRecordOud);
if (rv) {
isam_perror("reading next record");
break;
}
if (strncmp(sleutel, vorigeSleutel, 20) <= 0) {
printf("Sleutels staan verkeerd gesorteerd: %s komt voor %s\n",
vorigeSleutel, sleutel);
}
if (strncmp(sleutel, maxSleutel, 20) > 0)
break;
i++;
if (report) {
printKlant(stderr, NULL, sleutel, &klantRecordOud);
}
if ((int) klantRecordOud.laatsteMailing < datum - 200) {
klantRecordNieuw = klantRecordOud;
klantRecordNieuw.laatsteMailing = datum;
/*
* Nog te controleren: Lees ik na een update wel het direct
* volgende record?
*/
rv = isam_update(ip, sleutel, &klantRecordOud,
&klantRecordNieuw);
if (rv) {
isam_perror("updating record");
break;
}
j++;
}
}
while (strncmp(sleutel, maxSleutel, 20) <= 0);
printf("Er zijn %d records gelezen; mailings zijn verzonden aan %d\n",
i, j);
return i;
}
int
leesBestaandRecord(isamPtr ip, int sleutelNr)
{
klant klantRecord;
int rv;
/*
* Als klantgegevens uitvragen
*/
rv = isam_readByKey(ip, sleutels[sleutelNr], &klantRecord);
if (rv && report) {
isam_perror("reading a record by key");
}
return rv;
}
int
poetsBestaandRecord(isamPtr ip, int sleutelNr)
{
klant klantRecord;
int rv;
/*
* Als klantgegevens wissen
*/
rv = isam_readByKey(ip, sleutels[sleutelNr], &klantRecord);
if (rv) {
if (report)
isam_perror("reading a record by key");
return rv;
}
rv = isam_delete(ip, sleutels[sleutelNr], &klantRecord);
if (rv) {
isam_perror("deleting a record by key");
}
return rv;
}
int
main(int argc, char *argv[])
{
isamPtr ip;
FILE *inp;
char sleutel[20] = { 0 };
klant nieuweKlant;
klant oudeKlant;
char str[512];
int i, j;
struct ISAM_CACHE_STATS initStats, stats, bsStats;
memset(&nieuweKlant, 0, sizeof(nieuweKlant));
/*
* Lees het bestand met namen (en voorvoegsels)
*/
srand48(171717);
if (argc < 4) {
printf("Gebruik: %s namen initialen titels [optional-debug]\n",
argv[0]);
return -1;
}
if (argc == 5) {
report = 1;
printf("Produceer meer debug uitvoer\n");
}
inp = fopen(argv[1], "r");
if (inp) {
i = 0;
printf("Lees namen van %s\n", argv[1]);
while (fgets(str, 512, inp)) {
strncpy(namen[i].naam, strtok(str, ";\t\n"), 64);
strncpy(namen[i].voorvoegsel, strtok(NULL, ";\t\n"), 16);
i++;
}
fclose(inp);
Nnamen = i;
}
else {
perror("Failed to open names file");
exit(-1);
}
/*
* Lees het bestand met initialen
*/
inp = fopen(argv[2], "r");
if (inp) {
i = 0;
printf("Lees initialen van %s\n", argv[2]);
while (fgets(str, 512, inp)) {
strncpy(initialen[i], strtok(str, "\n"), 16);
i++;
}
fclose(inp);
Ninit = i;
}
else {
perror("Failed to open initials file");
exit(-1);
}
/*
* Lees het bestand met titels
*/
inp = fopen(argv[3], "r");
if (inp) {
i = 0;
printf("Lees titels van %s\n", argv[3]);
while (fgets(str, 512, inp)) {
strncpy(titels[i], strtok(str, "\n"), 16);
i++;
}
fclose(inp);
Ntitels = i;
}
else {
perror("Failed to open titles file");
exit(-1);
}
/*
* Probeer een isam bestand aan te maken. Als dat mislukt, bestaat het
* mogelijk al - probeer het dan te lezen
*/
ip = isam_create("klant.isam", 20, sizeof(klant), 8, 360);
if (!ip) {
/*
* Mislukt ... bestaat het al ?
*/
isam_perror("Failed to create file");
ip = isam_open("klant.isam", 1);
if (!ip) {
isam_perror("Failed to open file");
exit(-1);
}
/*
* Lees alle sleutels
*/
for(i = 0; 0 == isam_readNext(ip, sleutels[i], &nieuweKlant); i++);
Nsleutels = i;
printf("Bestaand bestand met %d records geopend\n", Nsleutels);
}
else {
/*
* Vul het bestand, min of meer sequentieel
*/
i = 0;
while (maakSleutel(sleutel)) {
maakKlant(&nieuweKlant);
if (isam_writeNew(ip, sleutel, &nieuweKlant)) {
isam_perror("Failed to create customer record");
}
else {
if (report) {
printKlant(stdout, NULL, sleutel, &nieuweKlant);
}
strncpy(sleutels[i], sleutel, 20);
i++;
}
}
printf("Isam bestand bevat %d records\n", i);
Nsleutels = i;
/*
* Dit hoeft niet, maar test open en close
*/
isam_close(ip);
ip = isam_open("klant.isam", 1);
}
isam_cacheStats(&initStats);
printf("Stats after opening isam file...\n");
printf("calls: %d\nreads: %d\nwrites: %d\nhwrites: %d\n\n", initStats.calls,
initStats.reads, initStats.writes, initStats.hwrites);
/*
* Doe een aantal bewerkingen op het bestand -
* lees sequentieel plus update
* lees op sleutel
* poets
* schrijf nieuw
*/
leesBereik(ip, "2300", "4500", berekenDag (25, 1, 2002));
for (i = 0, j = 0; i < 500; i++) {
if (leesBestaandRecord(ip, lrand48 () % Nsleutels))
j++;
}
printf("%d records gelezen, %d mislukt\n", i, j);
for (i = 0, j = 0; i < 200; i++) {
if (poetsBestaandRecord(ip, lrand48 () % Nsleutels))
j++;
randomNieuwRecord(ip);
}
printf("%d nieuwe klanten, %d vertrokken\n", i, i - j);
leesBereik(ip, "2300", "4500", berekenDag (25, 1, 2002));
for (i = 0, j = 0; i < 500; i++) {
if (leesBestaandRecord(ip, lrand48 () % Nsleutels))
j++;
}
printf("%d records gelezen, %d mislukt\n", i, j);
for (i = 0, j = 0; i < 200; i++) {
if (poetsBestaandRecord(ip, lrand48 () % Nsleutels))
j++;
randomNieuwRecord(ip);
}
printf("%d nieuwe klanten, %d vertrokken\n", i, i - j);
leesBereik(ip, "2300", "4500", berekenDag (25, 1, 2002));
for (i = 0, j = 0; i < 500; i++) {
if (leesBestaandRecord(ip, lrand48 () % Nsleutels))
j++;
}
printf ("%d records gelezen, %d mislukt\n", i, j);
for (i = 0, j = 0; i < 200; i++) {
if (poetsBestaandRecord(ip, lrand48 () % Nsleutels))
j++;
randomNieuwRecord(ip);
}
printf ("%d nieuwe klanten, %d vertrokken\n", i, i - j);
leesBereik(ip, "1000", "9999", berekenDag(25, 1, 2002));
leesBereik(ip, "1000", "9999", berekenDag(25, 1, 2002));
isam_cacheStats(&bsStats);
printf("Stats after Dick Albada's benchmark...\n");
printf("calls: %d\nreads: %d\nwrites: %d\nhwrites: %d\n\n",
bsStats.calls - initStats.calls,
bsStats.reads - initStats.reads,
bsStats.writes - initStats.writes,
bsStats.hwrites - initStats.hwrites);
/*
* Sequentieel lezen
*/
isam_setKey(ip, sleutels[0]);
i = 0;
while (0 == isam_readNext(ip, sleutels[i], &nieuweKlant))
i++;
/*
* Veel readBykey()
*/
for(i = 0; i < 1000; i++) {
maakSleutel(sleutel);
isam_readByKey(ip, sleutel, &nieuweKlant);
}
/*
* flink aantal update
*/
for(i = 0; i < 400; i++) {
j = lrand48() % Nsleutels;
isam_readByKey(ip, sleutels[j], &oudeKlant);
maakKlant(&nieuweKlant);
isam_update(ip, sleutels[j], &oudeKlant, &nieuweKlant);
}
/*
* Write 100 new records
*/
for(i = 0; i < 100; i++)
randomNieuwRecord(ip);
/*
* Delete keys (at the end)
*/
for(i = 0; i < 100; i++) {
j = Nsleutels - 1;
isam_readByKey(ip, sleutels[j], &nieuweKlant);
isam_delete(ip, sleutels[j], &nieuweKlant);
Nsleutels--;
}
printf("Stats after benchmarking:\n1000 readByKey\n400 update\n");
printf("100 writes\n100 delete\n\n");
isam_cacheStats(&stats);
printf("calls: %d\nreads: %d\nwrites: %d\nhwrites: %d\n",
stats.calls - bsStats.calls - initStats.calls,
stats.reads - bsStats.reads - initStats.reads,
stats.writes - bsStats.writes - initStats.writes,
stats.hwrites - bsStats.hwrites - initStats.hwrites);
isam_close(ip);
return 0;
}
/* This file contains the source for a very basic program to test the
isam library.
The program should be linked with the isam.o and index.o files.
To run it, give it one parameter: the isam file. If no such file
exists, it will be created.
The program will ask for a key; if no record with that key exists,
you will be allowed to create it, otherwise you are offered several
possibilities.
-------------------------------------------------------------------------
Author: G.D. van Albada
University of Amsterdam
Faculty of Science
Informatics Institute
dick at science.uva.nl
Version: 0.0
Date: December 2001 / January 2002
-------------------------------------------------------------------------
The program should not be considered to be a good example of production
code - it lacks comments, naming is ad-hoc, etc.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "isam.h"
void
instruct(void)
{
char str[256];
printf("Do you want instuctions? (y/n) [y]\n");
if (!fgets(str, 256, stdin)) {
printf("Stopping program\n");
exit(0);
}
if (str[0] != 'y' && str[0] != 'Y' && str[0] != 'j' && str[0] != 'J')
return;
printf("This program allows you to test your isam routines.\n");
printf("Run it as\n");
printf("isam_test file_name\n");
printf("If a file file_name exists, isam_test will open it.\n");
printf(" (if the format and magic number is correct)\n");
printf("If it does not exist, isam_test will try to create a \n");
printf("file of that name.\n");
printf("Next, isam_test will enter a loop in which it\n");
printf("1. asks for a key value.\n");
printf("2. attempts to read a record with that key from the file.\n");
printf
("3. if it succeeds, it will ask you if you want to delete or\n");
printf(" modify the record.\n");
printf
("4. if it fails, isam_test will allow you to create a new record.\n");
printf
("Isam_test leaves the loop only at the end of the input file.\n");
printf("Type a [ctrl]D to generate such an EOF from your keyboard.\n");
printf("The program can be made to execute illegal actions, like\n");
printf("creating a record with an existing key, or deleting a\n");
printf("non-existent record by specifying a second command-line\n");
printf("parameter. If this parameter is numerical with value N,\n");
printf("an illegal command will be generated every 1 in N\n");
printf("commands; otherwise N will be set to 4\n");
printf("\n");
}
int
main(int argc, char *argv[])
{
int rv, i;
char key[17], data[68], dat[68], str[256];
char keyx[17];
int N_illegal = 4, count;
isamPtr fd;
instruct();
if (argc < 2) {
printf("isam_test needs one (file) argument\n");
exit(23);
}
printf("Calling isam_open for %s\n", argv[1]);
fd = isam_open(argv[1], 1);
printf("Isam_open returned %p\n", fd);
if (fd == NULL) {
isam_perror("I.e.");
if (isam_error == ISAM_NO_SUCH_FILE
|| isam_error == ISAM_OPEN_FAIL) {
printf("Now attempting to use isam_create\n");
fd = isam_create(argv[1], 17, 68, 12, 160);
printf("Isam_create returned %p\n", fd);
if (fd == NULL) {
isam_perror("I.e.");
printf("Stopping program\n");
exit(-3);
}
}
else {
printf("Stopping program\n");
exit(-3);
}
}
if (argc == 3) {
sscanf(argv[2], "%d", &N_illegal);
N_illegal = (N_illegal < 2) ? 2 : N_illegal;
printf("Attempting an illegal action every 1 out of %d times\n",
N_illegal);
}
else {
N_illegal = 1 << 30;
}
printf("Give key >");
count = 1;
while (fgets(str, 256, stdin)) {
i = strlen(str);
while (i && str[i] < ' ') {
str[i] = '\0';
i--;
}
str[16] = '\0';
strcpy(key, str);
rv = isam_readByKey(fd, key, data);
if (rv) {
isam_perror("Not found");
printf("No record with key '%s' found\n", key);
}
else {
printf("Key: '%s'\nData: '%s'\n", key, data);
}
if (count++ >= N_illegal) {
count = 1;
rv = (rv) ? 0 : -1;
printf("Attempting illegal action - beware!\n");
}
if (rv) {
printf("Create a record with key '%s' ?\n", key);
if (!fgets(str, 256, stdin)) {
printf("Stopping program\n");
if (isam_close(fd)) {
isam_perror("Isam_closed failed miserably");
}
exit(0);
}
if (str[0] == 'y' || str[0] == 'Y') {
for (i = 0; i < 68; i++)
data[i] = '#';
printf("Give data >");
if (!fgets(str, 256, stdin)) {
printf("Stopping program\n");
if (isam_close(fd)) {
isam_perror("Isam_closed failed miserably");
}
exit(0);
}
i = strlen(str);
while (i && str[i] < ' ') {
str[i] = '\0';
i--;
}
str[67] = '\0';
for (i = 0; i < 68; i++)
data[i] = '#';
strcpy(data, str);
if (isam_writeNew(fd, key, data))
isam_perror("Error in isam_writeNew");
}
else {
strcpy(keyx, key);
isam_setKey(fd, key);
rv = isam_readNext(fd, key, data);
printf("Next record:");
if (rv) {
isam_perror("Not found");
printf("No record with key > '%s' found\n", key);
} else {
printf("Key: '%s'\nData: '%s'\n", key, data);
}
isam_setKey(fd, keyx);
rv = isam_readPrev(fd, key, data);
printf("Preceding record:");
if (rv) {
isam_perror("Not found");
printf("No record with key < '%s' found\n", keyx);
}
else {
printf("Key: '%s'\nData: '%s'\n", key, data);
}
}
}
else {
nogeens:
printf
("[N]ext, [P]revious, [D]elete or [U]pdate record with this key?\n");
if (!fgets(str, 256, stdin)) {
printf("Stopping program\n");
if (isam_close(fd)) {
isam_perror("Isam_closed failed miserably");
}
exit(0);
}
if (count++ >= N_illegal) {
count = 1;
data[0]++;
data[17] = '\0';
printf("Attempting illegal action - beware!\n");
}
switch (str[0]) {
case 'd':
case 'D':
if (isam_delete(fd, key, data))
isam_perror("Error in isam_delete");
break;
case 'u':
case 'U':
printf("Give data >");
if (!fgets(str, 256, stdin)) {
printf("Stopping program\n");
if (isam_close(fd)) {
isam_perror("Isam_closed failed miserably");
}
exit(0);
}
i = strlen(str);
while (i && str[i] < ' ') {
str[i] = '\0';
i--;
}
str[67] = '\0';
for (i = 0; i < 68; i++)
dat[i] = '#';
strcpy(dat, str);
if (isam_update(fd, key, data, dat))
isam_perror("Error in isam_update");
break;
case 'n':
case 'N':
rv = isam_readNext(fd, key, data);
printf("Next record:");
if (rv) {
isam_perror("Not found");
printf("No record with key > '%s' found\n", key);
break;
}
else {
printf("Key: '%s'\nData: '%s'\n", key, data);
}
goto nogeens;
case 'p':
case 'P':
rv = isam_readPrev(fd, key, data);
printf("Preceding record:");
if (rv) {
isam_perror("Not found");
printf("No record with key < '%s' found\n", key);
break;
}
else {
printf("Key: '%s'\nData: '%s'\n", key, data);
}
goto nogeens;
}
}
printf("Give key >");
}
printf("Normal end of programme\n");
isam_close(fd);
return 0;
}
Aarnoudse; ;
Afsarmanesh; ;
Akker;van den ;
Al-Dabass; ;
Alava; ;
Albada;van ;
Albright; ;
Alexandrov; ;
Allen; ;
Amersfoort;van ;
Apers; ;
Arlabosse; ;
Artoli; ;
Aten; ;
Athanassoula; ;
Atherton; ;
Baerends; ;
Baggio; ;
Bajaja; ;
Baker; ;
Bal; ;
Ballintijn; ;
Bartosek; ;
Bauckhage; ;
Baud; ;
Beemster; ;
Belleman; ;
Belloum; ;
Bergman; ;
Bernhardt; ;
Bhoedjang; ;
Binder; ;
Blaak; ;
Blom; ;
Blume; ;
Boasson; ;
Bode; ;
Boer;den ;
Bontekoe; ;
Boonand; ;
Boulanger; ;
Bouten; ;
Braan; ;
Braekman; ;
Brebbia; ;
Breeman; ;
Brinkhorst; ;
Brummen;van ;
Bubak; ;
Buchner; ;
Buyya; ;
Capasso; ;
Carbone; ;
Carels; ;
Chen; ;
Cheng; ;
Chylek; ;
Clague; ;
Clinckemaillie; ;
Coccia; ;
Colbrook; ;
Corperaal; ;
Coveney; ;
Crilly; ;
Cuesta; ;
Dantzig;van ;
Davier; ;
Davies; ;
Dekker; ;
Dekker; ;
Demongeot; ;
Deurloo; ;
Dijkman; ;
Dikken; ;
Dillman; ;
Doi; ;
Dongarra; ;
Donk;van der ;
Doornbos; ;
Doornbos; ;
Dorst; ;
Driel;van ;
Dubbeldam; ;
Dubois; ;
Earnshaw; ;
Ebeling; ;
Elout; ;
Emmen; ;
Epema; ;
Ercal; ;
Evans; ;
Fafone; ;
Farman; ;
Figdor; ;
Finmo; ;
Flokstra; ;
Floros; ;
Freijlink; ;
Frenkel; ;
Friedrich; ;
Frijlink; ;
Fritzon; ;
Frossati; ;
Fu; ;
Fuchs; ;
Funika; ;
Garcia-Ruiz; ;
Gaussens; ;
Gehring; ;
Gemund;van ;
Gentzsch; ;
Germans; ;
Gershon; ;
Gillet; ;
Gisbergen;van ;
Graaf;van der ;
Graaff; ;
Grandinetti; ;
Grethlein; ;
Greve; ;
Grimminck; ;
Groen; ;
Gromov; ;
Grondelle;van ;
Groot;de ;
Grooth;de ;
Gruber; ;
Gueron; ;
Guravage; ;
Haan; ;
Habing; ;
Halderen;van ;
Hamza; ;
Hanegraaff; ;
Hannema; ;
Harms; ;
Hartel; ;
Heederik; ;
Heethaar; ;
Heijboer; ;
Heijboer; ;
Heijnsdijk; ;
Heinz; ;
Hello; ;
Hendrikse; ;
Hertzberger; ;
Heuvel;van den ;
Hirleman; ;
Hirose; ;
Hoefsloot; ;
Hoekstra; ;
Hoffmann; ;
Hofman; ;
Holten;van ;
Holtslag; ;
Hossfeld; ;
Hovenier; ;
Witt-Huberts;de;
Hulst;van der ;
Hummel; ;
Huntley; ;
Huot; ;
Hussaini; ;
Hllen; ;
Iedema; ;
Inamura; ;
Ingber; ;
Iskra; ;
Jacobs; ;
Jane; ;
Jones; ;
Jonker; ;
Juliano; ;
Kaandorp; ;
Kacsuk; ;
Kaiser; ;
Kanade; ;
Kandhai; ;
Kanter;de ;
Karsch; ;
Kartawidjaja; ;
Karyadi; ;
Kasdorp; ;
Kataja; ;
Kate;ten ;
Kauranne; ;
Kempen;van ;
Kerckhoffs; ;
Kester; ;
Kielmann; ;
Kluijver;de ;
Knijnenburg; ;
Koburg; ;
Koelink; ;
Koelma; ;
Kolk;van der ;
Kommers; ;
Kong; ;
Koponen; ;
Kruit;van der ;
Krse; ;
Kuz; ;
Laak;ter ;
Laan;van der ;
Lagendijk; ;
Lagerberg; ;
Laitinen; ;
Lapiks; ;
Larriba; ;
Lauwerier; ;
LePage; ;
Leer;van ;
Lees; ;
Leeuwen;van ;
Lehmann; ;
Lemke; ;
Lew; ;
Liddell; ;
Liet;van de ;
Linden;van der ;
Lisounkin; ;
Livny; ;
Lonsdale; ;
Louis; ;
Lowe; ;
Lumme; ;
Luque; ;
Maaskant; ;
Maassen; ;
Machi'; ;
Maeda; ;
Marechal; ;
Margalef; ;
Marsh; ;
Maruszewski; ;
Matsushita; ;
Mazzitelli; ;
McEvoy; ;
Meakin; ;
Meijer; ;
Mergel; ;
Merks; ;
Mes;de ;
Metzler; ;
Meyer; ;
Michalewicz; ;
Mishchenko; ;
Mocinski; ;
Mochnacki; ;
Monien; ;
Mourabit;al ;
Muinonen; ;
Muiswinkel;van ;
Mul;de ;
Nadrachal; ;
Nazief; ;
Nieuwpoort;van ;
Nijhof; ;
Nijs;de ;
Niskanen; ;
Noga; ;
Noordmans; ;
Nooren; ;
Noteboom; ;
Obelleiro; ;
Oberski; ;
Olariu; ;
Onate; ;
Overeinder; ;
Pagter;de ;
Pallottino; ;
Pandolfi; ;
Papathanassiadis; ;
Pavelka; ;
Pedlar; ;
Peek; ;
Petersen; ;
Piech; ;
Pierre; ;
Pimentel; ;
Piskunov; ;
Pizzella; ;
Podhorszki; ;
Pol; ;
Potma; ;
Powers; ;
Pronk; ;
Prusinkiewicz; ;
Quinten; ;
Radulescu; ;
Rahola; ;
Rechenberg; ;
Reeuwijk;van ;
Reeve; ;
Reinefeld; ;
Rembold; ;
Renambot; ;
Renes; ;
Renner; ;
Roberts; ;
Rodriguez; ;
Rogalla; ;
Roller; ;
Romein; ;
Haar Romeny;ter;
Ronde;de ;
Ronga; ;
Boer Rookhuizen; ;
Rosendale;van ;
Rozemeijer; ;
Rue;de ;
Ruiter;de ;
Rhl; ;
Sander; ;
Sanders; ;
Santoso; ;
Satz; ;
Schaeffer; ;
Schimmel; ;
Schoneveld; ;
Schrer; ;
Schwefel; ;
Serazzi; ;
Shane; ;
Shlesinger; ;
Silfhout;van ;
Simon; ;
Sips; ;
Sloot; ;
Sluijk; ;
Sluiter; ;
Smit; ;
Smyth; ;
Soest;van ;
Soliman; ;
Soll; ;
Somsen; ;
Sowa-Pieklo; ;
Spijk; ;
Spinnato; ;
Spitzer; ;
Spoelder; ;
Steen;van der ;
Steen;van ;
Steman; ;
Stolk; ;
Streekstra; ;
Suarez; ;
Succi; ;
Swart;de ;
Szopa; ;
Talia; ;
Tan; ;
Tanenbaum; ;
Tel; ;
Tensen; ;
Teuben; ;
Thevenon; ;
Thorpe; ;
Timonen; ;
Tolxdorff; ;
Tomassini; ;
Tonino; ;
Travis; ;
Trenning; ;
Trip; ;
Trizac; ;
Tzafestas; ;
Valero; ;
Vandoni; ;
Vannier; ;
Veldema; ;
Venema; ;
Veneziano; ;
Verbraeck; ;
Verstoep; ;
Vesseur; ;
Vicsek; ;
Vidal; ;
Videen; ;
Visser; ;
Vlachoutsis; ;
Vliet;van ;
Voigt; ;
Voogd; ;
Vosselman; ;
Vossepoel; ;
Vries;de ;
Vries;de ;
Waele;de ;
Wals; ;
Wang; ;
Wasniewsky; ;
Wassmuth; ;
Waters; ;
Weerts; ;
Wesselius; ;
Westerhoff; ;
Wijker; ;
Wilkinson; ;
Williams; ;
Wismller; ;
Withagen; ;
Woerden;van ;
Wolters; ;
Wolters; ;
Wriedt; ;
Wyrzykowski; ;
Wrn; ;
Yakali; ;
Zaremba; ;
Zbik; ;
Zhang; ;
Zhang; ;
Zhao; ;
ZhongWei; ;
Zhou; ;
Zijp; ;
Zomaya; ;
Zuidervaart; ;
a1ra18
y
SCHFER, J.S.E. 5925105 HEF K409 a1ra18 @nikhef.nl
aaearts
y
AARTS. Ir E. 5361 328 II P aaearts @fwi.uva.nl
adddlag
y
LAGENDIJK, prof. dr A. 5725 155 VEF V65 adddlag @phys.uva.nl
adllaar
y
ADELAAR. M.E.(maan,dins,donderdag) 5208 324 B P adllaar @fwi.uva.nl
aibaida
y
PAALMAN. mevr. Prof. Dr A.B. 6087 219 I P aibaida @fwi.uva.nl
albbada
y
ALBADA. W.P. van 6085 117 III P albbada @fwi.uva.nl
alblban
y
PONSE. Dr A. 7592 245 III 403 alblban @fwi.uva.nl
alealec
y
MAASSEN VAN DEN BRINK, ir A. 5922 358 TF V65 alealec @phys.uva.nl
alebert
y
VISSER. A. 5361 328 II P alebert @fwi.uva.nl
alfejan
y
HOMBURG. A. 5091 217 I P alfejan @fwi.uva.nl
alifons
y
HOEKSTRA. Dr Ir A. 7543 206 IV 403 alifons @fwi.uva.nl
amdlder
y
MULDER, drs A. 6315 212 VEF V65 amdlder @phys.uva.nl
ammhels
y
MICHELS, dr A.C. 6394 123 VEF V65 ammhels @phys.uva.nl
ammmerl
y
AMMERLAAN, prof. dr C.A.J. 5614 147 VEF V65 ammmerl @phys.uva.nl
amulder
y
MULDER, mw A. 5716 146 VEF V65 amulder @phys.uva.nl
andreja
y
PRIJATELJ. mevr. Drs A. 5299 320 II P andreja @fwi.uva.nl
annandy
y
PIMENTEL. Drs A.D. 7578 113 IV 403 annandy @fwi.uva.nl
annanne
y
TROELSTRA. Prof. Dr A.S. 5298 312 II P annanne @fwi.uva.nl
antanuj
y
DEV. Drs A. 7564 29 IV 403 antanuj @fwi.uva.nl
anuanny
y
CRAJ. A. mevr. 6076 115a B P anuanny @fwi.uva.nl
apiapt
y
APT. prof. Dr K.R. 6054 321 II P apiapt @fwi.uva.nl
arhnoud
y
VISSER. Drs A. 7513 105 IV 403 arhnoud @fwi.uva.nl
ariari
y
MAASKANT. Ing A. 6438 116 CEG P ariari @fwi.uva.nl
arnarno
y
KUIJLAARS. Dr Ir A.B.J. 5097 211 I P arnarno @fwi.uva.nl
arnevdm
y
MARK. A. van der 6069 011a B P arnevdm @fwi.uva.nl
atehmer
y
ATHMER, P. 6378 K18 VEF V65 atehmer @phys.uva.nl
aveelon
y
CARRDE AVELON, I. 5965 DID NA170 aveelon @phys.uva.nl
axwaxel
y
ROEST, A. 6395 123 VEF V65 axwaxel @phys.uva.nl
azawart
y
ZWART, A. 5759 T111 VEF V65 azawart @phys.uva.nl
baaaaij
y
BAAIJ, E.W. 6346 115 VEF V65 baaaaij @phys.uva.nl
baeerle
y
BUERLE, drs G.G.A. 5768 343 TF V65 baeerle @phys.uva.nl
baibaay
y
BAAIJ, mw C.H.M. 6334 221 VEF V65 baibaay @phys.uva.nl
bakbais
y
BAIS, prof. dr ir F.A. 5770 353 TF V65 bakbais @phys.uva.nl
baskker
y
BAKKER, dr H. 5736 282 VEF V65 baskker @phys.uva.nl
batbas
y
BAKKER, drs B.V. de 5920 356 TF V65 batbas @phys.uva.nl
bautson
y
BATSON, mw J.S. 6329 224 VEF V65 bautson @phys.uva.nl
beaerry
y
HALDEREN. A.W. van 7579 223 IV 403 beaerry @fwi.uva.nl
bekster
y
BEEMSTER. Drs M. 7565 108 IV 403 bekster @fwi.uva.nl
benamin
y
BENJAMIN. J. 6085 117 III P benamin @fwi.uva.nl
benbenb
y
BRUIDEGOM, B. 5885 WBO NA170 benbenb @phys.uva.nl
benkker
y
BEKKER, dr F.F. 5713 165 VEF V65 benkker @phys.uva.nl
berarda
y
SMITS. B.A.M. 5905 13 B P berarda @fwi.uva.nl
berenno
y
MOSTERD. Ing. B. 7517 46 CEG 403 berenno @fwi.uva.nl
berhout
y
BERKHOUT, dr J.J. 6343 111 Sys V65 berhout @phys.uva.nl
bernard
y
BOLLEGRAAF. Dr. B. 6553 122 III/WO P bernard @fwi.uva.nl
bijanca
y
JONGKIND. mevr. Drs B.R. 7502 4 CEG 403 bijanca @fwi.uva.nl
biovoet
y
BIJVOET, dr J. 5718 116 VEF V65 biovoet @phys.uva.nl
bjobjo
y
OVEREINDER. Drs B.J. 7536 205 CEG 403 bjobjo @fwi.uva.nl
blbndel
y
BLONDEL. P. 7471 310 III F blbndel @sara.nl
bloblo
y
LO. B. 6085 117 III/WO P bloblo @fwi.uva.nl
Blondel
y
BLONDEL, P.F.C 7471 310 SARA 403 Blondel @sara.nl
bobbob
y
HERTZBERGER. Prof. Dr L.O. 7463 212 IV 403 bobbob @fwi.uva.nl
bobobby
y
HOEK. B. van den 7482 342 F bobobby @astro.uva.nl
bombobd
y
DIERTENS. Ir B. 7554 146 CEG 403 bombobd @fwi.uva.nl
bonnaar
y
BOMINAAR, S.A.R.C. 6345 B22 V65 bonnaar @phys.uva.nl
boobos
y
BOS, mw M.G.J.O. 5712 145 VEF V65 boobos @phys.uva.nl
boooncz
y
BONCZ. Drs P.A. 7580 106 IV 403 boooncz @fwi.uva.nl
bosboon
y
BOON, dr P.N.M. 5416/5874 DID NA170 bosboon @phys.uva.nl
brocker
y
BROUCKRE, dr G. de 5784 265 VEF V65 brocker @phys.uva.nl
brommer
y
BROMMER, dr P.E. 5737 295 VEF V65 brommer @phys.uva.nl
brorohm
y
BROHM. R. 5361 328 II P brorohm @fwi.uva.nl
brostri
y
BRONSSTRING. M. 6085 117 III P brostri @fwi.uva.nl
brssaar
y
BRUSSAARD, drs P. 5878 277 TF V65 brssaar @phys.uva.nl
bruruck
y
BRCK, dr E.H. 5640 B65 VEF V65 bruruck @phys.uva.nl
bruuwer
y
BROUWER, mw F.I. 5105 326 VEF V65 bruuwer @phys.uva.nl
burchow
y
BUSCHOW, prof. dr K.H.J. 5714 163 VEF V65 burchow @phys.uva.nl
caesper
y
DIK. Drs B. C. 7554 146 CEG 403 caesper @fwi.uva.nl
casarel
y
BERG. Dr C.A. van den 7540 21 IV 403 casarel @fwi.uva.nl
cdeboer
y
BOER. N.H.G. de 7515 112 CEG 403 cdeboer @fwi.uva.nl
ceacees
y
BOL. Ing. C.J. 6438 116 CEG P ceacees @fwi.uva.nl
chorlie
y
ALDERHOUT, C.P.A. 5789 T115 VEF V65 chorlie @phys.uva.nl
chrhong
y
CHONG, mw Y.L. 5790 254 TF V65 chrhong @phys.uva.nl
churisk
y
KLAASSEN. Prof. Dr C.A.J. 5010 235 I P churisk @fwi.uva.nl
chuuvan
y
VAN THANG, Chu 5794 B59 VEF V65 chuuvan @phys.uva.nl
cmblder
y
MULDER, drs C.H.T. 5967/3519 DID NA170 cmblder @phys.uva.nl
colcoby
y
GEIJSEL. mevr. Dr J.M. 6081 218 I P colcoby @fwi.uva.nl
conolpa
y
COLPA, dr J.H.P. 5737 295 VEF V65 conolpa @phys.uva.nl
corcong
y
CONG. Drs T.D. 6097 237 I P corcong @fwi.uva.nl
cperins
y
PRINS, dr C. 6340 219 VEF V65 cperins @phys.uva.nl
crwmers
y
CREMERS. Dr J.H. 5257 220 I P crwmers @fwi.uva.nl
cvmcvw
y
WEERT, prof. dr Ch.G. van 5740 WBO NA170 cvmcvw @phys.uva.nl
dabnnyb
y
BIRMINGHAM, D.A. 5923 360 TF V65 dabnnyb @phys.uva.nl
dandam
y
DAM. Drs J. van 7560 40 IV 403 dandam @fwi.uva.nl
debboer
y
BOER, drs J.F. de 5629 S30 VEF V65 debboer @phys.uva.nl
debeurs
y
BEURS, ir C. de 5964 DID NA170 debeurs @phys.uva.nl
decsser
y
VISSER, dr A. de 5732 B61 VEF 22V65 decsser @phys.uva.nl
deggier
y
GIER, drs J.C. de 5922 358 TF V65 deggier @phys.uva.nl
degoede
y
GOEDE, G. de 5886 DID NA170 degoede @phys.uva.nl
degoeje
y
GOEJE, ir P. de 6355/6301 BOS NA172 degoeje @phys.uva.nl
deguijn
y
BRUIJN, drs R. de 6395 123 VEF V65 deguijn @phys.uva.nl
delroot
y
GROOT, J. de 5720 156 DFA V65 delroot @phys.uva.nl
deneeuw
y
LEEUW, P.J. de 6361 T115 VEF V65 deneeuw @phys.uva.nl
deputer
y
OUTER, P.N. den 5710 187/9 VEF V65 deputer @phys.uva.nl
devaepe
y
PAEPE. Dr P.J. I.M. de 6079 232 I P devaepe @fwi.uva.nl
dicdick
y
ALBADA. Dr G.D. van 7534 104 IV 403 dicdick @fwi.uva.nl
dieckdj
y
JONGH. Dr D.H.J. de 6061 314 II P dieckdj @fwi.uva.nl
dieksen
y
DIRKSEN, R. 5644 B53 VEF V65 dieksen @phys.uva.nl
dirctie
y
LANGELAAR, dr J. 5925000 HEF K409 dirctie @nikhef.nl
dirdirk
y
DEKKER. Prof. Dr Th.J. 7463 211 IV 403 dirdirk @fwi.uva.nl
dirdirk
y
EDEL, D. 7485 SYS K403 dirdirk @phys.uva.nl
dirdirk
y
EDEL. D. 7485 306 OBP F dirdirk @astro.uva.nl
diriest
y
DIEST, R.J.J. van 6395 119 VEF V65 diriest @phys.uva.nl
doanbos
y
DORENBOS, V. 5958 DID NA170 doanbos @phys.uva.nl
doldolf
y
WINTER. D. de 7474 330 F doldolf @astro.uva.nl
doloets
y
DOETS. Dr H.C. 6054 321 II P doloets @fwi.uva.nl
domlsma
y
DOLSMA, K. 6415 DID NA170 domlsma @phys.uva.nl
dornico
y
ZAMBELLA. Dr D. 6071 319 II P dornico @fwi.uva.nl
drtbant
y
DRABANT. Dr B. 5203 228 I P drtbant @fwi.uva.nl
duehman
y
HOLLANDER, drs A.G.S. 6371 K07 VEF V65 duehman @phys.uva.nl
edadwin
y
STEFFENS. Ing. E.H. 7551 143 CEG 403 edadwin @fwi.uva.nl
edodens
y
EDENS. Drs E. 6088 231 I P edodens @fwi.uva.nl
edvedoh
y
DOOIJES. Dr E.H. 7523 44 IV 403 edvedoh @fwi.uva.nl
edwdvdh
y
HEUVEL. E. van den 7493 327 WP F edwdvdh @astro.uva.nl
ehohaas
y
HAAS. Drs E. de 7515 112 II 403 ehohaas @fwi.uva.nl
eklkooi
y
KOOI, mw drs E. 6363 208 VEF V65 eklkooi @phys.uva.nl
elmrmei
y
ELLERMEIJER, dr A.L. 5963 DID NA170 elmrmei @phys.uva.nl
emiemma
y
MEULEN. Dr E. v/d 7583 227 III 403 emiemma @fwi.uva.nl
erierik
y
HENDRIKSEN. Dr E. 6064 230 I P erierik @fwi.uva.nl
eririca
y
VEENHOF. E. 7491/2 324 OBP(SECR.) F eririca @astro.uva.nl
ernkjan
y
LINDEN. Dr H.J.B.M. van der 6090 330 ILLC P ernkjan @fwi.uva.nl
ernnest
y
ROTTERDAM. E.P. 6511 316 II P ernnest @fwi.uva.nl
ertnstk
y
KOPER. Drs E.W.M. 6079 232 I P ertnstk @fwi.uva.nl
esbther
y
EVERAARTS. E. 5803 20 B P esbther @fwi.uva.nl
fadaber
y
FABER. Dr C.F. 5257 220 I P fadaber @fwi.uva.nl
fbrjong
y
JONG, drs F.B. de 5008 324 VEF V65 fbrjong @phys.uva.nl
feuerry
y
KROON. Drs F.J. 5470 12 B P feuerry @fwi.uva.nl
fluluks
y
FLUKS. M. 7474 330 F fluluks @astro.uva.nl
fmalder
y
MULDER, F.M.A. 5751 315 BIB V65 fmalder @phys.uva.nl
fraankt
y
TUIJNMAN. Dr F. (vrijdags) 7512 201 IV 403 fraankt @fwi.uva.nl
fraanse
y
FRANSE, prof. dr J.J.M. 5641 142 VEF V65 fraanse @phys.uva.nl
fraklin
y
LAARHOVEN, F. 5765 289 DFA V65 fraklin @phys.uva.nl
fraklin
y
LAARHOVEN, F. 5720 156 DFA V65 fraklin @phys.uva.nl
Frarank
y
LINDEN. F. van der 7514 202 IV 403 Frarank @fwi.uva.nl
frarans
y
LOTTY. F.J. 7505/6438 006/116 CEG 403/P frarans @fwi.uva.nl
frbansv
y
VOORBRAAK. Drs F.P.J.M. 5235 325 II P frbansv @fwi.uva.nl
frdings
y
FRINGS, dr P.H. 5744 164 VEF V65 frdings @phys.uva.nl
freeekh
y
HUELE. F. 5365 212 I P freeekh @fwi.uva.nl
frefrb
y
BOER, prof. dr F.R. de 5717 151 VEF V65 frefrb @phys.uva.nl
frienay
y
FRENAY, Th. 5862 DID NA170 frienay @phys.uva.nl
gadmers
y
GAEMERS, prof. dr K.J.F. 5769 357 TF V65 gadmers @phys.uva.nl
gaegade
y
GADE, mw R. 5771 368 TF V65 gaegade @phys.uva.nl
geegedi
y
SCHRIEK. mevr. G.Th. van 6084 115 B P geegedi @fwi.uva.nl
geegeer
y
GEER. Prof Dr G.B.M. van der 5247 221 I P geegeer @fwi.uva.nl
gelerke
y
GEERKE, drs H.P. 5958 DID NA170 gelerke @phys.uva.nl
gelvers
y
GEVERS. Drs Th. 7560 40 IV 403 gelvers @fwi.uva.nl
genders
y
GELDERS, H.J. 7187 177 VEF V65 genders @phys.uva.nl
gerardk
y
KOK. G.P. 7582 226 III 403 gerardk @fwi.uva.nl
gergene
y
MAGNIER. E. 7476 333 POSTDOC F gergene @astro.uva.nl
gergert
y
POLETIEK. G. 7503 5 CEG 403 gergert @fwi.uva.nl
gevtjan
y
SAVONIJE. GJ. 7497 331 WP F gevtjan @astro.uva.nl
gidiero
y
GILLIERON, mw L.H. 5180/5773 315/258 BIB/TF V65 gidiero @phys.uva.nl
gilijam
y
GILIJAMSE, J.W. 5647 B62 VEF V65 gilijam @phys.uva.nl
goiieve
y
HAMMERSCHLAG. G. 7488 344 WP F goiieve @astro.uva.nl
grinste
y
GRUNER. S. 7541 111 IV 403 grinste @fwi.uva.nl
gririmm
y
GRIMM, U. 6308 362 TF V65 gririmm @phys.uva.nl
gronten
y
GRINTEN, mw H.M. van der 6356 315 BIB V65 gronten @phys.uva.nl
gruroen
y
GROEN. Prof Dr Ir F.C.A. 7463 23 IV 403 gruroen @fwi.uva.nl
gu2guus
y
BALKEMA. Dr A.A. 6097 237 I P gu2guus @fwi.uva.nl
gulhela
y
GUICHELAAR, dr J. 5701 WBO NA170 gulhela @phys.uva.nl
guuulik
y
GULIK, dr P.S. van der 6390 B11 VEF V65 guuulik @phys.uva.nl
h00h02
y
ENGELEN, prof. dr J.J. 5925043 HEF K409 h00h02 @nikhef.nl
h53h50
y
KAMPS, drs M. de 5925050 HEF K409 h53h50 @nikhef.nl
h74h73
y
VREESWIJK, drs M. 5925124 HEF K409 h74h73 @nikhef.nl
h8ch84
y
KOOYMAN, dr P.M. 5925023 HEF K409 h8ch84 @nikhef.nl
haeison
y
HARRISON, ing. B.A. 5730 T115 VEF V65 haeison @phys.uva.nl
hamideh
y
AFSARMANESH. mevr. Dr H. 7512 201 IV 403 hamideh @fwi.uva.nl
hamuebo
y
HACQUEBORD, F. 5774 377 TF V65 hamuebo @phys.uva.nl
hanammi
y
ALBERTS. H. 7477 334 OIO F hanammi @astro.uva.nl
haransm
y
MEER. Dr H. van der 7006 120 III/WO P haransm @fwi.uva.nl
harmsze
y
HARMSZE, mw F.A.P. 5719 267 V65 harmsze @phys.uva.nl
heierik
y
HEEDERIK. R.N. 6085 117 III P heierik @fwi.uva.nl
hejvell
y
LINDEN v/d HEUVELL, prof. dr ir H.B. v. 5167 318 VEF V65 hejvell @amolf.nl
heneler
y
HEIJELER, R. 5968 DID NA170 heneler @phys.uva.nl
henenkp
y
PIJLS. Dr H.G.J. 5380 234 I P henenkp @fwi.uva.nl
henenkv
y
VOORTHUIS. Dr H. 7535 109 IV 403 henenkv @fwi.uva.nl
henhenk
y
POT, H.A. 5865 Sys NA170 henhenk @phys.uva.nl
henhenk
y
SIPS. Prof. Dr Ir H.J. 7463 211 IV 403 henhenk @fwi.uva.nl
henhenk
y
SPRUIT. H. 7455 303 WP F henhenk @astro.uva.nl
hererke
y
NOORDMANS. Drs H.J. 7517 46 IV 403 hererke @fwi.uva.nl
hernnes
y
HENNES, drs E. 5868 WBO NA170 hernnes @phys.uva.nl
hetrick
y
HETRICK, J. 5772 345 TF V65 hetrick @phys.uva.nl
hetrman
y
TJIN A DJIE H.R.E. 7471 310 F hetrman @astro.uva.nl
heuette
y
KNOL. H. 7463 47 B 403 heuette @fwi.uva.nl
hiiorst
y
HILHORST, L. 6346 T115 VEF V65 hiiorst @phys.uva.nl
hilbers
y
HILBERS, ing. M.F. 5638 B65 VEF V65 hilbers @phys.uva.nl
hilmans
y
HIJMANS, dr T.W. 6364 226 VEF V65 hilmans @phys.uva.nl
hloieuw
y
LIEUW. H. 6085 117 III/WO P hloieuw @fwi.uva.nl
hmlenaa
y
MOLENAAR, mw H.J. 5886 DID NA170 hmlenaa @phys.uva.nl
hogeman
y
HONDEMAN, F.J. 5969 DID NA170 hogeman @phys.uva.nl
honlman
y
HOLMAN, ing. G.J.F. 6373 K03 VEF V65 honlman @phys.uva.nl
huihugh
y
McEVOY. Drs H. 7565 108 IV 403 huihugh @fwi.uva.nl
hurhuib
y
HENRICHS. H. 7466 301 WP F hurhuib @astro.uva.nl
hvlssum
y
ROSSUM, drs J. van 5861 OWB NA170 hvlssum @phys.uva.nl
hw3hwl
y
LENSTRA. H.W. 6087 219 I P hw3hwl @fwi.uva.nl
i7ni73
y
VERMEULEN, dr ir J.C. 5925108 HEF K409 i7ni73 @nikhef.nl
iakian
y
TSIMPERIDIS, drs I. 5644 B53 VEF V65 iakian @phys.uva.nl
iceicke
y
ICKE. V. 7495 343 WP F iceicke @gouwe.strw.leidenuniv.nl
idsmaat
y
MAAT-GERSDORF, mw drs M.I. de 5793 B51 VEF V65 idsmaat @phys.uva.nl
iniinst
y
FAVEREY. E. 7486 345 OBP F iniinst @astro.uva.nl
irairma
y
HOLLANDER. I 6083 119 B P irairma @fwi.uva.nl
irmiris
y
HETTELINGH. mevr. Drs I. 6557 112 B P irmiris @fwi.uva.nl
iswisam
y
HAGMUSA, I.E.H. 5642 B57 VEF V65 iswisam @phys.uva.nl
izawart
y
ZWART, mw B.A. 5716 146 VEF V65 izawart @phys.uva.nl
jacaapk
y
KAANDORP. Dr J.A. 7539 222 IV 403 jacaapk @fwi.uva.nl
jacacco
y
KONIJN. Drs J. 7542 224 B 403 jacacco @fwi.uva.nl
jacacob
y
BRUNEKREEF. Ir J.J. 7583 227 III/WO 403 jacacob @fwi.uva.nl
jadcvis
y
VISSER, J. 5949 voorl. NA170 jadcvis @phys.uva.nl
jahsper
y
STOKMAN. Drs J.V. 5097 211 I P jahsper @fwi.uva.nl
jananny
y
POT-VERBREE. mevr. J. 6516 130 B P jananny @fwi.uva.nl
janjanb
y
BERGSTRA. prof. Dr J.A. 7591 244 III 403 janjanb @fwi.uva.nl
janjank
y
KOOPSTRA, J. 5925069 HEF K409 janjank @nikhef.nl
janjanr
y
RONDE. Drs J. F. de 7536 205 IV 403 janjanr @fwi.uva.nl
janjanw
y
WORTELBOER. Ing. J.H.P. 7501 3 CEG 403 janjanw @fwi.uva.nl
jankker
y
DEKKER, dr J.A. 5966 DID NA170 jankker @phys.uva.nl
jannstu
y
STUIVENBERG. J. 7455 303 GAST F jannstu @astro.uva.nl
jaswieg
y
WIEGERINCK. Dr J.J.O.O. 5097 211 I P jaswieg @fwi.uva.nl
jeeroen
y
VOOGD. J. 7539 222 IV 403 jeeroen @fwi.uva.nl
jennsen
y
HANSEN, dr J.E. 5164 348 VEF V65 jennsen @phys.uva.nl
jernsen
y
JENSEN, D. 5721 156 DFA V65 jernsen @phys.uva.nl
jkikoch
y
KOCH, prof. dr J.H. 5772 345 TF V65 jkikoch @phys.uva.nl
jkojser
y
KEIJSER, drs J.J. 6362 204 VEF V65 jkojser @phys.uva.nl
jmehels
y
MICHELS, dr J.P.J. 6349 210 VEF V65 jmehels @phys.uva.nl
JohJoep
y
VESSEUR, drs. J.J.J. 7514 202 CEG 403 JohJoep fwi.uva.nl
johohan
y
BENTHEM. prof. Dr J.F.A.K. van 5807 313 II P johohan @fwi.uva.nl
Jomoyce
y
TANGALI. H. 7563 203 B 403 Jomoyce @fwi.uva.nl
jonenee
y
JONGENEELEN, T. 6342 T115 VEF V65 jonenee @phys.uva.nl
jonjohn
y
TELTING. J. 7475 332 OIO F jonjohn @astro.uva.nl
jonjon
y
MOUNTJOY. Drs J.D. 7541 111 IV 403 jonjon @fwi.uva.nl
jorjonk
y
JONK. Drs A. 7580 106 IV 403 jorjonk @fwi.uva.nl
josoris
y
HILLEBRAND. Drs J.A. 7581 225 III 403 josoris @fwi.uva.nl
joyjose
y
LAGERBERG. mevr. Drs J.M. 7513 105 IV 403 joyjose @fwi.uva.nl
jsdsmit
y
SMIT, prof. dr J. 5743 349 TF V65 jsdsmit @phys.uva.nl
juddith
y
SPIJK. Drs. J. 6557 112 B P juddith @fwi.uva.nl
jvldoes
y
DOES. J. van der 5235 325 II P jvldoes @fwi.uva.nl
kaeyzel
y
KAYZEL, drs F.E. 5647 B62 VEF V65 kaeyzel @phys.uva.nl
kaneway
y
KALDEWAIJ, dr A. 5805 of 5239 dir. ondw.inst. P kaneway @fwi.uva.nl
kardhai
y
KANDHAI. D. 6085 117 III P kardhai @fwi.uva.nl
karpant
y
KARAPANTSIOS, dr T.D. 6362 204 V65 karpant @phys.uva.nl
katarin
y
DOORN. mw. K. 5803 20 B P katarin @fwi.uva.nl
kavttie
y
SCHOOT. mevr. C.J. 5074 111a B P kavttie @fwi.uva.nl
kayherc
y
KAVEHERCY, S. 6085 117 III P kayherc @fwi.uva.nl
kdiroot
y
GROOT, C. de 5977 291 VEF V65 kdiroot @phys.uva.nl
kelsper
y
KEIJSPER. mw. Drs J. 5091 217a I P kelsper @fwi.uva.nl
keriles
y
KERDILES. G. 5208 324 II P keriles @fwi.uva.nl
kerkerf
y
KERF, dr E.A. de 5769 364 TF V65 kerkerf @phys.uva.nl
kerller
y
KELLER, N. 5732 361 VEF V65 kerller @phys.uva.nl
kiaircz
y
KIRCZ, dr J.G. 5719 267 V65 kiaircz @phys.uva.nl
klaasse
y
KLAASSE, dr J.C.P. 5633 B58 VEF/COO V65 klaasse @phys.uva.nl
kleasse
y
KLAASSE, dr J.C.P. 5889 VEF/COO NA170 kleasse @phys.uva.nl
Koelink
y
KOELINK, H.T. 5203 228 I P Koelink @fwi.uva.nl
kolelma
y
KOELMA. Drs D.C. 7516 28 IV 403 kolelma @fwi.uva.nl
konmann
y
KOLLMANN, drs M. 5745 263 TF V65 konmann @phys.uva.nl
kooonah
y
MIRANDA. mevr. M. de 6083 119 B P kooonah @fwi.uva.nl
kopoops
y
KOOPS, W. 5796 B43 VEF V65 kopoops @phys.uva.nl
korkop
y
KOP, drs H.J. 5710 B35 VEF V65 korkop @phys.uva.nl
korvsky
y
KOZLOVSKY. O. 6092 225 I P korvsky @fwi.uva.nl
kosvaar
y
KOREVAAR. Prof. Dr J. 6091 213 I P kosvaar @fwi.uva.nl
kovster
y
KOSTER, drs. W.D. 6315 212 VEF V65 kovster @phys.uva.nl
koxvacs
y
KOVCS, dr Z. 5775 243 TF V65 koxvacs @phys.uva.nl
kozkox
y
KOX, dr A.J. 5739 242 TF V65 kozkox @phys.uva.nl
kozziol
y
KOZIOL, Z.J. 5647 B62 V65 kozziol @phys.uva.nl
kporins
y
PRINS, dr K.O. 6336 220 VEF V65 kporins @phys.uva.nl
kroroon
y
KROON, drs M. 5646 B45 VEF V65 kroroon @phys.uva.nl
krprose
y
KRSE. Dr Ir B.J.A. 7520 41 IV 403 krprose @fwi.uva.nl
kumppen
y
KUPPEN, W.A.A. 6356 315 BIB V65 kumppen @phys.uva.nl
laengen
y
LANGEN, drs M. de 6371 VEF V65 laengen @phys.uva.nl
lammain
y
LAMAIN. Dr W. 6553 122 III/WO P lammain @fwi.uva.nl
lanlamb
y
LAMB, dr J.S.W. 5745 TF V65 lanlamb @phys.uva.nl
leeleen
y
TORENVLIET. Dr L. 6065 317 II P leeleen @fwi.uva.nl
leelex
y
SCHRIJVER. Prof. Dr A. 592-4087 592-4189 I CWI leelex @cwi.nl
leemake
y
LEERMAKERS, drs L.J. 5953 DID NA170 leemake @phys.uva.nl
lenuwen
y
LEEUWEN, dr W.A. van 5747 255 TF V65 lenuwen @phys.uva.nl
leoleo
y
DORST. Dr L. 7511 107 IV 403 leoleo @fwi.uva.nl
leoneke
y
VEN. mevr. H.M. van der 6516 130 B P leoneke @fwi.uva.nl
leuleon
y
MOONEN. Ing. L.M.F. 7588 241 III 403 leuleon @fwi.uva.nl
lexsink
y
LEUSINK, drs A.C. 5965 DID NA170 lexsink @phys.uva.nl
lhddrik
y
HENDRIKS. A. 6061 314 II P lhddrik @fwi.uva.nl
liebeth
y
BIBLIOTHEEK WCW 7489 320 BIBL. 403 liebeth @fwi.uva.nl
liebeth
y
ITERSON. mevr. E.S. van 7489 320 B 403 liebeth @fwi.uva.nl
lielide
y
STOLTE. L. 7487 346 OBP F lielide @astro.uva.nl
lieping
y
PING, Liu 6310 209 VEF V65 lieping @phys.uva.nl
linhout
y
LIESHOUT, T.S.H. van 6346 T115 VEF V65 linhout @phys.uva.nl
liuinda
y
SCHNATER. mevr. L.M 6516 130 B P liuinda @fwi.uva.nl
lmdijer
y
LANGEMEIJER, ing. P.M. 5730 T115 Sys V65 lmdijer @phys.uva.nl
lotrens
y
LOURENS, S. 5869 DID NA170 lotrens @phys.uva.nl
louodie
y
VO TE. L. 7455 303 FAX:033-651560 F louodie @astro.uva.nl
lououis
y
LOUIS, J.M. 5765 222 VEF V65 lououis @phys.uva.nl
luattik
y
LUTTIK. B. 6085 117 III P luattik @fwi.uva.nl
maerice
y
MAURICE, drs G. 5416 Sys NA170 maerice @phys.uva.nl
mantenc
y
COOLEN. Dr T.M.T. 5208 324 II P mantenc @fwi.uva.nl
maranne
y
KALSBEEK. mevr. Drs M.B. 6925 322 II P maranne @fwi.uva.nl
mararco
y
VRIES. M.W. 6051 329 II P mararco @fwi.uva.nl
marcelm
y
MONTERIE. Drs M. 6092 215 I (gast) P marcelm @fwi.uva.nl
marinbm
y
BERGMAN. Drs M. 7579 223 CEG 403 marinbm @fwi.uva.nl
markvdb
y
BRAND. Dr M.G.J. van den 7593 246 III 403 markvdb @fwi.uva.nl
marmarc
y
BRUGMAN. M.A. 6438 116 CEG P marmarc @fwi.uva.nl
marmare
y
MAR, A.C.M. 5733 T115 VEF V65 marmare @phys.uva.nl
marmark
y
GEUSEBROEK. Drs J.M. 7564 29 IV 403 marmark @fwi.uva.nl
marputy
y
MANUPUTY, R.J.D. 5757 TB09 VEF V65 marputy @phys.uva.nl
marrtin
y
HEEMSKERK. M. 7471 310 F marrtin @astro.uva.nl
marrtin
y
KOERS. M. 5177 11 GB P marrtin @fwi.uva.nl
mattens
y
MATTENS, dr W.C.M. 5715 158 dir V65 mattens @phys.uva.nl
matynov
y
MARTYNOV, drs I. 5642 B57 VEF V65 matynov @phys.uva.nl
mautens
y
MATTENS. Dr W.C.M. 6094/7463 114/211 B P/403 mautens @phys.uva.nl
mdnmdwp
y
WILD PROPITIUS, drs M.D.F. de 5774 377 TF V65 mdnmdwp @phys.uva.nl
mdrkker
y
DEKKER. M. 5205 223 I P mdrkker @fwi.uva.nl
mdwmdr
y
RIJKE. Dr M. de 5924080 236 CWI CWI mdwmdr @cwi.nl
meceurs
y
MEURS. J.W. 6085 117 III P meceurs @fwi.uva.nl
mesvsky
y
MENOVSKY, dr A.A. 5657 183 VEF V65 mesvsky @phys.uva.nl
meumes
y
MES. Drs A. de 7501 3 CEG/IV 403 meumes @fwi.uva.nl
micchel
y
EIJCK, ir M.A. van 5774 377 TF V65 micchel @phys.uva.nl
michiel
y
KLIS. M.van der 7498 328 WP F michiel @astro.uva.nl
micielb
y
BERGER. M. 7482 342 F micielb @astro.uva.nl
mikiell
y
LAMBALGEN. Dr M. van 6060 323 II P mikiell @fwi.uva.nl
mikilco
y
LANDTMAN, M. 5003 V65 mikilco @phys.uva.nl
milulas
y
MIKULAS. Dr S. 6095 326 II P milulas @fwi.uva.nl
mklmk
y
KERSTEN. Prof. Dr M.L. 592.4066 M351 IV CWI mklmk @fwi.uva.nl
moleman
y
MOLEMAN, A.C. 5760 395 VEF V65 moleman @phys.uva.nl
monnaar
y
MOLENAAR, drs P.P.M. 5956 DID NA170 monnaar @phys.uva.nl
mononic
y
FOPPELE. mevr. Drs M.A.H.M. 6070 112a B P mononic @fwi.uva.nl
moodend
y
OUDENDIJK, M. 5765 289 VEF V65 moodend @phys.uva.nl
moodijk
y
MOOLDIJK, A. 5964 DID NA170 moodijk @phys.uva.nl
mooique
y
KLEINENDORST. mevr. P.M. 7463 208 B 403 mooique @fwi.uva.nl
moshuyz
y
MOOLHUYZEN, W.F. 5760 395 VEF V65 moshuyz @phys.uva.nl
moumosk
y
MOSK, drs A. 6389 B35 VEF V65 moumosk @phys.uva.nl
mrrroos
y
ROOS. mevr. M.F.B. 6094 114 B P mrrroos @fwi.uva.nl
mtiutwe
y
TRAUTWEIN. Drs M. 6508 318 II P mtiutwe @fwi.uva.nl
mwtwijz
y
WIJZENBEEK, drs M. 5737 295 VEF V65 mwtwijz @phys.uva.nl
naeasha
y
ALECHINA. mw. Drs N.A. 5299 320 II P naeasha @fwi.uva.nl
ndukker
y
DEKKER-HILLEBRAND, mw N. 5869 DID NA170 ndukker @phys.uva.nl
necuman
y
NEUMAN. Drs C.D.D. 6282 218a I P necuman @fwi.uva.nl
niecola
y
CICCOLI. N. 5203 228 I P niecola @fwi.uva.nl
niehuis
y
NIENHUIS, prof. dr B. 5749 251 TF V65 niehuis @phys.uva.nl
nieiese
y
NIESE. E. 6085 117 III P nieiese @fwi.uva.nl
niekemp
y
NIENKEMPER, drs J.J.K. 5885 WBO NA170 niekemp @phys.uva.nl
nikwenh
y
NIEUWENHUIZEN, dr Th.M. 6332 233 VEF V65 nikwenh @phys.uva.nl
niuklas
y
ENGSNER. N. 6071 319 II P niuklas @fwi.uva.nl
nmdller
y
MULLER, mw drs N.M. 5920 356 TF V65 nmdller @phys.uva.nl
oldierp
y
OLIVIER. drs. P. 7581 225 III 403 oldierp @fwi.uva.nl
olienzl
y
OLDENZIEL, dr J.G. 5817 WBO NA170 olienzl @phys.uva.nl
olivier
y
OLIVIER. Drs B.E. 6095 326 II P olivier @fwi.uva.nl
on8buro
y
ONDERWIJSBUREAU 6516 130 B P on8buro @fwi.uva.nl
p6up68
y
KESGIN, mw M.J. 5925003 HEF K409 p6up68 @nikhef.nl
paiaulv
y
VITANYI. Prof. Dr P.M.B. 6065 317 II/CWI P paiaulv @fwi.uva.nl
pauaula
y
UIJTHOVEN TOL, mw P.S. 5773 258 TF V65 pauaula @phys.uva.nl
pauaulk
y
KLINT. Prof. Dr P. 592.4126 229 III/CWI 403 pauaulk @fwi.uva.nl
PauPaul
y
GROOT, P 7470 309 403 PauPaul @astro.uva.nl
pbnalas
y
BIALAS, dr P. 5767 382 TF V65 pbnalas @phys.uva.nl
pearslo
y
SLOOT. Dr P.M.A. 7537 213 lV 403 pearslo @fwi.uva.nl
petavin
y
PENDAVINGH. Drs R.A. 5091 217a I P petavin @fwi.uva.nl
peteter
y
EMDE BOAS. Dr P. van 6065 317 II P peteter @fwi.uva.nl
phahilo
y
ZIJLSTRA. mevr. Ph. 5217 214 B P phahilo @fwi.uva.nl
phipham
y
NGUYEN HAI, Pham 5644 B53 VEF V65 phipham @phys.uva.nl
pieeter
y
HARTEL. Dr P.H. 7566 110 IV 403 pieeter @fwi.uva.nl
pieieth
y
HEMKER. Prof. Dr P.W. 5203 228 I P pieieth @fwi.uva.nl
piepia
y
PFLUGER. mevr. Dr P.R. 5204/7538 226/204 I/IV P/403 piepia @fwi.uva.nl
pioietr
y
RODENBURG. Dr P.H. 7589 242 III 403 pioietr @fwi.uva.nl
pjajohn
y
JOHN, drs P. 5919 354 TF V65 pjajohn @phys.uva.nl
plelank
y
PLANK, drs R.W.F. van der 5919 354 TF V65 plelank @phys.uva.nl
poipost
y
POST, dr T. 5108 111 Sys V65 poipost @phys.uva.nl
porstra
y
POELSTRA, mw A.A.M. 5720 156 DFA V65 porstra @phys.uva.nl
possius
y
PORSIUS, A.J. 5631 159 DFA V65 possius @phys.uva.nl
pponkse
y
PINKSE, drs P.W.H. 6338 B35 VEF V65 pponkse @phys.uva.nl
prhsken
y
PRUISKEN, prof. dr A.M.M. 5746 262 TF/VEF V65 prhsken @phys.uva.nl
pruronk
y
PRONK. Drs G.G. 7543 206 IV 403 pruronk @fwi.uva.nl
psksthe
y
THE. P. 7496 338 WP F psksthe @astro.uva.nl
pstpsh
y
STEVENHAGEN. Dr P. 5202 224 I P pstpsh @fwi.uva.nl
pttptk
y
KAHABKA. P. 7476 333 POSTDOC F pttptk @astro.uva.nl
pu5tter
y
PUTTER. Drs H. 5091 217 I P pu5tter @fwi.uva.nl
q00q05
y
DAM, dr P.H.A. van 5925116 HEF K409 q00q05 @nikhef.nl
q13q10
y
APELDOORN, dr G.W. van 5925118 HEF K409 q13q10 @nikhef.nl
q3aq33
y
WOLF, mw. dr E. de 5925123 HEF K409 q3aq33 @nikhef.nl
quaquak
y
QUAK. Drs W. 7515 112 II/IV 403 quaquak @fwi.uva.nl
racusse
y
RASMUSSEN, F.B. 5793 B51 VEF V65 racusse @phys.uva.nl
rasiman
y
RASIMAN. S. 6082 111 III P rasiman @fwi.uva.nl
rasssen
y
RAASSEN, dr A.J.J. 5006 333 VEF V65 rasssen @phys.uva.nl
rececep
y
ZANTEN, J. van 5877 REC NA170 rececep @phys.uva.nl
redolds
y
REYNOLDS, dr M.W. 6338 202 VEF V65 redolds @phys.uva.nl
reiptie
y
PAASSCHEN, K. van 5663 B69 REC V65 reiptie @phys.uva.nl
renrein
y
BOOMGAARD. Dr Ir R. van den 7521 42 NWO/IV 403 renrein @fwi.uva.nl
reyensw
y
WATERS. R. 7468 305 WP F reyensw @astro.uva.nl
rhcrhd
y
DIJKGRAAF. Prof. Dr R.H. 5209 233 I P rhcrhd @fwi.uva.nl
ribersm
y
RIEMERSMA, A.J. 5656 185 VEF V65 ribersm @phys.uva.nl
richard
y
CARELS. Ing. R. 7504 6 CEG 403 richard @fwi.uva.nl
rieardk
y
KELLERMANN DEIBEL. Drs R.J. 7550 222 SION 403 rieardk @fwi.uva.nl
robbbel
y
BELLEMAN. R. 7579 223 IV 403 robbbel @fwi.uva.nl
rodsita
y
MUNTSLAG. mevr. R.Y. 7542 224 B P rodsita @fwi.uva.nl
roeoelf
y
TAKENS. R. 7499 347 WP F roeoelf @astro.uva.nl
roerobv
y
VELDMAN. R.M. 6064 230 I P roerobv @fwi.uva.nl
ronroes
y
ROES, mw J.U.M. 5863 162 GRIFF V65 ronroes @phys.uva.nl
rosdoes
y
DOES. Prof. Dr R.J.M.M. IBIS UvA B.V. 6024 215 I P rosdoes @fwi.uva.nl
ruiuudv
y
VELDHUIS. Ing. R.W. 7552 144 CEG 403 ruiuudv @fwi.uva.nl
ruurudy
y
WIJNANDS. R. 7479 336 PROM. F ruurudy @astro.uva.nl
ruuuudr
y
ROEL. Dr R.W.J. 7009 121 III/WO P ruuuudr @fwi.uva.nl
rvnsser
y
VISSER-VAN DEN BERG, mw R.B. 5860 OWB NA170 rvnsser @phys.uva.nl
saoskia
y
PRINS. S. 7480 337 AIO F saoskia @astro.uva.nl
sasnnes
y
SANNES, P. 6346 T115 VEF V65 sasnnes @phys.uva.nl
sbhsman
y
BOSMAN. S. 6085 117 III P sbhsman @fwi.uva.nl
schattr
y
SCHLATTER, H. 5656 185 VEF V65 schattr @phys.uva.nl
schneve
y
SCHONEVELD. Drs A. 7539 222 IV 403 schneve @fwi.uva.nl
schuten
y
SCHOUTEN, prof. dr J.A. 6339 225 VEF V65 schuten @phys.uva.nl
scnylen
y
SCHUIJLENBURG, ing. W.J. 6337 B07 VEF V65 scnylen @phys.uva.nl
seatija
y
SETIJA, I. 6338 202 VEF V65 seatija @phys.uva.nl
serenna
y
HOUWEN. Prof. Dr P.J. van der 5203 228 I/CWI P serenna @fwi.uva.nl
seterge
y
LAZZARINI, S. 5923 360 TF V65 seterge @phys.uva.nl
smeeets
y
SMEETS, mw E.M.W. 6055 152 P&O V65 smeeets @phys.uva.nl
smemagt
y
SMAGT. Drs P.P.P. van der 7524 45 IV 403 smemagt @fwi.uva.nl
smplder
y
SMEULDERS. Prof. Dr Ir. A.W.M. 7463 22 IV 403 smplder @fwi.uva.nl
soephie
y
FISCHER. mevr. Drs S. 6508 318 II P soephie @fwi.uva.nl
speprik
y
SPRIK, dr R. 5645 B49 VEF V65 speprik @phys.uva.nl
sprpeek
y
SPEEK. S. L. 6508 318 II P sprpeek @fwi.uva.nl
stiefan
y
DIETERS. S. 7479 336 POSTDOC F stiefan @astro.uva.nl
stribbe
y
STIBBE, drs F.S. 5864 OWB NA170 stribbe @phys.uva.nl
stsrien
y
STRIEN. Prof. Dr S.J. van 5296 216 I P stsrien @fwi.uva.nl
sudtorp
y
SUTTORP, dr L.G. 5748 253 TF V65 sudtorp @phys.uva.nl
sutusan
y
USKDARLI. Drs mevr. S. 7585 229 III 403 sutusan @fwi.uva.nl
svlalen
y
DALEN, mw S.M. van 5887 OWB NA170 svlalen @phys.uva.nl
sy0lvia
y
RIGA, S 5200 P021 B/ GB P sy0lvia @fwi.uva.nl
t6nt60
y
GAEMERS, prof. dr K.J.F. 5925003 HEF K409 t6nt60 @nikhef.nl
taiautz
y
TAUTZ, S. 5795 B63 VEF V65 taiautz @phys.uva.nl
tautang
y
TANG, drs W.H. 5767 382 TF V65 tautang @phys.uva.nl
teankel
y
WINKEL, J. te 5009 T113 VEF V65 teankel @phys.uva.nl
temeije
y
JONG. T. de 7495 343 WP F temeije @sron.rug.nl
teremme
y
TEMME, S. 6395 119 VEF V65 teremme @phys.uva.nl
tewwijn
y
TERWIJN. Drs S.A. 6925 322 II P tewwijn @fwi.uva.nl
theheor
y
RUNNENBURG. Prof. Dr J.Th. 6096 236 I P theheor @fwi.uva.nl
theheos
y
SUIDGEEST. T.J.P. 7463 208 B 403 theheos @fwi.uva.nl (co-mgr)
thepapa
y
PAPATHANASSIADIS. Drs Th. 7578 113 lV 403 thepapa @fwi.uva.nl
thethao
y
XUAN-THAO, mw 5793 B51 VEF V65 thethao @phys.uva.nl
thetheo
y
JANSSEN. Dr Th.M.V. 5361 328 II P thetheo @fwi.uva.nl
thjeets
y
SMEETS, mw M.T.M.C.D. 6055 152 P&O V65 thjeets @phys.uva.nl
thkheun
y
BRUINS. Prof. Drs T.(alleen vrijdags) 7535 109 IV 403 thkheun @fwi.uva.nl
thothk
y
KOORNWINDER. Prof. Dr T.H. 5297 229 I P thothk @fwi.uva.nl
thsomas
y
AUGUSTEIJN. T. 7478 335 F thsomas @astro.uva.nl
tietim
y
OOSTERBROEK. T. 7467 304 AIO F tietim @astro.uva.nl
tijtij
y
SMIT, T. 5925126 HEF K409 tijtij @phys.uva.nl
tijtijn
y
SMIT, T. 5773 252 TF V65 tijtijn @phys.uva.nl
tiltijn
y
SMIT. T. 592.5126 346 AIO H tiltijn @astro.uva.nl
timilde
y
TILDE. de 5806 K 011 P timilde @fwi.uva.nl
tjbepke
y
BLANKSMA. Dr Tj. 5204 226 I P tjbepke @fwi.uva.nl
tmmtmb
y
BELLONI. T. 7478 335 POSTDOC F tmmtmb @astro.uva.nl
toctoto
y
INGE. Drs A. van 7578 113 IV 403 toctoto @fwi.uva.nl
tontom
y
GREGORKIEWICZ, dr T. 5643 B55 VEF V65 tontom @phys.uva.nl
totonny
y
PISA-BLIJLEVEN. A.P.M. 6076 115 B P totonny @fwi.uva.nl
tsihuit
y
SCHUITEMAKER, T. 5163 342 VEF V65 tsihuit @phys.uva.nl
tuiuijn
y
TUIJN, drs C. 5763 392 VEF V65 tuiuijn @phys.uva.nl
tultung
y
TUNG, Le Duc 5635 B83 VEF V65 tultung @phys.uva.nl
tunuijn
y
TUIJN, drs C. 5874 WBO NA170 tunuijn @phys.uva.nl
uynings
y
UYLINGS, dr P.H.M. 5006 333 VEF V65 uynings @phys.uva.nl
valanes
y
ES. Dr A.J. van 5365 212 I P valanes @fwi.uva.nl
vanbart
bart
y BART, drs C. van 5968 DID NA170 vanbart @phys.uva.nl
vbburen
y
BUUREN, O. van 5889 VEF/COO NA170 vbburen @phys.uva.nl
vbuemen
y
BLOEMEN, W.F.A. van 7563 P&O K403 vbuemen @phys.uva.nl
vdeberg
y
BERG, dr H.R. van den 6386 B06 VEF V65 vdeberg @phys.uva.nl
vdhenen
y
DEENEN, drs B. van 6395 119 VEF V65 vdhenen @phys.uva.nl
vdhooft
y
HOOFT. F. van der 7477 334 OIO F vdhooft @astro.uva.nl
vdhuvel
y
HEUVEL. Drs E. R. van den 5091 217 I P vdhuvel @fwi.uva.nl
vdphorn
y
HORN, dr L.J. van den 5776 361 TF V65 vdphorn @phys.uva.nl
vdrveen
y
VEEN, prof. dr J.F. van der 6352 143 VEF V65 vdrveen @phys.uva.nl
vdupoll
y
POLL. S. van der 6085 117 III P vdupoll @fwi.uva.nl
vdvuijn
y
DUIJN, drs V.H.M. 5647 B42 VEF V65 vdvuijn @phys.uva.nl
verduyn
y
VERDUYN LUNEL. Dr S.M. 5202 224 I P verduyn @fwi.uva.nl
vererkm
y
VERBERKMOES, A. 6308 362 TF V65 vererkm @phys.uva.nl
verinde
y
VERLINDE, prof. dr H.L. 5769 357 TF V65 verinde @phys.uva.nl
viasser
y
VISSER. Drs. E. 7590 243 III 403 viasser @fwi.uva.nl
visinie
y
MEIJER-MES. mevr. V. 7549 141 SION 403 visinie @fwi.uva.nl
vlander
y
VLAANDEREn, drs C.L. 5875 NA170 vlander @phys.uva.nl
vleming
y
VLAMING, dr R. 5771 352 TF V65 vleming @phys.uva.nl
vr5ssum
y
ROSSUM, drs M.C.W. van 6332 233 VEF V65 vr5ssum @phys.uva.nl
vroeugd
y
VREUGD. Drs C. de 6088 231 I P vroeugd @fwi.uva.nl
w5aw55
y
ECHTELT. J. van 592.5007 NIKHEF K409 w5aw55 @nikhef.nl
wagsink
y
WASSINK, A.J. 5009 T113 SYS V65 wagsink @phys.uva.nl
walallr
y
WAALL. Dr R.W. van der 5374 222 I P walallr @fwi.uva.nl
walaven
y
WALRAVEN, prof. dr J.T.M. 6330 205 VEF V65 walaven @phys.uva.nl
wallter
y
HOFFMANN. Dr W. 7538 204 IV 403 wallter @fwi.uva.nl
walstra
y
WALSTRA, T.R. 5876 WBO NA170 walstra @phys.uva.nl
walwals
y
WALS, drs J. 5008 324 VEF V65 walwals @phys.uva.nl
waslter
y
HOFFMANN. Dr W. 6081 218 I P waslter @fwi.uva.nl
weeweis
y
WEIS. 5806 K 011 P weeweis @fwi.uva.nl
weigdam
y
WEGDAM, dr G.H. 6313 218 VEF V65 weigdam @phys.uva.nl
weiijer
y
WEIJER, mw R. 5716 146 VEF V65 weiijer @phys.uva.nl
wijdijk
y
WIEDIJK. Drs M. 7533 103 IV 403 wijdijk @fwi.uva.nl
wijenga
y
WIJBENGA, mw P. 6343 111 SYS V65 wijenga @phys.uva.nl
wimstra
y
WIJKSTRA. Drs M. 7522 43 IV 403 wimstra @fwi.uva.nl
wiszenh
y
WITZENHAUSEN, mw F.J. 6334 221 VEF V65 wiszenh @phys.uva.nl
witwimv
y
VREE. Dr W.G. (alleen vrijdags) 7535 109 IV 403 witwimv @fwi.uva.nl
wkrwks
y
SPRIJ. Drs W.K. 7548 140 SION 403 wkrwks @fwi.uva.nl
wooring
y
WORRING. Dr M 7521 42 IV 403 wooring @fwi.uva.nl
wv7wvos
y
VOS, dr W.L. 6388 VEF V65 wv7wvos @phys.uva.nl
y4ky47
y
BUSKENS, J.P.M. 5925038 HEF K409 y4ky47 @nikhef.nl
yankali
y
YAKALI. Drs.. H.H. 7524 45 IV 403 yankali @fwi.uva.nl
yaoyang
y
YANG HUA, drs 5763 392 VEF V65 yaoyang @phys.uva.nl
yskolde
y
BENTVELSEN. mw. Drs Y.M. 6067 111a B P yskolde @fwi.uva.nl
yuoyuri
y
ENGELHARDT. Y. 6511/2072 316 II P yuoyuri @let.uva.nl
yuragan
y
KAGAN, dr M.Yu. 6378 113 TF V65 yuragan @phys.uva.nl
yv6onne
y
VOORN. mevr. Y.E.Ch. 5217 214 B P yv6onne @fwi.uva.nl
z6az66
y
LINDE, prof. dr F.L. 5925134 HEF K409 z6az66 @nikhef.nl
zayzaal
y
ZAAL. Drs C.G. 5205 223 I P zayzaal @fwi.uva.nl
zbbszek
y
STRUZIK. Ir Z.R. 7522 43 IV 403 zbbszek @fwi.uva.nl
zeneber
y
ZEVENBERGEN, mw drs I. 5642 B57 VEF V65 zeneber @phys.uva.nl
zoerva
y
ZONDERVAN, ing. J. 5733 T115 VEF V65 zoerva @phys.uva.nl
De heer
Mevrouw
De heer
Mevrouw
De heer
Mevrouw
De heer
Mevrouw
De heer
Mevrouw
Mw. dr.
Mw. drs.
dra.
dr.
drs.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment