Howard Chu writes:
h.b.furuseth@usit.uio.no wrote:
Changes from a failed liblmdb operation can be visible. Sometimes the resulting DB will also be inconsistent. The operation should invalidate the affected transaction/cursors or revert the change.
The transaction should be invalidated. Nothing more can be done once any error occurs in a transaction.
That would break back-mdb for MDB_NOTFOUND/MDB_KEYEXIST. And at least MDB_KEYEXIST can happen after touching pages, which affects the txn size even if the change "does nothing".
I expected to generally invalidate except in necessary cases, and from then on make more cases "gentle" at our convenience without spending much time on it.
put(MDB_MULTIPLE) can write some of the provided items and then fail, but be able to keep the txn usable. (...)
No, "partial success" is not allowed. A transaction is atomic, all or nothing.
It would be atomic like a partial OS write(). It'd be up to the user what to do next. Not that I care myself if it is supported.
A failed txn could still grow the txn size, unless MDB "un-touches" pages which memcmp says have not changed, rewinds me_pglast and me_pghead, etc. Which seems a lot of work, likely not worth the trouble.
pghead/pglast should not persist into the environment until a successful commit. Until then any error should just discard them.
Sorry, I meant a failed _operation_ could grow them and thus affect the committed freelist size.
I think cursors need a C_INVALID flag, so future ops cannot give a surprising success result instead of failing: get(MDB_NEXT/MDB_PREV) take ~C_INITIALIZED to mean (re)start from the beginning/end.
Good idea.
...or C_VALID so a single OR/AND can set/clear them both.
Don't know how often reverting is a relevant option. (...)
Reverting is irrelevant. Once a txn is aborted no changes are visible.
True, but I meant while the txn is still live and usable. Hopefully it's only relevant for "nice to have" cases.