Stefan Hett: XML und Mehrbenutzerproblematik

Kurz gesagt:

Datenbanken können nicht eingesetzt werden. Deshalb liegt eine Realisierung über XML-Dateien nahe. Problem: Fehlende Mehrbenutzermöglichkeit von XML.

Spontan fallen mir jetzt 3 mögl. Lösungswege ein und wollte mich im Netz mal informieren, wie andere die Thematik angegangen sind. Leider ohne viel Erfolg (weder diverse Foren noch Googel spuckte was sinnvolles aus).

Wenn jmd mir ein paar Quellen geben könnte, die sich mit dem Thema beschäftigen wäre ich sehr dankbar.

----

lange Version:

Ein paar Statements zu diesen Lösungswegen würden mich sehr freuen (vor allem Probleme, die auftreten können und ich im Moment noch nicht sehe):

Noch einige Infos:
Es wird davon ausgegangen, dass auf einem Server eine große XML-Datei liegt, in der sämtliche Daten gespeichert sind. Tägl. finden < 100 Zugriffe darauf statt (primär Lesezugriffe) - also wenige Kollissionen.
Die Performance ist vorerst nur zweitrangig.

Lösungsweg 1:
Auf dem Server wird ein Daemon (Service) installiert.
Lese-/Schreibzugriffe finden über diesen Service statt.
Szenario 1:
User 1 liest Datensatz x
User 2 liest Datensatz x
User 2 speichert geänderten Datensatz x
User 1 wird über die Änderungen am Datensatz informiert
Problem: Lösung über Service nur ungern, da oft nur "DAU"-Anwender da sind.

Lösungsweg 2:
Überprüfung findet Clientseitig statt.
Szenario 1:

  • User 1 liest Datensatz x - Client setzt Flag: Datensatz wird von User 1 gelesen
  • User 2 liest Datensatz x - Client setzt Flag: Datensatz wird von User 2 gelesen
  • User 2 will Datensatz x speichern - Client setzt Flag: Möchte gerne Datensatz speichern
  • User 1 will Datensatz x speichern - Client sieht Flag von User 2: Möchte gerne Datensatz speichern - setzt Flag: User 2 darf Datensatz speichern
  • User 2 sieht granted-Flag von User 1, speichert Daten und löscht Flag
  • User 1 sieht das User 2 fertig ist und sonst keiner mehr liest und speichert Daten
    Problem: Clients müssen andauernd überprüfen, ob die von ihnen gelesenen Datensätze einen Schreibwunsch haben.
    Einfachere Lösungen ohne dieses geflagge können zu Problemen führen afair ist das die gleiche Lösung die beim Linux-Kernel eingesetzt wird um das Problem des gleichzeitigen Zugriffes auf Ressourcen zu lösen. Hoffe das war so richtig übertragen, nicht dass da jetzt noch ein Prob auftreten kann. :)

