[linux-l] Re: [linux-l] Re: [linux-l] Transaktionen? und Prozessesnapshots für alle und jeden und überall und jederzeit

Steffen Dettmer steffen at dett.de
So Aug 31 14:47:29 CEST 2003


* Jan Krueger wrote on Tue, Aug 26, 2003 at 09:25 +0000:
> On Wednesday 20 August 2003 09:04, Steffen Dettmer wrote:
> > > Das OS könnte dann höchstens die Hilfe geben, ein signal, hallo
> > > prozeß du warst gesnapshottet.
> >
> > Dann muß man da ein flag setzen. Was macht man dann?
> > Sicherheitshalber (weil Zustand ja nicht bekannt) geht man am
> > besten raus, bis zurück an den Anfang auf Applikationslevel,
> > initialisiert alles neu, damit man sich drauf verlassen kann.
> 
> Überprüft sämtliche handler auf ihre gültigkeit, beantragt sie
> gegebenenfalls neu, und macht dann halt weiter.

Ja, diese Prüfung muß theoretisch an jeder beliebigen Stelle
gemacht werden, wo ein Snapshot gemacht werden kann, da nach
einem Snap möglicherweise Sockets etc. hin sind.

> > einschläfern ist ja auch weniger das Problem, denk ich. Bloß mit
> > Folgefehlern (beispielsweise merkwürdigen Socketverhalten, was
> > normalerweise schlicht und ergreifend mit exit quitiert wird)
> > klarzukommen, ist vielleicht schon schwieriger...
> 
> Socket neu einrichten, fertig.

Ja, also mußt Du vor jeder Socket-Operation prüfen, ob nicht
vielleicht ein Snap gemacht wurde. Was machst Du, wenn mitten in
einer Kommunikationssitzung ein Snap gemacht wurde?
Neuinitialisieren heißt ja, neu verbinden. Da muß dann auch der
Client mitmachen. Das kann natürlich schiefgehen, ne ganz neue
Fehlerklasse. Muß man die Applikationen und Bibliotheken für
anpassen. Da muß man dann hier bestimmte Fehler, die sonst nie
auftreten dürfen, plötzlich ignorieren, weil *hier* doch nicht
schlimm. Schon schwierig, oder?

> > Stell Dir das doch mal im Code vor. Im Prinzip muß doch nach jeder
> > Zeile (man kann ja immer snapshoten):
> >
> > if (global.flag.snapshotrestored) {
> > 	/* alle Daten checken */
> > }
> >
> Na momentchen bitte, Ein heutiges Programm fragt doch auch
> nicht nach jeder Zeile of es ein SIGTERM/SIGUSR1 oder so
> bekommt, sondern dafür gibt es einen signalhandler der halt
> immer wieder mal überprüft wird oder auch nicht, was im fall
> von SIGKILL auch ziemlich egal wäre.

Ja, schließlich wird der signalhandler bei SIGKILL nicht
aufgerufen, aber egal :)

Was macht der signalhandler? Einen Socket initialisieren? Wie
soll das gehen: Du hast ne globale Funktion, die async-safe sein
sollte, und die soll dann plötzlich die privaten Daten von
beliebigen Modulen initialisieren? Vielleicht muß ein Logfile neu
geöffnet werden, weil es per NFS geschrieben wird. Wie macht ein
signalhandler das? Maximal sieht er den Filedeskriptor, woher
weiß er, zu welchem File das gehört? Benutzt man globale Daten?
Wie initialisiert man was globales async-safe? Geht einfach
nicht! Es kommt einfach zu einem Deadlock. Vielleicht hat man
Glück, und es geht, weil der Hauptthread zufällig nichts benutzt,
als in den Sighandler gesprungen wurde, doch ist das
unwahrscheinlich, wie ja auch bei signalen. Schon ein SIGHUP
richtig zu verarbeiten, ist schnell ein Aufriß...

> > Ja, klar, könnte man machen. Fragt sich eben nur, ob das viel
> > Sinn macht. So ähnlich funktionierte ja so ein Perl compiler:
> > einfach memory dumpen (gut, sind paar MB, aber schnell ist's),
> > beim Start dann laden.
> 
> na super! Wenn man mozilla so starten könnte, oder openoffice :)

(Geht natürlich nur vor dem Einsprung in die erste Routine)

> > Ja, in beiden Fällen, oder?!
> >
> > // system buffered I/O
> > int sysfd = open("/tmp/file", 0);
> > write(sysfd, "some data", 10);
> > close(sysfd);
> >
> > // raw I/O
> > int rawfd = open("/dev/raw/0", 0);
> > write(rawfd, "some data", 10); // dauert...
> > close(rawfd);
> >
> > Ist doch genauso, nur das open ist anders, oder?
> 
> Also rawIO ist doch sinnlos. Sag ich doch :)

Wie kommst Du jetzt hierdrauf? Nur, weil es auch filedesriptoren
benutzt? Dann wäre socket Kommunikation auch sinnlos, weil es
filedesriptoren benutzt? :)

> > > > ? Nee... Wenn jemand eine Datei liest, schreibt und nach 3
> > > > Stunden nochmal einen Block davon neu schreibt (also einen
> > > > exklusiven Lock hat), kann logischerweise 3 Stunden niemand
> > > > anders die Datei lesen, weil er ja nicht wissen kann, ob der
> > > > erste geschriebene Block commitet wird oder nicht. 
> > >
> > > Eben. Diese beiden verhalten sich wie ein einziger. und der
> > > kann immer, weil er ja der einzige ist, halt intern doppelt.
> >
> > ? Jedenfalls muß der andere eben 3 Stunden einfach nur warten...
> 
> Worauf denn? er hat doch ne jederzeit identische kopie auf der
> er arbeiten kann.

