DCVS Überblick

Motivation

CVS ist ein weit verbreitetes Versionskontrollsystem, das sowohl im kommerziellen Bereich als auch in der Open-Source-Entwicklung in vielen Projekten eingesetzt wird. Die Vorteile und Schwächen von CVS sind hinlänglich bekannt; gerade deswegen ist es vielleicht oft noch das Mittel der Wahl, obwohl inzwischen modernere und leistungsfähigere Systeme existieren.

Eine der Unzulänglichkeiten von CVS ist, dass es von einem streng zentralistischen Modell ausgeht und nur geringe Unterstützung für `offline'-Operationen bietet. Alle Entwickler müssen also für fast alle Versionskontrolloperationen direkten Zugriff (TCP/IP) über eine möglichst schnelle Leitung auf das zentrale Repositorium haben. Dies ist insbesondere für weltweit verteilte Projekte oft problemeatisch oder zumindest suboptimal. Besser wäre es, wenn sich das zentrale CVS Repositorium auf verschiedene Rechner aufteilen ließe und die Abstimmung der Inhalte unsichtbar für die Benutzer, die jeweils mit einer lokalen Kopie arbeiten, im Hintergrund automatisch abläuft.

Nun ist ein CVS Repositorium von seiner Struktur her denkbar ungeeignet, um eine `echte' Verteilung im Sinne eines transaktionsgesicherten Datenbanksystems zu implementieren. Es ist aber dennoch möglich, eine Variante der oben dargestellten Ideallösung zu realisieren, wenn man sich darauf beschränkt, an lokalen Servern jeweils nur auf definierten Entwicklungslinien (branches) zu arbeiten. (Dies ist auch der Ansatz, der bei dem bekannten ClearCase Produkt von Rational verfolgt wurde.)

Idee und Entwurf

In einem DCVS-System gibt es n gleichberechtigte Repositorien, deren Inhalte untereinander durch Hintergrundprozesse abgeglichen werden. Für diesen Abgleich wird eine erweiterte Variante des bekannten und extrem effizienten CVSup-Programms von John D. Polstra verwendet. Die Kombination von DCVS-Repositorium, DCVS-Server-Programm und erweitertem CVSup-Server wird im folgenden einfach als DCVS-Server oder noch kürzer Server bezeichnet.

Von jedem DCVS-Server können mit DCVS alle Inhalte aller Entwicklungslinien in einen DCVS-Workspace ausgecheckt werden. Alle das Repositorium nicht verändernden Operationen funktionieren genauso wie bei CVS, nur eben mit einem lokalen Repositorium.

Hier ist ein Beispiel eines kleinen DCVS-Server-Netzwerks zu sehen:

Was aber geschieht, wenn Veränderungen am Code vorgenommen werden sollen? Wenn von allen DCVS-Servern jederzeit beliebige Änderungen eingecheckt werden können, wird dies innerhalb von kurzer Zeit zu Konflikten und zu Datenverlust führen. Deshalb werden jedem DCVS-Server bestimmte Entwicklungslinien zugeteilt, für die er zuständig ist. Änderungen an einer bestimmten Entwicklungslinie können nur auf dem Server vorgenommen werden, der für diese Entwicklungslinie zuständig ist. Diese Trennung der Entwicklungslinien erlaubt es, den Datenabgleich der Repositorien auf RCS-Delta-Ebene automatisch im Hintergrund durchzuführen.

Was aber tun, wenn ich eine Entwicklungslinie in meinem Workspace habe, für die mein lokaler DCVS-Server nicht zuständig ist, ich aber trotzdem Änderungen einchecken möchte? Ganz einfach: ich erzeuge eine neue Entwicklungslinie, für die automatisch der lokale DCVS-Server zuständig ist, und schreibe meine Änderungen auf dieser zurück. Sollen diese Änderungen Bestandteil der ursprünglichen Linie werden, muss am dafür zuständigen Server nur eine Merge-Operation durchgeführt werden. DCVS bietet daher die Möglichkeit Change-Sets zu verwenden, mit denen jeder Entwickler an seinem lokalen Server in sich abgeschlossene Änderungspakete produziert, die dann von anderen benutzt werden können.

Wie kann nun erreicht werden, daß Deltas, die zu bestimmten DCVS-Entwicklungslinien gehören, in den DCVS-Repositorien eindeutig bestimmten DCVS-Servern zugeordnet werden? Wer das verstehen will, braucht einige Detailkenntnisse von RCS, dessen Dateiformat CVS für seine Versionierung verwendet. CVS identifiziert Entwicklungslinien mit sogenannten magic branches, das sind Versionsnummern mit einer geraden Anzahl von Elementen und einer 0 an der vorletzten Stelle, z.B. 1.34.0.4. Deltas dieser Entwicklinie werden nun mit den Nummern 1.34.4.1, 1.34.4.2, 1.34.4.3 usw. identifiziert. Um Entwicklungslinien auf verschiedenen Servern zu separieren, muß man nun sicherstellen, daß die Branch-Nummern (im Beispiel 4) auf jedem Server unterschiedlich sind. Das betrifft sowohl die Erzeugung von Branches (tags), als auch von neuen Deltas (beim Commit).

