Skip to content
Merged
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
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ with arcadedb.create_database("./mydb") as db:

## ✨ Features

- ☕ **No Java Installation Required**: Bundled JRE (~63 MiB uncompressed)
- ☕ **No Java Installation Required**: Bundled JRE (~44 MiB uncompressed)
- 🌍 **4 Platforms Supported**: Linux (x86_64, ARM64), macOS (ARM64), Windows (x86_64)
- 🚀 **Embedded Mode**: Direct database access in Python process (no network)
- 🌐 **Server Mode**: Optional in-process HTTP server with the Studio web UI: it costs ~8MB of wheel and nothing at runtime until you call `create_server()`
- 📦 **Self-contained**: All dependencies bundled (~69 MiB current Linux wheel)
- 📦 **Self-contained**: All dependencies bundled (~64 MiB current Linux wheel)
- 🔄 **Multi-model**: Graph, Document, Key/Value, Vector, Time Series
- 🔍 **Multiple query languages**: SQL and OpenCypher
- ⚡ **High performance**: Direct JVM integration via JPype
Expand All @@ -74,12 +74,12 @@ with arcadedb.create_database("./mydb") as db:

The `arcadedb-embedded` package is platform-specific and self-contained:

**Package Contents (the 26.10.1 Linux x86_64 wheel; varies by platform and version):**
**Package Contents (the 26.11.1.dev0 Linux x86_64 wheel; varies by platform and version):**

- **Wheel size (compressed)**: ~69 MiB
- **ArcadeDB JARs (uncompressed)**: ~34 MiB across 64 JARs
- **Bundled JRE (uncompressed)**: ~63 MiB (platform-specific Java 25 runtime via jlink)
- **Installed package size**: ~97 MiB
- **Wheel size (compressed)**: ~64 MiB
- **ArcadeDB JARs (uncompressed)**: ~42 MiB across 72 JARs
- **Bundled JRE (uncompressed)**: ~44 MiB (platform-specific Java 25 runtime via jlink)
- **Installed package size**: ~86 MiB

The compressed wheel size is measured from `dist/*.whl`, and the installed package size
is measured from the extracted `site-packages/arcadedb_embedded/` directory.
Expand Down
22 changes: 18 additions & 4 deletions scripts/Dockerfile.build
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ RUN if [ "$USE_LOCAL_JARS" = "1" ]; then \

# Copy JAR exclusion list
COPY scripts/jar_exclusions.txt /build/jar_exclusions.txt
# JDK modules the bundled JRE must not contain (see the file for why)
COPY scripts/jre_module_exclusions.txt /build/jre_module_exclusions.txt

