3.2. Représentation des fichiers séquentiels

On étudie dans cet exercice diverses représentations d'un fichier dont les enregistrements logiques sont de 50 octets.
A- On dispose d'un lecteur de bandes magnétiques à 1600 BPI (Bytes Per Inch). On suppose que l'espace interbloc est de 3/4 inch. Le temps de lecture ou d'écriture d'un bloc physique de T octets est 10 + 0.008 * T ms.
A.1- On place un enregistrement logique du fichier par bloc physique. Donner le coefficient d'utilisation de la bande ainsi que le temps de lecture/écriture d'un enregistrement logique.
A.2- Pour améliorer cette utilisation, proposer une structure d'un bloc physique permettant le regroupement de plusieurs enregistrements logiques dans un même bloc. Décrire brièvement l'algorithme de lecture, ainsi que l'algorithme d'écriture des enregistrements logiques du fichier.
A.3- Donner, dans les hypothèses de A.2, la taille d'un bloc en fonction du nombre n d'enregistrements logiques qu'il contient. Donner le coefficient d'utilisation de la bande et le temps moyen de lecture/écriture d'un enregistrement logique, lorsque n = 20 ou n = 50.
B- On dispose d'un disque dont les secteurs sont de 1024 octets. On suppose que le temps moyen de lecture/écriture de s secteurs consécutifs est 8 + s ms (On ne prend pas en compte le mouvement du bras, car on suppose le bras “ bien placé ” au moment de l'opération).
B.1- On place un enregistrement logique du fichier par secteur. Donner le coefficient d'utilisation du disque ainsi que le temps d'exécution de lecture/écriture par enregistrement logique, lors d'un accès séquentiel au fichier.
B.2- On applique la méthode de regroupement vue en A.2. Donner le coefficient d'utilisation de la bande et le temps moyen de lecture/écriture d'un enregistrement logique, lorsque n = 20 ou n = 50.
B.3- Donner la valeur de n qui utilise au mieux les blocs physiques sur 1 secteur; donner dans ce cas le coefficient d'utilisation du disque ainsi que le temps moyen de lecture/écriture d'un enregistrement logique dans ce cas. Même question lorsque les blocs occupent 2, puis 3 secteurs.
C- Le disque comporte 16 secteurs par piste, 20 faces, et 900 cylindres.
C.1- Proposer une numérotation linéaire de l'ensemble des secteurs, ainsi que l'algorithme associé permettant de retrouver à partir d'un numéro virtuel de secteur ses numéros de secteur, face, cylindre.
C.2- L'espace attribué au fichier est une collection d'au plus 24 groupes de secteurs virtuels contigus, le premier groupe étant de taille s, et les suivants étant de taille i. Proposer une représentation de l'espace alloué à un fichier. Définir les algorithmes de lecture et d'écriture séquentielle d'un enregistrement logique, en supposant les enregistrements regroupés par bloc de 1 secteur comme précisé en B.3.
C.3- Évaluer le nombre d'enregistrements logiques du fichier suivant les valeurs des paramètres s et i. Donner les critères de choix qui permettraient de déterminer ces paramètres.
C.4- Application numérique, d'une part au cas où l'on sait que le fichier contiendra exactement 500000 enregistrements logiques, d'autre part au cas où le fichier contiendra entre 300000 et 1000000 enregistrements.
Solution du problème 3.2

3.2.1. Question A

3.2.1.1. Question A.1

L'espace interbloc représente 3/4 * 1600 octets, soit 1200 octets. L'occupation est donc de 50 / 1250, soit 4 %. Le temps de lecture/écriture est de 10 + 0.008 * 50, soit 10.4 ms.

3.2.1.2. Question A.2

Lorsque les enregistrements sont de taille fixe, la structure la plus simple est de les mettre les uns derrière les autres, à charge pour les sous programmes de lecture et d’écriture de ces enregistrements de découper le bloc physique selon la taille connue des enregistrements logiques. Lorsqu’ils sont de taille variable, il faut connaître la taille de chacun. Le choix d’un caractère spécial comme séparateur n’est pas en général acceptable, car cela implique de l’interdire dans les enregistrements eux-mêmes, ce qui est une contrainte pour l’utilisateur. L’autre solution est de faire précéder chaque enregistrement de sa taille. Dans beaucoup de systèmes, la structure est définie de façon standard et complète, pour permettre de prendre en compte d'une part les enregistrements de taille variable, les blocs de taille variable, ainsi que les opérations de lecture arrière. Une certaine redondance est présente, pour permettre des contrôles. La structure d'un bloc physique pourrait être la suivante:
	numéro_bloc  2 octets
	long_bloc	  2 octets
		long_enrg		   2 octets
		enregistrement	   p octets	   n fois
		long_enrg		   2 octets
	long_bloc	  2 octets
	numéro_bloc  2 octets
