From 1f902f3be9ef5e8ecb7b1fc633717ec16058f1d4 Mon Sep 17 00:00:00 2001 From: Andrew Hind Date: Mon, 7 Nov 2011 14:37:53 +0000 Subject: [PATCH] Fix for ALF-10449 SOLR Index backup is not available via cron - regression WRT lucene implementation git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@31806 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../Search/solr/solr-backup-context.xml | 91 +++++++++ .../Search/solr/solr-backup.properties | 5 + .../search/impl/solr/SolrBackupClient.java | 173 ++++++++++++++++++ .../repo/search/impl/solr/SolrBackupJob.java | 60 ++++++ 4 files changed, 329 insertions(+) create mode 100644 config/alfresco/subsystems/Search/solr/solr-backup-context.xml create mode 100644 config/alfresco/subsystems/Search/solr/solr-backup.properties create mode 100644 source/java/org/alfresco/repo/search/impl/solr/SolrBackupClient.java create mode 100644 source/java/org/alfresco/repo/search/impl/solr/SolrBackupJob.java diff --git a/config/alfresco/subsystems/Search/solr/solr-backup-context.xml b/config/alfresco/subsystems/Search/solr/solr-backup-context.xml new file mode 100644 index 0000000000..81105818ad --- /dev/null +++ b/config/alfresco/subsystems/Search/solr/solr-backup-context.xml @@ -0,0 +1,91 @@ + + + + + + + + + org.alfresco.repo.search.impl.solr.SolrBackupJob + + + + + + + + + + + + + + + + + + + + ${solr.backup.alfresco.cronExpression} + + + + + + + + + ${solr.backup.alfresco.remoteBackupLocation} + + + alfresco + + + + + + + + + + + org.alfresco.repo.search.impl.solr.SolrBackupJob + + + + + + + + + + + + + + + + + + + + ${solr.backup.archive.cronExpression} + + + + + + + + + ${solr.backup.archive.remoteBackupLocation} + + + archive + + + + + + + \ No newline at end of file diff --git a/config/alfresco/subsystems/Search/solr/solr-backup.properties b/config/alfresco/subsystems/Search/solr/solr-backup.properties new file mode 100644 index 0000000000..082ebeeb04 --- /dev/null +++ b/config/alfresco/subsystems/Search/solr/solr-backup.properties @@ -0,0 +1,5 @@ +solr.backup.alfresco.cronExpression=0 0 2 * * ? +solr.backup.archive.cronExpression=0 0 4 * * ? +solr.backup.alfresco.remoteBackupLocation= +solr.backup.archive.remoteBackupLocation= + diff --git a/source/java/org/alfresco/repo/search/impl/solr/SolrBackupClient.java b/source/java/org/alfresco/repo/search/impl/solr/SolrBackupClient.java new file mode 100644 index 0000000000..571df0f6ec --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/solr/SolrBackupClient.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.search.impl.solr; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.lock.JobLockService; +import org.alfresco.repo.lock.JobLockService.JobLockRefreshCallback; +import org.alfresco.repo.lock.LockAcquisitionException; +import org.alfresco.repo.solr.SOLRAdminClient; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.common.params.ModifiableSolrParams; +import org.springframework.beans.factory.InitializingBean; + +/** + * @author Andy + */ +public class SolrBackupClient implements InitializingBean +{ + private static final Log logger = LogFactory.getLog(SolrBackupClient.class); + + // Lock key + private QName lock; + + private JobLockService jobLockService; + + private String remoteBackupLocation; + + private String core; + + private SOLRAdminClient solrAdminClient; + + + public void setSolrAdminClient(SOLRAdminClient solrAdminClient) + { + this.solrAdminClient = solrAdminClient; + } + + public void setCore(String core) + { + this.core = core; + } + + public void setJobLockService(JobLockService jobLockService) + { + this.jobLockService = jobLockService; + } + + public void setRemoteBackupLocation(String remoteBackupLocation) + { + this.remoteBackupLocation = remoteBackupLocation; + } + + public void execute() + { + + String lockToken = getLock(60000); + if (lockToken == null) + { + + } + // Use a flag to keep track of the running job + final AtomicBoolean running = new AtomicBoolean(true); + jobLockService.refreshLock(lockToken, lock, 30000, new JobLockRefreshCallback() + { + @Override + public boolean isActive() + { + return running.get(); + } + + @Override + public void lockReleased() + { + running.set(false); + } + }); + try + { + executeImpl(running); + } + catch (RuntimeException e) + { + throw e; + } + finally + { + // The lock will self-release if answer isActive in the negative + running.set(false); + jobLockService.releaseLock(lockToken, lock); + } + } + + /** + * @param running + */ + private void executeImpl(AtomicBoolean running) + { + if((remoteBackupLocation == null) || (remoteBackupLocation.length() == 0)) + { + if(logger.isInfoEnabled()) + { + logger.info("Back up of SOLR core skipped - no remote backup localtion set for: "+core); + } + } + + try + { + ModifiableSolrParams params = new ModifiableSolrParams(); + params.set("qt", "/"+core+"/replication"); + params.set("command", "backup"); + params.set("location", remoteBackupLocation); + + QueryResponse response = solrAdminClient.query(params); + + + if(logger.isInfoEnabled()) + { + logger.info("Back up of SOLR core completed: "+core); + } + + } + catch(SolrServerException e) + { + throw new AlfrescoRuntimeException("Bakup for core "+core+ " feailed .... ", e); + } + + } + + private String getLock(long time) + { + try + { + return jobLockService.getLock(lock, time); + } + catch (LockAcquisitionException e) + { + return null; + } + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() throws Exception + { + lock = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "SolrBackupClient-"+core); + + } +} diff --git a/source/java/org/alfresco/repo/search/impl/solr/SolrBackupJob.java b/source/java/org/alfresco/repo/search/impl/solr/SolrBackupJob.java new file mode 100644 index 0000000000..68b7247fd1 --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/solr/SolrBackupJob.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.search.impl.solr; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +/** + * Triggers the back up of SOLR stores (the back up is made on the remote SOLR server) + * {@link org.alfresco.repo.content.cleanup.ContentStoreCleaner}. + *

+ * The following parameters are required: + *

    + *
  • solrBackupClient: The content store cleaner bean
  • + *
+ * + * @author Andy hind + */ +public class SolrBackupJob implements Job +{ + public SolrBackupJob() + { + } + + /** + * Calls the cleaner to do its work + */ + public void execute(JobExecutionContext context) throws JobExecutionException + { + JobDataMap jobData = context.getJobDetail().getJobDataMap(); + // extract the SOLR backup client to use + Object solrBackupClientObj = jobData.get("solrBackupClient"); + if (solrBackupClientObj == null || !(solrBackupClientObj instanceof SolrBackupClient)) + { + throw new AlfrescoRuntimeException( + "SolrBackupJob data must contain valid 'solrBackupClient' reference"); + } + SolrBackupClient solrBackupClient = (SolrBackupClient) solrBackupClientObj; + solrBackupClient.execute(); + } +}