2.2.1 The Naming Model
Pomocne jest posiadanie modelu tego, jak nazwy są kojarzone z określonymi obiektami. Projektant systemu tworzy schemat nazewnictwa, który składa się z trzech elementów. Pierwszym elementem jest przestrzeń nazw, na którą składa się alfabet symboli wraz z regułami składni, które określają, które nazwy są dopuszczalne. Drugim elementem jest algorytm mapowania nazw, który kojarzy niektóre (niekoniecznie wszystkie) nazwy z przestrzeni nazw z niektórymi (znowu niekoniecznie wszystkimi) wartościami w uniwersum wartości, które jest trzecim i ostatnim elementem schematu nazewnictwa. Wartość może być obiektem lub może to być inna nazwa z oryginalnej przestrzeni nazw lub z innej przestrzeni nazw. Odwzorowanie nazwa-wartość jest przykładem wiązania, a gdy takie odwzorowanie istnieje, mówi się, że nazwa jest związana z wartością. Rysunek 2.10 ilustruje.
W większości systemów, zazwyczaj kilka odrębnych schematów nazewnictwa działa jednocześnie. Na przykład, system może używać jednego schematu nazewnictwa dla nazw skrzynek poczty elektronicznej, drugiego schematu nazewnictwa dla hostów internetowych, trzeciego dla plików, a czwartego dla adresów pamięci wirtualnej. Kiedy interpreter programu napotyka nazwę, musi wiedzieć, który schemat nazewnictwa wywołać. Środowisko towarzyszące użyciu nazwy zwykle dostarcza wystarczająco dużo informacji, aby zidentyfikować schemat nazewnictwa. Na przykład, w programie użytkowym, autor tego programu wie, że program powinien oczekiwać, iż nazwy plików będą interpretowane tylko przez system plików, a nazwy hostów internetowych będą interpretowane tylko przez jakąś usługę sieciową.
Interpreter, który napotyka nazwę, uruchamia algorytm mapowania nazw odpowiedniego schematu nazewnictwa. Algorytm mapowania nazw rozwiązuje nazwę, co oznacza, że odkrywa i zwraca powiązaną z nią wartość (z tego powodu algorytm mapowania nazw jest również nazywany resolverem). Algorytm mapowania nazw jest zwykle kontrolowany przez dodatkowy parametr, zwany kontekstem. Dla danego schematu nazewnictwa może istnieć wiele różnych kontekstów, a pojedyncza nazwa przestrzeni nazw może być mapowana na różne wartości, gdy resolwer używa różnych kontekstów. Na przykład, w zwykłym dyskursie, gdy osoba odnosi się do nazw “ty”, “tutaj” lub “Alicja”, znaczenie każdej z tych nazw zależy od kontekstu, w którym osoba je wypowiada. Z drugiej strony, niektóre schematy nazewnictwa mają tylko jeden kontekst. Takie schematy nazewnictwa dostarczają tak zwanych uniwersalnych przestrzeni nazw i mają tę miłą właściwość, że nazwa zawsze ma to samo znaczenie w tym schemacie nazewnictwa, bez względu na to, kto jej używa. Na przykład, w Stanach Zjednoczonych, numery ubezpieczenia społecznego, które identyfikują rządowe konta emerytalne i podatkowe, stanowią uniwersalną przestrzeń nazw. Gdy istnieje więcej niż jeden kontekst, interpreter może powiedzieć resolwerowi, którego z nich powinien użyć lub resolwer może użyć kontekstu domyślnego.
Możemy podsumować model nazewnictwa definiując następującą operację konceptualną na nazwach:
value ← resolve (nazwa, kontekst)
Gdy interpreter napotyka nazwę w obiekcie, najpierw dowiaduje się, jaki schemat nazewnictwa jest zaangażowany, a zatem, którą wersję resolve powinien wywołać. Następnie identyfikuje odpowiedni kontekst, rozwiązuje nazwę w tym kontekście i zastępuje nazwę rozwiązaną wartością, gdy kontynuuje interpretację. Zmienna context mówi resolve, którego kontekstu użyć. Ta zmienna zawiera nazwę znaną jako odwołanie do kontekstu.
W procesorze, numery rejestrów są nazwami. W prostym procesorze, zestaw nazw rejestrów i rejestry, z którymi te nazwy są związane, są ustalone w czasie projektowania. W większości innych systemów, które używają nazw (w tym schemat nazewnictwa rejestrów w niektórych procesorach o wysokiej wydajności), możliwe jest tworzenie nowych i usuwanie starych wiązań, wyliczanie przestrzeni nazw w celu uzyskania listy istniejących wiązań oraz porównywanie dwóch nazw. Dla tych celów definiujemy cztery kolejne operacje konceptualne:
status ← bind (nazwa, wartość, kontekst)
status ← unbind (nazwa, kontekst)
list ← enumerate (kontekst)
result ← compare (nazwa1, nazwa2)
Pierwsza operacja zmienia kontekst przez dodanie nowego wiązania; wynik statusu informuje, czy zmiana się powiodła (może się nie powieść, jeśli proponowana nazwa narusza reguły składni przestrzeni nazw). Po udanym wywołaniu bind, resolve zwróci nową wartość dla name.*Druga operacja, unbind, usuwa istniejące wiązanie z kontekstu, przy czym status ponownie informuje o sukcesie lub porażce (być może dlatego, że nie było takiego istniejącego wiązania). Po udanym wywołaniu unbind, resolve nie będzie już zwracać tej wartości dla nazwy. Operacje bind i unbind pozwalają na użycie nazw do tworzenia połączeń pomiędzy obiektami i późniejszej zmiany tych połączeń. Projektant obiektu może, poprzez użycie nazwy do odwołania się do obiektu składowego, wybrać obiekt, z którym ta nazwa jest związana albo wtedy, albo w późniejszym czasie poprzez wywołanie bind, i wyeliminować wiązanie, które nie jest już odpowiednie poprzez wywołanie unbind, wszystko bez modyfikowania obiektu, który używa nazwy. Ta zdolność do opóźniania i zmiany wiązań jest potężnym narzędziem używanym w projektowaniu prawie wszystkich systemów. Niektóre implementacje nazewnictwa zapewniają operację enumerate, która zwraca listę wszystkich nazw, które mogą być rozwiązane w kontekście. Niektóre implementacje enumerate mogą również zwracać listę wszystkich wartości aktualnie powiązanych w kontekście. Na koniec, operacja compare informuje (true lub false) czy nazwa1 jest taka sama jak nazwa2 czy nie. Znaczenie słowa “taki sam” jest interesującym pytaniem, omówionym w sekcji 2.2.5, i może wymagać dostarczenia dodatkowych argumentów kontekstowych.
Różne schematy nazewnictwa mają różne reguły dotyczące unikalności mapowań nazwa-wartość. Niektóre schematy nazewnictwa mają regułę, że nazwa musi mapować do dokładnie jednej wartości w danym kontekście, a wartość musi mieć tylko jedną nazwę, podczas gdy w innych schematach nazewnictwa jedna nazwa może mapować do kilku wartości lub jedna wartość może mieć kilka nazw, nawet w tym samym kontekście. Innym rodzajem reguły unikalności jest reguła przestrzeni nazw unikalnego identyfikatora, która zapewnia zestaw nazw, które nigdy nie będą ponownie używane przez cały okres istnienia przestrzeni nazw, a raz związane, zawsze pozostaną związane z tą samą wartością. Mówi się, że taka nazwa ma stabilne wiązanie. Jeśli przestrzeń nazw unikalnych identyfikatorów ma również zasadę, że wartość może mieć tylko jedną nazwę, unikalne nazwy stają się przydatne do śledzenia obiektów w długim okresie czasu, do porównywania odniesień, aby sprawdzić, czy są one do tego samego obiektu, oraz do koordynacji wielu kopii w systemach, w których obiekty są replikowane dla wydajności lub niezawodności. Na przykład, numer konta klienta w większości systemów bilingowych stanowi unikalny identyfikator przestrzeni nazw. Numer konta będzie zawsze odnosił się do tego samego konta klienta, tak długo jak to konto istnieje, pomimo zmian w adresie klienta, numerze telefonu, a nawet imieniu i nazwisku. Jeśli konto klienta zostanie usunięte, numer konta tego klienta nie zostanie kiedyś ponownie użyty dla innego konta klienta. Nazwane pola w ramach konta, takie jak saldo należności, mogą się zmieniać od czasu do czasu, ale wiązanie między numerem konta klienta a samym kontem jest stabilne.
Algorytm mapowania nazw plus pojedynczy kontekst niekoniecznie mapują wszystkie nazwy przestrzeni nazw na wartości. Tak więc możliwym wynikiem wykonania resolve może być wynik not-found, który resolve może przekazać do wywołującego albo jako zarezerwowaną wartość, albo jako wyjątek. Z drugiej strony, jeśli schemat nazewnictwa pozwala na mapowanie jednej nazwy do kilku wartości, możliwym wynikiem może być lista wartości. W takim przypadku operacja odwiązania może wymagać dodatkowego argumentu określającego, która wartość ma zostać odwiązana. Wreszcie, niektóre schematy nazewnictwa zapewniają odwrotne wyszukiwanie, co oznacza, że wywołujący może dostarczyć wartość jako argument algorytmu mapowania nazw i dowiedzieć się, jaka nazwa lub nazwy są związane z tą wartością.
Rysunek 2.10 ilustruje model nazewnictwa, pokazując przestrzeń nazw, odpowiadające jej uniwersum wartości, algorytm mapowania nazw i kontekst, który kontroluje algorytm mapowania nazw.
W praktyce spotyka się trzy często używane algorytmy mapowania nazw:
Table lookup
■
Recursive lookup
■
Multiple lookup
Najczęściej spotykaną implementacją kontekstu jest tablica par {nazwa, wartość}. Gdy implementacja kontekstu jest tabelą, algorytm mapowania nazw jest po prostu odszukiwaniem nazwy w tej tabeli. Sama tabela może być złożona, obejmując haszowanie lub B-drzewa, ale podstawowa idea jest wciąż taka sama. Powiązanie nowej nazwy z wartością polega na dodaniu tej pary {nazwa, wartość} do tabeli. Rysunek 2.11 ilustruje tę powszechną implementację modelu nazewnictwa. Dla każdego kontekstu istnieje jedna taka tabela, a różne konteksty mogą zawierać różne wiązania dla tej samej nazwy.
Przykłady z rzeczywistego świata zarówno ogólnego modelu nazewnictwa, jak i implementacji table-lookup są liczne:
Książka telefoniczna jest kontekstem table-lookup, który wiąże nazwy osób i organizacji z numerami telefonów. Podobnie jak w przykładzie sieci teleinformatycznej, numery telefonów są same w sobie nazwami, które firma telefoniczna rozwiązuje w fizyczne występy linii, używając algorytmu mapowania nazw, który obejmuje kody obszarów, centrale i fizyczne przełączniki. Książki telefoniczne dla Bostonu i San Francisco są dwoma kontekstami tego samego schematu nazewnictwa; każda konkretna nazwa może pojawić się w obu książkach telefonicznych, ale jeśli tak, to prawdopodobnie jest związana z różnymi numerami telefonów.
Małe liczby całkowite nazywają rejestry procesora. Wartością jest sam rejestr, a odwzorowanie od nazwy do wartości jest realizowane przez okablowanie.
Komórki pamięci są podobnie nazywane liczbami zwanymi adresami, a odwzorowanie od nazwy do wartości jest ponownie realizowane przez okablowanie. W rozdziale 5 opisano mechanizm zmiany nazw adresów, znany jako pamięć wirtualna, który wiąże bloki adresów wirtualnych z blokami sąsiadujących ze sobą komórek pamięci. Gdy system implementuje wiele pamięci wirtualnych, każda pamięć wirtualna stanowi odrębny kontekst; dany adres może odnosić się do innej komórki pamięci w każdej pamięci wirtualnej. Komórki pamięci mogą być również współdzielone między pamięciami wirtualnymi, w którym to przypadku ta sama komórka pamięci może mieć takie same (lub różne) adresy w różnych pamięciach wirtualnych, jak określono przez wiązania.
Typowy komputerowy system plików wykorzystuje kilka warstw nazw i kontekstów: sektory dyskowe, partycje dyskowe, pliki i katalogi są wszystkimi nazwanymi obiektami. Katalogi są przykładami kontekstów typu table-lookup. Dana nazwa pliku może pojawić się w kilku różnych katalogach, związanych z tymi samymi lub różnymi plikami. W rozdziale 2.5 przedstawiono studium przypadku nazewnictwa w unixowym systemie plików.
Komputery łączą się z sieciami teleinformatycznymi w miejscach zwanych punktami przyłączenia do sieci. Punkty przyłączenia do sieci są zwykle nazywane za pomocą dwóch różnych schematów nazewnictwa. Pierwszy z nich, stosowany wewnątrz sieci, obejmuje przestrzeń nazw składającą się z liczb w polu o stałej długości. Nazwy te są związane, czasem na stałe, a czasem tylko na krótko, z fizycznymi punktami wejścia i wyjścia z sieci. Drugi schemat nazewnictwa, używany przez klientów sieci, odwzorowuje bardziej przyjazną dla użytkownika uniwersalną przestrzeń nazw złożoną z łańcuchów znaków na nazwy z pierwszej przestrzeni nazw. Rozdział 4.4 jest studium przypadku Systemu Nazw Domenowych, który zapewnia przyjazne dla użytkownika nazewnictwo punktów zaczepienia dla Internetu.
Programista identyfikuje zmienne procedury za pomocą nazw, a każde uruchomienie procedury zapewnia odrębny kontekst, w którym większość takich nazw jest rozwiązywana. Niektóre nazwy, określane jako “statyczne” lub “globalne”, mogą zamiast tego być rozwiązywane w kontekście, który jest współdzielony między aktywacjami lub między różnymi procedurami. Kiedy procedura jest kompilowana, niektóre z oryginalnych, przyjaznych użytkownikowi nazw zmiennych mogą zostać zastąpione identyfikatorami całkowitymi, które są wygodniejsze do manipulowania przez maszynę, ale model nazewnictwa nadal obowiązuje.
Uniform Resource Locator (URL) w World Wide Web jest mapowany na konkretną stronę internetową przez stosunkowo skomplikowany algorytm, który rozbija URL na kilka części składowych i rozwiązuje te części przy użyciu różnych schematów nazewnictwa; wynik ostatecznie identyfikuje konkretną stronę internetową. Sekcja 3.2 jest studium przypadku tego schematu nazewnictwa.
System billingowy klienta zazwyczaj utrzymuje co najmniej dwa rodzaje nazw dla każdego konta klienta. Numer konta nadaje mu nazwę w przestrzeni nazw o unikalnym identyfikatorze, ale istnieje również odrębna przestrzeń nazw osobowych, które również mogą być używane do identyfikacji konta. Obie te nazwy są zazwyczaj mapowane do rekordów konta przez system bazy danych, tak że konta mogą być wyszukiwane albo przez numer konta, albo przez nazwę osobową.
Te przykłady podkreślają również rozróżnienie między “nazewnictwem” a wiązaniem. Niektóre, ale nie wszystkie, konteksty “nazywają” rzeczy, w tym sensie, że mapują nazwę na obiekt, który jest powszechnie uważany za posiadający tę nazwę. Tak więc, książka telefoniczna nie “nazywa” ani ludzi, ani linii telefonicznych. Gdzie indziej istnieją konteksty, które wiążą nazwiska z ludźmi i które wiążą numery telefonów z konkretnymi fizycznymi telefonami. Książka telefoniczna wiąże nazwiska ludzi z nazwami telefonów.