Use transaction lock file to provide details abour currently running transaction#2391
Use transaction lock file to provide details abour currently running transaction#2391m-blaha wants to merge 8 commits intorpm-software-management:mainfrom
Conversation
0738f32 to
43b79e3
Compare
| info.set_pid(toml::find_or<pid_t>(data, "pid", -1)); | ||
| info.set_start_time(toml::find_or<time_t>(data, "start_time", 0)); | ||
| } catch (const toml::syntax_error &) { | ||
| // Return default/empty ActiveTransactionInfo on TOML syntax errors |
There was a problem hiding this comment.
Both these exceptions mean that the lock file exists, but contains damaged/incorrect data not digestible by TOML parser. Since data from the lock file are not crucial for dnf5 behavior (only contains details about a concurrently running transaction), instead of throwing an error an empty ActiveTransactionInfo object is returned.
There was a problem hiding this comment.
Maybe I'm missing something here, but that feels like it is obscuring what is happening by returning an empty ActiveTransactionInfo object. Damaged or incorrect data in the lock file feels like it warrants a new exception type so that it is more clear what is happening and where. Or at least to help a developer debugging something going wrong.
There was a problem hiding this comment.
I guess you are right. I originally thought that the parsing errors are not worth handling properly. But yeah, it definitely makes debugging harder and it's better to do the error handling right away than adding it later.
There was a problem hiding this comment.
@dcantrell I've added a commit with parsing errors handling.
| } catch (const toml::syntax_error &) { | ||
| // Return default/empty ActiveTransactionInfo on TOML syntax errors | ||
| } catch (const toml::type_error &) { | ||
| // Return default/empty ActiveTransactionInfo on TOML type errors |
| try { | ||
| write_content(transaction_info.to_toml()); | ||
| } catch (const SystemError & e) { | ||
| //TODO(mblaha): log the error (would require base object) |
There was a problem hiding this comment.
At least in the interim should this just go to stderr?
There was a problem hiding this comment.
Hm, we try to keep libdnf5 quiet. It does not print to stderr at all.
There was a problem hiding this comment.
If libdnf5 is logging, stderr is not all that different, right? If we are to log here but are not [yet], then stderr feels appropriate. Either that or raise an exception.
There was a problem hiding this comment.
If the catch block is going to do nothing here, I suggest just removing the try/catch block entirely and leaving the function as just a call to write_content().
Extend the Locker class to include the ability to read and write the contents of the lock file. This feature is intended to record information identifying the process that acquired the lock.
Introduce a new ActiveTransactionInfo class for storing transaction metadata. This metadata will be saved in the lock file, allowing other processes to provide the user with information about the currently running transaction.
This class can write details about transaction into transaction lock file in TOML format.
If a transaction run fails because another transaction is running concurrently, record information about that transaction so it can be used later to generate a clearer error message.
Errors are no longer silently ignored, a new ActiveTransactionInfoParseError is thrown instead. The error is caught and logged during the transaction run.
fa9351f to
d4bf88e
Compare
dcantrell
left a comment
There was a problem hiding this comment.
It looks good, I only have a few minor questions and based on your answers or changes I'll mark it as approved.
| try { | ||
| write_content(transaction_info.to_toml()); | ||
| } catch (const SystemError & e) { | ||
| //TODO(mblaha): log the error (would require base object) |
There was a problem hiding this comment.
If the catch block is going to do nothing here, I suggest just removing the try/catch block entirely and leaving the function as just a call to write_content().
| throw SystemError(errno, M_("Failed to write to lock file \"{}\""), path); | ||
| } | ||
|
|
||
| // Ensure data is written to disk |
There was a problem hiding this comment.
The single call to fsync() does not technically ensure data is written to the file. Annoyingly you have to fsync() both the fd for the file and a separate fd for the directory containing the file.
This may be splitting hairs because we're also at the mercy of the kernel VFS layer and ultimately the filesystem driver and the storage device driver, but at least in userspace the control given to guarantee data is on the device we have to do two fsync() calls.
|
|
||
| std::string content; | ||
| content.reserve(1024); | ||
| char buffer[1024]; |
There was a problem hiding this comment.
Style preference, I like using BUFSIZ for arbitrary buffers rather than hardcoding a value. In theory it keeps the code using platform-preferred buffer sizes as defined by the C library at build time.
This PR:
For: #2355