Avoka Blog: Adobe LiveCycle

March 17, 2009

Speedup JBoss LiveCycle Startup

JBoss Start-up Performance

Starting JBoss with a fully configured LiveCycle installation can take an awfully long time! We’ve done some digging and found that a large portion of this time is spent unpacking the LiveCycle EAR file – and copying these files into the jboss/server/all/tmp directory. In fact a fully configured LiveCycle EAR can amount to over 800 MB of data being written – which adds a considerable amount of time to the start-up.

JBoss supports unpacked EAR and WAR files in the deploy directory, which will save these files from being unpacked at start-up time. To simplify this we’ve created a small utility that unpacks the LiveCycle EAR file and all of its contents into the deploy directory.  

We’ve found that its halved the JBoss start-up time – on my laptop this saved nearly 8 minutes – which is lots when you have to restart Jboss often.

Instructions:

Download Link
 

 

 

  1. Download the utility and unzip the file. You should have a file called “AdobeJBossEarUnpacker.jar
  2. Run the Jar – it will prompt you for the location of the JBoss deploy directory (typically its under your LiveCycle install directory in /jboss/server/all/deploy).
  3. That’s it. It will create a copy of your LiveCycle.ear file then proceed to unpack LiveCyle inside your deploy directory. Whenever you need to redeploy LiveCycle make sure you delete the exploded directory first. 

Startup Sequence

While we are on the topic of starting JBoss another really handy trick is to make use of the “deploy.last” sub-directoy. Any files placed in this directory won’t be deployed until all the files in the main deploy directrry have started. This can be very handy when you have an application that is dependant on a LiveCycle service – which means that you don’t want it to start until LiveCycle its-self has fully started.

PS – Thanks to Malcolm Edgar for some great investigative work and creating the unpacker util.

February 10, 2009

How to read a LiveCycle stack trace

Filed under: Application Servers, LiveCycle, LiveCycle Administration — htreisman @ 11:01 am

When an error occurs in LiveCycle, you’ll usually get some sort of stack trace in the application server log files. It’s very important to be able to read and understand the stack trace, because this is your best opportunity to find out what went wrong.

A typical stack trace often looks quite daunting at first, something like this: (Don’t try to read it, just scroll down…)

javax.ejb.TransactionRolledbackLocalException: Got error 139 from storage engine; CausedByException is:
Got error 139 from storage engine
at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:247)
at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:335)
at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:166)
at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:153)
at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:192)
at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122)
at org.jboss.ejb.SessionContainer.internalInvoke(SessionContainer.java:624)
at org.jboss.ejb.Container.invoke(Container.java:873)
at org.jboss.ejb.plugins.local.BaseLocalProxyFactory.invoke(BaseLocalProxyFactory.java:415)
at org.jboss.ejb.plugins.local.StatelessSessionProxy.invoke(StatelessSessionProxy.java:88 )
at $Proxy180.writeObject(Unknown Source)
at com.adobe.pof.omapi.POFObjectManagerLocalEJBAdapter.writeObject(POFObjectManagerLocalEJBAdapter.java:135)
at com.adobe.workflow.datatype.POFVariableContainer.write(POFVariableContainer.java:133)
at com.adobe.workflow.pat.service.PATExecutionContextImpl.writeResults(PATExecutionContextImpl.java:108 )
at com.adobe.workflow.engine.ProcessEngineBMTBean.continueBranchAtAction(ProcessEngineBMTBean.java:2944)
at com.adobe.workflow.engine.ProcessEngineBMTBean.asyncContinueBranchCommand(ProcessEngineBMTBean.java:2392)
at sun.reflect.GeneratedMethodAccessor528.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.invocation.Invocation.performCall(Invocation.java:345)
at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:214)
at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:149)
at org.jboss.webservice.server.ServiceEndpointInterceptor.invoke(ServiceEndpointInterceptor.java:54)
at org.jboss.ejb.plugins.CallValidationInterceptor.invoke(CallValidationInterceptor.java:48 )
at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:106)
at org.jboss.ejb.plugins.AbstractTxInterceptorBMT.invokeNext(AbstractTxInterceptorBMT.java:158 )
at org.jboss.ejb.plugins.TxInterceptorBMT.invoke(TxInterceptorBMT.java:62)
at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:154)
at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:153)
at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:192)
at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122)
at org.jboss.ejb.SessionContainer.internalInvoke(SessionContainer.java:624)
at org.jboss.ejb.Container.invoke(Container.java:873)
at org.jboss.ejb.plugins.local.BaseLocalProxyFactory.invoke(BaseLocalProxyFactory.java:415)
at org.jboss.ejb.plugins.local.StatelessSessionProxy.invoke(StatelessSessionProxy.java:88 )
at $Proxy200.asyncContinueBranchCommand(Unknown Source)
at com.adobe.workflow.engine.ProcessCommandControllerBean.doOnMessage(ProcessCommandControllerBean.java:133)
at com.adobe.workflow.engine.ProcessCommandControllerBean.onMessage(ProcessCommandControllerBean.java:94)
at sun.reflect.GeneratedMethodAccessor439.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.invocation.Invocation.performCall(Invocation.java:345)
at org.jboss.ejb.MessageDrivenContainer$ContainerInterceptor.invoke(MessageDrivenContainer.java:475)
at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:149)
at org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor.invoke(MessageDrivenInstanceInterceptor.java:101)
at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:106)
at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:335)
at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:166)
at org.jboss.ejb.plugins.RunAsSecurityInterceptor.invoke(RunAsSecurityInterceptor.java:94)
at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:192)
at org.jboss.ejb.MessageDrivenContainer.internalInvoke(MessageDrivenContainer.java:389)
at org.jboss.ejb.Container.invoke(Container.java:873)
at org.jboss.ejb.plugins.jms.JMSContainerInvoker.invoke(JMSContainerInvoker.java:1077)
at org.jboss.ejb.plugins.jms.JMSContainerInvoker$MessageListenerImpl.onMessage(JMSContainerInvoker.java:1379)
at org.jboss.jms.asf.StdServerSession.onMessage(StdServerSession.java:256)
at org.jboss.mq.SpyMessageConsumer.sessionConsumerProcessMessage(SpyMessageConsumer.java:904)
at org.jboss.mq.SpyMessageConsumer.addMessage(SpyMessageConsumer.java:160)
at org.jboss.mq.SpySession.run(SpySession.java:333)
at org.jboss.jms.asf.StdServerSession.run(StdServerSession.java:180)
at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(PooledExecutor.java:748 )
at java.lang.Thread.run(Thread.java:595)

Note that there’s a second separate exception here. This line doesn’t start with “at”. This is usually the “caused by” part of the same exception.

java.sql.SQLException: Got error 139 from storage engine
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2928 )
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1571)
at com.mysql.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:1124)
at com.mysql.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:676)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1166)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1082)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1067)
at org.jboss.resource.adapter.jdbc.CachedPreparedStatement.executeUpdate(CachedPreparedStatement.java:81)
at org.jboss.resource.adapter.jdbc.WrappedPreparedStatement.executeUpdate(WrappedPreparedStatement.java:227)
at com.adobe.pof.adapter.JDBCAdapter.updateObject(JDBCAdapter.java:519)
at com.adobe.pof.adapter.JDBCAdapter.updateObject(JDBCAdapter.java:442)
at com.adobe.pof.omapi.POFObjectManagerImpl.writeObject(POFObjectManagerImpl.java:254)
at com.adobe.pof.omapi.POFObjectManagerRemoteBean.writeObject(POFObjectManagerRemoteBean.java:271)
at sun.reflect.GeneratedMethodAccessor381.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.invocation.Invocation.performCall(Invocation.java:345)
at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:214)
at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:149)
at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:154)
at org.jboss.webservice.server.ServiceEndpointInterceptor.invoke(ServiceEndpointInterceptor.java:54)
at org.jboss.ejb.plugins.CallValidationInterceptor.invoke(CallValidationInterceptor.java:48 )
at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:106)
at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:335)
at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:166)
at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:153)
at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:192)
at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122)
at org.jboss.ejb.SessionContainer.internalInvoke(SessionContainer.java:624)
at org.jboss.ejb.Container.invoke(Container.java:873)
at org.jboss.ejb.plugins.local.BaseLocalProxyFactory.invoke(BaseLocalProxyFactory.java:415)
at org.jboss.ejb.plugins.local.StatelessSessionProxy.invoke(StatelessSessionProxy.java:88 )
at $Proxy180.writeObject(Unknown Source)
at com.adobe.pof.omapi.POFObjectManagerLocalEJBAdapter.writeObject(POFObjectManagerLocalEJBAdapter.java:135)
at com.adobe.workflow.datatype.POFVariableContainer.write(POFVariableContainer.java:133)
at com.adobe.workflow.pat.service.PATExecutionContextImpl.writeResults(PATExecutionContextImpl.java:108 )
at com.adobe.workflow.engine.ProcessEngineBMTBean.continueBranchAtAction(ProcessEngineBMTBean.java:2944)
at com.adobe.workflow.engine.ProcessEngineBMTBean.asyncContinueBranchCommand(ProcessEngineBMTBean.java:2392)
at sun.reflect.GeneratedMethodAccessor528.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.invocation.Invocation.performCall(Invocation.java:345)
at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:214)
at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:149)
at org.jboss.webservice.server.ServiceEndpointInterceptor.invoke(ServiceEndpointInterceptor.java:54)
at org.jboss.ejb.plugins.CallValidationInterceptor.invoke(CallValidationInterceptor.java:48 )
at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:106)
at org.jboss.ejb.plugins.AbstractTxInterceptorBMT.invokeNext(AbstractTxInterceptorBMT.java:158 )
at org.jboss.ejb.plugins.TxInterceptorBMT.invoke(TxInterceptorBMT.java:62)
at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:154)
at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:153)
at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:192)
at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122)
at org.jboss.ejb.SessionContainer.internalInvoke(SessionContainer.java:624)
at org.jboss.ejb.Container.invoke(Container.java:873)
at org.jboss.ejb.plugins.local.BaseLocalProxyFactory.invoke(BaseLocalProxyFactory.java:415)
at org.jboss.ejb.plugins.local.StatelessSessionProxy.invoke(StatelessSessionProxy.java:88 )
at $Proxy200.asyncContinueBranchCommand(Unknown Source)
at com.adobe.workflow.engine.ProcessCommandControllerBean.doOnMessage(ProcessCommandControllerBean.java:133)
at com.adobe.workflow.engine.ProcessCommandControllerBean.onMessage(ProcessCommandControllerBean.java:94)
at sun.reflect.GeneratedMethodAccessor439.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.invocation.Invocation.performCall(Invocation.java:345)
at org.jboss.ejb.MessageDrivenContainer$ContainerInterceptor.invoke(MessageDrivenContainer.java:475)
at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:149)
at org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor.invoke(MessageDrivenInstanceInterceptor.java:101)
at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:106)
at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:335)
at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:166)
at org.jboss.ejb.plugins.RunAsSecurityInterceptor.invoke(RunAsSecurityInterceptor.java:94)
at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:192)
at org.jboss.ejb.MessageDrivenContainer.internalInvoke(MessageDrivenContainer.java:389)
at org.jboss.ejb.Container.invoke(Container.java:873)
at org.jboss.ejb.plugins.jms.JMSContainerInvoker.invoke(JMSContainerInvoker.java:1077)
at org.jboss.ejb.plugins.jms.JMSContainerInvoker$MessageListenerImpl.onMessage(JMSContainerInvoker.java:1379)
at org.jboss.jms.asf.StdServerSession.onMessage(StdServerSession.java:256)
at org.jboss.mq.SpyMessageConsumer.sessionConsumerProcessMessage(SpyMessageConsumer.java:904)
at org.jboss.mq.SpyMessageConsumer.addMessage(SpyMessageConsumer.java:160)
at org.jboss.mq.SpySession.run(SpySession.java:333)
at org.jboss.jms.asf.StdServerSession.run(StdServerSession.java:180)
at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(PooledExecutor.java:748 )
at java.lang.Thread.run(Thread.java:595)

Usually, if there are two exceptions, the second one, often preceded by “Caused by” gives you more detailed information. So I’m just going to ignore the first exception for now, halving the amount of detail I need to worry about.

Then I typically ignore anything that doesn’t belong to Adobe or the component implementation (i.e. All the “jboss” stuff)

Now that I’ve reduced it down to a manageable amount, I start from the bottom up, trying to work out what’s going on when the error occurred. This helps us both to understand, diagnose, and potentially reproduce the problem. The very top line usually contains the actual error. See annotations below, working from the bottom up:

java.sql.SQLException: Got error 139 from storage engine

4. error 139: We got a strange error from the “storage engine”, meaning the database itself. Let’s go google that. (I’ll leave this as an exercise for the reader.)

at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2928 )
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1571)
at com.mysql.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:1124)
at com.mysql.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:676)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1166)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1082)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1067)

3. executeUpdate: We seem to be updating a row in the database using the mySQL JDBC driver

at com.adobe.pof.adapter.JDBCAdapter.updateObject(JDBCAdapter.java:519)
at com.adobe.pof.adapter.JDBCAdapter.updateObject(JDBCAdapter.java:442)
at com.adobe.pof.omapi.POFObjectManagerImpl.writeObject(POFObjectManagerImpl.java:254)
at com.adobe.pof.omapi.POFObjectManagerRemoteBean.writeObject(POFObjectManagerRemoteBean.java:271)
at $Proxy180.writeObject(Unknown Source)
at com.adobe.pof.omapi.POFObjectManagerLocalEJBAdapter.writeObject(POFObjectManagerLocalEJBAdapter.java:135)
at com.adobe.workflow.datatype.POFVariableContainer.write(POFVariableContainer.java:133)
at com.adobe.workflow.pat.service.PATExecutionContextImpl.writeResults(PATExecutionContextImpl.java:108 )