Pour réaliser les opérations de lecture et d'écriture, on doit disposer d'un tampon de au moins T octets, et de trois variables numéro donnant le numéro du bloc en cours, long repérant la longueur du bloc courant et position repérant la position dans le bloc du prochain enregistrement à lire (ou écrire). Nous ne nous préoccupons ici que de la lecture avant, laissant au lecteur le soin de réaliser l'opération de lecture arrière. Les procédures pourraient être comme suit:
procédure lire_enrg(var enregistrement: tableau_octets; var l_enrg: entier);
début si position >= long - 4 alors
		numéro:=numéro+1; lire_bloc; {lecture physique dans le tampon[0..T-1]}
		si tampon[0..1] ≠ numéro alors erreur("numéro de bloc erroné") finsi;
		long := tampon[2..3]; position := 4;
	  finsi;
	  l_enrg := tampon[position .. position + 1];
	  enregistrement := tampon[position + 2 .. position + 1 + l_enrg];
	  position := position + 4 + l_enrg;
fin;
procédure écrire_enrg( enregistrement : tableau_octets; l_enrg : entier);
début si position + l_enrg + 8 > taille_max alors
		numéro := numéro + 1;			   { fin de préparation du bloc }
		tampon[0 .. 1] := numéro;
		tampon[2 .. 3] := position + 4;
		tampon[position .. position + 1] := position + 4;
		tampon[position + 2 .. position + 3] := numéro;
		écrire_bloc;					 { écriture physique du tampon }
		position := 4;
	  finsi;
	  tampon[position .. position + 1] := l_enrg;
	  tampon[position + 2 .. position + 1 + l_enrg] := enregistrement;
	  tampon[position + 2 + l_enrg .. position + 3 + l_enrg] := l_enrg;
	  position := position + 4 + l_enrg;
fin;

3.2.1.3. Question A.3

La taille d'un bloc est T = 8 + n * ( p + 4 ), soit dans notre cas, T = 8 + n * 54. On peut mesurer l'utilisation de deux façons, soit en prenant l'ensemble des informations écrites, soit en ne considérant que les enregistrements seuls. On a donc:
n
T
utilisation
util. stricte
temps

8+n(4+p)
T/(T+1200)
np/(T+1200)
(10+810-3 T)/n
20
1088
48 %
44 %
0.94 ms
50
2708
69 %
64 %
0.63 ms

3.2.2. Question B

3.2.2.1. Question B.1

En prenant 1 secteur par enregistrement logique, le coefficient d'utilisation du disque est de 50 / 1024, soit environ 4.9 %. Le temps d'une opération est de 9 ms par enregistrement logique.

3.2.2.2. Question B.2

Avec la méthode de regroupement définie en A.2, comme il faut un nombre entier de secteurs par bloc, on a donc:
n
T
s
utilisation
util. stricte
temps

8+n(4+p)
T/1024
T/1024s
np/1024s
(8+s)/n
20
1088
2
53 %
49 %
0.5 ms
50
2708
3
88 %
81 %
0.22 ms

3.2.2.3. Question B.3

En conservant la méthode de A.2, la valeur optimale de n pour un bloc de s secteurs est la partie entière de (1024 * s - 8) / (p + 4). On a donc:
s
n
T
utilisation
util. stricte
temps

(1024s-8)/(p+4)
8+n(4+p)
T/1024s
np/1024s
(8+s)/n
1
18
980
96 %
88 %
0.5 ms
2
37
2006
98 %
90 %
0.27 ms
3
56
3032
98.7 %
91 %
0.2 ms

3.2.3. Question C

3.2.3.1. Question C.1

Une numérotation linéaire possible est nv = ns + 16 * (nf + 20 * nc). Cette numérotation permet de donner des numéros consécutifs à tous les secteurs d'un même cylindre, et donc d'éviter les mouvements de bras entre secteurs virtuels voisins. L'algorithme permettant de retrouver les numéros de secteur, face, cylindre d'un secteur virtuel est le suivant:
ns := nv mod 16;
nf := (nv % 16) mod 20;
nc := (nv % 16) % 20;

3.2.3.2. Question C.2

L'espace alloué au fichier peut être représenté par la structure suivante:
espace = article s, i: entier;				{ taille 1er groupe et suivants }
			    nbg : entier;		{ nombre de groupes effectifs du fichier }
			    tab : tableau [0 .. 23] de entier;
			     {tab[i] est le numéro virtuel du premier secteur du groupe i}
	    finarticle;
