Use transaction lock file to provide details abour currently running transaction - #2391
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().
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().
d4bf88e to
3473640
Compare
| TransactionLocker transaction_locker(lock_file_path, info); | ||
| if (!transaction_locker.write_lock()) { | ||
| return TransactionRunResult::ERROR_LOCK; | ||
| } | ||
| transaction_locker.write_transaction_metadata(); |
There was a problem hiding this comment.
NGL it feels quite verbose
At least for naming:
| TransactionLocker transaction_locker(lock_file_path, info); | |
| if (!transaction_locker.write_lock()) { | |
| return TransactionRunResult::ERROR_LOCK; | |
| } | |
| transaction_locker.write_transaction_metadata(); | |
| TransactionLocker lock(lock_file_path, info); | |
| if (!lock.write_lock()) { | |
| return TransactionRunResult::ERROR_LOCK; | |
| } | |
| lock.write_transaction_metadata(); |
As for the interface itself, I would say that it can be easily deduced from the type name, so even
write_lock()->write()write_transaction_metadata()->write_metadata()
wouldn't reduce the clarity IMO
Now that I'm looking at it, why don't we merge the write_lock() and write_transaction_metadata() into one method? In this case, I guess it would even make sense to fail with ::ERROR_LOCK when the metadata cannot be stored properly?
| TransactionLocker transaction_locker(lock_file_path, info); | ||
| if (!transaction_locker.write_lock()) { | ||
| auto content = transaction_locker.read_content(); | ||
| concurrent_transaction = std::make_unique<ActiveTransactionInfo>(ActiveTransactionInfo::from_toml(content)); |
There was a problem hiding this comment.
I guess we can guarantee only one concurrent transaction, because of the shared path?
3473640 to
991c706
Compare
dcantrell
left a comment
There was a problem hiding this comment.
I like this revision. Apologies for the delay getting back to it!
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.
991c706 to
9e06f54
Compare
Errors are no longer silently ignored, a new ActiveTransactionInfoParseError is thrown instead. The error is caught and logged during the transaction run.
9e06f54 to
5b8a3cc
Compare
9541e3f
This PR:
For: #2355