/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.apache.blur.lucene.index; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import java.net.URI; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.blur.store.hdfs.BlurLockFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.lucene.analysis.core.KeywordAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field.Store; import org.apache.lucene.document.StringField; import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.index.BlurIndexWriter; import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexableField; import org.apache.lucene.store.Directory; import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.InfoStream; import org.apache.lucene.util.Version; import org.junit.Test; public class BlurIndexWriterTest { private Configuration _configuration = new Configuration(); private final Object lock = new Object(); @Test public void testIndexRelocationFencing() throws CorruptIndexException, LockObtainFailedException, IOException, InterruptedException { final AtomicBoolean fail1 = new AtomicBoolean(); final AtomicBoolean fail2 = new AtomicBoolean(); final Path hdfsDirPath = new Path(toUri("./target/tmp/BlurIndexWriterTest")); final Directory directory = new RAMDirectory(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { BlurIndexWriter writer = null; try { BlurLockFactory blurLockFactory = new BlurLockFactory(_configuration, hdfsDirPath, "node1", "1"); directory.setLockFactory(blurLockFactory); IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_43, new KeywordAnalyzer()); conf.setInfoStream(getInfoStream()); writer = new BlurIndexWriter(directory, conf); writer.addIndexes(addDir("1")); waitToLooseLock(); writer.prepareCommit(); fail1.set(true); } catch (IOException e) { e.printStackTrace(); if (writer != null) { try { writer.rollback(); } catch (IOException e1) { e1.printStackTrace(); } } if (writer != null) { try { writer.close(); } catch (IOException e1) { e1.printStackTrace(); } } } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { try { waitForDirInThread1ToBeAdded(directory); BlurLockFactory blurLockFactory = new BlurLockFactory(_configuration, hdfsDirPath, "node2", "2"); directory.setLockFactory(blurLockFactory); IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_43, new KeywordAnalyzer()); conf.setInfoStream(getInfoStream()); BlurIndexWriter writer = new BlurIndexWriter(directory, conf); obtainLock(); writer.addIndexes(addDir("2")); writer.commit(); writer.close(); } catch (IOException e) { e.printStackTrace(); fail2.set(true); } } }); thread1.start(); thread2.start(); thread1.join(); thread2.join(); if (fail1.get()) { fail(); } if (fail2.get()) { fail(); } DirectoryReader reader = DirectoryReader.open(directory); List<AtomicReaderContext> leaves = reader.leaves(); assertEquals(leaves.size(), 1); assertEquals(reader.numDocs(), 1); Document document = reader.document(0); assertEquals("2", document.get("f")); reader.close(); } protected InfoStream getInfoStream() { return new InfoStream() { @Override public void close() throws IOException { } @Override public void message(String component, String message) { System.out.println("Thread [" + Thread.currentThread().getName() + "] Comp [" + component + "] Message [" + message + "]"); } @Override public boolean isEnabled(String component) { return false; } }; } private void waitForDirInThread1ToBeAdded(Directory directory) throws IOException { while (true) { String[] listAll = directory.listAll(); if (Arrays.asList(listAll).contains("_0.fnm")) { return; } try { Thread.sleep(100); } catch (InterruptedException e) { throw new IOException(e); } } } protected void waitToLooseLock() throws IOException { synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { throw new IOException(e); } } } private void obtainLock() { synchronized (lock) { lock.notify(); } } private Directory addDir(String v) throws IOException { RAMDirectory directory = new RAMDirectory(); IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_43, new KeywordAnalyzer()); IndexWriter writer = new IndexWriter(directory, config); writer.addDocument(getDoc(v)); writer.close(); return directory; } private Iterable<? extends IndexableField> getDoc(String v) { Document document = new Document(); document.add(new StringField("f", v, Store.YES)); return document; } private URI toUri(String f) { return new File(f).getAbsoluteFile().toURI(); } }