Details
Description
I was hunted by this bug for a long time, but I didn't had time to investigate. Since it happens mostly(almost every time) on my workstation and not in production I wasn't worry about it until now, when I have in investigate some huge performance degradation and I cannot do it if the AbstractBaseManager.setRegion doesn't work during development. It is actually also a bug of Scarab(I will post a similar bug in their bug tracking) which it is possible due wrong handling during Torque initialization.
I'm using Scarab (http://scarab.tigris.org/) and they use Turbine & Torque. Everything works nice, except that Torque is initialized twice.
First, it is initialize by Turbine and the stack trace is this one :
main@1, priority=5, in group 'main', status: 'RUNNING'
at org.tigris.scarab.components.TorqueComponent.initialize(TorqueComponent.java:105)
at org.apache.fulcrum.yaafi.framework.container.ServiceComponentImpl.initialize(ServiceComponentImpl.java:280)
at org.apache.fulcrum.yaafi.framework.container.ServiceContainerImpl.incarnate(ServiceContainerImpl.java:472)
at org.apache.fulcrum.yaafi.framework.container.ServiceContainerImpl.incarnate(ServiceContainerImpl.java:522)
at org.apache.fulcrum.yaafi.framework.container.ServiceContainerImpl.initialize(ServiceContainerImpl.java:201)
at org.apache.fulcrum.yaafi.framework.factory.ServiceManagerFactory.create(ServiceManagerFactory.java:141)
at org.apache.turbine.services.yaaficomponent.TurbineYaafiComponentService.init(TurbineYaafiComponentService.java:194)
at org.apache.fulcrum.BaseServiceBroker.initService(BaseServiceBroker.java:398)
at org.apache.fulcrum.BaseServiceBroker.doInitService(BaseServiceBroker.java:477)
at org.apache.fulcrum.BaseServiceBroker.initServices(BaseServiceBroker.java:449)
at org.apache.fulcrum.BaseServiceBroker.init(BaseServiceBroker.java:262)
at org.apache.turbine.Turbine.configure(Turbine.java:707)
at org.apache.turbine.Turbine.init(Turbine.java:193)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1,105)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:932)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:3,951)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4,225)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:759)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:739)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:524)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:608)
at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:535)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:470)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1,122)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:310)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1,021)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:718)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1,013)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:442)
at org.apache.catalina.core.StandardService.start(StandardService.java:450)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:709)
at org.apache.catalina.startup.Catalina.start(Catalina.java:551)
at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:294)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:432)
Second time is initialize by a Search Service and the stack trace looks like this :
Thread-2@854, priority=5, in group 'UpdateIndex', status: 'RUNNING'
at org.tigris.scarab.components.TorqueComponent.initialize(TorqueComponent.java:104)
at org.apache.fulcrum.yaafi.framework.container.ServiceComponentImpl.initialize(ServiceComponentImpl.java:280)
at org.apache.fulcrum.yaafi.framework.container.ServiceContainerImpl.incarnate(ServiceContainerImpl.java:472)
at org.apache.fulcrum.yaafi.framework.container.ServiceContainerImpl.incarnate(ServiceContainerImpl.java:522)
at org.apache.fulcrum.yaafi.framework.container.ServiceContainerImpl.initialize(ServiceContainerImpl.java:201)
at org.apache.fulcrum.yaafi.framework.factory.ServiceManagerFactory.create(ServiceManagerFactory.java:141)
at org.apache.turbine.services.yaaficomponent.TurbineYaafiComponentService.init(TurbineYaafiComponentService.java:194)
at org.apache.fulcrum.BaseServiceBroker.getService(BaseServiceBroker.java:572)
at org.tigris.scarab.services.ServiceManager.getService(ServiceManager.java:91)
at org.tigris.scarab.services.ServiceManager.lookup(ServiceManager.java:75)
at org.tigris.scarab.util.word.SearchFactory.getInstance(SearchFactory.java:73)
at org.tigris.scarab.util.word.LuceneSearchIndex$UpdateThread.run(LuceneSearchIndex.java:781)
at java.lang.Thread.run(Thread.java:595)
I'm not sure why Search Service tries to initialize Torque again(it should be initialize by Turbine), anyway this is not related with Torque but this is how I was able to find this bug.
Also they change TorqueComponent, which looks like this :
public class TorqueComponent
extends org.apache.torque.avalon.TorqueComponent
{
static
{ ScarabUtil.initializeScarab(); }public TorqueComponent()
{ super(); }/**
- Creates a new instance.
* - @param torqueInstance The instance of the Torque core used by
- this component.
*/
protected TorqueComponent(TorqueInstance torqueInstance) { super(torqueInstance); }
/**
- @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
*/
public void configure(Configuration configuration)
throws ConfigurationException { // we retrieve the configuration from Turbine runtime @see #initialize() getLogger().debug("configure(" + configuration + ")"); }/**
- @see org.apache.avalon.framework.activity.Initializable#initialize()
*/
public void initialize()
throws Exception { getLogger().debug("initialize()"); //return the configuration object with the torque values only. Torque.init(Turbine.getConfiguration()); }
}
You can see they initialize Torque with Turbine configuration(composite configuration, it contains also Torque configuration file) and since TorqueComponent.initialize() is called twice, TorqueInstance.init(Configuration) is called twice.
The current implementation of TorqueInstance.init(Configuration) is wrong. First it changes the configuration and than calls initialize() which should change the current configuration with "conf.subset(Torque.TORQUE_KEY)" . Because Torque was already intialized, TorqueInstance.initialize() returns without changing the configuration with a subset configuration. Due this improper initialization, when Search Services starts Torque gets a composite configuration(Turbine's configuration) instead of a subset of Turbine configuration(Torque's configuration). Every Configuration.getXX() fails (returns default values), cache is not initialized and maybe some other (lazy) things are not correct either.
private synchronized void initialize() throws TorqueException
{
log.debug("initialize()");
if (isInit)
{ log.debug("Multiple initializations of Torque attempted"); return; }if (conf == null || conf.isEmpty())
{ throw new TorqueException("Torque cannot be initialized without " + "a valid configuration. Please check the log files " + "for further details."); } .....
}
public void init(Configuration conf)
throws TorqueException
I will propose a fix for Scarab
if (!Torque.isInit()) {
Torque.init(Turbine.getConfiguration());
}
but this should be fixed also in Torque to prevent users making mistakes like this one.
Also " log.debug("Multiple initializations of Torque attempted");" was not very inspired because usually you don't activate debug level on Torque, even during development(except you suspect something is really wrong with Torque). It should be logged with error level(better throw an exception) if calling init() is wrong or in the worst case it should skip calls to init() after first call.
I think Torque should throw an exception in initialize() but also should avoid changing the configuration before calling initialize().
Thanks.