ΕΘΝΙΚΟ ΜΕΤΣΟΒΙΟ ΠΟΛΥΤΕΧΝΕΙΟ ΣΧΟΛΗ ΗΛΕΚΤΡΟΛΟΓΩΝ ΜΗΧΑΝΙΚΩΝ ΚΑΙ ΜΗΧΑΝΙΚΩΝ ΥΠΟΛΟΓΙΣΤΩΝ ΤΟΜΕΑΣ ΤΕΧΝΟΛΟΓΙΑΣ ΠΛΗΡΟΦΟΡΙΚΗΣ ΚΑΙ ΥΠΟΛΟΓΙΣΤΩΝ ΠΡΟΧΩΡΗΜΕΝΑ ΘΕΜΑΤΑ ΒΑΣΕΩΝ Ε ΟΜΕΝΩΝ ΦΘΙΝΟΠΩΡΟ 2005 Λύση ΑΣΚΗΣΗΣ #1 Τ. Σελλής ΕΡΩΤΗΜΑ 1: Στα παρακάτω Ri() σηµαίνει ότι η δοσοληψία i διαβάζει το δεδοµένο Χ και Wi() σηµαίνει ότι η δοσοληψία i γράφει το δεδοµένο Χ. Για κάθε ένα από τα παρακάτω προγράµµατα (schedules) απαντήστε τις παρακάτω ερωτήσεις: (α) Είναι το πρόγραµµα σειριοποιήσιµο; Αν ναι, δώστε ένα ισοδύναµο σειριακό πρόγραµµα. Αν όχι, εξηγείστε σύντοµα γιατί. (β) Μπορεί να προκύψει το πρόγραµµα αυτό από πρωτόκολλο συντονισµού µε κλείδωµα σε δυο φάσεις (two-phase locking); Σύντοµα εξηγείστε γιατί ναι ή γιατί όχι. Πρόγραµµα 1 Πρόγραµµα 2 Πρόγραµµα 3 W2() R1() W1(Y) R3() W3(Y) R1() W2() R1() W3(Y) W2() R2() R1(Y) R4() W3() R1() W2() R1(Y) R2() W3(Y) W2() R3() ΑΠΑΝΤΗΣΗ: (α) Για το πρώτο πρόγραµµα ο αντίστοιχος γράφος σειριοποιησιµότητας είναι ο παρακάτω: Y Εφόσον σχηµατίζεται κύκλος µεταξύ των κόµβων 1, 3, 2 και µεταξύ των κόµβων 1 και 2, το πρόγραµµα δεν είναι σειριοποιήσιµο. Για το δεύτερο πρόγραµµα, ο γράφος σειριοποιησιµότητας έχει ως εξής: Y Εφόσον σχηµατίζεται κύκλος µεταξύ των κόµβων 1, 2, 3 το πρόγραµµα δεν είναι σειριοποιήσιµο. 1
Τέλος για το τρίτο πρόγραµµα ο γράφος σειριοποιησιµότητας φαίνεται στο επόµενο σχήµα. Y Στον παραπάνω γράφο δεν υπάρχει κανένας κύκλος συνεπώς το αντίστοιχο πρόγραµµα είναι σειριοποιήσιµο. Το ισοδύναµο σειριακό πρόγραµµα είναι το Τ1 Τ2 Τ3. (β) Τα προγράµµατα 1 και 2 δεν είναι δυνατόν να προκύψουν από το πρωτόκολλο συντονισµού µε κλείδωµα σε δυο φάσεις (two-phase locking) διότι δεν είναι σειριοποιήσιµα. Αντίθετα το τρίτο πρόγραµµα µπορεί να προκύψει από το πρωτόκολλο συντονισµού µε κλείδωµα σε δυο φάσεις µε τον ακόλουθο τρόπο: S1() R1() 2() W2() S1(Y) R1(Y) U1() U1(Y) 2() R2() 3(Y) W3(Y) W2() U2() U2() S3() R3() U3(Y) U3() C123 ΕΡΩΤΗΜΑ 2: Ας υποθέσουµε ότι έχουµε τέσσερις δοσοληψίες που κάνουν τα ακόλουθα: οσοληψία 1 οσοληψία 2 οσοληψία 3 οσοληψία 4 R1() R1(Y) W1() W1(Y) R2() R2() R2() W2() W3() W3(Y) R3() W3() R4() W4() και σε µια εκτέλεση τους παράγεται το Πρόγραµµα 1 ενώ σε µία άλλη το Πρόγραµµα 2 Πρόγρ. 1 Πρόγρ. 2 R4() W3() R2() R1() W4() W3(Y) R1(Y) W1() R3() W3() R2() W1(Y) R2() W2() R1() R2() R2() W3() W3(Y) R4() R1(Y) W4() W1() R2() R3() W3() W2() W1(Y) Για κάθε ένα από τα παραπάνω προγράµµατα (α) αποδείξτε ότι είναι ή δεν είναι σειριοποιήσιµο, (β) σε περίπτωση που είναι, δώστε το ισοδύναµο σειριακό, και (γ) σε περίπτωση που δεν είναι, δώστε ένα λίγο αλλαγµένο πρόγραµµα που θα το έκανε σειριοποιήσιµο. ΑΠΑΝΤΗΣΗ: (α) Για το πρώτο πρόγραµµα ο γράφος σειριοποιησιµότητας έχει ως εξής:,y, 2
Εφόσον ο γράφος δεν έχει κύκλους, το πρώτο πρόγραµµα είναι σειριοποιήσιµο. Αντίστοιχα για το δεύτερο ο γράφος σειριοποιησιµότητας φαίνεται παρακάτω:,y, Το δεύτερο πρόγραµµα δεν είναι σειριοποιήσιµο διότι ο αντίστοιχος γράφος σειριοποιησιµότητας περιέχει τρεις κύκλους (-, - και --). (β) Εφόσον ο γράφος για το πρώτο πρόγραµµα δεν έχει κύκλους, αυτό είναι σειριοποιήσιµο και ένα ισοδύναµο σειριακό πρόγραµµα είναι το Τ4 Τ3 Τ2. (γ) Το δεύτερο πρόγραµµα µπορεί να γίνει σειριοποιήσιµο µε τις παρακάτω αλλαγές : RR11( ()) R2() R2() W3() R1() W3(Y) R4() R1(Y) W4() W1() R2() R3() W2() W3() W22( () ) W1(Y) Ο γράφος σειριοποιησιµότητας του τελευταίου προγράµµατος φαίνεται στο επόµενο σχήµα.,y, Ένα ισοδύναµο σειριακό πρόγραµµα είναι το Τ4 Τ2 Τ3. ΕΡΩΤΗΜΑ 3 Ας υποθέσουµε ότι χρησιµοποιούµε πρωτόκολλο συντονισµού µε κλείδωµα σε δυο φάσεις (2-PL). Τα κλειδώµατα αναπαριστώνται ως εγγραφές µε τέσσερα πεδία: <obj_id, LOCK, no_trans, trans_list> όπου το obj_id είναι ένα µοναδικό χαρακτηριστικό για το αντικείµενο που κλειδώνεται, το LOCK είναι είτε S-LOCK είτε -LOCK, το no_trans δηλώνει τον αριθµό των δοσοληψιών που έχουν S-LOCK στο συγκεκριµένο αντικείµενο (ή 1 σε περίπτωση -LOCK) και το trans_list είναι δείκτης στη λίστα µε τις δοσοληψίες που έχουν κλείδωµα στο συγκεκριµένο αντικείµενο. Οι βασικές πράξεις που υποστηρίζονται από το σύστηµα για ένα αντικείµενο i είναι οι: S(T i, j): Αίτηση για S-LOCK στο αντικείµενο j από τη δοσοληψία T i. (T i, j): Αίτηση για -LOCK στο αντικείµενο j από τη δοσοληψία T i. U(T i, j ): Αίτηση για άρση του κλειδώµατος στο αντικείµενο j από τη δοσοληψία T i. LOCK( j ): Επιστροφή του τύπου κλειδώµατος που υπάρχει στο j, το οποίο µπορεί να είναι ένα από τα NO-LOCK,S-LOCK, -LOCK. 3
ώστε τον ψευδοκώδικα για τα S(Ti, j), (Ti, j), U(Ti, j), έτσι ώστε, χωρίς να αλλάξει ο αλγόριθµος 2-PL, (α) να υποστηρίζονται µετατροπές κλειδωµάτων και (β) να αποφεύγεται το πρόβληµα της λιµοκτονίας (starvation). ΑΠΑΝΤΗΣΗ: Η λύση που ακολουθεί είναι ενδεικτική και ο στόχος της είναι να είναι όσο το δυνατόν πιο απλή γίνεται. Για τις ανάγκες της άσκησης θεωρούµε ότι για κάθε αντικείµενο j έχουµε µία ουρά αναµονής µε τις δοσοληψίες που βρίσκονται σε αναµονή για κάποιο κλείδωµα στο j. Ο διαχειριστής κλειδωµάτων αφυπνίζει πάντα τη δοσοληψία που βρίσκεται στη κεφαλή (head) της ουράς, ενώ η πράξη wait() τοποθετεί πάντα µια δοσοληψία στο τέλος (tail) της ουράς. Επιπλέον, ορίζουµε τις ακόλουθες συναρτήσεις: lookup(j,ti): επιστρέφει τον τύπο κλειδώµατος που έχει στην κατοχή της η δοσοληψία Ti για το αντικείµενο j ή NO-LOCK σε περίπτωση που δεν έχει κάποιο κλείδωµα στο j. NoLocks(j): επιστρέφει τον αριθµό των δοσοληψιών που έχουν στην κατοχή τους κλείδωµα στο j. Στην περίπτωση που κάποια δοσοληψία έχει -LOCK στο j τότε µπορεί να είναι µόνο 1. lookup-queue(j): επιστρέφει τον πιο περιοριστικό τύπο κλειδώµατος για τον οποίο περιµένει µία δοσοληψία στην ουρά αναµονής του αντικειµένου j. ηλαδή, εάν περιµένουν µόνο δοσοληψίες για S-Lock, τότε επιστρέφει S-Lock, εάν περιµένει τουλάχιστον µια δοσοληψία για -Lock επιστρέφει -Lock και εάν δεν υπάρχει καµία δοσοληψία στην ουρά αναµονής για το j, επιστρέφει NO-LOCK. S(Ti, j) if (lookup(j, Ti) = S-Lock ) then // η δοσοληψία έχει ήδη S-LOCK στο j. if (lookup(j, Ti) = -Lock ) then // Παρατήρηση #1 (στο τέλος) LOCK(j) S-Lock ; if (lookup(j, Τi) = NO LOCK ) then if (LOCK(j) = NO LOCK ) then LOCK(j) S-Lock ; Trans_reading 1; if (LOCK(j) = S-LOCK ) then if (lookup-queue(j) = -Lock ) then // Παρατήρηση #2 wait(); //Until LOCK(j) = NO LOCK και o διαχειριστής κλειδωµάτων αφυπνίσει τη δοσοληψία call S(j); Trans_reading Trans_reading + 1; // LOCK(j) = Χ-LOCK wait(); //Until LOCK(j) = NO LOCK και o διαχειριστής κλειδωµάτων αφυπνίσει τη δοσοληψία call S(j); 4
(Ti, j) if (lookup(j, Ti) = -Lock ) then // η δοσοληψία έχει ήδη -LOCK στο j. if (lookup(j, Ti) = S-Lock ) then if (NoLocks(j) > 1) then // Παρατήρηση #3 wait(head_of_queue); //Until LOCK(j) = NO LOCK και o διαχειριστής κλειδωµάτων αφυπνίσει τη δοσοληψία call (j); LOCK(j) Χ-Lock ; if (lookup(j, Ti) = NO LOCK ) then if (LOCK(j) = NO LOCK ) then LOCK(j) -Lock ; wait(); //Until LOCK(j) = NO LOCK και o διαχειριστής κλειδωµάτων αφυπνίσει τη δοσοληψία call (j); U(Ti, j) if (lookup(j, Ti) = NO LOCK ) then // η δοσοληψία δεν έχει κάποιο κλείδωµα στο j. if (LOCK(j) = -LOCK ) then LOCK(j) NO Lock ; // Παρατήρηση #5 Εάν η λίστα αναµονής για το δεν είναι κενή: αφύπνισε τη δοσοληψία που βρίσκεται στην κεφαλή της ουράς αναµονής; if (LOCK(j) = S-LOCK ) then Trans_reading Trans_reading 1; if (Trans_reading = 0) then LOCK(j) NO Lock ; // Παρατήρηση #5 Εάν η λίστα αναµονής για το δεν είναι κενή: αφύπνισε τη δοσοληψία που βρίσκεται στην κεφαλή της ουράς αναµονής; 5
Παρατήρηση #1: Υποβάθµιση κλειδώµατος. Φυσικά, είναι επιτρεπτή µόνο στη φάση συρρίκνωσης της δοσοληψίας, όµως για τον συγκεκριµένο έλεγχο είναι υπεύθυνος ο 2PL αλγόριθµος ο οποίος βρίσκεται στο από πάνω επίπεδο (καλεί τη λειτουργία S()). Παρατήρηση #2: Ο συγκεκριµένος έλεγχος επιτρέπει την αποφυγή της λιµοκτονίας δοσοληψιών που περιµένουν για -LOCK, λόγω του γεγονότος ότι τις προσπερνάνε συνεχώς δοσοληψίες που ζητούν S- LOCK σε ένα αντικείµενο, καθώς εάν περιµένει τουλάχιστον µία δοσοληψία για -LOCK τότε όλες οι υπόλοιπες τοποθετούνται µετά από αυτήν. Σε περιβάλλοντα µε πολλές αιτήσεις για -LOCKs, ο προτεινόµενος αλγόριθµος µπορεί στη χειρότερη περίπτωση πρακτικά να εµποδίσει περισσότερες από µια δοσοληψίες να έχουν S-LOCK σε ένα αντικείµενο, καθώς θα έρχονται συνεχώς αιτήσεις για -LOCK και όλες οι αιτήσεις για S-LOCK θα τοποθετούνται στο τέλος της ουράς. Σε αυτή την περίπτωση µπορούµε να τροποποιήσουµε τον αλγόριθµο ως εξής: Θεωρούµε ότι η ουρά αναµονής είναι ουρά µε βάρη. Κάθε αντικείµενο ξεκινάει µε κάποιο αρχικό βάρος κατά την εισαγωγή του στην ουρά: w1 σε περίπτωση που είναι αίτηση για S-LOCK και w2 σε περίπτωση που είναι αίτηση για -LOCK. Θέτουµε τα w1 και w2 µε κάποιες τιµές (ανάλογα µε τη συµπεριφορά του αλγορίθµου που θέλουµε να πετύχουµε), όµως πάντα w1 > w2. Επιτρέπουµε µία αίτηση για S-LOCK µε βάρος w να προσπερνάει µία αίτηση για -LOCK µε βάρος w εάν w > w. Εάν βρει µία αίτηση για Χ-LOCK µε w w, τότε τοποθετείται ακριβώς πίσω από αυτήν στην ουρά. Αντίστοιχα, εάν µία αίτηση για S-LOCK φτάσει στην κεφαλή της ουράς, τότε παραχωρείται στην αντίστοιχη δοσοληψία το κλείδωµα και η αίτηση αποµακρύνεται από την ουρά αναµονής. Κάθε φορά που µία αίτηση προσπερνάει µία άλλη, το βάρος της τελευταίας τροποποιείται σύµφωνα µε κάποιο τύπο (και πάλι ανάλογα µε τη συµπεριφορά του αλγορίθµου που θέλουµε να πετύχουµε). Παραδείγµατος χάριν, θα µπορούσε να είναι w new = w old + 1 ή w new = w old * 1.1 κτλ. Παρατήρηση #3: Αναβάθµιση κλειδώµατος. Εάν η δοσοληψία Ti που ζητάει την αναβάθµιση κλειδώµατος σε ένα αντικείµενο j είναι η µόνη που έχει S-LOCK στο j, της επιτρέπεται η µετατροπή του S-LOCK σε -LOCK. Αντίθετα, εάν υπάρχει τουλάχιστον µία ακόµα δοσοληψία που έχει S-LOCK στο j, η Ti θα πρέπει να περιµένει να ελευθερωθεί το j από κλειδώµατα για να µπορέσει να πάρει -LOCK. Για να είναι σωστή η συγκεκριµένη λύση δεν θα πρέπει να εκτελεστεί το κλασικό wait(), καθώς αυτό θα τοποθετούσε τη δοσοληψία στο τέλος της ουράς αναµονής. Όµως, εάν υπάρχει τουλάχιστον µία ακόµα δοσοληψία Tk στην ουρά αναµονής, η οποία να περιµένει για -LOCK, η πράξη αυτή κάνει µη σειριοποιήσιµο το χρονοπρόγραµµα (καθώς είχαµε Ti Tk και προσθέσαµε το Tk Ti). Το αντίστοιχο ισχύει υπό προϋποθέσεις ακόµα και για δοσοληψίες που περιµένουν για S-LOCK. Έτσι, η πιο ασφαλής λύση είναι να τοποθετήσουµε την Τi στην κεφαλή της ουράς αναµονής, το οποίο γίνεται µέσω της λειτουργίας wait(head_of_queue). Παρατήρηση #4: Τόσο η αναβάθµιση όσο και η υποβάθµιση κλειδώµατος από µία δοσοληψία σε ένα αντικείµενο j δεν µπορούν να οδηγήσουν σε λιµοκτονία τις υπόλοιπες δοσοληψίες εφόσον χρησιµοποιείται ο αλγόριθµος 2-PL (λόγω των φάσεων επέκτασης και συρρίκνωσης του αλγορίθµου). 6
Παρατήρηση #5: Μια τελευταία τροποποίηση του αλγορίθµου θα µπορούσε να επιτρέπει στον διαχειριστή κλειδωµάτων (µέσω της U()), όταν αφυπνίζει µία δοσοληψία που περιµένει για S-LOCK να αφυπνίζει και όλες τις υπόλοιπες δοσοληψίες στην ουρά αναµονής, οι οποίες περιµένουν επίσης για S- LOCK. Ο διαχειριστής κλειδωµάτων αφυπνίζει µόνο όσες δοσοληψίες δεν βρίσκονται πιο πίσω στην ουρά από µία δοσοληψία µε αίτηση για -LOCK ή σύµφωνα µε τους κανόνες της παρατήρησης #2. 7