campo-sirio/include/btrbase.c

715 lines
20 KiB
C
Executable File

#include "ccommon.h"
#include "genconst.h"
#include "ccustio.h"
#include "cbpltree.h"
#include "bplpriv.h"
#include "btrread.h"
#include "btrbase.h"
#include "checks.h"
#include <memory.h>
void Move(byte ,int ,int ,int ,char *,char *);
/*
@(SHF) Funzioni di base per il B+Tree
@($) ZPage B+TREE
@(ID)
Azzera una pagina del B+TREE.
@(FD)
*/
void ZPage(ActPage)
Page *ActPage; /* pagina attuale */
{
ActPage->PA.PageHeader.TPage = EmptyPage;
ActPage->PA.PageHeader.PathNumber = 0;
ActPage->PA.PageHeader.Flags = 0;
ActPage->PA.PageHeader.Father = NoLink;
ActPage->PA.PageHeader.Prev = NoLink;
ActPage->PA.PageHeader.Next = NoLink;
ActPage->PA.PageHeader.NKey = 0;
memset(ActPage->PA.AreaForKey, ' ', AreaLen);
}
/*
@($) GetHeader B+TREE
@(ID)
Legge l'header di un indice.
Restituisce il codice di errore.
@(FD)
@(ISV)
junk = variabile spazzatura per la chiamata della funzione "sleep".
w = descrittore della finestra.
@(FSV)
*/
int GetHeader(FilCheck, HPage, LockMode, Err)
FilCtrl *FilCheck; /* identificatore indice */
Page *HPage; /* pagina dell' indice */
int LockMode; /* lock sull'header */
int *Err; /* codice di errore */
{
do
{
CRead(&FilCheck->Fil, (char *) HPage, 1L, LockMode);
if (TESTLOCK(FilCheck->Fil.IOR))
message_box("Sono in attesa dell' indice");
} while TESTLOCK(FilCheck->Fil.IOR);
return((*Err = FilCheck->Fil.IOR));
}
/*
@($) PutHeader B+TREE
@(ID)
Scrive l'header di un indice.
Restituisce il codice di errore.
@(FD)
*/
int PutHeader(FilCheck, HPage, LockMode, Err)
FilCtrl *FilCheck; /* identificatore indice */
Page *HPage; /* pagina in cui scrivere l'header */
int LockMode; /* lock sull'header */
int *Err; /* errore */
{
CWrite(&FilCheck->Fil, (char *) HPage, 1L, LockMode);
return((*Err = FilCheck->Fil.IOR));
}
/*
@($) GetAPage B+TREE
@(ID)
Legge una pagina generica dell'indice.
Restituisce il codice di errore.
@(FD)
*/
int GetAPage(FilCheck, ActPage, Pg, Err)
FilCtrl *FilCheck; /* identificatore indice */
Page *ActPage; /* pagina letta */
RecNoType Pg; /* numero di pagina */
int *Err; /* codice di errore */
{
CRead(&FilCheck->Fil, (char *) ActPage, Pg + FilCheck->FHead.CABlock + 1,
NoLock);
return((*Err = FilCheck->Fil.IOR));
}
/*
@($) PutAPage B+TREE
@(ID)
Scrive una pagina generica dell'indice.
Restituisce il codice di errore.
@(FD)
*/
int PutAPage(FilCheck, ActPage, Pg, Err)
FilCtrl *FilCheck; /* identificatore indice */
Page *ActPage; /* pagina attiva */
RecNoType Pg; /* numero della pagina */
int *Err; /* codice errore */
{
CWrite(&FilCheck->Fil, (char *) ActPage, Pg + FilCheck->FHead.CABlock + 1,
NoLock);
return((*Err = FilCheck->Fil.IOR));
}
/*
@($) GetAKey B+TREE
@(ID)
Estrae una chiave da una pagina.
@(FD)
@(ISV)
BgnItem = numero di byte precedenti alla chiave dall'inizio della pagina.
@(FSV)
*/
void GetAKey(ActPage, KeyLen, Pstion, KKey, Index)
Page ActPage; /* pagina attiva */
int KeyLen; /* lunghezza della chiave */
int Pstion; /* numero chiave nella pagina */
TKey KKey; /* Valore chiave (in output) */
RecNoType *Index; /* indice associato a questa chiave */
{
int BgnItem;
BgnItem = (Pstion - 1) * (KeyLen + IndLen);
strcpy(KKey, (char *)(ActPage.PA.AreaForKey + BgnItem));
*Index = *((RecNoType *)(ActPage.PA.AreaForKey + BgnItem + KeyLen));
}
/*
@($) PutAKey B+TREE
@(ID)
Mette una chiave in una pagina.
@(FD)
@(ISV)
BgnItem = numero di byte precedenti alla chiave dall'inizio della pagina.
@(FSV)
*/
void PutAKey(KKey, Index, Pstion, KeyLen, ActPage)
TKey KKey; /* valore della chiave */
RecNoType Index; /* indice */
int Pstion; /* posizione nella quale scrivere la chiave */
int KeyLen; /* lunghezza della chiave */
Page *ActPage;/* pagina attiva */
{
register int BgnItem;
BgnItem = (Pstion - 1) * (KeyLen + IndLen);
strcpy((char *)(ActPage->PA.AreaForKey + BgnItem), KKey);
*((RecNoType *)(ActPage->PA.AreaForKey + BgnItem + KeyLen)) = Index;
}
/*
@($) Repos B+TREE
@(ID)
Riposizione all'ultima chiave letta dall'ultima operazione.
@(FD)
@(ISV)
WKey, WKey1 = variabili di lavoro contenenti chiavi.
WPos = variabile di lavoro contenente il numero di chiave nella pagina.
WPag = variabile di lavoro contenente il numero di pagina attuale.
WInd,WInd1 = variabili di lavoro contenenti indici associati alle chavi Wkey.
@(FSV)
@(IN)
Serve solo in multiutenza (XENIX).
@(FN)
*/
void Repos(FilCheck, BError)
FilCtrl *FilCheck; /* identificatore indice */
int *BError; /* codice errore (in output) */
{
TKey WKey, WKey1;
int WPos = FilCheck->Pos, WError;
RecNoType WPag = FilCheck->CurPag, WInd, WInd1;
if (GetAPage(FilCheck, &PathPage, WPag, BError) != NoErr) return;
if (PathPage.PA.PageHeader.NKey < WPos) WPos = PathPage.PA.PageHeader.NKey ;
GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, WPos, WKey, &WInd);
if ((strcmp(WKey, FilCheck->Key) == 0) && (WInd == FilCheck->Ind)) return ;
strcpy(WKey1, FilCheck->Key) ;
WInd = FilCheck->Ind ;
BTrRead(FilCheck, FilCheck->Key, WKey, &WInd1, BError) ;
if (*BError == BTrEmptyTree) return ;
if (FilCheck->Base[FilCheck->PN].DupKeys == TRUE)
{
while ((strcmp(WKey, WKey1) == 0) && (WInd1 < WInd))
{
if (WPos < PathPage.PA.PageHeader.NKey) WPos++;
else
if (PathPage.PA.PageHeader.Next == NoLink) break;
else
{
WPag = PathPage.PA.PageHeader.Next;
if (GetAPage(FilCheck, &PathPage, WPag, BError) != NoErr) return;
WPos = 1;
}
GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, WPos, WKey, &WInd1);
}
}
if (GetAPage(FilCheck, &PathPage, WPag, &WError) != NoErr) return;
if ((strcmp(WKey, WKey1) == 0) && (WInd == WInd1))
{
FilCheck->CurPag = WPag;
FilCheck->Pos = WPos;
}
else
{
if (*BError != BTrEOF)
{
FilCheck->CurPag = WPag;
FilCheck->Pos = WPos;
strcpy(FilCheck->Key, WKey) ;
FilCheck->Ind = WInd1;
*BError = BTrKeyNotFound;
}
}
}
/*
@($) BTrNext B+TREE
@(ID)
Restituisce la chiave successiva all'ultima letta.
@(FD)
@(ISV)
WKey = variabile di lavoro contenente la chiave.
- Versione DOS e XENIX
@(FSV)
*/
void BTrNext(FilCheck, KKey, IndSr, BError)
FilCtrl *FilCheck; /* identificatore indice */
TKey KKey; /* valore della chiave */
RecNoType *IndSr; /* indice associato */
int *BError; /* codice errore */
{
TKey WKey;
if (FilCheck->CurPag == NoLink)
{
MaxKey(FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Key);
BTrRead(FilCheck, FilCheck->Key, WKey, IndSr, BError) ;
*BError = BTrEOF;
}
else
{
#ifdef DOS
if (adelete)
{
adelete = FALSE;
#endif
Repos(FilCheck, BError) ;
if (*BError != NoErr)
{
if (*BError == BTrKeyNotFound)
{
strcpy(KKey,FilCheck->Key);
*IndSr = FilCheck->Ind ;
*BError = NoErr ;
}
return;
}
#ifdef DOS
}
else
if (GetAPage(FilCheck, &PathPage, FilCheck->CurPag, BError) != NoErr) return;
#endif
if (FilCheck->Pos < PathPage.PA.PageHeader.NKey)
{
FilCheck->Pos++;
GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
}
else
{
if (PathPage.PA.PageHeader.Next == NoLink)
{
GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
/*MaxKey(FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Key);*/
*BError = BTrEOF;
}
else
{
FilCheck->CurPag = PathPage.PA.PageHeader.Next;
if (GetAPage(FilCheck, &PathPage, FilCheck->CurPag, BError) != NoErr) return;
FilCheck->Pos = 1;
GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
}
}
strcpy(KKey,FilCheck->Key);
FilCheck->Ind = *IndSr ;
}
}
/*
@($) BTrPrev B+TREE
@(ID)
Restituisce la chiave successiva all'ultima.
@(FD)
@(ISV)
WKey = variabile di lavoro contenente una chiave.
- Versione DOS e XENIX
@(FSV)
*/
void BTrPrev(FilCheck, KKey, IndSr, BError)
FilCtrl *FilCheck; /* identificatore indice */
TKey KKey; /* valore della chiave (in output) */
RecNoType *IndSr; /* indice associato */
int *BError; /* codice di errore */
{
TKey WKey;
if (FilCheck->CurPag == NoLink)
{
MinKey(FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Key);
BTrRead(FilCheck, FilCheck->Key, WKey, IndSr, BError) ;
*BError = BTrBOF;
}
else
{
#ifdef DOS
if (adelete)
{
adelete = FALSE;
#endif
Repos(FilCheck, BError) ;
if ((*BError != NoErr) && (*BError != BTrKeyNotFound))
{
if (*BError == BTrEOF)
{
strcpy(KKey,FilCheck->Key);
*IndSr = FilCheck->Ind ;
*BError = NoErr ;
}
return;
}
#ifdef DOS
}
else
if (GetAPage(FilCheck, &PathPage, FilCheck->CurPag, BError) != NoErr) return;
#endif
*BError = NoErr;
if (FilCheck->Pos > 1)
{
FilCheck->Pos--;
GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
}
else
{
if (PathPage.PA.PageHeader.Prev == NoLink)
{
GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
/*MinKey(FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Key);*/
*BError = BTrBOF;
}
else
{
FilCheck->CurPag = PathPage.PA.PageHeader.Prev;
if (GetAPage(FilCheck, &PathPage, FilCheck->CurPag, BError) != NoErr) return;
FilCheck->Pos = PathPage.PA.PageHeader.NKey;
GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
}
}
strcpy(KKey, FilCheck->Key);
FilCheck->Ind = *IndSr ;
}
}
/*
@($) Move B+TREE
@(ID)
Sposta a destra od a sinistra un numero di byte "NByt" da una sorgente "Buff1"
ad una destinazione "Buff2".
@(FD)
@(ISV)
w = area di transito.
@(FSV)
*/
void Move(RghOrLft, NByt, BytBeg, BytDest, Buff1, Buff2)
byte RghOrLft; /* destra o sinistra */
int NByt; /* numero di byte da spostare */
int BytBeg; /* num. byte inizio sorgente */
int BytDest; /* num. byte inizio destinazione */
AreaKey Buff1; /* sorgente */
AreaKey Buff2; /* destinazione */
{
AreaKey w;
memcpy(w, &Buff1[BytBeg], NByt);
memcpy(&Buff2[BytDest], w, NByt);
}
/*
@($) ShiftPage B+TREE
@(ID)
Esegue uno spostamento di un certo numero di posizioni (coppie chiave-puntatore)
all'interno della pagina.
@(FD)
@(ISV)
Len = lunghezza di una coppia chiave-puntatore.
Beg = numero di byte dall'inizio della pagina alla chiave "StartK" (esclusa).
Dest = byte al quale si deve postare la coppia chiave-puntatore.
@(FSV)
*/
void ShiftPage(RghOrLft, StartK, NPos, MxKey, KeyLen, Page1)
byte RghOrLft; /* destra o sinistra */
int StartK; /* chiave di partenza */
int NPos; /* numero di posizioni da saltare */
int MxKey; /* numero max chiavi in una pagina */
int KeyLen; /* lunghezza di una chiave */
Page *Page1; /* pagina attiva */
{
register int Len = KeyLen + IndLen;
register int Beg = (StartK - 1) * Len;
register int Dest;
if (RghOrLft == RightDir)
{
Dest = Beg + NPos * Len;
if (Page1->PA.PageHeader.NKey + NPos <= MxKey)
{
Move(RightDir, (Page1->PA.PageHeader.NKey - StartK + 1) * Len, Beg, Dest, Page1->PA.AreaForKey, Page1->PA.AreaForKey);
Page1->PA.PageHeader.NKey += NPos;
}
}
else
{
Dest = Beg - NPos * Len;
if (StartK - NPos > 0)
{
if (StartK <= Page1->PA.PageHeader.NKey)
Move(LeftDir, (Page1->PA.PageHeader.NKey - StartK + 1) * Len, Beg, Dest, Page1->PA.AreaForKey, Page1->PA.AreaForKey);
Page1->PA.PageHeader.NKey -= NPos;
memset(&Page1->PA.AreaForKey[Page1->PA.PageHeader.NKey * Len], ' ', NPos * Len);
}
}
}
/*
@($) ShiftOut B+TREE
@(ID)
Sposta un certo numero di chiavi da una pagina.
@(FD)
@(ISV)
Len = lunghezza coppia chiave-puntatore.
@(FSV)
*/
void ShiftOut(FromK, Numk, ToK, KeyLen, Page1, Page2)
int FromK; /* prima chiave da spostare */
int Numk; /* numero di chiavi da spostare */
int ToK; /* posizione nella pagina destinazione */
int KeyLen;/* lunghezza della chiave */
Page *Page1;/* puntatore alla pagina destinazione */
Page *Page2;/* puntatore alla pagina sorgente */
{
register int Len = KeyLen + IndLen;
if (Page1->PA.PageHeader.TPage == Page2->PA.PageHeader.TPage)
Move(LeftDir, Numk * Len, (FromK - 1) * Len, (ToK - 1) * Len, Page2->PA.AreaForKey, Page1->PA.AreaForKey);
}
/*
@($) FindPos B+TREE
@(ID)
Cerca una chiave all'interno di una pagina.
Restituisce la chiave piu' simile.
@(FD)
@(ISV)
low = numero della chiave.
j = incremento in byte di coppia chiave puntatore.
@(FSV)
*/
int FindPos(ActPage, KKey, KeyLen, KeyOut, IndOut)
Page *ActPage; /* pagina attiva */
TKey KKey; /* valore chiave (input) */
int KeyLen; /* lunghezza della chiave */
TKey KeyOut; /* valore chiave (output) */
RecNoType *IndOut; /* indice associato */
{
register int low = 1, j = 0;
while (strcmp((char *)(ActPage->PA.AreaForKey + j), KKey) < 0)
if (low < ActPage->PA.PageHeader.NKey)
{
low++;
j += (KeyLen + IndLen);
}
else break;
strcpy(KeyOut, (char *)(ActPage->PA.AreaForKey + j));
*IndOut = *((RecNoType *)(ActPage->PA.AreaForKey + j + KeyLen));
return(low);
}
/*
@($) PerformOp B+TREE
@(ID)
Effettua operazioni di Underflow e Overflow sull'indice.
@(FD)
@(ISV)
Pst = variabile di lavoro contenente numeri chiave.
W = contatore.
OldKey = variabile di lavoro contenente il valore di chiavi.
@(FSV)
*/
void PerformOp(RecOp,ActPage,Pg,OvUnFlow,Temp,MxKey,MnKey,KeyLen,BError)
KOp RecOp; /* struttura contenente le operazioni da effettuare */
Page *ActPage; /* pagina attiva */
RecNoType Pg; /* numero pagina */
BOOLEAN *OvUnFlow;/* underflow opp. overflow */
KeyInd *Temp; /* di lavoro, contiene una coppia chiave-puntatore */
int MxKey; /* numero max chiave */
int MnKey; /* numero min chiave */
int KeyLen; /* lunghezza della chiave */
int *BError; /* codice errore */
{
int Pst, W, i;
TKey OldKey;
for (W = 0; W <= 1; W++)
{
if (RecOp[W].FlagOp)
{
RecOp[W].FlagOp = FALSE;
if (RecOp[W].Which == Inser)
{
Pst = 0;
while (Pst < ActPage->PA.PageHeader.NKey )
{
GetAKey(*ActPage, KeyLen, ++Pst, IntKey, &IntIndex);
if (IntIndex == RecOp[W].where) break;
}
if (ActPage->PA.PageHeader.NKey == MxKey)
{
GetAKey(*ActPage, KeyLen, MxKey, IntKey, &IntIndex);
if (strcmp(IntKey, RecOp[W].KeyAndInd.KKey) < 0)
{
strcpy(Temp->KKey, RecOp[W].KeyAndInd.KKey);
Temp->Ind = RecOp[W].KeyAndInd.Ind;
}
else
{
strcpy(Temp->KKey, IntKey);
Temp->Ind = IntIndex;
ActPage->PA.PageHeader.NKey--;
ShiftPage(RightDir, Pst, OnePos, MxKey, KeyLen, ActPage);
PutAKey(RecOp[W].KeyAndInd.KKey, RecOp[W].KeyAndInd.Ind, Pst, KeyLen, ActPage);
}
*OvUnFlow = TRUE;
}
else
{
*OvUnFlow = FALSE;
if (strcmp(IntKey, RecOp[W].KeyAndInd.KKey) < 0)
{
ActPage->PA.PageHeader.NKey++;
PutAKey(RecOp[W].KeyAndInd.KKey, RecOp[W].KeyAndInd.Ind, ActPage->PA.PageHeader.NKey, KeyLen, ActPage);
RecOp[W].FlagOp = TRUE;
RecOp[W].Which = Change;
RecOp[W].KeyAndInd.Ind = Pg;
}
else
{
ShiftPage(RightDir, Pst, OnePos, MxKey, KeyLen, ActPage);
PutAKey(RecOp[W].KeyAndInd.KKey, RecOp[W].KeyAndInd.Ind, Pst, KeyLen, ActPage);
}
}
}
else
if (RecOp[W].Which == Change)
{
Pst = 0;
GetAKey(*ActPage, KeyLen, ++Pst, IntKey, &IntIndex);
while ((IntIndex != RecOp[W].KeyAndInd.Ind) && (Pst < ActPage->PA.PageHeader.NKey))
GetAKey(*ActPage, KeyLen, ++Pst, IntKey, &IntIndex);
if (IntIndex == RecOp[W].KeyAndInd.Ind)
PutAKey(RecOp[W].KeyAndInd.KKey, IntIndex, Pst, KeyLen, ActPage);
*OvUnFlow = FALSE;
if ((IntIndex == RecOp[W].KeyAndInd.Ind) && (Pst == ActPage->PA.PageHeader.NKey))
{
RecOp[W].FlagOp = TRUE;
RecOp[W].Which = Change;
RecOp[W].KeyAndInd.Ind = Pg;
}
}
else
if (RecOp[W].Which == Delet)
{
Pst = 0;
GetAKey(*ActPage, KeyLen, ++Pst, IntKey, &IntIndex);
while ((IntIndex != RecOp[W].KeyAndInd.Ind) && (Pst < ActPage->PA.PageHeader.NKey))
GetAKey(*ActPage, KeyLen, ++Pst, IntKey, &IntIndex);
if (IntIndex == RecOp[W].KeyAndInd.Ind)
{
*OvUnFlow = (ActPage->PA.PageHeader.NKey == MnKey);
ShiftPage(LeftDir, ++Pst, OnePos, MxKey, KeyLen, ActPage);
}
}
if ((!OvUnFlow) && (Pst >= ActPage->PA.PageHeader.NKey))
{
RecOp[W].FlagOp = TRUE;
RecOp[W].Which = Change;
GetAKey(*ActPage, KeyLen, ActPage->PA.PageHeader.NKey, IntKey, &IntIndex);
strcpy(RecOp[W].KeyAndInd.KKey, IntKey);
RecOp[W].KeyAndInd.Ind = Pg;
}
}
}
}
/*
@($) ZrecOp B+TREE
@(ID)
Azzera la struttura delle operazioni da effettuare.
@(FD)
@(ISV)
i = contatore.
@(FSV)
*/
void ZRecOp(R)
KOp R; /* struttura operazioni da azzerare */
{
int i;
for (i = 0; i <= 1; i++)
{
R[i].FlagOp = FALSE;
R[i].Which = Nothing;
R[i].Posit = NoLink;
R[i].where = -1;
MinKey(MaxArray, R[i].KeyAndInd.KKey);
R[i].KeyAndInd.Ind = NoLink;
}
}