Thanks, this makes the warm-cache benefit clear.

Still, 23 SELECTs for a cold resolve of a simple N1/N2/T2 path seems like a
high baseline. Is that expected to remain the normal cold-path shape, or can
the needed hierarchy, grants, and versions be obtained in a bounded number
of
backend operations?

I agree that a multi-pod deployment needs a version/conflict fence. For a
mutation, though, could that normally be the final conditional write, e.g.
UPDATE ... WHERE version = ?, rather than a separate version query on every
cache hit? A zero-row update would identify the conflict, and only that case
would need a reload.

The remaining question is the scope of that fence. A table operation can
depend
on inherited namespace/catalog facts, including effective storage
configuration,
locations, and allowed locations. If one of those changes after resolution,
how
is that detected before credential vending or commit? Checking only the
table
version would not cover an ancestor change.

Could we define that current-state/commit boundary first, and then measure
cold,
warm, and high-churn behavior against it? The 64 KiB property example seems
like a related but separate reason to keep common resolution paths bounded.

On Fri, Sep 4, 2026 at 6:56 PM Yufei Gu <[email protected]> wrote:

> +1 to Prithvi’s analysis. The version check is necessary to ensure
> consistency in a multi-pod Polaris deployment, since an individual pod
> cannot see entity updates made by its peers.
>
> Yufei
>
>
> On Fri, Sep 4, 2026 at 9:46 AM Prithvi S <[email protected]>
> wrote:
>
> > Hi Dmitri,
> >
> > Thanks for raising this.
> >
> > You are right that even on a cache hit, resolve still talks to JDBC. That
> > is by design: InMemoryEntityCache is not a "skip the database" cache. For
> > JDBC it is a "skip the expensive load" cache, with a version check as the
> > invalidation path.
> > I traced Resolver.resolveAll() with JDBC and compared a warmed
> > InMemoryEntityCache against cache == null on the same catalog. The
> workload
> > was a loadTable-like resolve (principal P1 with PRINCIPAL_ROLE:ALL,
> catalog
> > "test", path N1/N2/T2).
> >
> > On a warm cache, that resolve issued 1 SELECT:
> >
> > SELECT id, catalog_id, entity_version, grant_records_version
> > FROM ENTITIES
> > WHERE (catalog_id, id) IN ((?, ?), ... ) AND realm_id = ?
> >
> > Without the cache, the same resolve issued 23 SELECTs: 9 full entity rows
> > (including properties / internal_properties) and 14 grant-record lookups.
> > Scenario Cache SELECTs Payload
> > N1/N2/T2 (small properties) no-cache 23 947 B
> > N1/N2/T2 cold-cache 23 947 B
> > N1/N2/T2 warm-cache 1 144 B
> > N1/N2/T1 (64KiB properties) no-cache 23 66 KB
> > N1/N2/T1 warm-cache 1 144 B
> > deep path (6 segments) no-cache 29 959 B
> > deep path (6 segments) warm-cache 1 192 B
> >
> > So the version check is real, but it replaces the full entity JSON and
> the
> > grant-record queries. Cold cache looks the same as no cache; the gain is
> on
> > subsequent resolves of the same entities.
> >
> > I have not measured a full REST request or a stale-cache / high-churn
> path,
> > so I do not want to claim an end-to-end speedup from this :)
> > For the resolve path itself, the query shape is clear.
> >
> > WDYT?
> >
> > Thanks,
> > Prithvi
> >
> > On Fri, Sep 4, 2026 at 6:50 AM Dmitri Bourlatchkov <[email protected]>
> > wrote:
> >
> > > Hi All,
> > >
> > > InMemoryEntityCache is currently used in Apache Polaris with JDBC
> > > Persistence.
> > >
> > > However, as far as I can tell, even for cached entities, the resolve
> will
> > > still issue a JDBC query to confirm that the latest version was
> returned
> > > from the cache.
> > >
> > > So, the question is: does this cache provide any considerable
> efficiency
> > > gain?
> > >
> > > Has anyone measured the performance difference with and without this
> > cache?
> > >
> > > Would anyone be willing to carry out such a test?
> > >
> > > WDYT?
> > >
> > > Thanks,
> > > Dmitri.
> > >
> >
>

Reply via email to