Skip to content

[IMP] orm: parallel iter_browse#320

Open
cawo-odoo wants to merge 2 commits into
odoo:masterfrom
odoo-dev:master-imp_parallel_iter_browse-cawo
Open

[IMP] orm: parallel iter_browse#320
cawo-odoo wants to merge 2 commits into
odoo:masterfrom
odoo-dev:master-imp_parallel_iter_browse-cawo

Conversation

@cawo-odoo

@cawo-odoo cawo-odoo commented Sep 12, 2025

Copy link
Copy Markdown
Contributor

[IMP] orm: add optional parallelism to iter_browse.attr()

In some cases, e.g. if it is known that calling a certain method on the model will only trigger inserts or it is clear that updates will be disjunct, such method calls can be done in parallel.

[IMP] orm: add optional parallelism to iter_browse.create()

Like the same support added to __attr__ in the parent commit, this can only be used by callers when it is known that database modifications will be distinct, not causing concurrency issues or side-effects on the results.

@robodoo

robodoo commented Sep 12, 2025

Copy link
Copy Markdown
Contributor

Pull request status dashboard

@KangOl

KangOl commented Sep 12, 2025

Copy link
Copy Markdown
Contributor

upgradeci retry with always only base in all versions

Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch from 866b0fe to c484df4 Compare September 12, 2025 12:47
Comment thread src/util/orm.py
@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch from c484df4 to efa83ee Compare September 12, 2025 14:06

@aj-fuentes aj-fuentes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To simplify the code I think we should check UPG_PARALLEL_ITER_BROWSE only once.

Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated

@aj-fuentes aj-fuentes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proposal: get rid of the hack injecting params.

Code is simpler, easier to read, and less hacky.

Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
@cawo-odoo

cawo-odoo commented Sep 15, 2025

Copy link
Copy Markdown
Contributor Author

Proposal: get rid of the hack injecting params.

Code is simpler, easier to read, and less hacky.

It is true that it looks that way, but there's one big disadvantage: it reduces the possible use-cases, because now everything in there (including {kw,}args) needs to be 🥒able.

Comment thread src/util/orm.py Outdated
@aj-fuentes

Copy link
Copy Markdown
Contributor

Proposal: get rid of the hack injecting params.
Code is simpler, easier to read, and less hacky.

It is true that it looks that way, but there's one big disadvantage: it reduces the possible use-cases, because now everything in there (including {kw,}args) needs to be 🥒able.

Do you have a use case where we need to pass more complex objects? I think once we have it we can make this hacky.

Comment thread src/util/orm.py Outdated
@cawo-odoo

cawo-odoo commented Sep 15, 2025

Copy link
Copy Markdown
Contributor Author

Do you have a use case where we need to pass more complex objects? I think once we have it we can make this hacky.

Honestly, I find it more hacky to pass around all the constant parameters through IPC for each task than to store them away once before fork. I think since we're in an importable script and do not need to rename the module like in upgrade scripts, we don't have to use the attribute on the function object, if that's what is ugly. I guess, we could also just use a global here (but i would need to try it first to be sure).

@aj-fuentes

aj-fuentes commented Sep 15, 2025

Copy link
Copy Markdown
Contributor

Do you have a use case where we need to pass more complex objects? I think once we have it we can make this hacky.

Honestly, I find it more hacky to pass around all the constant parameters through IPC for each task than to store them away once before fork. I think since we're in an importable script and do not need to rename the module like in upgrade scripts, we don't have to use the attribute on the function object, if that's what is ugly. I guess, we could also just use a global here (but i would need to try it first to be sure).

You are missing the point. In your analysis, which isn't wrong, you're tying the code to the internal implementation of the standard Python library. That's hacky (not to mention attaching values to functions). The interface of map allows to pass any extra parameters we need. That's the logical solution. There is zero need of extra "what's going on here", or "are we cleaning this up after?". OTOH in current implementation, we need to know and explain that it uses pickle, that we don't want to use it, that it is better because this and that... etc, to make the hacky implementation look like it is necessary. That's my point.

