/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2010, Red Hat, Inc. and/or its affiliates or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat, Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program 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 this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.hibernate.search.test.directoryProvider; import java.io.File; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; import org.apache.lucene.queryParser.QueryParser; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.HibernateException; import org.hibernate.cfg.Configuration; import org.hibernate.search.FullTextSession; import org.hibernate.search.Search; import org.hibernate.search.SearchException; import org.hibernate.search.test.TestConstants; import org.hibernate.search.util.impl.FileHelper; import org.hibernate.search.util.logging.impl.Log; import org.hibernate.search.util.logging.impl.LoggerFactory; /** * Test case for master/slave directories. * * @author Emmanuel Bernard * @author Hardy Ferentschik */ public class FSSlaveAndMasterDPTest extends MultipleSFTestCase { private static final Log log = LoggerFactory.make(); /** * The lucene index directory which is shared between master and slave. */ final static String masterCopy = "/master/copy"; /** * The lucene index directory which is specific to the master node. */ final static String masterMain = "/master/main"; /** * The lucene index directory which is specific to the slave node. */ final static String slave = "/slave"; /** * The lucene index directory which is specific to the slave node. */ final static String slaveUnready = "/slaveUnready"; private File root; /** * Verifies that copies of the master get properly copied to the slaves. * * @throws Exception in case the test fails. */ public void testProperCopy() throws Exception { // assert that the slave index is empty FullTextSession fullTextSession = Search.getFullTextSession( getSlaveSession() ); Transaction tx = fullTextSession.beginTransaction(); QueryParser parser = new QueryParser( getTargetLuceneVersion(), "id", TestConstants.stopAnalyzer ); List result = fullTextSession.createFullTextQuery( parser.parse( "location:texas" ) ).list(); assertEquals( "No copy yet, fresh index expected", 0, result.size() ); tx.commit(); fullTextSession.close(); // create an entity on the master and persist it in order to index it Session session = getMasterSession(); tx = session.beginTransaction(); SnowStorm sn = new SnowStorm(); sn.setDate( new Date() ); sn.setLocation( "Dallas, TX, USA" ); session.persist( sn ); tx.commit(); session.close(); int waitPeriodMilli = 2010; // wait a bit more than 2 refresh periods (one master / one slave) - 2 * 1 * 1000 + 10 Thread.sleep( waitPeriodMilli ); // assert that the master has indexed the snowstorm log.debug( "Searching master" ); fullTextSession = Search.getFullTextSession( getMasterSession() ); tx = fullTextSession.beginTransaction(); result = fullTextSession.createFullTextQuery( parser.parse( "location:dallas" ) ).list(); assertEquals( "Original should get one", 1, result.size() ); tx.commit(); fullTextSession.close(); // assert that index got copied to the salve as well log.debug( "Searching slave" ); fullTextSession = Search.getFullTextSession( getSlaveSession() ); tx = fullTextSession.beginTransaction(); result = fullTextSession.createFullTextQuery( parser.parse( "location:dallas" ) ).list(); assertEquals( "First copy did not work out", 1, result.size() ); tx.commit(); fullTextSession.close(); // add a new snowstorm to the master session = getMasterSession(); tx = session.beginTransaction(); sn = new SnowStorm(); sn.setDate( new Date() ); sn.setLocation( "Chennai, India" ); session.persist( sn ); tx.commit(); session.close(); Thread.sleep( waitPeriodMilli ); //wait a bit more than 2 refresh (one master / one slave) // assert that the new snowstorm made it into the slave log.debug( "Searching slave" ); fullTextSession = Search.getFullTextSession( getSlaveSession() ); tx = fullTextSession.beginTransaction(); result = fullTextSession.createFullTextQuery( parser.parse( "location:chennai" ) ).list(); assertEquals( "Second copy did not work out", 1, result.size() ); tx.commit(); fullTextSession.close(); session = getMasterSession(); tx = session.beginTransaction(); sn = new SnowStorm(); sn.setDate( new Date() ); sn.setLocation( "Melbourne, Australia" ); session.persist( sn ); tx.commit(); session.close(); Thread.sleep( waitPeriodMilli ); //wait a bit more than 2 refresh (one master / one slave) // once more - assert that the new snowstorm made it into the slave log.debug( "Searching slave" ); fullTextSession = Search.getFullTextSession( getSlaveSession() ); tx = fullTextSession.beginTransaction(); result = fullTextSession.createFullTextQuery( parser.parse( "location:melbourne" ) ).list(); assertEquals( "Third copy did not work out", 1, result.size() ); tx.commit(); fullTextSession.close(); } private Session getMasterSession() { return getSessionFactories()[0].openSession(); } private Session getSlaveSession() { return getSessionFactories()[1].openSession(); } static File prepareDirectories(String testId) { String superRootPath = TestConstants.getIndexDirectory(); File root = new File( superRootPath, testId ); if ( root.exists() ) { FileHelper.delete( root ); } if ( !root.mkdirs() ) { throw new HibernateException( "Unable to setup test directories" ); } File master = new File( root, masterMain ); if ( !master.mkdirs() ) { throw new HibernateException( "Unable to setup master directory" ); } master = new File( root, masterCopy ); if ( !master.mkdirs() ) { throw new HibernateException( "Unable to setup master copy directory" ); } File slaveFile = new File( root, slave ); if ( !slaveFile.mkdirs() ) { throw new HibernateException( "Unable to setup slave directory" ); } File slaveUnreadyFile = new File( root, slaveUnready ); if ( !slaveUnreadyFile.mkdirs() ) { throw new HibernateException( "Unable to setup slave directory" ); } return root; } protected void setUp() throws Exception { this.root = prepareDirectories( getClass().getSimpleName() + "." + this.getName() ); super.setUp(); } protected void tearDown() throws Exception { super.tearDown(); cleanupDirectories( root ); } static void cleanupDirectories( File root ) { log.debugf( "Deleting test directory %s ", root.getAbsolutePath() ); FileHelper.delete( root ); } protected int getSFNbrs() { return 2; } protected Class<?>[] getAnnotatedClasses() { return new Class[] { SnowStorm.class }; } public void testSourceNotReady() throws Exception { int retries = 1; Configuration cfg = new Configuration(); //slave(s) cfg.setProperty( "hibernate.search.default.sourceBase", root.getAbsolutePath() + masterCopy + "nooooot" ); cfg.setProperty( "hibernate.search.default.indexBase", root.getAbsolutePath() + slave ); cfg.setProperty( "hibernate.search.default.refresh", "1" ); //every second cfg.setProperty( "hibernate.search.lucene_version", "LUCENE_CURRENT" ); cfg.setProperty( "hibernate.search.default.directory_provider", "filesystem-slave" ); cfg.setProperty( "hibernate.search.default.retry_marker_lookup", String.valueOf( retries ) ); cfg.addAnnotatedClass( SnowStorm.class ); long start = System.nanoTime(); try { cfg.buildSessionFactory(); } catch ( SearchException e ) { final long elapsedTime = TimeUnit.NANOSECONDS.toSeconds( System.nanoTime() - start ); assertTrue( "Should be around 10 seconds: " + elapsedTime, elapsedTime > retries*5 - 1 ); // -1 for safety } } protected void configure(Configuration[] cfg) { //master cfg[0].setProperty( "hibernate.search.default.sourceBase", root.getAbsolutePath() + masterCopy ); cfg[0].setProperty( "hibernate.search.default.indexBase", root.getAbsolutePath() + masterMain ); cfg[0].setProperty( "hibernate.search.default.refresh", "1" ); //every second cfg[0].setProperty( "hibernate.search.lucene_version", "LUCENE_CURRENT" ); cfg[0].setProperty( "hibernate.search.default.directory_provider", "filesystem-master" ); //slave(s) cfg[1].setProperty( "hibernate.search.default.sourceBase", root.getAbsolutePath() + masterCopy ); cfg[1].setProperty( "hibernate.search.default.indexBase", root.getAbsolutePath() + slave ); cfg[1].setProperty( "hibernate.search.default.refresh", "1" ); //every second cfg[1].setProperty( "hibernate.search.lucene_version", "LUCENE_CURRENT" ); //keep the fqcn to make sure non short cut solutions still work cfg[1].setProperty( "hibernate.search.default.directory_provider", "filesystem-slave" ); } }