Visitar URL original
fix: serialise native handle lifetime against concurrent close by andygrove · Pull Request #115 · apache/datafusion-java · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
fix: serialise native handle lifetime against concurrent close
SessionContext and DataFrame each held a raw `long nativeHandle` guarded
by `if (nativeHandle == 0) throw`. The check and the JNI call were
separate operations, so a concurrent close() could free the native Box
between them and leave the other thread dereferencing freed memory.

Introduce a package-private NativeHandle that owns the pointer. Every
call pins the handle for its duration (acquire/release); close() and the
consuming operations claim it, waiting for in-flight calls to drain
before handing the pointer back to Rust to be freed.

acquire() never blocks, which is what lets the two-handle set operations
and joins pin both DataFrames without a lock-ordering hazard. A read/write
lock would not: its readers queue behind a waiting writer, so opposing pin
orders with closes interleaved could deadlock. claim() is the only
blocking operation and always makes progress, since a thread holding a pin
is inside a native call and never claims.

No native change is needed. Every non-consuming JNI entry point already
takes a shared reference, and DataFusion's SessionContext and DataFrame
are Send + Sync, so only the handle's lifetime had to be serialised.

Closes #40
  • Loading branch information
andygrove committed Aug 6, 2026
commit f19a1fbfa27800ca5fdff097282594eb42d9af6c
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ try (var allocator = new RootAllocator();
}
```

`SessionContext` and `DataFrame` are `AutoCloseable` and not thread-safe.
`SessionContext` and `DataFrame` are `AutoCloseable` and safe to share
across threads: `close()` waits for calls already in flight to return
before releasing the native object, and a call that loses the race to a
`close()` throws `IllegalStateException`.

## Documentation

Expand Down
Loading
Loading