Skip to content

JVM wheel: the read path crosses into the JVM more often than it needs to (get_raw, one, count, lookup_by_key, transaction mark) #213

Closed

Description

@tae898

On the JVM wheel (arcadedb-jvm), a warm point read spends only 46.3% of the calling thread's CPU in the engine. An untimed async-profiler pass (CPU samples of the Python-driven thread, main wheel, warm point reads) put the rest in Java glue (5.4%), JNI and libjvm (10.7%), JPype C++ (5.2%) and CPython (28.7%). In a mixed window (3 reader threads and 1 writer) the engine share is 45.5%, with lock and futex frames at 17.7%, because JPype releases and takes the GIL on every crossing. So 53.7% of a point read is not the engine, and part of it is the number of calls into the JVM per Python call.

Five common calls still cross more than they need to on main:

  • Document.get_raw() (so get(), Vertex.get(), Edge.get()) does has() then get(): 2 crossings and 2 scans of the record. get() already answers null for an absent property.
  • ResultSet.one() iterates: hasNext()/next() per row plus the close, 4 crossings for a single row. first() already does this in one crossing through RowAccess.firstAndClose.
  • ResultSet.count() crosses twice per row.
  • Database.lookup_by_key() is one crossing but builds a String[] and an Object[] through JPype first.
  • The transaction-stack mark taken before every begin() asks isTransactionActive() and getNestedTransactions() separately: with db.transaction() is 4 crossings and run_in_transaction() is 6.

This was first written as humemai/arcadedb-embedded-python#524 (closed unmerged when the bindings moved here, never measured with a timed run). The fix is a port of it onto main, one commit per cut, with tests that count the crossings and pin that the answers, errors and result-set state equal the plain path's. The native backend is not touched.

What is measured so far is the cost share above (untimed) and crossing counts; there is no timing of the change yet. A timed ABBA A/B of the main wheel against the PR's wheel (point reads, one(), Document.get, small transactions, a 4-thread mixed window, with an A/A control and a rule written before the first timed run) is prepared, and the PR should not merge on the counts alone.

Activity

  1. added this to the 26.11.1 milestone on Nov 5, 2026
  2. added
    concurrencyThreads, transactions and conflicts
    jvmThe arcadedb-jvm package (JPype build)
    performanceSpeed or memory of the bindings, with a measurement
    on Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    concurrencyThreads, transactions and conflictsjvmThe arcadedb-jvm package (JPype build)performanceSpeed or memory of the bindings, with a measurement

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions