Are those optimizations for all ObjectContexts, not just the app-scoped
single context used by many threads that you mentioned?

On Mon, Oct 12, 2026 at 7:15 PM Andrus Adamchik <[email protected]> wrote:

> And there are more select optimizations. All the CPU time savings below
> are "the Cayenne part of a select query" :
>
> * https://issues.apache.org/jira/browse/CAY-3049 Faster, lower-overhead
> LRU snapshot cache. Saves 40-60% CPU time on plain selects, 20-45% with
> prefetches.
> * https://issues.apache.org/jira/browse/CAY-3050 [STILL IN PROGRESS, but
> almost ready] Faster. Saves 30-40% CPU time on plain selects, 20-40% with
> prefetches. 25-30% less memory allocation.
> * https://issues.apache.org/jira/browse/CAY-3051 somewhat lower memory
> allocation overhead
>
> The numbers almost look too good to be true :) But good data structures go
> a long way. I will be checking this in a real application soon, and would
> love an independent confirmation once CAY-3050 makes it in.
>
> Andrus
>
> > On Oct 11, 2026, at 6:34 PM, Andrus Adamchik <[email protected]>
> wrote:
> >
> > Hi,
> >
> > Just pushed a couple of big improvements to DataContext read
> concurrency. Related jiras: CAY-3044, CAY-3045, CAY-3046, CAY-3047,
> CAY-3048.
> >
> > Consider a single DataContext used by many threads in parallel for
> selecting objects. I have a number of very active read-only apps, and an
> app-scoped DataContext has always been the default pattern, especially
> valuable with local cache. It works great until concurrency increases
> causing every single select to queue up on ObjectStore waiting to load its
> rows into the context.
> >
> > So there was a de-facto hard cap on context throughput. Previously, I
> solved this via context pooling. This is ugly and luckily is no longer
> needed in this release. In my benchmarks, throughput improved 2x. This
> number will vary depending on the connection pool, CPU, DB speed of course.
> But lock contention is gone and the new usage advice is:
> >
> > 1. If you DON'T use local cache, then a new DataContext per thread (=
> per request) is the most performant option.
> > 2. If you DO use local cache (or want to keep such option open for the
> future; or don't want to deal with per-request scope), use a shared
> DataContext and don't worry about locking. This option is slightly (~5%)
> slower than a per-thread context, but this is negligible.
> >
> > Before the release, I would appreciate if someone could try it out and
> report any issues. The changes touch on the object / snapshot consistency
> model. So if you see anything weird, like older versions of objects
> appearing after newer ones, please report. (To be clear, I don't expect
> this to happen :))
> >
> >
> > ---
> >
> > Finally, some high-level technical details. You can stop reading here :)
> >
> > * Instead of broad per-select lock to load objects, the locking is done
> per object, using private "striped" locks. I was surprised using
> "synchronized" in a loop (on different monitors) is not slow. But
> apparently it is fast with modern Java.
> > * ObjectContext / ObjectStore object lookups are not synchronized anymore
> > * Eventual consistency of object states is ensured by per-object locks
> and incrementing snapshot versions. We had snap versions before, but now
> they are faster, smarter and actually help.
> > * Merge strategy fix to avoid excessive to-one faulting post-query. I
> was occasionally confused seeing objects fetched one-by-one right after
> they were fetched by another query prefetch. Thought this was due to weak
> references. Nope, just faulty merge logic + concurrency.
> > * Per-statement snapshot versions (instead of per-object)
> > * Safer fault checking to avoid a specific race condition causing
> ClassCastExceptions under load
> >
> >
> > Andrus
>
>

Reply via email to