Safe File Save (atomic update)

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Sinds de introductie van ext4 hebben sommige apps/users last van file corruptie na een crash. Het is geen bug in het FS en niet alleen met ext4 heeft men er last van.
Een temp file schrijven, fsync en rename wordt vaak voorgesteld, maar dat heeft ook nadelen. Meta-data, inclusief file owner, gaat dan mogelijk verloren en je hebt permissie nodig om een temp file te schrijven. Sommigen vinden het file owner issue geen punt.
Hoe doen anderen dit en wat vinden anderen hier van?
Welke code wordt gebruikt om dit wel goed te doen?

De non-atomic variant is iets als (pseudo):
C++:
1
2
3
4
5
6
7
int safe_save(const char* fname, const void* s, size_t cb_s)
{
    int fd = open(fname);
    write(fd, s, cb_s);
    // fsync(fd);
    close(fd);
}

[ Voor 16% gewijzigd door Olaf van der Spek op 29-12-2010 18:33 ]


  • Rainmaker
  • Registratie: Augustus 2000
  • Laatst online: 14-07-2024

Rainmaker

RHCDS

Je kunt de file toch openen als O_SYNC? Hiermee hoef je niet iedere keer een fsync te geven.

C++:
1
int fd = open(fname, O_SYNC)


Ik ben er eerlijk gezegd niet zo in thuis, maar een probleem met metadata / file owner i.c.m. fsync komt mij absoluut niet bekend voor...

We are pentium of borg. Division is futile. You will be approximated.


  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

"na een crash" -- van wat?

All my posts are provided as-is. They come with NO WARRANTY at all.


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 07:02

BoAC

Memento mori

Mijn applicaties crashen nooit >:)

Maar inderdaad, ik herken dit ook niet eigenlijk..

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Het systeem. Of een (externe) disk die wordt ontkoppeld zonder unmount.
Rainmaker schreef op donderdag 30 december 2010 @ 02:36:
Je kunt de file toch openen als O_SYNC? Hiermee hoef je niet iedere keer een fsync te geven.

C++:
1
int fd = open(fname, O_SYNC)


Ik ben er eerlijk gezegd niet zo in thuis, maar een probleem met metadata / file owner i.c.m. fsync komt mij absoluut niet bekend voor...
Je wil de file van voor safe_save of van erna. Maar als je systeem crasht na open (truncate), dan zit je met een lege file (bijvoorbeeld).

  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

Olaf van der Spek schreef op donderdag 30 december 2010 @ 11:28:
[...]

Het systeem. Of een (externe) disk die wordt ontkoppeld zonder unmount.
Dat levert, in combinatie met write-caching, altijd corrupte (of ontbrekende, wat in veel gevallen hetzelfde is) data op als je in-place writes doet zonder O_DIRECT. Niets vreemds dus.

[ Voor 6% gewijzigd door CyBeR op 30-12-2010 11:30 ]

All my posts are provided as-is. They come with NO WARRANTY at all.


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
CyBeR schreef op donderdag 30 december 2010 @ 11:30:
Dat levert, in combinatie met write-caching, altijd corrupte (of ontbrekende, wat in veel gevallen hetzelfde is) data op als je in-place writes doet zonder O_DIRECT. Niets vreemds dus.
Ja, doh. Er staat niet voor niets dat dat de non-atomic variant is. O_DIRECT is trouwens geen garantie op succes.

[ Voor 13% gewijzigd door Olaf van der Spek op 30-12-2010 11:36 ]


  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

Olaf van der Spek schreef op donderdag 30 december 2010 @ 11:34:
[...]

Ja, doh. Er staat niet voor niets dat dat de non-atomic variant is.
Dan snap ik niet wat het doel van dit topic is. Dit "issue" wat jij beschrijft bestaat al sinds de eeuwigheid en is een bekend gegeven onder iedereen die met enigszins serieuze data werkt. Het is niet iets nieuws sinds ext4 ofzo, wat jij lijkt te insinueren in je startpost.
O_DIRECT is trouwens geen garantie op succes.
Wel als de write cache van je drives en/of raid controllers ook uit staan (of een batterij backup hebben). Dan gaat 't alleen nog mis als je systeem mid-write crasht, maar wat je geschreven hebt staat dan wel degelijk op disk. Moet je alleen nog zorgen dat je file format atomic updates toestaat. Een leuke om naar te kijken in dit opzicht is eigenlijk zo ongeveer elk RDBMS.