Cette structure est contenue dans le descripteur du fichier. Elle est retrouvée depuis le disque lors de l'ouverture du fichier, et sera éventuellement réécrite sur disque en cas de modification (nouvelle allocation). Pour permettre de parcourir le contenu du fichier, on dispose d'une variable supplémentaire nsf qui repère le numéro logique du secteur correspondant au bloc actuellement dans le tampon. Ce numéro varie depuis 0 jusqu'à N-1, si N est le nombre total de secteurs du fichier. L'algorithme de lecture d'un enregistrement logique est le même que précédemment. Nous n'avons qu'à préciser l'opération de lecture des blocs physiques.
procédure lire_bloc;
début nsf := nsf + 1;
	  si nsf < espace.s alors nv := espace.tab[0] + nsf; {premier groupe}
	  sinon ng := (nsf - espace.s) % espace.i + 1;      {groupes suivants}
		    si ng ≥ espace.nbg alors erreur ("non alloué"); finsi;
		    nv := espace.tab[ng] + (nsf - espace.s) mod espace.i;
	  finsi;
	  ns := nv mod 16; nf := (nv % 16) mod 20; nc := (nv % 16) % 20;
	  lire_secteur (tampon, ns, nf, nc);
fin;
De même, l'algorithme d'écriture d'un enregistrement logique est le même que précédemment, et c'est même ce qui justifie de prendre la même structure de bloc. Nous n'avons qu'à définir la procédure d'écriture des blocs physiques.
procédure écrire_bloc;
début si nsf < espace.s alors nv := espace.tab[0] + nsf;  {premier groupe}
	  sinon ng := (nsf - espace.s) % espace.i + 1;       {groupes suivants}
		tantque ng ≥ espace.nbg faire
			si espace.nbg = 24 alors erreur ("trop de groupes"); finsi;
			demande_allocation( espace.tab[espace.nbg], espace.i);
			espace.nbg := espace.nbg + 1;
		fait;
		nv := espace.tab[ng] + (nsf - espace.s) mod espace.i;
	  finsi;
	  ns := nv mod 16; nf := (nv % 16) mod 20; nc := (nv % 16) % 20;
	  écrire_secteur (tampon, ns, nf, nc);
	  nsf := nsf + 1;
fin;

3.2.3.3. Question C.3

La réponse à B.3 précise qu'il y a 18 enregistrements logiques par secteur. Le nombre de secteurs alloués au fichier est s + (nbg - 1) * i. Donc le nombre d'enregistrements logiques du fichier est 18 * (s + (nbg - 1) * i) au plus, pour un nombre fixé de groupes. Si tous les groupes sont alloués, le nombre d'enregistrements peut atteindre 18 * (s + 23 * i). Par ailleurs, toujours pour un nombre de groupes fixé, il en contient:
nbg
nombre minimal d'enregistrements
nombre maximal d'enregistrements
0
0
0
1
1
18 * s
> 1
18 * (s + (nbg - 2) * i)) + 1
18 * (s + (nbg - 1) * i))
Cependant, le dernier groupe alloué ne sera occupé en moyenne qu'à 50 %. La perte sera donc de 9 * s ou de 9 * i suivant les cas. Ceci permet d'énoncer quelques critères de choix:
a) Si le nombre d'enregistrements logiques du fichier, disons N, est connu lors de la création, et ne doit pas varier, un seul groupe permet de diminuer les mouvements de bras, puisque l'espace alloué est contigu, donc occupe des cylindres consécutifs. Mais encore faut-il trouver un espace de s = N / 18 secteurs consécutifs libres.
b) Si le nombre N n'est connu que par sa limite inférieure N1 et sa limite supérieure N2, on doit avoir s + 23 * i  N2 / 18. Pour minimiser la perte d'espace pour non utilisation, on peut prendre i = (N2 - N1 ) / (18 * 24) et s = N1 / 18 + i. La perte d'espace sera alors en moyenne équivalente à 9 * i enregistrements logiques du fichier. Mais encore faut-il trouver un espace libre contigu d'au moins s secteurs.
c) Il est toujours possible de diminuer s, pour faciliter l'allocation du premier groupe, mais il faut alors augmenter i en conséquence. Cependant, si l'allocation du premier groupe est impossible dans ce cas, il est inutile de prendre s < i, car l'allocation des groupes suivants sera de toute façon impossible. On peut donc en déduire que s  N2 / (18 * 24). Par ailleurs, on doit avoir i  ((N2 / 18) - s) / 23, pour pouvoir ranger les N2 enregistrements.

3.2.3.4. Question C.4

Dans le cas où N = 500000, de a) ci-dessus, on en déduit que l'on peut prendre s = 500000 / 18 = 27778 secteurs. Ceci représente 10 % de l'espace total du disque, qu'il faut trouver de façon contiguë. Si ceci n'est pas possible, de c) ci-dessus, on en déduit que s  500000 / (18 * 24) = 1158 secteurs, et i  (27778 - s) / 23.
Dans le cas où N1 = 300000 et N2 = 1000000, de b) ci-dessus, on en déduit que l'on peut prendre i = 700000 / (18 * 24) = 1621, et s = 16667 + 1621 = 18288. Notons que en vertu de c) ci-dessus, on doit avoir s  2315, et i  (55560 - s) / 23.