A while ago I wrote a pretty simple but useful little app for taking notes. It uses a note hierarchy and saves each notebook in saparate XML. I am using the app for two years and everything worked fine. One of my friends also uses it and just recently he reported that he cannot open one of the notepads. I inspected the problem and saw that one of the xml files was empty! It's not really a great tregedy in this case, but it could be!
I really doubt it that it is a bug in my code, since the only place I save the note is in the Note::Save() method which looks like this:
public void Save()
{
lock(this)
{
this.WriteXml(this.notesPath);
}
}
WriteXml method looks like this:
private void WriteXml(string path)
{
XmlDocument xmlDoc = new XmlDocument();
// Write down the XML declaration
XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0","utf-8",null);
XmlElement rootNode = xmlDoc.CreateElement("Note");
xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement);
rootNode.SetAttribute("Name", this.Name);
rootNode.SetAttribute("Version", "1.0");
// Write content here ....
xmlDoc.AppendChild(rootNode);
xmlDoc.Save(path);
}
The bug that would cause all the content to be blank before writing to the file is also not possible, because then we would at least have the XML declaration there...
The only culprit I can suspect is that xmlDoc.Save() is not immune to things like abrupt system resets (power outage etc).
While open, each notes gets saved on each major change and also every 10 seconds while writing the text. So there is some opportunities to disturb the writing to disk.
Can you please comment on that What is general practice with writing data do disk that cannot be lost Is xmlDoc first deleting the file and then writing the new one Is it possible to achieve transactional style of operation here.. do I have to implement some kind of system around that to prevent this in the future
I was worried about things like that, but also wondering why this is not emphasized..
Maybe it is some kind of possible bug after all I really cannot think what else could it be Please help!
David

XML catastrophe - important for everyone
pmxinos
EDIT:
SAVE
1. Write data.backup
2. delete data.xml and rename data.backup to data.original.
LOAD
1. Check which one is newer and load it.
Vaish
Csaba Vegso
Save:
1. Write the .RESTORE file
3. Create empty .RESTORE_OK file
4. Delete the .XML
5. Copy .RESTORE to .XML
6. Delete .RESTORE_OK
7. Delete .RESTORE
Load:
1. If .RESTORE_OK and RESTORE exist
- delete .XML
- copy .RESTORE to .XML
- delete .RESTORE_OK
- delete .RESTORE
- load .XML
2. else
- load .XML
This way it's taken care of:
- failures during rename (that's why I copy and delete the file)
- errors while writing to restore file.. it could happen that data there get's corrupted and then XML file is replaced with corrupted .RESTORE on load
As always: do you see any potential problem with this scheme
Peter Haik
Weird. I wrote a Notes app about 4 or five days ago for personal use. Whil my notes were being saved I got another BSOD (getting em a lot lately) and I came back to find an empty file :>
I was thinking of maybe performing backups whenever the user saves, then checking to see if it's a valid xml file and restoring the backup file.
-=SAVING=-
1. Write the backup
2. Write the file
-=LOADING=-
1. Load the file
2. If file is corrupt then load the backup file.
Would this work
Anant Badgujar
RonanDiniz
I guess that solution is, as both of you (Tom and Andrew) say:
- first write the temporary file
- write the real file with some kind of unique word at the end
- delete temp file if the execution reaches this point
Loading:
- try to read the file
- if its empty, doesn't exist or doesn't contain the magic word, look for the FILE.RESTORE and rename it
Hmm maybe the "magic word" thing is an overkill.. just trying to see if the writing was interrupted in the middle.. maybe the only thing that we have to check on load is if the RESTORE file exists.. that way there is no need for catching the xml reading exceptions and checking for that magic word
So Andrew: you wouldn't have to check if the file is corrupt (cannot tell that easily as we saw). Existence of the restore file is enough.. but for that you need to delete it when the writing of the original succeeds. Wait a second.. what if you get a BSOD between the successful write and just before deleting a restore file.. Ah ok.. no problem since the files are identical and when you restart the app, it will restore the file with most recent information anyway..
Any comments
Thank you both and I guess I know what to do with this now.
David