Expand my Community achievements bar.

PersistenceException and InvalidItemStateException: OakState0001 exception in AEM 6.5.10

Avatar

Level 2

In my project, I have multiple event listeners, workflows, and Sling jobs that can modify the very same asset at the same time which sometimes causes commit conflicts. Obviously, different JCR sessions try to save different changes. I thought that refreshing the session before the actual .commit() call would help, but it didn't.

 

I need some explanation why the following code throws this exception

org.apache.sling.api.resource.PersistenceException: Unable to commit changes to session.

..

Caused by: javax.jcr.InvalidItemStateException: OakState0001: Unresolved conflicts in /content/dam...

 

 

ResourceResolver rr1 = ...get new service resource resolver
ResourceResolver rr2 = ...get new service resource resolver

Node node1 = rr1.getResource("/content/dam/.../asset.jpg/jcr:content/metadata").adaptTo(Node.class);
node1.setProperty("dc:title", "title 1");

Node node2 = rr2.getResource("/content/dam/.../asset.jpg/jcr:content/metadata").adaptTo(Node.class);
node2.setProperty("dc:title", "title 2");

rr1.commit();
rr2.refresh();
rr2.commit();

5 Replies

Avatar

Community Advisor

@dominik_lackovi If you are updating metadata on the same asset, you need not to take 2 separate resourceResolver, instead you can try as below - 

private static Map<String, Object> addAssetData(final Asset asset, final Hit hit, Map<String, Object> map)
throws RepositoryException {

String title = asset.getName();

if (StringUtils.isNotBlank(asset.getMetadataValue(DamConstants.DC_TITLE))) {
title = asset.getMetadataValue(DamConstants.DC_TITLE);
}

// Excerpt
String excerpt = hit.getExcerpt();
if (StringUtils.isBlank(hit.getExcerpt())) {
excerpt = StringUtils.stripToEmpty(asset.getMetadataValue(DamConstants.DC_DESCRIPTION));
if (excerpt.length() > MAX_EXCERPT_LENGTH) {
excerpt = StringUtils.substring(excerpt, 0, (MAX_EXCERPT_LENGTH - ELLIPSE_LENGTH)) + "...";
}
}

map.put(CF_PATH, asset.getPath());
map.put(CF_NAME, asset.getName());
map.put(CF_TITLE, title);
map.put(CF_EXCERPT, excerpt);
map.put(CF_MIMETYPE, asset.getMimeType());
map.put(CF_SIZE, getSize(asset));
map.put(CF_CACHE_KILLER, getCacheKiller(asset));
map.put(CF_TYPE, "Asset");
map.put(CF_LAST_MODIFIED, getLastModified(asset));

return map;
}

Ref _ 

acs-aem-commons/ContentFinderHitBuilder.java at master · Adobe-Consulting-Services/acs-aem-commons (...

Avatar

Level 4

This happens when two threads try to write at same JCR location.

The resource is modified by two concurrent sessions hence the conflict.

session.refresh(true) , should be used to avoid it.

Avatar

Level 2

If you check my code example, you will see that I'm refreshing the second session before committing. I was expecting that this would prevent the exception but it is still thrown. This is the part I don't understand. Maybe one session cannot refresh changes from another one?

Avatar

Community Advisor

PersistenceException

This exception will be thrown during the try to persist changes to a PersistableValueMap

 

Each time you call Adaptable.adaptTo(Class)  you get a new map instance which does not share modified properties with other representations.

 

The reason you code is throwing the following Exception is because you are using adaptTo for changing property.

Instead, use ModifiableValueMap and you should not get these exceptions.

Example : resource.adaptTo(ModifiableValueMap.class);

 

Avatar

Community Advisor

Hi @dominik_lackovi 

What you said makes sense that different sessions are trying to save to same node. 
Have you looked at https://helpx.adobe.com/in/experience-manager/kb/how-to-find-conflicts-when-getting-oakstate0001.html and https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/javax-jcr-invaliditemstate... for relevant discussions? They seem to be concluding what we think is happening here. But the logs may help identifying what other thread/functionality is happening concurrently. We can disable one and test if that is really the cause.

 

Can we also try to use rr.hasChanges() in this code and else where, where we suspect a session is making changes to the target nodes? Then try to commit.

We can also explore session.hasPermissions and session.refresh.