# Remove excluded JARs based on jar_exclusions.txt
RUN echo "🗑️ Removing excluded JARs..." && \
Expand Down Expand Up @@ -107,11 +109,14 @@ RUN echo "🔍 Analyzing JARs with jdeps..." && \
else \
FILTERED_MODULES="${DETECTED_MODULES}" ; \
fi && \
if [ -n "${FILTERED_MODULES}" ]; then \
REQUIRED_MODULES="${FILTERED_MODULES},jdk.management,jdk.zipfs,jdk.unsupported,jdk.incubator.vector" ; \
else \
REQUIRED_MODULES="java.se,jdk.management,jdk.zipfs,jdk.unsupported,jdk.incubator.vector" ; \
grep -v '^#' /build/jre_module_exclusions.txt | tr -d '\r' | sed '/^[[:space:]]*$/d' > /build/jre_excluded_modules.list && \
echo "📦 Excluded modules: $(paste -sd ',' /build/jre_excluded_modules.list)" && \
FILTERED_MODULES=$(echo "${FILTERED_MODULES}" | tr ',' '\n' | sed '/^$/d' | grep -vxFf /build/jre_excluded_modules.list | paste -sd "," -) && \
if [ -z "${FILTERED_MODULES}" ]; then \
echo "❌ jdeps found no modules; the java.se fallback would bring back the excluded modules, so the build stops" && \
exit 1 ; \
fi && \
REQUIRED_MODULES="${FILTERED_MODULES},jdk.management,jdk.zipfs,jdk.unsupported,jdk.incubator.vector" && \
echo "🔨 Building minimal JRE for platform: ${TARGET_PLATFORM}" && \
echo "📦 Detected modules (raw): ${DETECTED_MODULES}" && \
echo "📦 Detected modules (filtered): ${FILTERED_MODULES}" && \
Expand All @@ -135,6 +140,15 @@ RUN echo "🔍 Analyzing JARs with jdeps..." && \
fi ; \
echo "" ; \
echo "✅ JRE build complete!" ; \
echo "📊 JRE size after jlink: $(du -sm /build/jre | cut -f1) MB" ; \
BAD_MODULES=$(/build/jre/bin/java --list-modules | sed 's/@.*//' | grep -xFf /build/jre_excluded_modules.list || true) ; \
if [ -n "$BAD_MODULES" ]; then \
echo "❌ the JRE contains excluded modules (another module requires them): $BAD_MODULES" ; \
exit 1 ; \
fi ; \
echo "✅ No excluded module in the JRE" ; \
find /build/jre -name '*.so' -type f -exec strip --strip-unneeded {} + ; \
echo "📊 JRE size after stripping native libraries: $(du -sm /build/jre | cut -f1) MB" ; \
else \
echo "⚠️ jmods directory not found under ${JAVA_HOME}. Falling back to copying full JDK runtime." ; \
mkdir -p /build/jre ; \
Expand Down
31 changes: 25 additions & 6 deletions scripts/build-native.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PY_BINDINGS_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
DIST_DIR="$PY_BINDINGS_DIR/dist"
JAR_EXCLUSIONS_FILE="$SCRIPT_DIR/jar_exclusions.txt"
JRE_MODULE_EXCLUSIONS_FILE="$SCRIPT_DIR/jre_module_exclusions.txt"

# Parameters
PLATFORM="${1:-}"
Expand Down Expand Up @@ -238,13 +239,23 @@ fi
# jdk.incubator.vector: Required for vectorized execution paths
# NOTE: the java.se umbrella used to be force-added as a safety net; with the
# package embedded-only and jdeps detection fixed, the detected set gates the
# JRE (full suite + examples verify each build). java.se remains the fallback
# when detection yields nothing.
if [ -n "$FILTERED_MODULES" ]; then
REQUIRED_MODULES="${FILTERED_MODULES},jdk.management,jdk.zipfs,jdk.unsupported,jdk.incubator.vector"
else
REQUIRED_MODULES="java.se,jdk.management,jdk.zipfs,jdk.unsupported,jdk.incubator.vector"
# JRE (full suite + examples verify each build). Detection that yields nothing
# stops the build: the java.se umbrella would bring back the excluded modules.
# JDK modules the bundled JRE must not contain (jre_module_exclusions.txt says why).
# Removed from the detected set here, and checked in the finished JRE below.
if [[ ! -f "$JRE_MODULE_EXCLUSIONS_FILE" ]]; then
echo -e "${RED}❌ JRE module exclusion file not found: ${JRE_MODULE_EXCLUSIONS_FILE}${NC}"
exit 1
fi
EXCLUDED_MODULES_LIST="$(mktemp)"
grep -v '^#' "$JRE_MODULE_EXCLUSIONS_FILE" | tr -d '\r' | sed '/^[[:space:]]*$/d' > "$EXCLUDED_MODULES_LIST"
echo -e "${CYAN}📦 Excluded modules: ${YELLOW}$(paste -sd ',' "$EXCLUDED_MODULES_LIST")${NC}"
FILTERED_MODULES=$(echo "$FILTERED_MODULES" | tr ',' '\n' | sed '/^$/d' | { grep -vxFf "$EXCLUDED_MODULES_LIST" || true; } | paste -sd "," -)
if [ -z "$FILTERED_MODULES" ]; then
echo -e "${RED}❌ jdeps found no modules; the java.se fallback would bring back the excluded modules, so the build stops${NC}"
exit 1
fi
REQUIRED_MODULES="${FILTERED_MODULES},jdk.management,jdk.zipfs,jdk.unsupported,jdk.incubator.vector"

