/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/indexer/impl/ConcurrentSearchIndexBuilderWorkerImpl.java $
* $Id: ConcurrentSearchIndexBuilderWorkerImpl.java 105078 2012-02-24 23:00:38Z ottenhoff@longsight.com $
***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.search.indexer.impl;
import java.util.Observable;
import java.util.Observer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.authz.api.SecurityAdvisor;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.api.ComponentManager;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.db.api.SqlService;
import org.sakaiproject.event.api.EventTrackingService;
import org.sakaiproject.search.api.SearchService;
import org.sakaiproject.search.indexer.api.IndexWorker;
import org.sakaiproject.search.indexer.api.IndexWorkerDocumentListener;
import org.sakaiproject.search.journal.api.ManagementOperation;
import org.sakaiproject.search.journal.impl.JournalSettings;
import org.sakaiproject.user.api.UserDirectoryService;
/**
* A management operation to perform indexing to the journal
*
* @author ieb
*/
public class ConcurrentSearchIndexBuilderWorkerImpl implements ManagementOperation,
IndexWorkerDocumentListener
{
private static final Log log = LogFactory
.getLog(ConcurrentSearchIndexBuilderWorkerImpl.class);
private boolean enabled = false;
/**
* dependency
*/
private UserDirectoryService userDirectoryService;
/**
* dependency
*/
private SearchService searchService;
/**
* dependency
*/
private IndexWorker indexWorker;
/**
* dependency
*/
private ComponentManager componentManager;
/**
* Dependency
*/
private ServerConfigurationService serverConfigurationService;
/**
* we need to watch local events to guage activity
*/
private EventTrackingService eventTrackingService;
/**
* Setting A load factor 1 is full load, 100 is normal The load factor
* controlls the backoff of the indexer threads. If the load Factor is high,
* the search threads back off more.
*/
private long loadFactor = 1000L;
/**
* Has been started once at least
*/
private boolean started = false;
/**
* threads should run
*/
private boolean runThreads = false;
/**
* The last time an index run was performed on this node
*/
private long lastIndexRun = System.currentTimeMillis();
/**
* The time the last event was seen
*/
private long lastEvent;
private ThreadLocal<String> nowIndexing = new ThreadLocal<String>();
private JournalSettings journalSettings;
private SqlService sqlService;
private SecurityService securityService;
public void destroy()
{
}
public void init()
{
if (started && !runThreads)
{
log.warn("JVM Shutdown in progress, will not startup");
return;
}
if (componentManager.hasBeenClosed())
{
log.warn("Component manager Shutdown in progress, will not startup");
return;
}
enabled = searchService.isEnabled() && "true".equals(serverConfigurationService.getString("search.indexqueue", "true"));
started = true;
runThreads = true;
if ( !enabled ) {
return;
}
eventTrackingService.addLocalObserver(new Observer()
{
public void update(Observable arg0, Object arg1)
{
lastEvent = System.currentTimeMillis();
}
});
}
/**
* @see java.lang.Runnable#run()
*/
public void runOnce()
{
if (!enabled)
{
return;
}
if (componentManager.hasBeenClosed())
{
log.info("Component Manager has been closed");
return;
}
nowIndexing.set("-");
if (journalSettings.getSoakTest() && (searchService.getPendingDocs() == 0))
{
log.error("SOAK TEST---SOAK TEST---SOAK TEST. Index Rebuild Started");
searchService.rebuildInstance();
}
log.debug("Run Processing Thread");
int totalDocs = searchService.getPendingDocs();
long now = System.currentTimeMillis();
long interval = now - lastEvent;
boolean process = false;
boolean createIndex = false;
if (totalDocs > 200)
{
loadFactor = 10L;
}
else
{
loadFactor = 1000L;
}
if (totalDocs == 0)
{
process = false;
}
else if (totalDocs < 20 && interval > (20 * loadFactor))
{
process = true;
}
else if (totalDocs >= 20 && totalDocs < 50 && interval > (10 * loadFactor))
{
process = true;
}
else if (totalDocs >= 50 && totalDocs < 90 && interval > (5 * loadFactor))
{
process = true;
}
else if (totalDocs > ((90 * loadFactor) / 1000))
{
process = true;
}
// should this node consider taking the lock ?
long lastIndexInterval = (System.currentTimeMillis() - lastIndexRun);
long lastIndexMetric = lastIndexInterval * totalDocs;
// if we have 1000 docs, then indexing should happen
// after 10 seconds break
// 1000*10000 10000000
// 500 docs/ 20 seconds
//
log.debug("Activity " + (lastIndexMetric > (10000L * loadFactor)) + " "
+ (lastIndexInterval > (60L * loadFactor)) + " " + createIndex);
if (true)
{
log.debug("===" + process + "=============PROCESSING ");
if (process)
{
lastIndexRun = System.currentTimeMillis();
int batchSize = 100;
if (totalDocs > 100000)
{
batchSize = 2000;
}
else if (totalDocs > 10000)
{
batchSize = 1000;
}
else if (totalDocs > 1000)
{
batchSize = 500;
}
else if (totalDocs > 500)
{
batchSize = 200;
}
securityService.pushAdvisor(new SecurityAdvisor() {
public SecurityAdvice isAllowed(String userId, String function, String reference)
{
return SecurityAdvice.ALLOWED;
}
});
try
{
indexWorker.process(batchSize);
}
finally
{
securityService.popAdvisor();
}
lastIndexRun = System.currentTimeMillis();
}
}
}
/**
* @see org.sakaiproject.search.indexer.api.IndexWorkerDocumentListener#indexDocumentEnd(org.sakaiproject.search.indexer.api.IndexWorker,
* java.lang.String)
*/
public void indexDocumentEnd(IndexWorker worker, String ref)
{
nowIndexing.set("-");
}
/**
* @see org.sakaiproject.search.indexer.api.IndexWorkerDocumentListener#indexDocumentStart(org.sakaiproject.search.indexer.api.IndexWorker,
* java.lang.String)
*/
public void indexDocumentStart(IndexWorker worker, String ref)
{
nowIndexing.set(ref);
}
/**
* @return the componentManager
*/
public ComponentManager getComponentManager()
{
return componentManager;
}
/**
* @param componentManager
* the componentManager to set
*/
public void setComponentManager(ComponentManager componentManager)
{
this.componentManager = componentManager;
}
/**
* @return the eventTrackingService
*/
public EventTrackingService getEventTrackingService()
{
return eventTrackingService;
}
/**
* @param eventTrackingService
* the eventTrackingService to set
*/
public void setEventTrackingService(EventTrackingService eventTrackingService)
{
this.eventTrackingService = eventTrackingService;
}
/**
* @return the indexWorker
*/
public IndexWorker getIndexWorker()
{
return indexWorker;
}
/**
* @param indexWorker
* the indexWorker to set
*/
public void setIndexWorker(IndexWorker indexWorker)
{
this.indexWorker = indexWorker;
}
/**
* @return the loadFactor
*/
public long getLoadFactor()
{
return loadFactor;
}
/**
* @param loadFactor
* the loadFactor to set
*/
public void setLoadFactor(long loadFactor)
{
this.loadFactor = loadFactor;
}
/**
* @return the searchService
*/
public SearchService getSearchService()
{
return searchService;
}
/**
* @param searchService
* the searchService to set
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @return the userDirectoryService
*/
public UserDirectoryService getUserDirectoryService()
{
return userDirectoryService;
}
/**
* @param userDirectoryService
* the userDirectoryService to set
*/
public void setUserDirectoryService(UserDirectoryService userDirectoryService)
{
this.userDirectoryService = userDirectoryService;
}
/**
*
* @param serverConfigurationService
*/
public void setServerConfigurationService(
ServerConfigurationService serverConfigurationService) {
this.serverConfigurationService = serverConfigurationService;
}
/**
* @return the journalSettings
*/
public JournalSettings getJournalSettings()
{
return journalSettings;
}
/**
* @param journalSettings
* the journalSettings to set
*/
public void setJournalSettings(JournalSettings journalSettings)
{
this.journalSettings = journalSettings;
}
/**
* @return the sqlService
*/
public SqlService getSqlService()
{
return sqlService;
}
/**
* @param sqlService the sqlService to set
*/
public void setSqlService(SqlService sqlService)
{
this.sqlService = sqlService;
}
/**
* @return the securityService
*/
public SecurityService getSecurityService()
{
return securityService;
}
/**
* @param securityService the securityService to set
*/
public void setSecurityService(SecurityService securityService)
{
this.securityService = securityService;
}
}