Για να τρέξετε το κάθε πρόγραμμα, μπορείτε να εκτελέσετε την εντολή make
στο directory που βρίσκεται το αρχείο Makefile
. Η επιλογή hp
κάνει compile την main για το αρχείο σωρού, η ht
για το αρχείο κατακερματισμού και η sht
για το αρχείο δευτερεύοντος ευρετηρίου. Τα εκτελέσιμα βρίσκονται στον κατάλογο build/
και πρέπει να εκτελεστούν από τον γονεϊκό κατάλογο. Άρα για παράδειγμα, για την εκτέλεση της main του αρχείου σωρού, θα πρέπει να εκτελέσετε ./build/hp_main
.
Οι παρακάτω συναρτήσεις εκμεταλλεύονται τις συναρτήσεις επιπέδου block BF_*
για την υλοποίησή τους, προσθέτοντας ωστόσο παραπάνω λειτουργικότητα.
HP_CreateFile
: Δημιουργεί το αρχείο με όνομαfilename
, δημιουργεί το block 0 κι αρχικοποιεί τις τιμές του όσον αφορά ταHP_info
καιHP_block_info
. Κάνει το block 0 dirty και το κάνει unpin. Τέλος, κλείνει το αρχείο.HP_OpenFile
: Ανοίγει το αρχείο σωρού με όνομαfilename
. Ελέγχει αν το αρχείο πρόκειται για αρχείο κατακερματισμού ή όχι. Αν όχι, συνεχίζει. Καθώς κάθε φορά που καλείται ηBF_OpenFile
τοfileDesc
αλλάζει, ενημερώνουμε κάθε φορά τοHP_info
του block 0. Κάνουμε dirty κι unpin το block 0, κρατώντας ωστόσο τοHP_info
στον σωρό κι επιστρέφοντάς το.HP_CloseFile
: Βρίσκει πόσα blocks έχει το αρχείο σωρού. Σε ένα for loop κάνει το καθένα unpin. Κλείνει το αρχείο κι αποδεσμεύει την μνήμη τουHP_info
που υπάρχει στον σωρό.HP_InsertEntry
: Βρίσκει το τελευταίο block του αρχείου σωρού. Ελέγχει αν υπάρχει αρκετός χώρος σε αυτό για την εγγραφή μιας πλειάδας. Αν ναι, αντιγράφει την πλειάδα σε αυτό. Αν όχι, δημιουργεί ένα νέο block στο τέλος του αρχείου σωρού, γράφει σε αυτό την πλειάδα και αρχικοποιεί τα metadata του. Έπειτα ενημερώνει τοHP_info
για το νέο block και το κάνει unpin. Τέλος, επιστρέφει τον αναγνωριστικό αριθμό του block στο οποίο έγινε τελικά η εγγραφή.HP_GetAllEntries
: Η συνάρτηση επιστρέφει μία μεταβλητήint read_blocks
. Αυτή αρχικοποιείται με -1 και ανανεώνεται όταν βρούμε ένα record με id
value. Αν επιστραφεί και δεν έχει αλλάξει, σημαίνει πως υπήρξε κάποιο σφάλμα. Διατρέχει όλα τα blocks του αρχείου σωρού, βρίσκει για το καθένα πόσες εγγραφές υπάρχουν και τυπώνει αυτές που έχουν id == value.
Ένα αρχείο σωρού χαρακτηρίζεται από τα εξής στοιχεία:
int fileDesc
: Ο αναγνωριστικός αριθμός ανοίγματος αρχείου από το επίπεδο block.int lastBlockDesc
: Ο αναγνωριστικός αριθμός του τελευταίου σε αριθμό block του αρχείου σωρού.char filetype[5]
: Ένα string που δηλώνει τον τύπο αρχείου. Μπορεί να είναι είτε “heap”, είτε “hashtable” είτε “sec-index”. Για αρχεία σωρού παίρνει την τιμή “heap”.
Ένα block ενός αρχείου σωρού χαρακτηρίζεται από τα εξής στοιχεία:
int blockDesc
: Ο αναγνωριστικός αριθμός του block στην αρίθμηση των block του αρχείου σωρού.int recsNum
: Το πλήθος εγγεγραμμένων πλειάδων στο συγκεκριμένο block.int nextBlock
: Ο αναγνωριστικός αριθμός του επόμενου block στην αρίθμηση των block του αρχείου σωρού. Αν δεν υπάρχει τότε έχει την τιμή -1, με την οποία αρχικοποιείται.
Το HP_ERROR
ορίζεται σε -1, καθώς δεν έχει αρχικοποιηθεί κι αλλιώς δεν δουλεύει η συνάρτηση CALL_BF
.
Οι παρακάτω συναρτήσεις εκμεταλλεύονται τις συναρτήσεις επιπέδου block BF_*
για την υλοποίησή τους, προσθέτοντας ωστόσο παραπάνω λειτουργικότητα.
HT_CreateFile
: Δημιουργεί το αρχείο με όνομαfilename
, δημιουργεί το block 0 κι αρχικοποιεί τις τιμές του όσον αφορά ταHT_info
καιHT_block_info
. Κάνει το block 0 dirty και το κάνει unpin. Τέλος, κλείνει το αρχείο.HT_OpenFile
: Ανοίγει το αρχείο κατακερματισμού με όνομαfilename
. Ελέγχει αν το αρχείο πρόκειται για αρχείο κατακερματισμού ή όχι. Αν ναι, συνεχίζει. Αρχικοποιεί το hashtable που θα υπάρχει στην μνήμη. Καθώς κάθε φορά που καλείται ηBF_OpenFile
τοfileDesc
αλλάζει, ενημερώνουμε κάθε φορά τοHT_info
του block 0. Κάνουμε dirty κι unpin το block 0, κρατώντας ωστόσο τοHT_info
στον σωρό κι επιστρέφοντάς το.HT_CloseFile
: Βρίσκει πόσα blocks έχει το αρχείο κατακερματισμού. Σε ένα for loop κάνει το καθένα unpin. Κλείνει το αρχείο κι αποδεσμεύει την μνήμη τουHT_info
που υπάρχει στον σωρό, καθώς και την μνήμη του hashtable.HT_InsertEntry
: Βρίσκει τον κάδο στον οποίο πρέπει να καταγραφεί η εγγραφή. Αν ο κάδος δεν έχει κάποιο block, τότε δημιουργεί ένα και το συσχετίζει με τον κάδο μέσω του hashtable. Βρίσκουμε αν στο πιο πρόσφατο block του κάδου χωράει η εγγραφή. Αν ναι, την γράφει εκεί. Αν όχι, δημιουργεί ένα νέο block για τον κάδο—το οποίο γίνεται το πιο πρόσφατό του—και γράφει εκεί την εγγραφή.HT_GetAllEntries
: Η συνάρτηση επιστρέφει μία μεταβλητήint read_blocks
. Αυτή αρχικοποιείται με -1 και ανανεώνεται όταν βρούμε ένα record με id
value. Αν επιστραφεί και δεν έχει αλλάξει, σημαίνει πως υπήρξε κάποιο σφάλμα. Η συγκεκριμένη συνάρτηση βρίσκει τον κάδο που περιέχει εγγραφές με id == value και διατρέχει όλα τα blocks του, από το πιο πρόσφατο προς το πρώτο.
Ένα αρχείο κατακερματισμού χαρακτηρίζεται από τα εξής στοιχεία:
int fileDesc
: Ο αναγνωριστικός αριθμός ανοίγματος αρχείου από το επίπεδο block.int lastBlockDesc
: Ο αναγνωριστικός αριθμός του τελευταίου σε αριθμό block του αρχείου κατακερματισμού.char filetype[10]
: Ένα string που δηλώνει τον τύπο αρχείου. Μπορεί να είναι είτε “heap”, είτε “hashtable” είτε “sec-index”. Για αρχεία κατακερματισμού παίρνει την τιμή “hashtable”.long int numBuckets
: Το πλήθος των κάδων που θα έχει το αρχείο κατακερματισμού.int *hashtable
: Ένας πίνακας μεταβλητού μεγέθους σε int. Το hashtable του αρχείου κατακερματισμού αναπαριστάται ως εξής: Η κάθε θέση του πίνακα hashtable αναπαριστά έναν κάδο. Δηλαδή για παράδειγμα, τοhashtable[2]
δηλώνει τον κάδο 2. Το περιεχόμενο της κάθε θέσης όμως είναι ένας int, ο οποίος ταυτίζεται με τοblockDesc
του block του κάδου που προστέθηκε πιο πρόσφατα σε αυτόν. Ένα παράδειγμα της μοντελοποίησης αυτής υπάρχει στο σχήμα@@latex:~@@fig-hashtable.
Ένα block ενός αρχείου κατακερματισμού χαρακτηρίζεται από τα εξής στοιχεία:
int blockDesc
: Ο αναγνωριστικός αριθμός του block στην αρίθμηση των block του αρχείου κατακερματισμού.int prevBlockDesc
: Ο αναγνωριστικός αριθμός του προηγούμενου block του κάδου. Αρχικοποιείται με -1 εφόσον δεν υπάρχει προηγούμενο block. Στο παράδειγμα του σχήματος fig-hashtable τοprevBlockDesc
του block 11 θα είναι ο αριθμός 7, ενώ τοprevBlockDesc
του block 7 θα είναι -1.int recsNum
: Το πλήθος εγγεγραμμένων πλειάδων στο συγκεκριμένο block.
Η συνάρτηση κατακερματισμού που χρησιμοποιήθηκε στη συγκεκριμένη υλοποίηση είναι η
Οι παρακάτω συναρτήσεις εκμεταλλεύονται τις συναρτήσεις επιπέδου block BF_*
για την υλοποίησή τους, προσθέτοντας ωστόσο παραπάνω λειτουργικότητα.
SHT_CreateSecondaryIndex
: Δημιουργεί το αρχείο δευτερεύοντος ευρετηρίου με όνομαsfileName
, δημιουργεί το block 0 κι αρχικοποιεί τις τιμές του όσον αφορά ταSHT_info
καιSHT_block_info
. Κάνει το block 0 dirty και το κάνει unpin. Τέλος, κλείνει το αρχείο.SHT_OpenSecondaryIndex
: Ανοίγει το αρχείο δευτερεύοντος ευρετηρίου με όνομαfilename
. Ελέγχει αν το αρχείο πρόκειται για αρχείο κατακερματισμού ή όχι. Αν ναι, συνεχίζει. Αρχικοποιεί το sht_hashtable που θα υπάρχει στην μνήμη. Καθώς κάθε φορά που καλείται ηBF_OpenFile
τοfileDesc
αλλάζει, ενημερώνουμε κάθε φορά τοSHT_info
του block 0. Κάνουμε dirty κι unpin το block 0, κρατώντας ωστόσο τοSHT_info
στον σωρό κι επιστρέφοντάς το.SHT_CloseSecondaryIndex
: Βρίσκει πόσα blocks έχει το αρχείο δευτερεύοντος ευρετηρίου. Σε ένα for loop κάνει το καθένα unpin. Κλείνει το αρχείο κι αποδεσμεύει την μνήμη τουSHT_info
που υπάρχει στον σωρό, καθώς και την μνήμη του sht_hashtable.SHT_SecondaryInsertEntry
: Δημιουργεί ένα νέοSHT_Record
από τοname
και τοblockid
. Βρίσκει τον κάδο του δευτερεύοντος ευρετηρίου στον οποίο πρέπει να καταγραφεί τοSHT_Record
, όπου σε περίπτωση λάθους επιστρέφει με τιμή -1. Αν ο κάδος δεν έχει ακόμα κάποιο κατανεμημένο σε αυτό block, τότε δημιουργεί ένα. Εισχωρεί τοSHT_Record
στο πιο πρόσφατο block του κάδου, αν χωράει σε αυτό. Αν όχι, τότε δημιουργεί ένα νέο block για τον κάδο και εισχωρεί εκεί την εγγραφή.SHT_SecondaryGetAllEntries
: Η συνάρτηση επιστρέφει μία μεταβλητήint read_blocks
. Αυτή αρχικοποιείται με -1 και ανανεώνεται όταν βρούμε ένα record με id
value. Αν επιστραφεί και δεν έχει αλλάξει, σημαίνει πως υπήρξε κάποιο σφάλμα. Η συγκεκριμένη συνάρτηση βρίσκει τον κάδο του δευτερεύοντος ευρετηρίου που μπορεί να περιέχει εγγραφές με hash value
hash(name)
της εγγραφής και διατρέχει τα blocks του. Αν βρει μια τέτοια εγγραφή, τότε φορτώνει το block τουdata.db
στο οποίο δείχνει η εγγραφή. Ύστερα, το διατρέχει ώσπου να βρει την εγγραφή με όνομαname
.
Αποτελεί μια εγγραφή του αρχείου δευτερεύοντος ευρετηρίου. Περιέχει:
char name[15]
: Το όνομα της εγγραφής. Έχει μέγιστο μήκος 15, όμοια με τοname
του structRecord
.int blockDesc
: Ο αναγνωριστικός αριθμός του block του αρχείου κατακερματισμού στο οποίο βρίσκεται η τιμή.
Ένα αρχείο δευτερεύοντος ευρετηρίου χαρακτηρίζεται από τα εξής στοιχεία:
int fileDesc
: Ο αναγνωριστικός αριθμός ανοίγματος αρχείου από το επίπεδο block.int lastBlockDesc
: Ο αναγνωριστικός αριθμός του τελευταίου σε αριθμό block του αρχείου δευτερεύοντος ευρετηρίου.char filetype[10]
: Ένα string που δηλώνει τον τύπο αρχείου. Μπορεί να είναι είτε “heap”, είτε “hashtable” είτε “sec-index”. Για αρχεία δευτερεύοντος ευρετηρίου παίρνει την τιμή “sec-index”.long int numBuckets
: Το πλήθος των κάδων που θα έχει το αρχείο δευτερεύοντος ευρετηρίου.int *sht_hashtable
: Ένας πίνακας μεταβλητού μεγέθους σε int, όμοιος με τον πίνακαhashtable
του αρχείου κατακερματισμού.
Ένα block ενός αρχείου δευτερεύοντος ευρετηρίου χαρακτηρίζεται από τα εξής στοιχεία:
int blockDesc
: Ο αναγνωριστικός αριθμός του block στην αρίθμηση των block του αρχείου δευτερεύοντος ευρετηρίου.int prevBlockDesc
: Ο αναγνωριστικός αριθμός του προηγούμενου block του κάδου. Αρχικοποιείται με -1 εφόσον δεν υπάρχει προηγούμενο block.int recsNum
: Το πλήθος εγγεγραμμένων πλειάδων στο συγκεκριμένο block.
Η συνάρτηση κατακερματισμού του αρχείου δευτερεύοντος ευρετηρίου ορίζεται στην SHT_Hash
. Παίρνει ως όρισμα το όνομα της εγγραφής και το πλήθος των κάδων του αρχείου. Επιστρέφει τον κάδο στον οποίο πρέπει να καταγραφεί η εγγραφή.
Ο αλγόριθμος κατακερματισμού εμπνεύστηκε εν μέρει από τον αλγόριθμο 16.2(a) του συγγράμματος [cite:@elmasriFundamentalsDatabaseSystems2016 574], ο οποίος φαίνεται στο σχήμα fig-hashing_algorithm.
Η υλοποίηση της συνάρτησης φαίνεται στο listing sht_hash.
Η συνάρτηση κατακερματισμού HashStatistics
βρίσκεται στο αρχείο src/stats.c
, μαζί με τις βοηθητικές της συναρτήσεις. Καλείται στο τέλος της κάθε main. Το filetype κάθε αρχείου περιγράφεται από string έτσι ώστε η πιθανότητα λάθους να είναι ελάχιστη, κάτι που με έναν απλό int δεν θα ίσχυε.
Οι βοηθητικές συναρτήσεις της HashStatistics
—οι οποίες αναπαριστούν και καθένα από τα βήματά της—είναι οι εξής:
int STATS_GetFiletype
: Επιστρέφει το filetype του αρχείου, όπου τιμή 1 δηλώνει αρχείο σωρού, τιμή 2 αρχείο κατακερματισμού και τιμή 3 αρχείο δευτερεύοντος ευρετηρίου. Αρχικοποιεί την μεταβλητήfiletype
σε -1, και την αλλάζει ανάλογα το είδος του αρχείου στην αντίστοιχη τιμή. Αν δεν βρεθεί αντιστοιχία σε κάποιο είδος αρχείου, παραμένει -1. Τέλος, η μεταβλητήfiletype
επιστρέφεται.int STATS_NumberOfBlocks
: Επιστρέφει το πλήθος των blocks του αρχείου. Εκμεταλλεύεται την έτοιμη συνάρτησηBF_GetBlockCounter
.int STATS_MinBlocksNum
: Επιστρέφει το ελάχιστο πλήθος εγγραφών που έχει κάθε bucket του αρχείου. Για κάθε bucket διατρέχουμε τα blocks, βρίσκουμε πόσες εγγραφές έχει το καθένα κι αθροίζουμε τις εγγραφές των blocks. Αν οι εγγραφές του bucket είναι λιγότερες από τοmin_records
, τότε το τελευταίο παίρνει την τιμή του πρώτου.int STATS_MaxBlocksNum
: Ίδια με την παραπάνω, αλλά επιστρέφει το μέγιστο πλήθος εγγραφών.int STATS_BucketsNum
: Επιστρέφει το πλήθος των κάδων του αρχείου κατακερματισμού/δευτερεύοντος ευρετηρίου. Χρησιμοποιείται για τον υπολογισμό του μέσου αριθμού των blocks που έχει κάθε bucket, καθώς ο τελευταίος θα ισούται με το πλήθος των blocks (STATS_NumberOfBlocks
) προς το πλήθος των κάδων.int STATS_PrintOverflowStats
: Εκτυπώνει το πλήθος των buckets που έχουν block υπερχείλισης, και πόσα block είναι αυτά για κάθε bucket. Διατρέχει τους κάδους κι υπολογίζει για τον καθέναν τις αντίστοιχες τιμές και τις εκτυπώνει.int HashStatistics
: Καλεί τις παραπάνω συναρτήσεις. Αυτή καλείται από την εκάστοτε main με τα κατάλληλα ορίσματα.
Οι “αυθαιρεσίες” όσον αφορά τους ορισμούς των συναρτήσεων βασίστηκε στις απαντήσεις του διδάσκοντα στο eClass.
- Τα αρχεία των εργασιών 1 και 2 βρίσκονται στους ίδιους καταλόγους καθώς έχουν κοινά αρχεία, βιβλιοθήκη κτλ.