[ Voor 32% gewijzigd door CyBeR op 30-12-2010 11:40 ]

All my posts are provided as-is. They come with NO WARRANTY at all.


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 07:02

BoAC

Memento mori

En dit probleem bestaat ook op andere OS-en like Windows of what-ever.

Je zou de sync optie mee kunnen geven aan mount :)

/edit

Nog een leuke uit de manpage voor fsync:
If the underlying hard disk has write caching enabled, then the data
may not really be on permanent storage when fsync() / fdatasync()
return.

When an ext2 file system is mounted with the sync option, directory
entries are also implicitly synced by fsync().
CyBeR schreef op donderdag 30 december 2010 @ 11:30:
[...]

Dat levert, in combinatie met write-caching, altijd corrupte (of ontbrekende, wat in veel gevallen hetzelfde is) data op als je in-place writes doet zonder O_DIRECT. Niets vreemds dus.
Maar dan beter nog icm O_SYNC als ik de manpage goed begrijp van open(2):
O_DIRECT (Since Linux 2.4.10)
Try to minimize cache effects of the I/O to and from this file.
In general this will degrade performance, but it is useful in
special situations, such as when applications do their own
caching. File I/O is done directly to/from user space buffers.
The O_DIRECT flag on its own makes at an effort to transfer data
synchronously, but does not give the guarantees of the O_SYNC
that data and necessary metadata are transferred. To guarantee
synchronous I/O the O_SYNC must be used in addition to O_DIRECT.
See NOTES below for further discussion.

A semantically similar (but deprecated) interface for block
devices is described in raw(8).

[ Voor 115% gewijzigd door BoAC op 30-12-2010 11:57 ]


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
CyBeR schreef op donderdag 30 december 2010 @ 11:36:
Dan snap ik niet wat het doel van dit topic is.
De vragen in de topic start lijken me toch vrij duidelijk. Ik zoek in feite de atomic variant van de geposte code. Een variant, die net als de non-atomic code de genoemde uitzonderingen niet heeft (liefst).
Dit "issue" wat jij beschrijft bestaat al sinds de eeuwigheid en is een bekend gegeven onder iedereen die met enigszins serieuze data werkt. Het is niet iets nieuws sinds ext4 ofzo, wat jij lijkt te insinueren in je startpost.
Dat was niet de bedoeling.
Wel als de write cache van je drives en/of raid controllers ook uit staan (of een batterij backup hebben). Dan gaat 't alleen nog mis als je systeem mid-write crasht,
Met andere woorden: geen garantie op succes
maar wat je geschreven hebt staat dan wel degelijk op disk. Moet je alleen nog zorgen dat je file format atomic updates toestaat. Een leuke om naar te kijken in dit opzicht is eigenlijk zo ongeveer elk RDBMS.
Dan kun je beter O_SYNC gebruiken dacht ik, maar dat is OT.
BoAC schreef op donderdag 30 december 2010 @ 11:45:
En dit probleem bestaat ook op andere OS-en like Windows of what-ever.
Heeft Windows wel een goede oplossing?

[ Voor 14% gewijzigd door Olaf van der Spek op 30-12-2010 12:01 ]


  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

Olaf van der Spek schreef op donderdag 30 december 2010 @ 11:55:
[...]

De vragen in de topic start lijken me toch vrij duidelijk.
Ja: hoe doe je atomic updates. Dat kan op de manier zoals je beschreef, en dat heeft nadelen zoals je beschreef. De andere optie kun je afkijken van rdbms'en, en die doen dat door transactie-gebaseerd te werken en de 'deze transactie is af'-flag atomic te maken (enkele bit).
Met andere woorden: geen garantie op succes
Dat is aan de beheerder van het systeem om te regelen. Als applicatieprogrammeur kún je dit niet zeker weten omdat, inderdaad, je niet kunt weten of er ergens een cache tussen zit die verloren kan gaan. De drives en de raid controllers zeggen in alle gevallen (ook met O_DIRECT of O_SYNC) dat de data op disk staat maar staan je ondertussen glashard voor te liegen. Dat kun je als applicatie niet ondervangen. Als beheerder wel, en daar kun je de afweging maken of die potentie voor corruptie belangrijk voor je is of niet. Zo wel kun je de cache uitzetten of voorzien van battery backup (of flash cache met een supercap gebruiken), zo niet kun je 't lekker laten zoals het is.
Dan kun je beter O_SYNC gebruiken dacht ik, maar dat is OT.
Dat ligt aan je applicatie.

