Skip to content

Encoding: native handle where it is born, value where it is cheapest#485

Merged
milyin merged 3 commits into
zenoh-flat-transitionfrom
encoding-cached-handle
Jul 16, 2026
Merged

Encoding: native handle where it is born, value where it is cheapest#485
milyin merged 3 commits into
zenoh-flat-transitionfrom
encoding-cached-handle

Conversation

@milyin

@milyin milyin commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What

Implements the encoding crossing-minimization model on top of ZettaScaleLabs/zenoh-flat-jni#5. The save-and-republish scenario (receive a sample with a custom encoding, keep the Encoding, pass it to session.put) no longer rebuilds the native encoding from its schema string on any send.

The ownership model:

  • Predefined constants stay value-only (id, schema=null): a send carries just the id inside the send call itself — no native handle ever exists for them, no extra crossing.
  • Custom (schema-carrying) encodings create their native handle at construction (Encoding.from("…;schema"), withSchema) — the one natural crossing — and every send after passes a bare jlong (the native side borrows and clones, so the handle is reusable forever).
  • Received encodings (sample/query/reply) arrive send-ready: the delivery decomposition includes the owned handle in the same single crossing.

Encoding stays a plain non-closeable value — (id, schema) equality/rendering via EncodingCodec unchanged; handle release is GC-managed (EncodingCleaner, shared bindings tier).

How

  • Encoding gains an internal val handle: JniEncoding? seeded at construction (custom) or delivery (received); EncodingCleaner.register in init.
  • Send call sites (Session put/get/declarePublisher, Publisher.performPut, Query.reply/replyErr, Querier.get) drive the generated encoding selector block through internal Encoding?.jniSel/jniId/jniSchema/jniHandle extension helpers — one flat call, zero extra crossings for the absent/preset/handle cases alike.
  • FlatCallbacks + Sample.fromParts/Query.fromParts take the new handle leaf.

Tests

New EncodingHandleTest (4 tests): presets never grow a handle (even after being sent), custom encodings own one from construction, a received encoding is send-ready and re-sends by the same untouched handle, preset round-trip. Full suite: 110 jvmTest, 0 failures.

Sequencing

Requires ZettaScaleLabs/zenoh-flat-jni#5 (the local composite build already provides it; Maven consumers need the flat-jni release).

🤖 Generated with Claude Code

milyin and others added 2 commits July 16, 2026 18:06
Minimize JNI crossings for every encoding flow (consumes zenoh-flat-jni
PR #5):

- Predefined constants stay VALUE-ONLY: a send carries just their id
  inside the send call itself — no native handle ever exists for them,
  no extra crossing.
- Custom (schema-carrying) encodings create their native handle at
  construction — the one natural crossing — and every send after passes
  a bare jlong (borrowed and cloned natively, reusable forever).
- Received encodings (sample/query/reply) arrive send-ready: the
  delivery decomposition now includes the owned handle, so the
  save-and-republish scenario never rebuilds the native value from its
  schema string. Handle release is GC-managed (EncodingCleaner in the
  shared tier); Encoding stays a plain non-closeable value with
  unchanged (id, schema) equality/rendering.

Send call sites drive the generated encoding selector block through the
internal Encoding?.jniSel/jniId/jniSchema/jniHandle helpers — one flat
call, zero extra crossings in every case.

New EncodingHandleTest covers the ownership model end-to-end; 110 jvm
tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
zenoh-flat-jni's Encoding, Session, Publisher, Subscriber, Queryable,
Querier, Scout, LivelinessToken and Query handles are now gc_managed
(milyin/prebindgen#82): a shared Cleaner frees an unreachable handle
whose owner never released it, with explicit close/undeclare settling
the release ticket first.

Delete the 8 deprecated-for-removal finalize() nets (JEP 421) — the JNI
handle is its own backstop now — and drop Encoding's EncodingCleaner
registration (superseded by the gc_managed class; the hand-written
helper is deleted in zenoh-flat-jni).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@milyin

milyin commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Second commit (554368b): with the JNI tier now GC-managed (ZettaScaleLabs/zenoh-flat-jni#5 + milyin/prebindgen#82), the 8 deprecated-for-removal finalize() nets (JEP 421) are deleted — Session, Scout, LivelinessToken, Publisher, Subscriber, Querier, Query, Queryable — and Encoding drops its cleaner registration (the handle class cleans itself). Explicit close/undeclare stays the primary path. 110/110 jvmTest green.

The encoding selector wire shape and gc_managed lifecycles this branch
consumes landed in ZettaScaleLabs/zenoh-flat-jni#5 (e802317); the old
pin predates it, so CI compiled against the previous
(present, id, schema) encoding signatures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@milyin
milyin merged commit 6731c28 into zenoh-flat-transition Jul 16, 2026
13 checks 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