Skip to content

Split MEOS initialisation in MEOSBridge into process-once and per-thread - #24

Merged
estebanzimanyi merged 1 commit into
MobilityDB:mainfrom
estebanzimanyi:fix/meosbridge-layered-init
Jul 23, 2026
Merged

Split MEOS initialisation in MEOSBridge into process-once and per-thread#24
estebanzimanyi merged 1 commit into
MobilityDB:mainfrom
estebanzimanyi:fix/meosbridge-layered-init

Conversation

@estebanzimanyi

Copy link
Copy Markdown
Member

MEOSBridge initialises MEOS on each stream thread by installing a no-exit error handler and then calling the full meos_initialize(). Two problems follow:

  1. The handler is defeated by ordering. meos_initialize() re-installs MEOS's exiting default handler, so calling it after the no-exit handler discards the no-exit handler — every thread ends with the exiting default, and any MEOS error ends the JVM with exit(EXIT_FAILURE).
  2. The per-thread reset race. The error handler is process-global, so running full meos_initialize() per thread means one thread's initialisation replaces the handler every other thread relies on.

MEOS setup has two lifetimes:

  • process-global — the allocator and the error handler;
  • thread-local — the timezone and collation caches; the PROJ, GEOS and GSL contexts are thread-local too and are created lazily by MEOS on first use.

This change installs the process-global part once per JVM through a holder whose class initialiser runs under the JVM class-initialisation lock — meos_initialize() first, then the no-exit handler, so the no-exit handler stands — and runs only meos_initialize_timezone + meos_initialize_collation per thread. PROJ/GEOS/GSL still initialise lazily per thread, so the spatial predicates are unaffected.

This mirrors the same fix in MobilitySpark (MeosThread).

MEOSBridge initialised MEOS on each stream thread by installing a no-exit
error handler and then calling the full meos_initialize(). That order also
defeats the handler: meos_initialize() re-installs MEOS's exiting default
handler, so the no-exit handler never takes effect and any MEOS error ends
the JVM with exit(EXIT_FAILURE). Running meos_initialize() per thread is
unsafe regardless, because the handler is process-global — one thread's
initialisation replaces the handler every other thread relies on.

MEOS setup has two lifetimes: the allocator and error handler are
process-global, while the timezone and collation caches are thread-local
(the PROJ, GEOS and GSL contexts are thread-local too and created lazily on
first use). Install the process-global part once per JVM through a holder
whose class initialiser runs under the JVM class-initialisation lock —
meos_initialize() first, then the no-exit handler — and run only
meos_initialize_timezone and meos_initialize_collation per thread. The
no-exit handler now stands, and no thread re-installs it.
@estebanzimanyi
estebanzimanyi merged commit 269edd0 into MobilityDB:main Jul 23, 2026
1 check passed
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.

1 participant