-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Assess risk of corruption of SQLite DB #15
Comments
Well, it is not only for the DB but also for the files being streamed: |
Thanks, this is a very good comment. In term of full disk, I see the problem for the WAL file (I need to check if SQLite already has a way to cope with this, it might).
|
I have to check how you implemented the sandbox, but I guess when receiving data you're already starting to write to disk?
This really depends on the filesystem used. Based on the documentation for
Yes and no, the problem is how you're going to recover from that: having extra bytes at the end of a pack gets unnoticed until you start writing to the pack again, or unless you do a consistency check (from the DB you should be able to get the metadata and then be able to check the size) or if you have a WAL to reply. Unfortunately there are other reasons for additional or missing bytes: having a crash after an operation could also leave you with a truncated file, even though you (the application) finished writing the data successfully. |
Yes. What I actually meant is not that there will not be leftover files on disk, but that there will be no leftover partial loose objects. BTW, this is also what AiiDA is doing now during .store(), so it's not going to be more but not even less reliable of the current behavior, I think.
Indeed. I also checked and the tests seem to indicate that this is also the case on Windows (I used earlier The question is rather what is the risk that the application thinks that the file has been moved, but the OS still has to do it and if the disk fails, the file remains in the old position or even worse the filesystem partition gets corrupted. But this is a general problem, and I imagine that modern journaled filesystems at least would not get a corrupted filesystem table. The second part of this comment is if also the filesystem table is cached, and if there exists a
My reasoning is that even if I append garbage to the end of a pack, this does not corrupt the disk-objectstore in the way it's implemented now: these bytes are just unaccounted for. It would be equivalent to having an object packed, and then soft-deleting it by just removing the reference from SQLite. Or a process that was adding packed data, but crashed. Actually, this makes me think that maybe, instead of opening always the pack in append mode, I could open it normally, and then seek to the last byte I am aware of (let's say largest offset in that pack+lenght of that pack, assuming that there is no overlap between packed objects by mistake), truncate the file, and then start writing again from there. The question is more to understand which are the conditions that might make the application think that it correctly appended to a file, and it was correctly closed, but then the data can get lost. I imagine that if I call |
It seems that you can actually get an
You should even be able to avoid the truncation until you finish writing. Position the file and start writing will simply overwrite it.
This is actually very difficult, as the PostgreSQL had to find out:
A very good read seems to be (have to study it once more in detail): https://danluu.com/file-consistency/ I haven't completely thought it through, but using buffered I/O for incoming data (without direct write to packs, for performance reasons) and direct I/O from there to packs might be something? Allowing for low latency writing while a low-prio thread will pack up the files later on (similar to |
Thanks for the very interesting links! I'll look into them in detail.
Then, packing is triggered by the user, when he/she wants. In my idea, this should be done e.g. in a cron job (daily or weekly, for instance). Packing will therefore be done in a different process, when the user wants, which is probably what you are suggesting, right? (The idea comes exactly form git, that by default stores loose objects, and then you can pack with (sorry if instead this was already very obvious and I misunderstood your comment). Regarding buffered vs. direct: I am not doing anything explicit in this direction. |
BTW, the good news is that in your link they say that SQLite is the best in taking care of these problems and SQLite+WAL didn't show any static vulnerability, better than e.g. Postgres, much better than git, ... (at least at the time the article was written). This justifies my choice of using SQLite+WAL (of course it's not enough per se, if then I introduce bugs in coordinating the SQLite DB with the packs content ;-) ). |
Check also #28 |
From the links (and from my experience after testing) it's clear that if there is a problem it's not going to be in the SQLite part, so closing this |
Note that anyway this should only happen during "maintenance" operations (see also #6).
One option is that maintenance operations always perform a backup of relevant files (e.g. of all pack indexes, including the various WAL files), maybe keeping a few past ones). Also, assess with tests that one can read properly historical versions.
Probably this is enough to feel confident that it's reliable?
The text was updated successfully, but these errors were encountered: