/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/journal/impl/SharedFilesystemJournalStorage.java $
* $Id: SharedFilesystemJournalStorage.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.journal.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.search.journal.api.JournalStorage;
import org.sakaiproject.search.journal.api.JournalStorageState;
import org.sakaiproject.search.transaction.api.IndexTransaction;
import org.sakaiproject.search.transaction.api.IndexTransactionException;
import org.sakaiproject.search.util.FileUtils;
/**
* @author ieb TODO Unit test
*/
public class SharedFilesystemJournalStorage implements JournalStorage
{
public void init()
{
}
public void destroy()
{
}
/**
* @author ieb
*/
private static class JournalStorageStateImpl implements JournalStorageState
{
protected File tmpZip;
protected File journalZip;
/**
* @param tmpZip
* @param journalZip
*/
public JournalStorageStateImpl(File tmpZip, File journalZip)
{
this.tmpZip = tmpZip;
this.journalZip = journalZip;
}
}
private static final Log log = LogFactory
.getLog(SharedFilesystemJournalStorage.class);
private JournalSettings journalSettings;
/**
* Tries to find the latest version of a shared transaction file, limiting
* to 1000 versions of any file. The last existing version is in the first
* element, the next file is in the second element.
*
* @param transactionId
* @return
*/
private File[] getTransactionFile(long transactionId)
{
File f = new File(journalSettings.getJournalLocation(), transactionId + ".zip");
File testFile = f;
int i = 0;
while (testFile.exists() && i < 1000)
{
f = testFile;
testFile = new File(journalSettings.getJournalLocation(), transactionId + "-"
+ i + ".zip");
i++;
}
File[] result = new File[2];
result[0] = f;
result[1] = testFile;
if (log.isDebugEnabled())
{
log.debug("F0:" + result[0] + ":" + result[0].exists() + " F1:" + result[1]
+ ":" + result[1].exists());
}
return result;
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.journal.api.JournalStorage#prepareSave(java.lang.String,
* long)
*/
public JournalStorageState prepareSave(String location, long transactionId)
throws IOException
{
File indexLocation = new File(location);
log.info("++++++ Saving " + indexLocation + " to shared");
File tmpZip = new File(journalSettings.getJournalLocation(), transactionId
+ ".zip." + System.currentTimeMillis());
//this will fail if the parent dirs exist
if (!tmpZip.getParentFile().exists())
{
if (!tmpZip.getParentFile().mkdirs())
{
log.warn("Couldn't create directory " + tmpZip.getParentFile().getPath());
}
}
String basePath = indexLocation.getPath();
String replacePath = String.valueOf(transactionId);
FileOutputStream zout = new FileOutputStream(tmpZip);
FileUtils.pack(indexLocation, basePath, replacePath, zout, journalSettings
.getCompressShared());
zout.close();
File[] journalZip = getTransactionFile(transactionId);
// save into the new space
return new JournalStorageStateImpl(tmpZip, journalZip[1]);
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.journal.api.JournalStorage#commitSave(org.sakaiproject.search.journal.api.JournalStorageState)
*/
public void commitSave(JournalStorageState jss) throws IOException
{
File journalZip = ((JournalStorageStateImpl) jss).journalZip;
File tmpZip = ((JournalStorageStateImpl) jss).tmpZip;
if (!tmpZip.renameTo(journalZip))
{
log.warn("couldn't rename " + tmpZip.getPath() + " to " + journalZip.getPath());
}
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.journal.api.JournalStorage#rollbackSave(org.sakaiproject.search.journal.api.JournalStorageState)
*/
public void rollbackSave(JournalStorageState jss)
{
if (jss != null)
{
File journalZip = ((JournalStorageStateImpl) jss).journalZip;
File tmpZip = ((JournalStorageStateImpl) jss).tmpZip;
if (tmpZip != null && tmpZip.exists())
{
if (!tmpZip.delete())
{
log.warn("counldn't delete " + tmpZip.getPath());
}
}
if (journalZip != null && journalZip.exists())
{
if (!journalZip.delete())
{
log.warn("counldn't delete " + journalZip.getPath());
}
}
}
}
/**
* @throws IOException
* @throws IOException
* @see org.sakaiproject.search.maintanence.api.JournalStorage#retrieveLaterSavePoints(long[],
* java.lang.String)
*/
public void retrieveSavePoint(long savePoint, String workingSpace) throws IOException
{
File ws = new File(workingSpace);
if (!ws.exists())
{
if (!ws.mkdirs())
{
log.warn("Couldn't create directory " + ws.getPath());
}
}
File[] f = getTransactionFile(savePoint);
// retrieve the existing transaction file
if (!f[0].exists())
{
log.error("======================================= Lost Shared Segment ================= \n" +
"\t"+f[0] + "\n" +
"\tThe above file does not exist, this should not happen and should be investigated ");
}
else
{
FileInputStream source = new FileInputStream(f[0]);
try
{
FileUtils.unpack(source, ws);
}
finally
{
source.close();
}
}
}
/**
* @see org.sakaiproject.search.transaction.api.TransactionListener#close(org.sakaiproject.search.transaction.api.IndexTransaction)
*/
public void close(IndexTransaction transaction) throws IndexTransactionException
{
}
/**
* @param savePoint
* @param workingSpace
* @return
*/
public File getLocalJournalLocation(long savePoint, String workingSpace)
{
return new File(workingSpace, String.valueOf(savePoint));
}
/**
* @param savePoint
* @throws IOException
*/
public void removeJournal(long savePoint) throws IOException
{
File[] f = getTransactionFile(savePoint);
// remove all existing transaction versions
while (f[0].exists())
{
if (log.isDebugEnabled())
{
log.debug("Removing " + f[0]);
}
FileUtils.deleteAll(f[0]);
f = getTransactionFile(savePoint);
}
}
/**
* @return the journalSettings
*/
public JournalSettings getJournalSettings()
{
return journalSettings;
}
/**
* @param journalSettings
* the journalSettings to set
*/
public void setJournalSettings(JournalSettings journalSettings)
{
this.journalSettings = journalSettings;
}
}