The number of fully concurrent threads per Java Virtual Machine is limited by the number of renderer instances configured for this system.
In a pure pdf renderer setup, the maximum number of instances is 4 (due to limitations when accessing native libraries via JNI). Other renderer engines, such as the InDesign® Server extension, allow configuring an arbitrary number of instances, so in theory an arbitrary number of parallel rendering threads is possible.
There is no linear correlation between the number of instances and number of documents, which can be processed simultaneously, however, there are correlations between the number of instances, documents being opened at the same time, active comet projects and fully parallel Java threads. This document describes the correlations and synchronization impacts.
Parts of the Java Rendering Library functionality is implemented in Java and (usually) not affected by any synchronicity limitations. At the end of this document, you can find an overview of classes / methods and their synchronization impacts.
This illustration shows the process flow of a partly or sometimes synchronized method call ("native lib" could also be an external InDesign® Server instance or any other renderer implementation).
The DocumentMetadata.getPreview
method can be accessed by several Java threads simultaneously.
If a PDF is already available for this document, previews for one document (e.g. for different spreads) can also be calculated simultaneously by several Java threads.
If the PDF isn't available yet, at least one thread will invoke a renderer operation (createPdf
in this case), which is synchronized on renderer instance and document level, i.e.:
From the host / client application point of view, synchronization is fully transparent. This means: the Java developer doesn't have to care about concurrency and race conditions. All synchronization is handled internally in the Java Rendering Library.
Also, if a operation requires a certain (native) application state, this is restored before processing the request and all relevant traces of interacting threads is removed.
One renderer instance can operate on several documents (OpenedDocument
instances) at the same time.
Since document operations rely on a certain renderer application status (e.g. connection to a certain comet project, see below for details), a sequence of commands must be run on this renderer
If two documents processed in different Java thread "share" the same renderer instance, one thread might affect the other for the part of operation utilizing renderer functionality
Again, from the host / client application point of view, this process is fully transparent. This means: the Java developer doesn't have to care about concurrency and race conditions. All grouping and synchronization is handled internally in the Java Rendering Library.
There is no limitation regarding the number of registered connections.
Also, one renderer instance can process several documents connected to different projects in parallel. Of course, if operations with these documents overlap, the status required for processing the actual document must be restored. This means: disconnect from the project currently connected to, if it doesn't match the documents connection, and connect to the project appropriate for the document.
"Swapping" connections is a time consuming operation (see illustration). We try to avoid this by delegating requests to renderer instances already connected to the required data source, but if there are more active connections than instances (or, if there are huge differences regarding the expected payload for each connection), the result may not be the best.
In an environment with many different projects, you should try to
As mentioned before, renderer operation may require some preprocessing and postprocessing, also the Observer pattern allows interception of all renderer operations before and after.
Therefore, a sequence of certain operations is run as an atomic operation as shown in the illustration below.
In plain words, the methods run as an atomic operation include:
The two known (or currently existing) renderer implementations (pdf renderer and InDesign® Server) are not multi threaded (at least not really) or not capable of processing multiple threads concurrently.
Though future rendering implementations may be thread safe and capable of processing multiple threads, we disallow this from the library side to ensure the correct state of the renderer.
A multi threaded renderer - from the library point of view - would be several instances of a renderer, which - in case of the pdf renderer - could be up to four (per JVM) and in case of InDesign® Server the number of InDesign® Server processes started and configured in the application.
This overview is not complete, but shows the most important methods only.
com.priint.comet.renderer.Renderer.initialize
com.priint.comet.renderer.Renderer.registerFactory
com.priint.comet.renderer.Renderer.registerConnection
com.priint.comet.renderer.Renderer.addObserver
and further methods, which may change the renderer configurationcom.priint.comet.renderer.Renderer.openDocument
com.priint.comet.renderer.Renderer.connect
com.priint.comet.renderer.Renderer.getObservers
com.priint.comet.renderer.Renderer.getNamedConnection
and further methods, which rely on the renderer status or can change the renderer statusconnect
) implicates too much complexity, they are all expected to return very fast.
com.priint.comet.renderer.OpenedDocument.close, save
com.priint.comet.renderer.OpenedDocument.execScript, execScriptCode, ...
com.priint.comet.renderer.OpenedDocument.build, placeTemplate, ...
com.priint.comet.renderer.OpenedDocument.addSpreads, removeSpreads, ...
com.priint.comet.renderer.OpenedDocument.createMetadata, createPdf, ...
com.priint.comet.renderer.OpenedDocument.getW2ML, getBytes, getMarkers ...
Synchronization of these methods takes place on
See illustration below
com.priint.comet.renderer.OpenedDocument.getMetadata
com.priint.comet.renderer.OpenedDocument.getPdf
com.priint.comet.renderer.OpenedDocument.getSpreadCount
com.priint.comet.metadata.DocumentMetadata.getSpreads, getElements, getGroups,...
com.priint.comet.metadata.DocumentMetadata.getPreview, getCometGroupPreviews, getGroupPreview, getPreviewOfClipping,...
com.priint.comet.metadata ...
any Class / methods processing DocumentMetadatacom.priint.comet.renderer.util.W2ML
W2ML document manipulations