All my posts are provided as-is. They come with NO WARRANTY at all.


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
CyBeR schreef op donderdag 30 december 2010 @ 12:01:
Ja: hoe doe je atomic updates. Dat kan op de manier zoals je beschreef, en dat heeft nadelen zoals je beschreef. De andere optie kun je afkijken van rdbms'en, en die doen dat door transactie-gebaseerd te werken en de 'deze transactie is af'-flag atomic te maken (enkele bit).
Het gaat om file updates, dus je kunt geen DBMS gebruiken of een ander file format.
Mijn punt is eigenlijk dat velen wel weten hoe het zou moeten, maar niemand dat blijkbaar heeft geimplementeerd (of concrete code kan posten) omdat het te complex is. Ook de nadelen helpen natuurlijk niet mee.
Zijn er geen libs die dit fatsoenlijk implementeren?
Dat is aan de beheerder van het systeem om te regelen. Als applicatieprogrammeur kún je dit niet zeker weten omdat, inderdaad, je niet kunt weten of er ergens een cache tussen zit die verloren kan gaan. De drives en de raid controllers zeggen in alle gevallen (ook met O_DIRECT of O_SYNC) dat de data op disk staat maar staan je ondertussen glashard voor te liegen. Dat kun je als applicatie niet ondervangen. Als beheerder wel, en daar kun je de afweging maken of die potentie voor corruptie belangrijk voor je is of niet. Zo wel kun je de cache uitzetten of voorzien van battery backup (of flash cache met een supercap gebruiken), zo niet kun je 't lekker laten zoals het is.
Ik doelde op partial writes van de hardware. Kun je als beheerder niks aan doen.

  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

Olaf van der Spek schreef op donderdag 30 december 2010 @ 12:24:
[...]