I take that perhaps you meant "less performant" instead of "more hacky", that I could agree. Yet the performance improvement is probably meaningless given the time the rest would take.

EDIT:
To be clear: I'm OK with current implementation. It can be r+ed once all details are tested.

I just don't like hacky stuff if there is a clearer way to express something. I agree that sometimes we need to sacrifice "clarity" for the sake of higher goals. I don't see them here.

@cawo-odoo

Copy link
Copy Markdown
Contributor Author

you're tying the code to the internal implementation of the standard Python library.

What do you mean? The fact that it forks? This whole thing is tied to that, as are all of our other uses of ProcessPoolExecutor, that's why #320 (comment) is important.

I also wanted simplicity: in the callback signature, to avoid as many serialisation issues as we can. OTOH, your suggestion is more readable and easier to understand. I think both are valid goals and they are only in conflict here, because ProcessPoolExecutor.map (not map) is not a simple interface, it just pretends to be. I made this point on the last PR already and it didn't change, there are all kinds of quirks in this thing.

Anyway. It is true that input to this code - if used - has to be chosen very carefully for all kinds of reasons. So maybe it is a good idea to restrict, in this way, the arguments that can be passed to the model attr being called, for the purpose of limiting the use-cases to simpler ones that hopefully have a lower risk of dangerous use.

@aj-fuentes

Copy link
Copy Markdown
Contributor

What do you mean? The fact that it forks?

No, the fact that map would use pickle to send the parameters.

Once more, I'm OK with this. You could probably include some comments about why you chose to do this. I'd say something like: "we want to avoid the overhead of serializing the same parameters for all ids via pickle in the map implementation. Warning: we need to clean them up in _end to avoid any potential conflicts".

Note that we need to keep in mind --some testing would be nice-- what happens for multiple calls to iter_browse with multiprocessing within the same run (upgrade step). I don't see anything problematic at the moment.

it just pretends to be

Yes. We should honor that --if we can--, that's the point.

@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch 10 times, most recently from d16c3f9 to 37353dc Compare September 26, 2025 13:25
Comment thread src/util/orm.py Outdated
@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch from 37353dc to ef79dc6 Compare September 29, 2025 07:58
@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch 4 times, most recently from c592fe8 to 7a16d08 Compare October 1, 2025 14:32
@cawo-odoo cawo-odoo marked this pull request as ready for review October 1, 2025 14:46
@cawo-odoo cawo-odoo requested review from a team and asno-odoo October 1, 2025 14:46
@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch 5 times, most recently from d1b8479 to 060b1a3 Compare October 8, 2025 11:55
Comment thread src/util/orm.py Outdated
Comment thread src/util/orm.py Outdated
@KangOl

KangOl commented Oct 24, 2025

Copy link
Copy Markdown
Contributor

In order to move on with this PR, let split it. Can you please extract the "generator and query" commits into a new PR?

@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch from 060b1a3 to edbcdb4 Compare October 24, 2025 12:48
@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch from edbcdb4 to 3f9db41 Compare November 10, 2025 13:23
@cawo-odoo

Copy link
Copy Markdown
Contributor Author

In order to move on with this PR, let split it. Can you please extract the "generator and query" commits into a new PR?

created #350 with those two commits

@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch from 3f9db41 to 94f0b0b Compare November 10, 2025 13:44
@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch 6 times, most recently from 45fb569 to be694ff Compare December 1, 2025 11:56
@cawo-odoo cawo-odoo force-pushed the master-imp_parallel_iter_browse-cawo branch 2 times, most recently from 2b18909 to 946c3a8 Compare December 5, 2025 07:14
@cawo-odoo

Copy link
Copy Markdown
Contributor Author

added fixups to get rid of the scattered _superchunk_size logic and replaced it with local "batching" logic around executor.map calls. I'll fix py2 compat when #350 has finally been merged.

In some cases, e.g. if it is known that calling a certain method on the model
will only trigger inserts or it is clear that updates will be disjunct, such
method calls can be done in parallel.
Like the same support added to `__attr__` in the parent commit, this can only
be used by callers when it is known that database modifications will be
distinct, not causing concurrency issues or side-effects on the results.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants