2010-09-21 12 views
10

Wenn ich eine einzelne Datei mit normalen IO-APIs lese und schreibe, ist garantiert, dass Schreibvorgänge pro Block blockweise sind. Das heißt, wenn mein Schreibvorgang nur einen einzigen Block ändert, garantiert das Betriebssystem, dass entweder der gesamte Block geschrieben wird oder gar nichts.Speicher Zugeordnete Dateien und atomare Schreibvorgänge von einzelnen Blöcken

Wie erreiche ich den gleichen Effekt für eine Memory-Mapped-Datei?

Memory-Mapped-Dateien sind einfach Byte-Arrays, also wenn ich das Byte-Array modifiziere, kann das Betriebssystem nicht wissen, wann ich einen Schreibvorgang für erledigt halte, also könnte es (auch wenn das unwahrscheinlich ist) Speicher gerade in der Mitte meines Blockschreibens, und in der Tat schreibe ich einen halben Block.

Ich würde eine Art von "Enter/Leave kritischen Abschnitt" oder eine Methode zum "Pinnen" der Seite einer Datei in den Speicher benötigen, während ich schreibe. Gibt es so etwas? Wenn ja, ist das portable über gemeinsame POSIX-Systeme & Windows?

+0

Wie viele Anwendungen interagieren mit Ihrer zugeordneten Datei? – Justin

+0

Nur ein Prozess, d. H. Der Datenbankserver. –

Antwort

4

Die Technik des Haltens journal scheint der einzige Weg zu sein. Ich weiß nicht, wie das funktioniert, wenn mehrere Apps in dieselbe Datei schreiben. Das Cassandra-Projekt hat eine good article, um Leistung mit einem Journal zu erhalten. Die wichtigste Sache ist, sicherzustellen, ist, dass das Journal nur Aufzeichnungen positive Aktionen (mein erster Ansatz war das Vor-Bild von jedem schreiben in das Journal, so dass Sie Rollback, aber es wurde übermäßig kompliziert) schreiben.

Also im Grunde Ihre Memory-Mapped-Datei hat eine transactionId in der Kopfzeile, wenn Ihre Kopfzeile in einen Block passt Sie wissen, es wird nicht beschädigt, obwohl viele Leute scheinen es zweimal mit einer Prüfsumme schreiben: [header[cksum]] [header[cksum]]. Wenn die erste Prüfsumme fehlschlägt, verwenden Sie die zweite.

Die Zeitschrift sieht ungefähr wie folgt aus:

[beginTxn[txnid]] [offset, length, data...] [commitTxn[txnid]] 

Sie halten nur Journaldatensätze anhängen, bis er zu groß wird, dann rollen sie irgendwann vorbei. Wenn Sie Ihr Programm starten, prüfen Sie, ob die Transaktions-ID für die Datei die letzte Transaktions-ID des Journals ist - falls nicht, geben Sie alle Transaktionen im Journal zur Synchronisierung ein.

+0

Ja, Journaling ist der Weg zu gehen, ich kenne diese Algorithmen. Aber das Problem ist, dass Sie selbst bei der Verwendung eines Journals garantieren müssen, dass einzelne Seiten der Datendatei (en) nur komplett geschrieben werden, sonst riskieren Sie eine "halbgeschriebene" Seite, und Sie können nicht erkennen, ob sie da ist ist beschädigt oder nicht. Deshalb suche ich nach einer Möglichkeit, atomare Schreibvorgänge von Seiten in zugeordneten Dateien durchzuführen. –

+1

Warum funktioniert das nicht? PartialWrite = (file.transaction-id Justin

+0

@MartinProbst: Sie können atomare Schreibvorgänge von Seiten überhaupt nicht tun. Es ist eine grundsätzlich asynchrone Operation für den Windows-Kernel, glaube ich. Sie werden wahrscheinlich die Funktion 'FlushFileBuffers' Win API ausprobieren. – Noldorin