Confluence throws 'org.hibernate.HibernateException: Unable to resolve owner of loading collection' when fetching attachment properties in a separate thread

Hi there,

Recently we were reported of slowness in Bob swift Attachment Table macro.
For information attachment-table macro does following steps,

  1. For each given space, gets the page list
  2. For each page, check view permission for logged in user and if permitted, list attachments of pages.
  3. For each attachment, fetch the properties like name, size, comment, creator, created date, etc

While troubleshooting macro code, we found that Confluence takes time at step 2.

To minimise the time, we created fixedThreadPool of size 1 ( if pool size > 1, then Confluence threw same below exception, so we tried with pool size = 1) and assigned every page to a thread i.e the thread will perform the task of getting list of attachments.
With this, we are able to save time in step 2 but Confluence throws below exception in step 3 every time while getting filesize property of the attachment i.e attachment.getFileSize();

2019-08-13 06:26:14,259 WARN [http-nio-8090-exec-105][engine.loading.internal.LoadContexts] cleanup HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@668ac984<rs=com.mchange.v2.c3p0.impl.NewProxyResultSet@504add1a [wrapping: null]>
– url: /display/AMTEST/Test-all+spaces | page: 350192291 | traceId: 19e938c7951b6943 | userName: advtables | referer: https://confluence6151.bobfire.com/display/AMTEST/Test-all+spaces | action: viewpage
2019-08-13 06:26:14,261 ERROR [http-nio-8090-exec-105][swift.confluence.table.AttachmentTableMacro] execute 
– url: /display/AMTEST/Test-all+spaces | page: 350192291 | traceId: 19e938c7951b6943 | userName: advtables | referer: https://confluence6151.bobfire.com/display/AMTEST/Test-all+spaces | action: viewpage
org.hibernate.HibernateException: Unable to resolve owner of loading collection [[com.atlassian.confluence.core.ContentEntityObject.contentProperties#347146581](https://ecosystem.atlassian.net/servicedesk/customer/portal/14/DEVHELP-3294#347146581)] for second level caching
at org.hibernate.engine.loading.internal.CollectionLoadContext.addCollectionToCache(CollectionLoadContext.java:321)

Please find the complete stacktrace is in the attachment.

Here is the code where we are creating thread pool of size 1,

final ExecutorService pool = Executors.newFixedThreadPool(1);
Collection<Future<?>> futures = new LinkedList<>();
for (Page page : pageList) {
futures.add(pool.submit(new Callable<String>() {
@Override
public String call() throws Exception

{ pageCounter.addAndGet(1); attachmentTableHelper.processForPage(info, list, page, pagePattern, pageLabelPattern, limit); //checks view permission on the page and add the attachments of page to the given synchronized list return page.getTitle(); }

}));
}
for (Future<?> f : futures) {
try

{ f.get(); }

catch (InterruptedException e) {
log.error("futureget - InterruptedException {} ", e.getMessage());
} catch (ExecutionException e) {
log.error("futureget - ExecutionException {} ", e.getMessage());
}
}
shutdownAndAwaitTermination(pool);

After attachment list is ready, we are looping through to get properties of each attachment in a old fashioned for loop. And at this moment it fails with above exception. Logically we have the attachment list ready and thread pool is shutdown and as we are looping thru the attachment list sequentially, it shall go smooth.
This problem is observed only when we have separate thread.

Is there an alternate get the attachments in thread-safe way ? Or is there an alternate to get the attachments without spanning separate thread?

Appreciate your help here.
Thank youSupport-2589-caching-issue.docx|attachment (23.8 KB)

Dear Sunita,

you should have a look at: Bitbucket

You may need to take care about the following:

  • Do you set the thread user in your thread?
  • Do you use a transaction template in each thread? Please keep in mind that some objects cannot be used cross templates. Rather than passing a page you may need to pass a pageId.

I hope that helps.

Kind regards

Andreas

1 Like

Thanks @andreas1 for your inputs!

Sorry it took me so long to respond, as I got occupied in another project.

I am not setting thread user explicitly. And we are not using transaction template in each thread.
I tried passing pageId instead of Page, and in each thread using pageManager getting the corresponding page object, but ended up again in same exception.

O.k. but you may also need to use a transaction template.