XiaoHongbo-Hope opened a new pull request, #9267:
URL: https://github.com/apache/paimon/pull/9267
## What
Follow-up to #9250. The concurrent-import fix added a `threading.RLock`
around `importlib.import_module()` in three package `__init__`s (`pypaimon`,
`pypaimon.tag`, `pypaimon.globalindex`) to serialize lazy resolution. That lock
introduced a **new** deadlock path, flagged as P1 in the #9250 review.
## Why the lock deadlocks
Production code does top-level `from pypaimon import Schema` (e.g.
`pypaimon/multimodal/connection.py`). With the root RLock in place:
- Thread A holds the root RLock, then imports a leaf module → waits on that
leaf's module lock.
- Thread B holds the leaf module lock (importing the leaf directly), then
resolves a top-level export → waits on the root RLock.
Classic lock-ordering inversion → `_DeadlockError` / `partially initialized
module` on concurrent cold-start imports (new Ray workers, parallel split
deserialization). Probabilistic, so CI easily misses it.
## Fix
Remove all three custom locks. Once the eager-init cycles are broken,
Python's own per-module import locks make `import_module` thread-safe and
idempotent, and the `globals()` assignment is atomic — the extra lock was both
redundant and the source of the new deadlock.
Removing the locks alone re-surfaces deadlocks in two more packages whose
eager sibling imports were previously masked by the lock, so those are also
converted to lazy `__getattr__`:
- `pypaimon.data` — lazy `__getattr__` (was 3/200 without it)
- `pypaimon.common.options` — lazy `__getattr__`, plus break the
`core_options`/`options` self-cycles via direct module imports (the package is
imported by name from many modules its own eager exports pull in)
## Test
New regression `test_concurrent_leaf_imports_and_top_level_export` races
leaf imports (`DataFileMeta`, `SimpleStats`, `query_auth_split`,
`index_file_meta`, `table_delete`, `multimodal.connection`) against top-level
exports (`Schema`, `CatalogFactory`) across 8 fresh processes with a 1e-6
switch interval.
## Stress (8-way, 400 fresh processes)
| | failures |
|---|---|
| master (#9250, with root lock) | 115/400 |
| this PR | 0/400 |
Master failures deadlock on
`_ModuleLock('pypaimon.common.options.core_options')` — the exact cycle broken
by the `common.options` lazy conversion.
## Verification
- `concurrent_import_test` + schema/options suite: 76 passed
- flake8 (`dev/cfg.ini`): clean
- Broad suite: 3661 passed, 63 skipped. The 13 failed / 14 collection errors
are all missing optional deps (`lance`, `mosaic`, `ray`, `parameterized`,
`_datasketches`, zstd) — confirmed identical on master.
Draft until CI confirms.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]