Hi all,
I have a web content structure and a template. I have about 200 articles already using this structure. I need to edit this structure to turn off a fields required settings. When I save the changes to the structure liferay becomes unresponsive. I have asked AI to summarise the findings.
Liferay DXP 2026.Q2 — Saving DDM Structure causes portal-wide freeze when structure has 100+ dependent articles
Environment:
- Liferay DXP 2026.q2.0, Docker deployment
- PostgreSQL (native, not containerized)
- Elasticsearch 8.19.18 (native)
- Java 21 (Zulu), G1GC, 12GB heap
- Upgraded from 2026.Q1.5-LTS
Symptom: Editing a Web Content Structure and clicking Save causes the entire portal to become unresponsive — not just for the editing session, but for all users. No errors are thrown in docker logs, no exceptions in the browser console. This structure has 100+ Web Content articles associated with it.
Diagnosis so far:
-
Thread dump during the freeze shows 6+ worker threads (
default-N)BLOCKED (on object monitor), all waiting on the same lock — aConcurrentHashMapinsideCounterFinderImpl.getCounterRegister. All are in this call chain:DDMStructureModelListener.onAfterUpdate → DDMFieldLocalServiceImpl.updateDDMFormValues → CounterLocalServiceImpl.increment → CounterFinderImpl.getCounterRegister [BLOCKED] -
The lock-holding thread is itself inside
CounterFinderImpl._obtainIncrement, executing a Hibernate query — while holding the global counter lock. -
pg_stat_activityduring the freeze shows all related sessions asidle in transaction/ wait_eventClientRead— meaning Postgres already returned results and is waiting on the application, not the other way around. No entries inpg_locksshow unblocked/waiting locks — ruling out a genuine DB-level deadlock. -
Counter batching itself appears correctly configured (
counter.increment=2000), and counters likeDDMField/DDMFieldAttributeshow healthy incrementing values in theCountertable — so this doesn’t look like a batching misconfiguration. -
Connection pool (
jdbc/LiferayPool, Tomcat JNDI resource) is generous (maxActive=100), so pool exhaustion seems unlikely to be the root trigger, though it may compound the impact.
Working theory: CounterFinderImpl’s counter-increment lock is global (not scoped per counter name), so when onAfterUpdate cascades through 100+ articles — each needing sequential ID allocations across multiple counters (DDMFormValues, DDMFormFieldValue, etc.) — all this work serializes through one lock. Combined with whatever else on the portal also needs new IDs at the same moment, this could produce a much longer real-world stall than expected, though 5+ minutes for ~100 articles still seems disproportionate.
Question for the community:
- Is this a known scaling characteristic of
DDMStructureModelListener.onAfterUpdate/CounterFinderImpllocking when a structure has a large number of dependent articles? - Has anyone seen this specific freeze pattern after upgrading to 2026.Q2, or is this likely unrelated to the version and just a data-volume issue we hadn’t hit before?
- Is there a supported way to defer/background this cascade (e.g., process structure-dependent reindexing asynchronously) rather than having it run synchronously in the save request thread?
Thanks for the swift reply. Lets see if I can get it working for.
– Mark_Clarke