Lösungsweg 3:
Schreibzugriffe führen nicht zum Überschreiben alter Datensätze sondern nur die Änderungen werden "geloggt".
Problem: Sehr kompliziert alle mögl. Fälle (die durch gleichzeitiges Speichern entstehen können) zu implementieren und die XML-Datei wird unnötig groß.

  1. Hi,

    Datenbanken können nicht eingesetzt werden. Deshalb liegt eine Realisierung über XML-Dateien nahe. Problem: Fehlende Mehrbenutzermöglichkeit von XML.

    XML ist ein Datenformat. Es hat keinerlei Probleme mit unendlich vielen unendlich diversen Zugriffen in unendlich kurzer Zeit über unendlich lange Zeiträume. Ich kann daher nur raten: Redest Du von parallelen _Datei_zugriffen?

    Spontan fallen mir jetzt 3 mögl. Lösungswege ein

    Vielleicht solltest Du erst mal das Problem nennen, bevor Du Dich an Lösungen versuchst. Dateizugriffe an sich lassen sich leicht regulieren.

    Es wird davon ausgegangen, dass auf einem Server

    Welcher Art?

    Tägl. finden < 100 Zugriffe darauf statt (primär Lesezugriffe) - also wenige Kollissionen.

    Lesezugriffe können pro Sekunde zig Tausend stattfinden, das ist problemfrei.

    User 2 speichert geänderten Datensatz x
    User 1 wird über die Änderungen am Datensatz informiert´

    Mit welchem Protokoll arbeitest Du? Warum ist eine Benachrichtigung des Clients wichtig?

    Überprüfung findet Clientseitig statt.

    Bei serverseitig gespeicherten Daten ist das, nun, suboptimal.

    • User 1 liest Datensatz x - Client setzt Flag: Datensatz wird von User 1 gelesen

    Der Client braucht sich kein Flag zu setzen, er weiß selbst, was er macht. Oder meinst Du "Server setzt Flag"?

    • User 1 will Datensatz x speichern - Client sieht Flag von User 2: Möchte gerne Datensatz speichern - setzt Flag: User 2 darf Datensatz speichern

    Server stellt fest, dass Daten gespeichert werden, die sich seit dem vom Client mitgesandten Zeitpunkt/der ID des Datenlesens verändert haben, und gibt eine Warnung/Fehlermeldung zurück.

    Schreibzugriffe führen nicht zum Überschreiben alter Datensätze sondern nur die Änderungen werden "geloggt".
    Problem: Sehr kompliziert alle mögl. Fälle (die durch gleichzeitiges Speichern entstehen können) zu implementieren und die XML-Datei wird unnötig groß.

    Lösung: Ein System einsetzen, welches dem Versionsmanagement dient, z.B. CVS oder SVN.

    Cheatah

    --
    X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
    X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
    X-Will-Answer-Email: No
    X-Please-Search-Archive-First: Absolutely Yes
    1. Hi und thx für die schnelle Antwort.

      Das ganze Problem hat sich schon in Luft aufgelöst. Hab mal wieder den Wald vor lauter Bäumen nicht gesehen.

      Habe überhaupt nicht drangedacht, dass Schreibzugriffe auf die Datei ja bereits vom OS gesteuert werden (exklusiver Schreibzugriff) und somit mein ganzer Gedankengang überflüssig war.

      Nochmal zur Klarstellung:
      Es arbeiteten x unabhängige Clients (PCs/Notebooks/etc.) mit einer Datei auf dem Server. Da halt die Clients nicht wissen, wer gerade mit der Datei auf dem Server "arbeitet" die ganzen Sachen mit den Flags & Co.

      Hat sich aber hiermit erledigt.

      Dennoch, danke für die schnelle Reaktion. ;-)

      1. Hi,

        Habe überhaupt nicht drangedacht, dass Schreibzugriffe auf die Datei ja bereits vom OS gesteuert werden (exklusiver Schreibzugriff) und somit mein ganzer Gedankengang überflüssig war.

        Irrtum. Während eines Schreibzugriffs sind Lesezugriffe weiterhin möglich. Wenn diese dann zu einem späteren Schreibzugriff führen - nun, Du wirst schon feststellen, wie wenig Daten eine zu Schreiben geöffnete Datei enthält ... ;-)

        Es arbeiteten x unabhängige Clients (PCs/Notebooks/etc.) mit einer Datei auf dem Server.

        Noch mal die Frage: Was für ein Server, welches Protokoll?

        Cheatah

        --
        X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
        X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
        X-Will-Answer-Email: No
        X-Please-Search-Archive-First: Absolutely Yes
        1. Habe überhaupt nicht drangedacht, dass Schreibzugriffe auf die Datei ja bereits vom OS gesteuert werden (exklusiver Schreibzugriff) und somit mein ganzer Gedankengang überflüssig war.
          Irrtum. Während eines Schreibzugriffs sind Lesezugriffe weiterhin möglich.

          Genau das hatte ich gehofft lässt sich auch direkt vermeiden. Damit wären dann zumindest direkte Kollissionen leicht zu vermeiden.
          Am Problem mit indirekten Kollissionen grübel ich gerade. :-)

          Damit's verständlicher wird (k.a. ob du weißt was ich mit (in-)direkten Kollissionen meine):
          Testszenario 2: (indirekte Kollission)

          • C1 liest Datensatz x + y.
          • C2 liest Datensatz x.
          • C2 speichert Datensatz x.
          • C1 druckt Datensatz x.
          • C1 berechnet Datensatz y und benutzt dazu Datensatz x.
          • C1 speichert Datensatz y. <--- Fehler erkennen!

          Testszenario 3: (direkte Kollission)

          • C1 liest Datensatz x.
          • C2 liest Datensatz x.
          • C2 speichert Datensatz x.
          • C1 speichert Datensatz x. <--- Fehler erkennen!

          Es arbeiteten x unabhängige Clients (PCs/Notebooks/etc.) mit einer Datei auf dem Server.
          Noch mal die Frage: Was für ein Server, welches Protokoll?

          Also als Server kommen unterschiedliche Systeme zum Einsatz. Vorest Windows NT und 2000 Systeme. Eventuell auch einige 2003er und u.u. später auch Linux-Server.
          Was das Protokoll angeht, da muss ich passen. Denke die Server haben nen shared-Directory, dass dann auf den Clients als Laufwerk X angelegt ist. Schreib-/Lesezugriffe würden dann ja beim Implementieren wie beim Arbeiten mit lokalen Laufwerken funktionieren, weshalb ich mir da bisher noch keinen Kopf gemacht hab.

          1. Hi,

            Irrtum. Während eines Schreibzugriffs sind Lesezugriffe weiterhin möglich.
            Genau das hatte ich gehofft lässt sich auch direkt vermeiden.

            annähernd direkt. Alle Zugriffe müssen einen Filelocking-Mechanismus implementiert haben, nebst ggf. einer Fehlerbehandlung, wenn ein Locking über einen nicht realistischen Zeitraum bestehen bleibt.

            • C1 liest Datensatz x + y.

            ... und erhält sie zusammen mit Zeitstempel t.

            • C1 speichert Datensatz y. <--- Fehler erkennen!

            Zeitstempel ist anders ---> Fehler erkannt! :-)

            Also als Server kommen unterschiedliche Systeme zum Einsatz. Vorest Windows NT und 2000 Systeme.

            Ich meinte eigentlich nicht die Rechner, sondern die Serversoftware.

            Was das Protokoll angeht, da muss ich passen.

            Naja, auf welche Weise kommunizieren die Clients mit dem Server/den Servern?

            Denke die Server haben nen shared-Directory, dass dann auf den Clients als Laufwerk X angelegt ist.

            Also Fileserver, sowas wie Sambar? Das wären dann im Grunde direkte Dateizugriffe, denen man eine Client-Server-Architektur nicht mehr anmerkt. In dem Fall wäre Dein Problem eventuell wirklich dadurch gelöst, dass das Filesystem Schreibzugriffe bei lesend geöffneten Dateien verweigert (was zu prüfen wäre). Dabei ist es unerheblich, welche Teile der Datei geändert werden sollen; die Datei wird atomar betrachtet.

            Schreib-/Lesezugriffe würden dann ja beim Implementieren wie beim Arbeiten mit lokalen Laufwerken funktionieren, weshalb ich mir da bisher noch keinen Kopf gemacht hab.

            Was möglicherweise auch daran liegt, dass auf einem lokalen System nur selten mehrere Leute parallele Dateizugriffe durchführen ;-)

            Cheatah

            --
            X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
            X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
            X-Will-Answer-Email: No
            X-Please-Search-Archive-First: Absolutely Yes
            1. Genau das hatte ich gehofft lässt sich auch direkt vermeiden.

              annähernd direkt. Alle Zugriffe müssen einen Filelocking-Mechanismus implementiert haben, nebst ggf. einer Fehlerbehandlung, wenn ein Locking über einen nicht realistischen Zeitraum bestehen bleibt.

              Hab's befürchtet... Das bastel ich gerad zusammen... ist schon komplexer als ich gehofft hatte. :(

              • C1 liest Datensatz x + y.
                ... und erhält sie zusammen mit Zeitstempel t.
              • C1 speichert Datensatz y. <--- Fehler erkennen!
                Zeitstempel ist anders ---> Fehler erkannt! :-)

              Hmmmmmm.... ok.... In dem Fall dann aber neues Problem:
              Bei jeder Berechnung müsste man überprüfen, ob sich die zu grunde liegenden Daten geändert haben (also Datensatz x). Das schreit förmlich nach ner eigenen Klasse... oder fällt dir da was einfacheres ein?

              Schreib-/Lesezugriffe würden dann ja beim Implementieren wie beim Arbeiten mit lokalen Laufwerken funktionieren, weshalb ich mir da bisher noch keinen Kopf gemacht hab.
              Was möglicherweise auch daran liegt, dass auf einem lokalen System nur selten mehrere Leute parallele Dateizugriffe durchführen ;-)

              Aneinander vorbeigeredet... da = welche Protokolle für den Datentransfer zwischen Server und Client eingesetzt werden, nicht, wie man Mehrbenutzerzugriff gestattet. ;-)

              1. Hi,

                (Kürzung aus Zeitgründen)

                Zeitstempel ist anders ---> Fehler erkannt! :-)
                Hmmmmmm.... ok.... In dem Fall dann aber neues Problem:
                Bei jeder Berechnung müsste man überprüfen, ob sich die zu grunde liegenden Daten geändert haben (also Datensatz x).

                Nach Deinen Aussagen sind Änderungen _an sich_ selten. Du kannst also problemarm feststellen, ob sich überhaupt etwas geändert hat, egal wo, und dann vielleicht noch als Goodie die betroffenen Daten mit den Originalwerten vergleichen, die der Client bekommen hatte (und natürlich dann auch wieder zurückschicken muss).

                Cheatah

                --
                X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
                X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
                X-Will-Answer-Email: No
                X-Please-Search-Archive-First: Absolutely Yes
  2. Hallo,

    lange Version:

    Lösungsweg 2:
    Überprüfung findet Clientseitig statt.

    nicht desto trotz muss etwas am Server die Datei flaggen. Du hast muss also Lüsungsweg 1 erst implementieren.

    Lösungsweg 4:
    Du setzt ein CVS ein, z.B. Subversion. Das können eigentlich auch "daus" bedienen, das betrifft auch eventuelle Konflikte. Ist nicht wirklich schwer.

    Lösungsweg 5:
    Es wird ein Tool/Editro eingesetzt, welche XML-Diff beherrsch und bei Konfliktlösugen behilflich ist.
    Z.B. http://www.altova.com/features_xmldiff.html oder oder gar http://www.altova.com/products_diffdog.html wobei es auch Freeware Editoren dazu gibt, allerdings das heisst wiederum versionierung.

    Lösungsweg 6:
    Ein Mix aus L1 und L2 ähnlich einem CMS, das ein Check-out / Check-in ermöglicht. Dass muss kein koplettes CMS sein, wenn du was kleines in z.B. in PHP schreiben kannst.

    Grüße
    Thomas

    --
    Surftip: kennen Sie schon Pipolino's Clowntheater?
    http://www.clowntheater-pipolino.net/
    1. Hi,

      Du setzt ein CVS ein, z.B. Subversion.

      eine interessante Formulierung. Ich war bisher der Ansicht, CVS sei ein Produkt, keine Gattung, dessen Nachfolger Subversion ist ;-)

      Cheatah

      --
      X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
      X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
      X-Will-Answer-Email: No
      X-Please-Search-Archive-First: Absolutely Yes
      1. Tah Cheatah, ;-)

        Du setzt ein CVS ein, z.B. Subversion.

        eine interessante Formulierung. Ich war bisher der Ansicht, CVS sei ein Produkt, keine Gattung, dessen Nachfolger Subversion ist ;-)

        *hehe*

        "Subversion is meant to be a better CVS, so it has most of CVS's features. Generally, Subversion's interface to a particular feature is similar to CVS's, except where there's a compelling reason to do otherwise." ;-)

        Also hast du recht, irgendwie. Vielleicht. ;-)

        Grüße
        Thomas

        --
        Surftip: kennen Sie schon Pipolino's Clowntheater?
        http://www.clowntheater-pipolino.net/
        1. Hi,

          Du setzt ein CVS ein, z.B. Subversion.
          Also hast du recht, irgendwie. Vielleicht. ;-)

          das liegt vermutlich daran, dass wir gerade von CVS auf SVN umsteigen ;-)

          Cheatah

          --
          X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
          X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
          X-Will-Answer-Email: No
          X-Please-Search-Archive-First: Absolutely Yes
          1. Hi Cheatah, hi Thomas,

            wie macht ihr das, wenn ihr mehrere Projekte/Module habt, die voneinander abhängig sind (lies: sie haben klar definierte Interfaces und können separat voneinander weiterentwickelt werden, ohne dass es zu Konflikten kommt)?

            In der Doku werden ja Lösungswege vorgeschlagen, zuerst die Aufteilung in Projekte, dann in "trunk" usw. bzw anders herum. Hat sich dies etabliert oder gibt es darüberhinaus ein Rezept?

            Was ich bei SVN sehr gut finde, sind die Verlinkbarkeit der Repositories und die (im Gegensatz zu herkömmlichen CVS) Möglichkeit Baselines zu ziehen bzw. Entwicklungen zu verzweigen.

            Ich arbeite im Moment (obwohl es eigentlich nicht der richtige Zeitpunkt ist) ebenfalls an der Migrierung eines Projektes von CVS zu SVN. Für eventuelle Tipps wäre ich euch sehr dankbar.

            Ciao, Frank

    2. Hi und auch thx für die Antwort.

      Habe mir deine beiden Links mal angeschaut. Wie schon gesagt, hat sich das Prob aber in Luft aufgelöst. :)

      Deinen Lösungsweg 6 kann ich aber nicht ganz nachvollziehen. L2 würde doch bereits das Check-out/-in über dieses ach so kompliziert ausgedachte Flag-System lösen, oder doch nicht?

      1. Hallo,

        Habe mir deine beiden Links mal angeschaut. Wie schon gesagt, hat sich das Prob aber in Luft aufgelöst. :)

        Na ja du hättest sagen können dass du in einem Windows-Netzwerk arbeitest ;-)

        Deinen Lösungsweg 6 kann ich aber nicht ganz nachvollziehen. L2 würde doch bereits das Check-out/-in über dieses ach so kompliziert ausgedachte Flag-System lösen, oder doch nicht?

        Nein, denn ein Client setzt am Server normalerweise keine Flags, das macht ein Programm das auf dem Server zugreift und den Client bedient.

        Grüße
        Thomas

        --
        Surftip: kennen Sie schon Pipolino's Clowntheater?
        http://www.clowntheater-pipolino.net/
        1. Deinen Lösungsweg 6 kann ich aber nicht ganz nachvollziehen. L2 würde doch bereits das Check-out/-in über dieses ach so kompliziert ausgedachte Flag-System lösen, oder doch nicht?
          Nein, denn ein Client setzt am Server normalerweise keine Flags, das macht ein Programm das auf dem Server zugreift und den Client bedient.

          Ok, meine Idee wäre jetzt gewesen in der XML-Datei (bzw. über eine 2. XML-Datei) das ganze zu steuern. Also in dem Fall dann doch Clientseitig um eben die Installation von Software auf dem Server zu umgehen.
          Die 2. XML-Datei könnte dann z.B. so aussehen:
          <access client="1" dataset="1" state="reading">
          <access client="2" dataset="1" state="reading">

          Step 2:
          <access client="1" dataset="1" state="reading">
          <access client="2" dataset="1" state="waiting"> <- will schreiben

          Step 4:
          <access client="1" dataset="1" state="granting"> <- erlaubt Schreiben
          <access client="2" dataset="1" state="waiting">

          Step 5:
          <access client="1" dataset="1" state="waiting"> <- will schreiben
          <access client="2" dataset="1" state="writing"> <- schreibt gerade

          Step 6:
          <access client="1" dataset="1" state="waiting"> <- will schreiben
          <- Schreiben fertig und liest nicht mehr

          Step 7:
          <access client="1" dataset="1" state="writing"> <- schreibt gerade

          Step 8:
          <- fertig