STUDIA INFORMATICA Volume 27 2006 Number 1 (66) Jarosław Pychowski Uniwersytet Łódzki, Wydział Matematyki i Informatyki Tomasz Kawczyński Uniwersytet Łódzki, Wydział Matematyki i Informatyki Arkadiusz Popa Uniwersytet Łódzki, Wydział Matematyki i Informatyki Ścibór Sobieski Uniwersytet Łódzki, Wydział Matematyki i Informatyki PGVCS – NARZĘDZIE DO WERSJONOWANIA DANYCH ORAZ STRUKTURY BAZ DANYCH Streszczenie. Celem artykułu jest opisanie mechanizmu wersjonowania pgVCS powstałego na potrzeby projektów realizowanych na potrzeby Uniwersytetu Łódzkiego. Głównym zadaniem pgVCS jest wersjonowanie danych oraz struktury bazy danych PostreSQL przeźroczyście dla użytkowników bazy. Umożliwia on na odczytanie z bazy, danych lub struktury z dowolnego okresu czasu. Słowa kluczowe: wersjonowanie, bazy danych, repozytorium PGVCS – MECHANISM TO VERSION DATAS AND DATA STRUCTURES. Summary. The purpose of this article is to describe the mechanism version control system pgVCS created for the University of Lodz. The first feature pgVCS can store and retrieve data from the database at the selected revision. The second mechanism is the property of choice and comparison of data between the revisions. Keywords: data bases, repository, version mechanism STUDIA INFORMATICA Volume 27 2006 Number 1 (66) 1.Wstęp Jak powszechnie wiadomo żaden duży projekt informatyczny nie może się obejść bez mechanizmu kontroli wersji. Wynika to z naturalnej potrzeby sprawdzania, jak zmieniał się kod źródłowy aplikacji, kto wykonywał zmiany, by ostatecznie móc porównywać kolejne wersje i np.: poprawiać błędy. Zarządzanie kodem źródłowym aplikacji jest często procesem bardzo złożonym (tak dzieje się w dużych projektach, gdzie bierze udział kilkunastu czy nawet kilkudziesięciu programistów). Istnieje jednak wiele narzędzi wspomagających i zarządzających tym procesem. Co jednak zrobić w przypadku, gdy zajdzie potrzeba zarządzania wersjami danych w relacyjnej bazie danych? Przypuśćmy, że musimy wybrać dane z bazy zgodnie z określoną wersją (określoną poprzez moment czasowy, autora czy też numer). Dodatkowo załóżmy, że struktura naszej bazy może być często modyfikowana, jak również dane w niej są często uaktualniane. Można zadać pytanie, gdzie taki problem może wystąpić. Autorzy w praktyce natknęli się na sygnalizowane problemy i zostali zmuszeni do zaprojektowania i wykonania systemu pgVCS, który ma pełnić rolę systemu kontroli wersji dla baz danych, ale również bazy pośredniczącej w wymianie danych pomiędzy różnymi systemami (w tym sensie zwykły system kontroli wersji również zapewnia tę funkcjonalność) – ta właśnie cecha, jak się okazało, stała się kluczowa z punktu widzenia użyteczności mechanizmu. System pgVCS stał się bazą integrującą wiele systemów informatycznych użytkowanych na UŁ (patrz Podsumowanie). Podstawowym celem powstania tego mechanizmu było zapewnienie funkcjonalności dającej możliwość wyboru danych z bazy o określonej wersji (pomimo iż struktura bazy danych mogła ulec zmianie). Ostatecznie uzyskano jednak znacznie więcej – bardzo wygodny i obecnie niezastąpiony mechanizm do integracji systemów informatycznych na podstawie ich danych. Tworząc system pgVCS Autorzy kierowali się następującymi wymaganiami: przeźroczystość przy wykorzystywaniu – jeśli użytkownik wykorzystuje w zwykły sposób system jako pośrednika wymiany danych to nie zauważa mechanizmu wersjonowania i nie musi wiedzieć jak on działa, łatwość korzystania z wersji – jeśli użytkownik potrzebuje skorzystać z mechanizmu wersjonowanie, nie powinien on nastręczać większego wysiłku niż zwykłe systemy wersjonowania. STUDIA INFORMATICA Volume 27 2006 Number 1 (66) pgVCS został oparty o silnik bazy danych PostgreSQL i opiera się na zestawie tabel, schematów i wyzwalaczy utworzonych w bazie danych. 2.Opis budowy mechanizmu wersjonowania pgVCS Założenie, by system był jak najbardziej prosty i przyjazny dla użytkownika udało się osiągnąć poprzez maksymalne zautomatyzowanie procesu wersjonowania. Jedynie modyfikacja struktury wymaga wywołania funkcji do odświeżenia w systemie pgVCS informacji o wprowadzonych modyfikacjach. W bazie danych stworzono trzy schematy, trzy tabele i osiem funkcji, w kolejnych podpunktach zostaną one opisane szczegółowo. 2.1.Schematy Do działania mechanizmu wersjonowania stworzono trzy schematy. Pierwszym jest schemat sys, w którym znajdują się funkcje oraz tabele, do których dostęp jest potrzebny do prawidłowego funkcjonowania pracy całego systemu. Kolejny schemat został nazwany zasobnik. W tym schemacie znajdują się kopie tabel produkcyjnych pgVCS’a przechowujące dane ze wszystkich kolejnych rewizji. Ze względu na bezpieczeństwo dostęp do danych ze schematu zasobnik został ograniczony do administratorów bazy danych Ostatni stworzony schemat został nazwany: wewnetrzne. Zawarte w nim są wszystkie funkcje pomocnicze, z których korzysta mechanizm pgVCS podczas pracy. Ten schemat również przeznaczony do użytkowania tylko przez administratora bazy danych. Wszystkie tabele przeznaczone do pracy (tabele produkcyjne), które chcemy objąć mechanizmem wersjonowania muszą znajdować się w schemacie public. Nie jest wymagane by tabele, ze schematu public, posiadały jakieś szczególne cechy. Tworząc je obowiązują zasady zgodne z regułami relacyjnych baz danych. 2.2.Tabele System wersjonowania pgVCS działa w oparciu o trzy tabele: wersja, atrybut oraz uprawnienie. Przy czym tabela uprawnienia służy do zarządzania uprawnieniami (dokładny opis w dalszej części artykułu), a tabela wersja przechowuje informacje o wszystkich STUDIA INFORMATICA Volume 27 2006 Number 1 (66) wersjach repozytorium oraz użytkownikach, którzy spowodowali stworzenie takiej wersji. Tabele te zawarte są w schemacie sys. Warto zaznaczyć, że koncepcja systemu pgVCS nie wymaga by tabele atrybut i uprawnienia posiadały klucz główny. Budowę tych tabel przedstawia rysunek 1. Dodatkowo w opisywanym wcześniej schemacie zasobnik tworzone są kopie wszystkich tabel ze schematu public. Wszystkie tabele ze schematu public wzbogacone są o dodatkową kolumnę wersja, w której przechowywana jest informacja jaki numer repozytorium posiada określony wiersz. Natomiast tabele ze schematu zasobnik posiadają dodatkowo dwie kolumny: początek i koniec, określające w ramach których rewizji repozytorium wybrany wiersz był aktualny Rysunek 1. Schemat bazy danych mechanizmu pgVCS Tabela wersja zawiera informacje o wersjach repozytorium, czasie jego powstania, użytkowniku, który dokonał modyfikacji i numerze pid połączenia. Tabelę tą można traktować jako pewnego rodzaju słownik wszystkich wersji repozytorium. Kolejna tabela, atrybut, przechowuje informacje dotyczące zmian samej struktury bazy danych. Struktura tej tabeli składa się z kolumn opisujących rodzaj zmienianej tabeli, typie i informacji od jakiej i do jakiej wersji zmiana ta miała miejsce. Każda zmiana struktury bazy danych, czyli dowolnych tabel w schemacie public, będzie skutkowała wygenerowaniem nowej wersji w repozytorium. Powstanie wtedy nowy wpis w tabeli sys.wersja. STUDIA INFORMATICA Volume 27 2006 Number 1 (66) Trzecią tabelą jest sys.uprawnienia, która przechowuje informacje o rodzaju uprawnień jaki przysługuje poszczególnym użytkownikom do określonych tabel. Określamy w niej czy użytkownik ma prawo modyfikować (update), wstawiać (insert), usuwać (delete) lub pobierać (select) dane z tabel podlegających kontroli wersji. Rodzaj uprawnień jest zapisywany w kolumnie rodzaj_uprawnień i może przyjmować wartości „r” lub „w”. Uprawnienia poziomu „r” pozwalają na czytanie danych z tabeli, a uprawnienia poziomy „w” pozwalają dodatkowo na wstawianie, modyfikowanie i usuwanie danych. Uprawnienia „w” można dodawać dla całych tabel jeśli kolumna atrybut posiada wartość NULL lub dla wybranych kolumn, jeżeli kolumna atrybut nie ma przypisanej wartości NULL, lecz wskazuje na określoną kolumnę. 2.3.Funkcje Cały mechanizm pgVCS oparty jest o zbiór funkcji, które dbają o jego spójność i bezpieczeństwo. sys.refresh() – funkcja ma za zadanie odczytać wszystkie tabele w schemacie public a następnie uaktualnić ich kopie w schemacie zasobnik (wyzwalacz: sys.reflect_table(tname text)), wywołuje wyzwalacz tworzący wyzwalacze dla każdej tabeli w schemacie public (sys.create_perm_tg(tname text)) oraz wyzwalacz niezbędny do aktualizacji uprawnień (sys.create_storage_triggers(tname text)); FOR r IN SELECT tablename FROM pg_tables WHERE schemaname = 'public' LOOP PERFORM sys.reflect_table(r.tablename); PERFORM sys.create_storage_triggers(r.tablename); PERFORM sys.create_perm_tg(r.tablename); END LOOP; sys.get_version() – funkcja zwraca aktualną wersję repozytorium. Jeśli nie istnieje to funkcja generuje odpowiedni wpis z wersją. SELECT INTO version v.wersja FROM sys.wersja v WHERE v.czas=now() and v.pid=pg_backend_pid(); IF NOT FOUND THEN INSERT INTO sys.wersja (czas, nazwa_uzytkownika, pid) VALUES (now(), session_user, pg_backend_pid()); version = currval('sys.wersja_wersja_seq'); END IF; IF version IS NULL THEN STUDIA INFORMATICA Volume 27 2006 Number 1 (66) RAISE EXCEPTION 'Unable to fetch current version'; END IF; RETURN version; sys.get_primary_key(schema text, name text) – zadaniem funkcji jest zwrócenie klucza głównego tabeli, której nazwa zostanie przekazana w argumencie funkcji. SELECT constraint_name AS name , array( ( SELECT quote_ident(column_name::text) FROM information_schema.key_column_usage AS cu WHERE cu.constraint_name = tc.constraint_name AND tc.constraint_schema = cu.constraint_schema AND tc.constraint_catalog = cu.constraint_catalog ) ) AS columns FROM information_schema.table_constraints AS tc WHERE constraint_type = 'PRIMARY KEY' AND table_schema = $1 AND table_name = $2 3. Działanie systemu pgVCS System rewizji danych oraz schematów bazy danych można wdrożyć w dowolnym momencie na działającej już bazie danych. W tym momencie wszystkie istniejące już dane będą posiadały rewizję 1, a każda następna modyfikacja danych bądź struktury bazy spowoduje stworzenie nowej wersji rewizji. Nowa rewizja tworzona jest na podstawie całej wykonanej sesji w bazie danych (całej transakcji). Jeżeli w ramach jednej transakcji zostało zmodyfikowanych wiele wierszy to wszystkie one będą posiadać ten sam numer wersji. 3.1.Wdrożenie systemu i jego aktualizacja Wdrożenie systemu polega na stworzeniu opisanych powyżej tabel, schematów i funkcji w bazie. Następnie należy wywołać funkcję refresh() ze schematu sys. Od tego momentu rozpocznie się wersjonowanie bazy danych. W dowolnym momencie możliwe jest zmodyfikowanie schematu bazy danych. Można tworzyć tabele, dodawać i usuwać kolumny. Po wykonaniu takich modyfikacji niezbędne jest zaktualizowanie struktury wersjonowania bazy, dlatego trzeba wywołać metodę sys.refresh(). STUDIA INFORMATICA Volume 27 2006 Number 1 (66) 3.2.Działanie – INSERT Przypuśćmy, że posiadamy w bazie danych tabelę tabela_1. Do tej tabeli wprowadzane są dane, poprzez instrukcję insert. W tym samym momencie generowana jest nowa wersja danych, tzn. wykonywany jest również nowy wpis w tabeli sys.wersja z aktualną wersją repozytorium. Wygenerowany aktualny numer repozytorium jest dopisywany do wstawianego wiersza do tabeli public.tabela_1 do specjalnej kolumny wersja. Kolumna ta oznacza numer wersji, w której znajduje się dany wiersz. Następnie tworzony jest wiersz w zasobnik.tabela_1 z następującymi wartościami: w kolumnie początek jest wpisywana wartość równa wygenerowanemu numerowi rewizji, a w kolumnie koniec jest wprowadzana wartość null. Wartość null w kolumnie koniec oznacza że wiersz jest najbardziej aktualny i ostatnio był modyfikowany w rewizji wskazanej przez kolumnę początek. 3.3.Działanie – UPDATE Przyjmijmy identyczne założenia, jak w poprzednim podpunkcie. Tym razem na tabeli tabela_1 robiona jest aktualizacja danych poprzez instrukcję update. Zmieniona została określona wartość w tabeli, a następnie wygenerowany zostanie nowy numer wersji w tabeli sys.wersja. Następnie zmodyfikowana zostanie kolumna wersja w tabeli public.tabela_1, zostanie wstawiona aktualny numer repozytorium. Następne zmiany będą zachodzić w tabeli zasobnik.tabela_1. Najpierw kolumna koniec modyfikowane wiersza zostanie oznaczona wartością aktualnej wersji repozytorium. Dalej zostanie stworzony nowy wpis w tabeli zasobnik.tabela_1 z nowymi wartościami. Teraz wartości kolumn w nowym wierszu są zgodne z wartościami w kolumnach w tabeli public.tabela_1, czyli posiadają wartości równe oryginalnemu zapytaniu modyfikującemu wykonanemu przez użytkownika. W nowo powstałym wierszu kolumna początek przyjmie wartość numerowi wygenerowanej wersji, a kolumna koniec będzie posiadała wartość null. 3.4.Działanie – DELETE Przyjmując identyczne założenia, jak w poprzednich podpunktach, usuńmy z tabeli public.tabela_1 wiersz, poprzez instrukcję delete. Usunięty zostanie wybrany wiersz z tabeli public.tabela_1. Analogicznie, jak poprzednio, wygenerowany zostanie nowy numer rewizji. Następnie wiersz w tabeli zasobnik.tabela_1 zostanie zaktualizowany (update) poprzez STUDIA INFORMATICA Volume 27 2006 Number 1 (66) ustawienie wartości kolumny koniec na aktualny numerek wersji. Dzięki temu wiersz ten zostanie oznaczy, że został usunięty w określonej wersji. 4. Użycie systemu wersjonowania pgVCS na przykładzie Uniwersytetu Łódzkiego Opisywany system został uruchomiony blisko 2 lata temu na bazie danych, która pełni rolę bazy migracyjnej między różnymi systemami pracującymi na Uniwersytecie Łódzkim. Systemy Elektronicznej Rekrutacji, USOS (Uniwersytecki System Obsługi Studiów), KIOD (Karta Indywidualnych Obciążeń Dydaktycznych) oraz Płatności wykorzystują bazę danych, z wdrożonym wersjonowaniem pgVCS, do migracji danych między sobą. Szczegółowy przepływ danych między tymi systemami przedstawia rysunek 2, gdzie grot oznacza kierunek przepływu danych. Rysunek 2. Schemat wymiany danych między różnymi systemami informatycznymi na Uniwersytecie Łódzkim Każdy z systemów informatycznych posiada własny system migracji danych do bazy pośredniej. W chwili obecnej system wersjonowania ma ponad 262 136 rewizji. Przy tak STUDIA INFORMATICA Volume 27 2006 Number 1 (66) dużej liczbie danych, z różnych systemów informatycznych, zalety pgCVS’a są w pełni widoczne. Najważniejsze z nich to: możliwość wyciągnięcia dowolnej rewizji danych, pełna kontrola źródła pochodzenia nowych oraz zmienionych rekordów w bazie (użytkownicy oraz systemy), prostota rozwiązania, możliwość tworzenia raportów z różnic danych między poszczególnymi wersjami, tzw. changelog. Zauważono również ograniczenia związane z wdrożeniem prezentowanego systemu wersjonowania. Ponieważ każda para systemów, z rysunku 2, wymieniająca dane między sobą tworzy własne zestawy tabel, istnieje niebezpieczeństwo redundancji danych. Nie do pominięcia jest również narzut czasowy przy aktualizowaniu i usuwaniu wierszy z bazy dla transakcji, które modyfikują znaczny procent danych. Zachodzący proces zaśmiecania indeksów skutkuje znacznym spadkiem wydajności. Dodatkowo statystyki (rozkład optymalizatora) stają się nieaktualne. Dlatego system działa najwydajniej dla transakcji modyfikujących niewiele wierszy. 5.Podsumowanie Jak wiadomo istnieją też inne metody synchronizacji danych pomiędzy systemami informatycznymi. Na przykład każdy system generuje dane w postaci plików o ustalonym formacie (np. XML) a następnie te pliki są przesyłane pomiędzy systemami. Jednak to podejście nie umożliwia zweryfikowania, czy dane zostały przesłane poprawnie, czy wykryty błąd leży po stronie aplikacji wysyłającej, czy odbierającej. Co prawda można pokusić się o wprowadzenie jakiegoś systemu wersjonowania (np. kolejne pliki mają różne nazwy lub zastosowanie gotowych rozwiązań typu VCS), ale nie rozwiązują one problemu, jak zweryfikować kompletność danych przesłanych. Weryfikacja taka może nie być możliwa do przeprowadzania w łatwy sposób, gdy pomiędzy systemami przesyłane są tylko i wyłącznie pakiety przyrostowe, co w wielu systemach może być jedyną możliwością przesyłania danych ze względu na duży rozmiar całego zbioru danych przetwarzanych przez system lub z braku w systemie wszystkich danych (dane przesłane do drugiego systemu mogą być archiwizowane). System STUDIA INFORMATICA Volume 27 2006 Number 1 (66) pgVCS nie ma tej wady. W bazie danych zawsze jest widoczny komplet danych przesłanych przez system źródłowy. System pgVCS spełnia wszystkie wymagania, jakie zostały przed nim postawione, zapewnia sprawną komunikację pomiędzy różnorodnymi systemami informatycznymi Uniwersytetu Łódzkiego. LITERATURA 1. 2. 3. 4. Zdzisław Dybikowski: PostgreSQL, Helion 2001 Korry Douglas: PostgresSQL (2nd Edition) (Developer’s Library) www.postgresql.org The PostgreSQL Global Development Group: The PostgreSQL Reference Manual Volume 2: Programming Guide Recenzent: tytuły Imię Nazwisko Wpłynęło do Redakcji 2 stycznia 2006 r. Abstract No major informatics project cannot be finished without a version control mechanism. There is a natural need to check how was the source code in a previous version, compare it and fix bugs. Source code management application is simple and generally well known. But how to carry out a review of data in the database? How to lead a review of changes in the structure of the database? The proposed mechanism allows to version data and database structure. pgVCS built as a triggers, diagrams and tables in a database. Let’s suppose that the structure of our database is updated frequently, or the data are updated frequently. To solve these problems we developed pgVCS system, which is a version control system for databases. STUDIA INFORMATICA Volume 27 2006 Number 1 (66) This system is capable to version all the changes in the database. In this way, the user can select data from the database from any version. In addition, this data can be retrieved regardless of changes in the structure of the database. The mechanism of version control was made as simple to use, and had to provide full transparency to the user. So users are using the database in the plane way, and the version control system process is completely automated. pgVCS was based on the PostgreSQL. Adres Ścibór Sobieski: Uniwersytet Łódzki, Wydział Matematyki i Informatyki, Katedra Analizy Matematycznej i Teorii Sterowania, ul. Banacha 22, 90-238 Łódź, Polska, [email protected] Arkadiusz Popa: Uniwersytet Łódzki, Wydział Matematyki i Informatyki, Katedra Analizy Matematycznej i Teorii Sterowania, ul. Banacha 22, 90-238 Łódź, Polska, [email protected] Tomasz Kawczyński: Uniwersytet Łódzki, Dział Systemów Ogólnouczelnianych, ul. Banacha 22, 90-238 Łódź, Polska, tomek.kawczyń[email protected] Jarosław Pychowski: Uniwersytet Łódzki, Wydział Matematyki i Informatyki, Katedra Metod Numerycznych, ul. Banacha 22, 90-238 Łódź, Polska, [email protected]