Skip to content

The engine comes with the client - #6

Merged
tamnd merged 1 commit into
mainfrom
zudb-native
Aug 20, 2026
Merged

tamnd merged 1 commit into
mainfrom
zudb-native

Conversation

@tamnd

@tamnd tamnd commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Using this client meant installing a libzu by hand and telling the JVM where it went. One more dependency now does it. zudb-native carries a build for every platform this client supports, Library.find looks for one on the class path between the environment variable and the platform's own search, and the resource is copied to a temp file once per JVM because no loader on any platform can map a resource.

Eight artifacts come out of one module and one staged directory, so they cannot disagree about what is in them. The one with no classifier holds all seven platforms at about twenty megabytes, which is what a program developed on a laptop and deployed to a cluster wants, and the only one that survives being shaded into an uber-jar. The seven classified ones hold one platform each at about three, which is what a container image that knows what it runs on wants.

Alpine is a platform here rather than a smaller Linux, because a shared object built against glibc does not load on musl and the failure talks about an interpreter rather than about a database. Library.flavour picks between the two by looking for musl's own loader, which is the one path the ABI fixes rather than a distribution.

Two things a user actually meets go with it. On the module path nothing requires this artifact, since there is no code in it to require, so a jar sitting on the path is never resolved and its library is invisible: the search notices it is on a module path and names --add-modules dev.zudb.natives instead of leaving a user to work out why the same run on a class path worked. And the automatic module name derived from the file name would be zudb.native, which is not a legal module name because native is a keyword, so every jar carries Automatic-Module-Name in its manifest.

The search also carries the places it ruled out now, and Zu.source() says which of the four answered, because a path on its own does not explain why the wrong engine got loaded and a property somebody set three shells ago is exactly the thing that does.

scripts/stage-natives.sh fills lib/ from a release tag with gh, or from a directory that already holds the archives. It stays outside target/ so a clean does not throw away a download, and the module is behind -Pnatives so an ordinary build never needs it.

Nothing in the test suite could check the claim this makes, because the suite is told where the library is so that it tests the binding rather than the search. So CI checks it the way a user meets it, on Linux and macOS: a class path, no property, no environment variable, and a statement that has to answer. Locally that run prints found /var/folders/.../libzu.dylib through the zudb-native artifact, darwin-arm64 and then the engine came out of the jar and answered, on the class path and on the module path both.

Four tests in LibraryTest cover the parts that do not need an engine: that musl only ever appears on Linux, that unpacking a resource produces the same bytes in a fresh directory each time, that a platform with no artifact is a search that carries on rather than a failure, and that the ruled-out list is in the documented order and never contains the place that answered.

A Java client is Java and the engine is a shared library, so until now
using this meant installing a libzu by hand and telling the JVM where it
went. One more dependency now does it: zudb-native carries a build for
every platform this client supports, Library.find looks for one on the
class path, and a resource is copied to a temp file because no loader on
any platform can map a resource.

Eight artifacts come out of one module and one staged directory, so they
cannot disagree about what is in them. The one with no classifier holds
all seven platforms and is what a program developed on a laptop and
deployed to a cluster wants, and the only one that survives being shaded.
The seven classified ones hold one platform each, which is what a
container image that knows what it runs on wants.

Alpine is a platform rather than a smaller Linux: a shared object built
against glibc does not load on musl, and says so in a message about an
interpreter rather than about a database. Library.flavour picks between
the two by looking for musl's own loader, which is the one path the ABI
fixes rather than a distribution.

Two things a user meets go with it. On the module path nothing requires
this artifact, because there is no code in it to require, so a jar that
is on the path is never resolved and its library is invisible; the search
notices it is on a module path and names --add-modules dev.zudb.natives
rather than leaving a user to work out why a class path run worked. And
the derived automatic module name would be zudb.native, which is not a
legal module name because native is a keyword, so every jar carries
Automatic-Module-Name in its manifest.

The search now also carries the places it ruled out, and Zu.source says
which of the four answered, because a path on its own does not explain
why the wrong engine is loaded and a property somebody set three shells
ago is exactly the thing that explains it.

Nothing in the test suite could check the claim this makes, since the
suite is told where the library is so that it tests the binding rather
than the search. So CI checks it the way a user meets it, on Linux and
macOS: a class path, no property, no environment variable, and a
statement that has to answer.
@tamnd
tamnd merged commit 7407c75 into main Aug 20, 2026
11 checks passed
@tamnd
tamnd deleted the zudb-native branch August 20, 2026 02:35
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