Het gaat om file updates, dus je kunt geen DBMS gebruiken of een ander file format.
Mijn punt is eigenlijk dat velen wel weten hoe het zou moeten, maar niemand dat blijkbaar heeft geimplementeerd (of concrete code kan posten) omdat het te complex is. Ook de nadelen helpen natuurlijk niet mee.
Zijn er geen libs die dit fatsoenlijk implementeren?
Nee, want als je file format er geen rekening mee houdt (zoals DMBS'en dat doen), dan kán het dus gewoon ook echt niet. Zelfs de 'schrijf je file en rename'-methode is niet compleet veilig. Die kan prima completed zijn maar in werkelijkheid nog in z'n geheel in disk write cache staan. Voordeel is wel dat als je dan crasht en reboot, je gewoon bent gebleven bij 'er is nog niets gebeurd' ipv ergens halverwege. Dus je nieuwe data is dan weg, maar je oude niet corrupt.
Ik doelde op partial writes van de hardware. Kun je als beheerder niks aan doen.
Als je hardware je voorliegt en daar geen provisie voor heeft, moet je die hardware dus niet gebruiken als je data je lief is.

All my posts are provided as-is. They come with NO WARRANTY at all.


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 07:02

BoAC

Memento mori

Olaf van der Spek schreef op donderdag 30 december 2010 @ 11:28:
[...]

Het systeem. Of een (externe) disk die wordt ontkoppeld zonder unmount.
[...]

Je wil de file van voor safe_save of van erna. Maar als je systeem crasht na open (truncate), dan zit je met een lege file (bijvoorbeeld).
Hier kun je niets tegen doen. Je kunt niet garanderen dat de file werkelijk uit (disk)cache naar disk is geschreven als je de disk ontkoppeld. Daarom eerst unmounten/ejecten voor ontkoppelen.
Olaf van der Spek schreef op donderdag 30 december 2010 @ 11:55:
[...]

De vragen in de topic start lijken me toch vrij duidelijk. Ik zoek in feite de atomic variant van de geposte code. Een variant, die net als de non-atomic code de genoemde uitzonderingen niet heeft (liefst).

[...]

Heeft Windows wel een goede oplossing?
Nee. Maar die probeert in geval van bijv een usb-stick wel te zorgen dat de file gegarandeerd weggeschreven is. Bij Win2k en WinXP moest je nog hardware ontkoppelen om de caching reden. Later is dat wel verbeterd maar garantie kan er volgens mij niet zijn.

Naar mijn idee probeer je met software iets te garanderen wat je hardware niet kan ondersteunen.

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
CyBeR schreef op donderdag 30 december 2010 @ 12:32:
Nee, want als je file format er geen rekening mee houdt (zoals DMBS'en dat doen), dan kán het dus gewoon ook echt niet. Zelfs de 'schrijf je file en rename'-methode is niet compleet veilig. Die kan prima completed zijn maar in werkelijkheid nog in z'n geheel in disk write cache staan. Voordeel is wel dat als je dan crasht en reboot, je gewoon bent gebleven bij 'er is nog niets gebeurd' ipv ergens halverwege. Dus je nieuwe data is dan weg, maar je oude niet corrupt.
De vraag was toch ook om atomic en niet om durable? Alhoewel met fsync durable ook mogelijk lijkt.
Als je hardware je voorliegt en daar geen provisie voor heeft, moet je die hardware dus niet gebruiken als je data je lief is.
Issues met partial writes heb je altijd, ook als je hardware niet 'liegt' en je O_DIRECT/O_SYNC gebruikt.
Dat hoeft ook niet.
Naar mijn idee probeer je met software iets te garanderen wat je hardware niet kan ondersteunen.
De hardware is het probleem niet, dat deel is al lang opgelost. Het probleem is de software.

[ Voor 15% gewijzigd door Olaf van der Spek op 30-12-2010 15:34 ]


Acties:
  • 0 Henk 'm!

  • Rainmaker
  • Registratie: Augustus 2000
  • Laatst online: 14-07-2024

Rainmaker

RHCDS

Ik denk dat ik eindelijk snap wat je bedoelt.

Use case; een applicatie die logt, maar de log regels bovenaan wil zetten ipv onderaan.

Je hebt nieuwe data, en je open()'t de logfile met truncate, schrijft de nieuwe data en daarna de oude data. Probleem nu is dat als de server crashed / hd eruit wordt getrokken tussen de truncate en de close(), je maar een halve logfile hebt.

Klopt het als ik het zo verwoord?

Je zou dan inderdaad met een temp file moeten werken (je kritieke pad zo kort mogelijk houden).

Ik zou dan de temp file vullen, de oude unlink()'en en een rename() doen. Op die manier kun je makkelijk een crash detecteren en oplossen.

Qua file permissies ken ik geen call die alle permissies van 1 file op de andere zet. Een ranzige workaround zou zijn een system() call te gebruiken om een "cp -p" te doen, en dan de nieuwe file te truncaten op open().

Mocht je het toch zelf willen doen:
stat() en chmod() voor de "normale" permissies
fgetxattr() en fsetxattr() voor ACL's

Ik ken geen library function die een file kopieert met permissies intact. Zal vast bestaan, maar ik ken m niet...

We are pentium of borg. Division is futile. You will be approximated.


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Rainmaker schreef op zondag 02 januari 2011 @ 17:26:
Klopt het als ik het zo verwoord?
Ja en nee. Het gaat ook om het updaten van bijvoorbeeld executables. Ik wil of de oude, of de nieuwe, maar niet iets anders.
Ik zou dan de temp file vullen, de oude unlink()'en en een rename() doen. Op die manier kun je makkelijk een crash detecteren en oplossen.
Unlink is niet nodig en zelfs schadelijk, omdat je dan een moment hebt waarop je geen file hebt.
Qua file permissies ken ik geen call die alle permissies van 1 file op de andere zet. Een ranzige workaround zou zijn een system() call te gebruiken om een "cp -p" te doen, en dan de nieuwe file te truncaten op open().

Mocht je het toch zelf willen doen:
stat() en chmod() voor de "normale" permissies
fgetxattr() en fsetxattr() voor ACL's
Kan niet, je kunt als non-root chown niet zo gebruiken.
Pagina: 1