2. writeResults: Yup, the engine is now trying to write the results that the component returned back into the process variables

at com.adobe.workflow.engine.ProcessEngineBMTBean.continueBranchAtAction(ProcessEngineBMTBean.java:2944)

1. continueBranchAtAction: a particular step is being “continued” – probably means that the component itself has already been executed, now we need to “continue” it to completion

at com.adobe.workflow.engine.ProcessEngineBMTBean.asyncContinueBranchCommand(ProcessEngineBMTBean.java:2392)

We still don’t know exactly why this failure occurred, but we have a much better idea of where and why it happened, and we’re well placed to diagnose further.

Obviously, every stack trace is different, but hopefully this gives you a technique that will help you to understand what went wrong, and fix it.

February 2, 2009

Free Desktop Alerter for LiveCycle Workspace

Filed under: LiveCycle Administration, LiveCycle Workspace — htreisman @ 9:01 pm

Avoka Alerter for Workspace provides notification of new tasks in your LiveCycle ES Workspace queues by sending task alerts to your desktop.

You can now be notified of LiveCycle ES Workspace tasks without having an open browser to host Workspace, or your email application to monitor notifications. Alerter also allows you to open, view and prioritize tasks, directly from the desktop!

alerter

The Alerter AIR application can just sit in the system tray. New tasks are alerted to your desktop as yellow “toast” popups. The opened application shows your personal work queue and each of your group queues as bars in a barchart. The longer the bar, the more tasks allocated to that queue.

Clicking on any task will open its respective form. Views are automatically refreshed.

And Yes, it’s completely FREE.

More information and download link.

June 16, 2008

LiveCycle directories – Global Storage/Temp, clustering, and more…

Filed under: LiveCycle, LiveCycle Administration, LiveCycle Architecture — htreisman @ 11:03 am

The information in this Blog is correct to the best of my knowledge – if you discover any errors, please post on the comments area.

Thanks to Pete Spencer of Adobe for his expertise.

General

  • You need to specify various directories when you configure LiveCycle using the Configuration Manager. These include:
    • Global Document Storage (GDS) Directory
    • Temporary Directory
    • Font Directories
  • The values you enter into Configuration Manager are stored within the LiveCycle ear file. The values in this ear file are only used during initializing (bootstrapping) the LiveCycle database – after this, they are no longer used, and the values from the database are used instead.
  • All of the directories must be specified from the perspective of the application server, NOT the perspective of the machine running Configuration Manager. In other words, these directories must exist on the application server. It’s therefore simplest if you actually run Configuration Manager on the target machine.
  • You can modify the directory names in the database using Adminui at any time, including after installation. Home > Settings > Core System Settings > Configurations. You must restart the server before your changes take effect. You MUST move files from the old GDS to the new GDS while the server is stopped. You do not need to reconfigure or redeploy your ear files.
  • There is only one directory location stored in the database, no matter how many instances you have in your cluster. In a clustered environment, you must set up your servers so that all of them have the same GDS, temp and font directory names. (There’s a way around this for the temp directory – see below.)

For example: if you’re running LiveCycle on different operating systems, you cannot set the System Font directory to c:\windows\fonts on one machine, and c:\winnt\fonts on a different machine. You will have to make the directory the same on all machines, even if this means copying files to matching directories.

Another example: You cannot set the Global Storage Directory to “C:\Adobe\Global” on one machine, and “\\machine1\c$\Adobe\Global” on another. You can use “\\machine1\c$\Adobe\Global” on both machines (although this would create a single point of failure).

  • Make sure that the user under which you run the Application Server has read/write access to the temp/GDS directories, and read access to the Font directories.
  • You can use the same LiveCycle ear files for installs onto multiple boxes (eg Dev, Test, Production), even if the actual directories on a second box don’t match those that you specified for the first box. You can deploy the LiveCycle ear files, run LiveCycle, and bootstrap the database. Then you can modify the directories using Adminui, and restart LiveCycle. Once you’ve done this, you can complete the configuration by installing components and samples, etc. (Note: We haven’t thoroughly tested this, and don’t know for sure that those directories in the LiveCycle ear file aren’t used for some other purpose – we recommend that you create separate LiveCycle ear files for each machine configuration.)