Wovon hat er eine Kopie? Von den nicht-geänderten Daten oder von
den geänderten? Eigentlich müßte die Datenbank *beide* (also
ALLE) Transaktionsmöglichkeiten durchspielen (also superpositiv
arbeiten), wenn es nicht blockieren soll! Die Kopie nützt ja nix,
kann ja sein, daß ein commit kommt, und die Kopie einfach mal
falsch ist! Beinhaltet die Kopie hingegen die Änderungen, kann es
ja sien, daß ein Rollback kommt, und wieder ist die Kopie falsch.
Kann man also nicht machen, man muß warten, hilft ja alles nix!

> > > Doch wenn das so kompliziert und damit schwer beherrschbar
> > > wird, ist vielleicht das gewählte Modell "Transaktion" das
> > > falsche und man hätte etwas besser geeignetes wählen sollen.
> >
> > Nein, ich denke eher, wenn die Thematik so komplex ist, gibt es
> > eben keine noch einfachere Lösung.
> 
> Vielleicht ist diese Komplexität gar nicht Notwendig würde man
> ein anderes Modell nehmen?

Du kennst ein einfacheres Modell für Nebenläufigkeiten bei
Datenmanipulationen, daß Transaktionssicher ist? Dachte immer,
wir reden hier schon über das einfachste mögliche?

> > > > Physiker würden sagen: "der Zustandsvektor ist superpositiv
> > > > und kollabiert bei commit".
> > >
> > > Des Bundeskanzlingers Katze :)
> >
> > Genau! BTW, wie geht's ihr eigentlich?? Hab noch nicht
> > nachgeguckt, vielleicht stirbt sie ja dabei ;)
> 
> Der letzte der nachgeschaut hat konnte nicht mit bestimmtheit
> sagen ob sie noch lebt oder nicht...

Versteh ich nicht. Wenn er nachgeguckt hat, weiß er es ja...

> > > also insgesamt 3^(Anzahl bits) wobei ich eben unterstelle,
> > > daß es nur diese 3 Zustände (0, 1, beides gleichzeitig)
> > > gibt.
> >
> > Yo, eben. Kann aber auch sein, daß es zu 25% 0 und zu 75% 1 ist.
> > Die Wahrscheinlichkeiten sind dann oft wieder beliebig, und damit
> > unendlich viele Zustände in der Superposition, und
> > unendlich^(Anzahl bits) ist recht groß :)
> 
> Ja, innerhalb des dritten Zustands, weil 25% 0 und 75% 1 auch beides 
> gleichzeitig ist. 

Nein, 0 und 1 ist gleichzeitig, mit Wahrscheinlichkeiten 25%/75%.
"25% 0" ist ja kein Zustand, sondern eine Wahrscheinlichkeiten
für einen Zustand.

> Was ist mit den Zuständen <0 und >1?

Gibt es genausowenig wie 0.5 bei einem Bit. Es ist eben gesetzt
oder nicht, ist doch klar?!

> > > Schon, nur halt nicht das read() und nicht das write()
> > > welches man sich mit man read oder man write anschauen
> > > kann, weil diese eben nicht direct sind
> >
> > Weißt Du doch nicht. Kann sein, daß Du in ne Datei, ne FIFO,
> > einen Socket schreibst, aber auch auf ein Terminal (/dev/tty
> > geöffnet) oder ein Gerät (/dev/sg0) - oder eben directIO
> > (/dev/raw/0). Sind alles nur Files :-)
> 
> Dann gibt es keinerlei Vorteil gegenüber einem File wenn man
> read und write benutzt. 
> Sag ich doch. directio ist sinnlos.

Wieso denn nur! Man! Die API ist gleich. Das heißt, der
Programmcode sieht ähnlich aus. War hat das dann keine Vorteile,
nur weil man die Funktionen sinnvollerweise gleich genannt hat?
Wie sich ein "read" verhält, interessiert *hier* den *Code*
nicht. Den Anwender interessiert es aber vielleicht, das sich das
read definiert synchron verhält. Auch wenn die Applikation keine
(einfache, direkte) Möglichkeit hat, herrauszukriegen, ob sie nun
gerade rawIO macht, oder nicht. Muß die Applikation
logischerweise dem Kernel "glauben", ist doch klar.

> > Dann merkt die Hardware trozdem nicht, wer das aufruft :)
> 
> retc = write(fd, offset, data, "mein name is oracle, write faster!");

also:

#include <unistd.h>

int main(void)
{
    int fd, offset, data, retc;

    retc = write(fd, offset, data, "mein name is oracle, write faster!");
}

> "oracle unknown, write delayed."

Ich kriege:

x.c:7: warning: passing arg 2 of `write' makes pointer from
integer without a cast
x.c:7: too many arguments to function `write'

Versteh ich alles nicht, sorry.

Ich hab den Eindruck, das Thema ist erschöpft.

oki,

Steffen

-- 
Dieses Schreiben wurde maschinell erstellt,
es trägt daher weder Unterschrift noch Siegel.




Mehr Informationen über die Mailingliste linux-l