echo -e "${CYAN}📦 Detected modules (raw): ${YELLOW}${DETECTED_MODULES}${NC}"
echo -e "${CYAN}📦 Detected modules (filtered): ${YELLOW}${FILTERED_MODULES}${NC}"
Expand All @@ -262,6 +273,14 @@ jlink \
--output "$PY_BINDINGS_DIR/temp_jre"

echo -e "${GREEN}✅ JRE built${NC}"
# A module that another module requires comes back through jlink's own resolution.
BAD_MODULES=$("$PY_BINDINGS_DIR/temp_jre/bin/java" --list-modules | tr -d '\r' | sed 's/@.*//' | { grep -xFf "$EXCLUDED_MODULES_LIST" || true; })
rm -f "$EXCLUDED_MODULES_LIST"
if [ -n "$BAD_MODULES" ]; then
echo -e "${RED}❌ the JRE contains excluded modules (another module requires them): ${BAD_MODULES}${NC}"
exit 1
fi
echo -e "${GREEN}✅ No excluded module in the JRE${NC}"
JRE_SIZE=$(du -sh "$PY_BINDINGS_DIR/temp_jre" | cut -f1)
echo -e "${CYAN}📊 JRE size: ${YELLOW}${JRE_SIZE}${NC}"

Expand Down
15 changes: 10 additions & 5 deletions scripts/jar_exclusions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ regex-*.jar
arcadedb-ha-raft-*.jar
arcadedb-metrics-*.jar
arcadedb-mongodbw-*.jar
# Embedded-unused (verified 2026-07-05 by quarantine + full suite/examples gate;
# micrometer must STAY - server startup requires it):
commons-math3-*.jar
jackson-*.jar
snappy-java-*.jar
# Verified 2026-07-05 by quarantine + full suite/examples gate; micrometer must STAY
# (server startup requires it):
arcadedb-tracing-*.jar
jline-*.jar
#
# NOT excluded, on purpose: that gate ran the embedded suite only, and these are
# reached in server mode (tests/test_jar_closure.py finds this class of mistake):
# jackson-*.jar swagger-core builds GET /api/v1/openapi.json with core,
# annotations, databind, dataformat-yaml and datatype-jsr310
# snappy-java-*.jar CompressedBodyDecoder and the Prometheus remote read and
# write routes
# commons-math3-*.jar jvector's ScoreTracker$TwoPhaseTracker
24 changes: 24 additions & 0 deletions scripts/jre_module_exclusions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# JDK modules the bundled jlink runtime must NOT contain, one per line.
#
# The module list of the runtime comes from `jdeps --print-module-deps` over the
# shipped jars. jdeps names a module as soon as one class in one jar refers to it,
# so optional users pull in big modules that no code path of the wheel reaches.
# Both build scripts (Dockerfile.build for Linux, build-native.sh for macOS and
# Windows) remove the modules below from that list, and after jlink they fail the
# build when one of them is still in `java --list-modules` (a module that another
# module requires comes back that way). Removing java.desktop also removes
# java.datatransfer and java.prefs, which only it requires.
#
# tests/test_jar_closure.py reads the class files of the shipped jars and fails
# when a class refers to a package of a JDK module that the runtime lacks, unless
# that reference is listed there with a reason. Adding a module here means adding
# the references of the jars it breaks to that list, or keeping the module.
#
# java.desktop: java.beans in Jackson (Java7SupportImpl), snakeyaml, commons-lang3,
# Micrometer Log4j2Metrics; java.awt in JTS (org.locationtech.jts.awt) and
# commons-math3; java.awt.datatransfer in jakarta.activation. About 12 MB of the wheel.
# jdk.jfr: only com.arcadedb.utility.JVMGCHistogramReporter, which nothing calls.
# java.compiler: only org.agrona.generation (agrona's code generator), which nothing calls.
java.desktop
jdk.jfr
java.compiler
Loading
Loading