Font Directories

  • These can be shared, or each application server in a cluster can have its own copy on a local drive.
  • If you’re running Configuration Manager on one machine, and deploying to another, you must copy the LiveCycle fonts from the installation directory (usually C:\Adobe\LiveCycle8\fonts) to a location on the application server machine.
  • Under Windows, the system fonts are generally either in C:\windows\fonts or c:\winnt\fonts.

Global Document Storage Directory (GDS)

  • The GDS should be considered an extension to the database, and is part of the persistent state of the LiveCycle system. Don’t “clean up” the files in this directory.
  • You should back up the files in this directory simultaneously with the database. See my previous post on this topic.
  • The GDS must be a single directory that is shared between all instances of LiveCycle in a cluster. Usually this means setting up the GDS on a shared drive, or a Storage Area Network (SAN).
  • It must also be referred to by exactly the same pathname for all instances of LiveCycle.
  • If you change the location of the GDS, you must ALSO move all the files to the new location while the server is stopped.

Temporary directory

  • Each running instance of LiveCycle requires its own temporary directory. There are a number of ways of specifying the temporary directory:
  • If you specific a non-blank directory in Configuration Manager (which also means a non-blank directory in adminui), then LiveCycle will use this value.
  • If you specify a blank directory in Configuration Manager/Adminui, then LiveCycle will use the Java VM java.io.tmpdir system property.
  • The java.io.tmpdir property can be set in several ways:
    • You can specify it explicitly in the command line that you use to launch the Java VM that runs LiveCycle. For example, “java -Djava.io.tmpdir=C:\temp …”
    • If you do not specify it explicitly, Java will set this value based on operating system defaults (eg value of “TEMP” system variable)
  • If you are using vertical clustering, the members of the cluster will each need their own temp directory, but they are sharing the same physical drive. Therefore
    • Leave the temporary directory blank in Configuration Manager/Adminui.
    • Specify a different java.io.tmpdir Java system property for each instance of LiveCycle.

June 6, 2008

Hot Back-ups of LiveCycle

Filed under: LiveCycle, LiveCycle Administration, LiveCycle Architecture — htreisman @ 4:17 pm

Most of LiveCycle’s data is held in the LiveCycle database. Backing up the database is easy – just use the native backup facilities provided by your database vendor.

Usually you can do a “hot” backup, while the application (i.e. LiveCycle) is still running. What the backup utility does is to set a “marker” in the database transaction log – the backup is the state of the entire database at the point in time the marker was set. The database will continue to run, and execute transactions, but the data from these new transactions won’t appear in the backup – so no matter how big the database is, you always get a consistent set of data.

LiveCycle is a bit more complicated, because it has the Global Document Storage directory (GDS). The GDS is really an extension or overflow for the database. For any large documents, these are actually stored in the GDS, rather than in the database – this helps with performance, and also helps to ensure that your database doesn’t grow too rapidly.

You always need to ensure that when you do a backup of your database, you do a backup of your GDS. Similarly, if you do a restore, you should also restore both the GDS and the database at the same time.

The trick is: how do you ensure that the database and GDS are consistent with each other? Any missing files in the GDS will cause LiveCycle to start throwing exceptions.

One technique is to shut down LiveCycle while you’re doing the backup. If you need to do hot backups, then there are different approaches depending on your version of LiveCycle.

LiveCycle 8 Update 1

In LiveCycle 8 update 1 (at the time of writing, in beta), Adobe have added “backup mode” to enable backups to be made more reliably. The steps are:

  • Turn on “backup mode” in the adminui – this will temporarily prevent LiveCycle from deleting any files from the GDS.
  • Backup the database.
  • Backup the GDS.
  • Turn backup mode off.

LiveCycle 8

There is no backup mode in LiveCycle 8. The following procedure is the one that we recommend for hot backups.

  • Backup the GDS
  • Backup the database
  • Backup the GDS again, to the same backup location. Ensure that you use a backup mode that adds any new or modified files, but does NOT remove any files that have been removed since the first backup.

You should also try to ensure that the entire process above occurs as quickly as possible. This may mean that you initially copy the files to a temporary location, and then perform the real backup (to tape or whatever) from there.

There is apparently a small window of possibility that errors occurs – if a file in the GDS is created and removed between the time that the first backup starts and the second backup completes. This is generally a small window. Thank you to Rob Ryan of Adobe for pointing this out.

Create a free website or blog at WordPress.com.