[cleaner] Make cleaner concurrent inside one archive - #3988
Conversation
|
Congratulations! One of the builds has completed. 🍾 You can install the built RPMs by following these steps:
Please note that the RPMs should be used only in a testing environment. |
|
How to get the sqlite DB locks: In an unpacked sosreport: And run |
TurboTurtle
left a comment
There was a problem hiding this comment.
From a pure review standpoint, I like this approach and the code changes overall. We'd want to ensure that the --jobs option gets exposed to report for leveraging in-line cleaning, but that can come later.
I am unsure of the need to carry both files and sqlite as the concurrency mechanism though. Especially if the results are largely the same. I have a preference to only carry files, but am certainly open to hearing why we should prefer the sqlite approach (if we only carry one forward).
That said, on python 3.13 (my Fedora daily driver install), I get this error when trying to clean an archive:
sosreport-terra-2025-04-22-xicbmuo : Beginning obfuscation...
Exception while processing sosreport-terra-2025-04-22-xicbmuo: cannot pickle 'BufferedReader' instances
No reports obfuscated, aborting...
and it is not immediately obvious to me where that BufferedReader is coming into play here but I suspect it is from the ProcessPoolExecutor instantiation.
What python version(s) are you able to get successful executions on?
|
One more bug: Because |
bd314b2 to
93fe8a3
Compare
|
The
The concurrency mechanism does not need to be configurable, I think sticking to either The |
cc00d15 to
72664af
Compare
c777375 to
6f4c2c2
Compare
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
6f4c2c2 to
516c61a
Compare
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
516c61a to
7eec966
Compare
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
7eec966 to
938a85a
Compare
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
938a85a to
841ca5b
Compare
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
841ca5b to
888926a
Compare
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
888926a to
ee19b28
Compare
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
ee19b28 to
3915edd
Compare
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
3915edd to
7305ce2
Compare
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
| from sos_tests import StageTwoReportTest | ||
|
|
||
| MOCK_FILE = '/tmp/sos-test-ipv6.txt' | ||
| MOCK_FILE = '/sos-test-ipv6.txt' |
There was a problem hiding this comment.
This change (and same in ipv6_test.py is tricky. Some previous test obfuscated tmp into obfuscatedword1. We replaced /etc/sos/cleaner/default_mapping by empty file, yet the cleaner's cache kept the mapping. So self.assertFileCollected(MOCK_FILE) fails as the filename is changed by cleaner in the tarball.
|
Various tests are failing the same way I fixed one instance of that failure in #3988 (comment) :
How to resolve it? A few ideas:
Any other idea? Any preferences? I think the 1st or 2nd option is less painful. |
I think that the first option is the best for now, with the idea of working on the fourth long term. |
|
After some offline discussion, the best is:
Until there will be another idea, I will follow the short-term solution in next few days. |
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
8fb933b to
04f27ef
Compare
|
/packit retest-failed |
|
I've created 3000 users, and thought I would try that, the first iteration from the original code took 65 mins. Second one had issues, the traceback/explanation is below Installed the package from my local PPA, based on the change as per our discussion last week, and that was quicker on the run1 run2 This was run in a container, so will try in a VM, and see if I get something different The issue on the second run, I got the following traceback I have user1 to user3000, and this traceback happens with a different username each time. This shouldn't happen, and will investigate what is going on. This is with the original code. This new version didn't have the traceback, so hopefully we won't see the issue |
|
IMHO that traceback can not happen in concurrent cleaner where I had to catch all exceptions to prevent child process termination (https://github.com/sosreport/sos/pull/3988/files#diff-64f7cecab583ab4d9d9a3d4d4d89fda30a4b0e5b8e9371cc8a156bdb626e2d0fR209-R211). In such a case, no sanitisation happens for the given line and parser. But we should investigate also the root cause of infinite recursion - that sounds like generic problem that my code would rather hide than resolve. |
|
So, just looking at those time fields, the Also, just realised, as we changed the tmp-dir for Debian/Ubuntu now in the policy to /tmp, not the obfuscated report and normal actually ended up in /var/tmp instead of /tmp, and this was unexpected :(; will debug this further |
|
I investigated the
Just one common username in mapping file and in This can't happen in concurrent cleaner, since (so the presence of this issue is yet another reason to review this PR :) ) |
|
Hi mainly @TurboTurtle but also others - can you please do a tech review of the codechanges as well? I would like to move this PR further / have it merged. |
TurboTurtle
left a comment
There was a problem hiding this comment.
I'm having some inconsistencies in performance. I've had some executions that run better than current main, and others that sit for 15+ minutes, using default values.
I've not been able to track down what's happening here as of yet.
Can you provide the sosreport you get stuck cleaner on, so I can investigate? If you run cleaner with |
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
04f27ef to
8b7467b
Compare
|
The new version contains the two Jake's comments applied. |
Generally it would hang on the system journal collection, but I've not been able to reproduce the issue since then. LGTM, would like to get any feedback from @arif-ali before merge, but also want to have this in before our release in August either way. |
arif-ali
left a comment
There was a problem hiding this comment.
Went through stuff over the past couple of days, looks good to me
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
8b7467b to
74220c1
Compare
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com> Signed-off-by: Pablo Fernández Rodríguez <pafernan@redhat.com>
Allow running cleaner concurrently via child processes. They synchronize on the ordering of items added to dataset of each mapper by creating numbered files in a directory specific for each mapper. Together with deterministic generation of obfuscated values, this ensures the individual processes end up with identical mappings. Resolves: sosreport#3097 Closes: sosreport#3988 Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
Draft version adding to the traditional sequential backend also sqlite3 and file based concurrent ones.
TL;DR: please review the idea, test it and comment or ack or nack the approach. Then I will fix the TODOs.
Let me explain various factors and reasons that affected the chosen implementation.
As very very first, I implemented both sqlite3 and files based approaches, see reasoning below. And left the original behaviour just for (performance) comparison (it must be run with
-j 1).First, mappings are very independent objects that do maintain their dataset on their own. Even adding an item to obfuscate (say, FQDN) means the dataset is updated a few times (by the host, FQDN and/or domain). I tried to respect this as I like that independency (and also changing it would require a lot of changes).
Also, the dataset is growing in time (as we discover more domains or IP networks) , which means some instances of lately discovered domain might not be obfuscated or that changing ordering of files to obfuscate result in different final mapping (also in the size of the final map). You can check it by yourself if you reorder the list from
get_file_list. So running cleaner concurrently - which means dataset being populated non-deterministically - can end up in different final map. Dont be confused by this as I was.I chose individual processes to sync over the pieces of information "we obfuscate item X as the first one, and item Y as the next". An option to exchange or sync on the whole mapping/datasets would mean 1) more data to sync and 2) altering the mapping classes "independent" behaviour.
This also means there are gaps in numbers and it is fine. The ordering number is the size of the dataset, which can be incremented more than by one when adding just one item. This is fine, as each and every process replays the same and adds the same stuff into its dataset. And also this allows a smart replay of the whole "how was the dataset created?" process at the end - see the
archive.load_parser_entries()call.Then, ProcessPoolExecutor has two limitations for us that I described directly in the code, plus one substantial one: passing the whole
SoSCleanerclass is not easily feasible. Doing so would prevent some code movement among classes and would be nicer to hook new code in, but it does not work easily. Trying that, I hit issues like "oh, cloningSoSCleanerinto a child process means cloning there sos arguments parsing that overrides some __* method that blocks successful process spawn and iteration over a list". It is possible to fix or hack those traps in our code, but after iteratively doing that for five such traps, I gave up this rabbit hole journey.Please, consider this as a draft only - see the number of TODO points, plus various methods need a better name. Anyway the code is functionally ready, works well(*) and scales fairly well.
(*) the only concern is that sqlite DB can lock itself. I did a few changes there, but still I seldomly hit a live-lock behaviour over locked DB on some artificial test cases (have 8 identical files each with 100 unique IP addresses inside a sosreport, and run cleaner with
-j 8is my "favourite" one).While I like the sqlite approach more (it looks so professional!), we cant choose it until we fix these live-locks / DB locks.
Gladly, the file-based approach works smoothly and provides comparable (or even slightly better) performance.
When speaking about performance, some benchmark tests are running. Results from 8cores RHEL10 beta, median time from 3 runs each:
a small, 11MB packed sosreport:
220MB packed sosreport:
350MB packed sosreport:
770MB packed sosreport:
1GB packed sosreport:
Closes: #3097
Please place an 'X' inside each '[]' to confirm you adhere to our Contributor Guidelines