DCVS ordnet deshalb jedem (Server, Collection)-Paar einen eindeutigen Bereich von Branch-Nummern zu (ein sogenannter Range). Jeder DCVS-Server weiß dadurch jederzeit, ob er für eine bestimmte Entwicklungslinie oder ein bestimmtes Delta einer Datei zuständig ist oder nicht. Falls ja, sind alle modifizierenden Operationen erlaubt; falls nein, können diese nur auf dem zuständigen (entfernten) Server ausgeführt werden.

Ein weiteres Problem bei der Verteilung von DCVS-Repositorien ist die Vergabe von Namen (tags) für Entwicklungslinien und geschlossene Konfigurationen. Diese müssen ebenfalls eindeutig einem Server zuzuordnen sein, so daß es keine Konflikte geben kann. DCVS löst dieses Problem pragmatisch, in dem es an jeden vom Benutzer vergebenen Tag eine eindeutige Server-Identifikation anhängt, z.B. _at_dcvs_mydomain_org.

Implementierung

DCVS besteht derzeit aus drei Programmen: dem erweiterten CVS-Programm dcvs, dem erweiterten CVSup-Server dcvsupd, und einem Administrationsprogramm cvsupadm.

Zentral für alle DCVS-Programme ist die DCVS-Konfigurationsdatei, die entweder dcvs_config heißt und in systemüblichen /etc-Verzeichnissen gesucht wird (dcvs), oder dcvsupd.servers, und im DCVSup-Basisverzeichnis gesucht wird (dcvsupd, dcvs). Die Standardinstallation geht derzeit davon aus, daß alles unter /usr/local/dcvs installiert wird, wobei die Konfigurationsdatei in /usr/local/dcvs/etc/dcvs_config steht.

Hier ist ein kleines Beispiel für eine DCVS-Konfigurationsdatei:
Der Einschub DCVS-Konfigurationsdatei (dcvs_config) konnte nicht dargestellt werden!

cvsupd ist erweitert worden um die Funktionalität, nur Deltas und Tags herauszugeben, für die der lokale DCVS-Server zuständig ist. Zusammen mit dem cvsup-Client und cron ist so ein pull-basiertes Distributionsmodell für DCVS-Repositorien zu realisieren. Künftige Erweiterungen werden das pull-Modell durch ein push-Modell ersetzen, und eventuell auch CVSup-Server und Klienten zu einem DCVSup-Daemon vereinigen. Zur Automatisierung der Replikationsvorgänge sollten die unten beschriebenen Skripte verwendet werden.

dcvs ist ein erweitertes CVS-Programm (basierend auf der CVS-Version in FreeBSD 4.6, die wiederum auf CVS 1.12.12 basiert), in dem die oben angesprochene Umstellung des Namensraums (s/CVS/DCVS/g) stattgefunden hat, und das um Überprüfungen bei den Repositorium-modifizierenden Operationen ergänzt wurde. Außerdem wurde in zahlreiche weitere DCVS-Kommandos automatische Erweiterungen für Konfigurationsnamen (Tags) eingebaut.

Sowohl dcvs als auch cvsup sind um entsprechendes POSIX file locking erweitert worden, um ihren gegenseitigen Auschluß sicherzustellen.

cvsupadm ist ein kleines Administrationsprogramm, mit dem derzeit z.B. CVSup-Collection-Konfigurationen aus DCVS-Konfigurationsdateien erzeugt und editiert werden können. Umfangreiche weitere Funktionalität ist vorgesehen aber noch nicht realisiert.

DCVS enthält außerdem einige Skripte zur Automatisierung der Replikation und Administration:

dcvsupd.sh
startet den DCVSup-Server mit korrekten Argumenten gemäß der DCVS-Konfigurationsdatei
dcvsup.sh
startet ein DCVS-Update für einen gegebenen Server mit korrekten Argumenten, die aus der DCVS-Konfigurationsdatei extrahiert werden
sdcvsup.sh
startet ein DCVS-Update für einen gegebenen Server mit korrekten Argumenten, die aus der DCVS-Konfigurationsdatei extrahiert werden; der Transport erfolgt über eine sichere Verbindung (SSH port forwarding)
dcvsup_push.sh
verteilt lokale Änderungen an alle anderen DCVS-Server (Push-Modell) über unsichere Verbindungen via SSH
sdcvsup_push.sh
verteilt lokale Änderungen an alle anderen DCVS-Server (Push-Modell) über sichere Verbindungen via SSH
dcvs_locks.sh
listet, prüft, oder erzeugt DCVS Lock-Verzeichnisse und -Dateien
dcvs_getconfig
ist kein Skript, sondern ein kleines m3-Programm, das Informationen aus der DCVS-Konfigurationsdatei extrahiert, und damit sehr nützlich für die Anwendung in Skripten

dcvs{at}elego.de