Search in sources :

Example 1 with SourceDirectoryFactory

use of org.apache.lucene.replicator.ReplicationClient.SourceDirectoryFactory in project lucene-solr by apache.

the class IndexAndTaxonomyReplicationClientTest method testConsistencyOnExceptions.

/*
   * This test verifies that the client and handler do not end up in a corrupt
   * index if exceptions are thrown at any point during replication. Either when
   * a client copies files from the server to the temporary space, or when the
   * handler copies them to the index directory.
   */
@Test
public void testConsistencyOnExceptions() throws Exception {
    // so the handler's index isn't empty
    replicator.publish(createRevision(1));
    client.updateNow();
    client.close();
    callback.close();
    // wrap sourceDirFactory to return a MockDirWrapper so we can simulate errors
    final SourceDirectoryFactory in = sourceDirFactory;
    final AtomicInteger failures = new AtomicInteger(atLeast(10));
    sourceDirFactory = new SourceDirectoryFactory() {

        private long clientMaxSize = 100, handlerIndexMaxSize = 100, handlerTaxoMaxSize = 100;

        private double clientExRate = 1.0, handlerIndexExRate = 1.0, handlerTaxoExRate = 1.0;

        @Override
        public void cleanupSession(String sessionID) throws IOException {
            in.cleanupSession(sessionID);
        }

        @SuppressWarnings("synthetic-access")
        @Override
        public Directory getDirectory(String sessionID, String source) throws IOException {
            Directory dir = in.getDirectory(sessionID, source);
            if (random().nextBoolean() && failures.get() > 0) {
                // client should fail, return wrapped dir
                MockDirectoryWrapper mdw = new MockDirectoryWrapper(random(), dir);
                mdw.setRandomIOExceptionRateOnOpen(clientExRate);
                mdw.setMaxSizeInBytes(clientMaxSize);
                mdw.setRandomIOExceptionRate(clientExRate);
                mdw.setCheckIndexOnClose(false);
                clientMaxSize *= 2;
                clientExRate /= 2;
                return mdw;
            }
            if (failures.get() > 0 && random().nextBoolean()) {
                // handler should fail
                if (random().nextBoolean()) {
                    // index dir fail
                    handlerIndexDir.setMaxSizeInBytes(handlerIndexMaxSize);
                    handlerIndexDir.setRandomIOExceptionRate(handlerIndexExRate);
                    handlerIndexDir.setRandomIOExceptionRateOnOpen(handlerIndexExRate);
                    handlerIndexMaxSize *= 2;
                    handlerIndexExRate /= 2;
                } else {
                    // taxo dir fail
                    handlerTaxoDir.setMaxSizeInBytes(handlerTaxoMaxSize);
                    handlerTaxoDir.setRandomIOExceptionRate(handlerTaxoExRate);
                    handlerTaxoDir.setRandomIOExceptionRateOnOpen(handlerTaxoExRate);
                    handlerTaxoDir.setCheckIndexOnClose(false);
                    handlerTaxoMaxSize *= 2;
                    handlerTaxoExRate /= 2;
                }
            } else {
                // disable all errors
                handlerIndexDir.setMaxSizeInBytes(0);
                handlerIndexDir.setRandomIOExceptionRate(0.0);
                handlerIndexDir.setRandomIOExceptionRateOnOpen(0.0);
                handlerTaxoDir.setMaxSizeInBytes(0);
                handlerTaxoDir.setRandomIOExceptionRate(0.0);
                handlerTaxoDir.setRandomIOExceptionRateOnOpen(0.0);
            }
            return dir;
        }
    };
    handler = new IndexAndTaxonomyReplicationHandler(handlerIndexDir, handlerTaxoDir, new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            if (random().nextDouble() < 0.2 && failures.get() > 0) {
                throw new RuntimeException("random exception from callback");
            }
            return null;
        }
    });
    final AtomicBoolean failed = new AtomicBoolean();
    // wrap handleUpdateException so we can act on the thrown exception
    client = new ReplicationClient(replicator, handler, sourceDirFactory) {

        @SuppressWarnings("synthetic-access")
        @Override
        protected void handleUpdateException(Throwable t) {
            if (t instanceof IOException) {
                try {
                    if (VERBOSE) {
                        System.out.println("hit exception during update: " + t);
                        t.printStackTrace(System.out);
                    }
                    // test that the index can be read and also some basic statistics
                    DirectoryReader reader = DirectoryReader.open(handlerIndexDir.getDelegate());
                    try {
                        int numDocs = reader.numDocs();
                        int version = Integer.parseInt(reader.getIndexCommit().getUserData().get(VERSION_ID), 16);
                        assertEquals(numDocs, version);
                    } finally {
                        reader.close();
                    }
                    // verify index is fully consistent
                    TestUtil.checkIndex(handlerIndexDir.getDelegate());
                    // verify taxonomy index is fully consistent (since we only add one
                    // category to all documents, there's nothing much more to validate.
                    ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
                    CheckIndex.Status indexStatus = null;
                    try (CheckIndex checker = new CheckIndex(handlerTaxoDir.getDelegate())) {
                        checker.setFailFast(true);
                        checker.setInfoStream(new PrintStream(bos, false, IOUtils.UTF_8), false);
                        try {
                            indexStatus = checker.checkIndex(null);
                        } catch (IOException | RuntimeException ioe) {
                        // ok: we fallback below
                        }
                    }
                } catch (IOException e) {
                    failed.set(true);
                    throw new RuntimeException(e);
                } catch (RuntimeException e) {
                    failed.set(true);
                    throw e;
                } finally {
                    // count-down number of failures
                    failures.decrementAndGet();
                    assert failures.get() >= 0 : "handler failed too many times: " + failures.get();
                    if (VERBOSE) {
                        if (failures.get() == 0) {
                            System.out.println("no more failures expected");
                        } else {
                            System.out.println("num failures left: " + failures.get());
                        }
                    }
                }
            } else {
                failed.set(true);
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                }
                throw new RuntimeException(t);
            }
        }
    };
    client.startUpdateThread(10, "indexAndTaxo");
    final Directory baseHandlerIndexDir = handlerIndexDir.getDelegate();
    int numRevisions = atLeast(20) + 2;
    for (int i = 2; i < numRevisions && failed.get() == false; i++) {
        replicator.publish(createRevision(i));
        assertHandlerRevision(i, baseHandlerIndexDir);
    }
    // disable errors -- maybe randomness didn't exhaust all allowed failures,
    // and we don't want e.g. CheckIndex to hit false errors. 
    handlerIndexDir.setMaxSizeInBytes(0);
    handlerIndexDir.setRandomIOExceptionRate(0.0);
    handlerIndexDir.setRandomIOExceptionRateOnOpen(0.0);
    handlerTaxoDir.setMaxSizeInBytes(0);
    handlerTaxoDir.setRandomIOExceptionRate(0.0);
    handlerTaxoDir.setRandomIOExceptionRateOnOpen(0.0);
}
Also used : MockDirectoryWrapper(org.apache.lucene.store.MockDirectoryWrapper) PrintStream(java.io.PrintStream) SourceDirectoryFactory(org.apache.lucene.replicator.ReplicationClient.SourceDirectoryFactory) DirectoryReader(org.apache.lucene.index.DirectoryReader) IOException(java.io.IOException) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Callable(java.util.concurrent.Callable) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) CheckIndex(org.apache.lucene.index.CheckIndex) Directory(org.apache.lucene.store.Directory) Test(org.junit.Test)

Example 2 with SourceDirectoryFactory

use of org.apache.lucene.replicator.ReplicationClient.SourceDirectoryFactory in project lucene-solr by apache.

the class IndexReplicationClientTest method testConsistencyOnExceptions.

/*
   * This test verifies that the client and handler do not end up in a corrupt
   * index if exceptions are thrown at any point during replication. Either when
   * a client copies files from the server to the temporary space, or when the
   * handler copies them to the index directory.
   */
@Test
public void testConsistencyOnExceptions() throws Exception {
    // so the handler's index isn't empty
    replicator.publish(createRevision(1));
    client.updateNow();
    client.close();
    callback.close();
    // wrap sourceDirFactory to return a MockDirWrapper so we can simulate errors
    final SourceDirectoryFactory in = sourceDirFactory;
    final AtomicInteger failures = new AtomicInteger(atLeast(10));
    sourceDirFactory = new SourceDirectoryFactory() {

        private long clientMaxSize = 100, handlerMaxSize = 100;

        private double clientExRate = 1.0, handlerExRate = 1.0;

        @Override
        public void cleanupSession(String sessionID) throws IOException {
            in.cleanupSession(sessionID);
        }

        @SuppressWarnings("synthetic-access")
        @Override
        public Directory getDirectory(String sessionID, String source) throws IOException {
            Directory dir = in.getDirectory(sessionID, source);
            if (random().nextBoolean() && failures.get() > 0) {
                // client should fail, return wrapped dir
                MockDirectoryWrapper mdw = new MockDirectoryWrapper(random(), dir);
                mdw.setRandomIOExceptionRateOnOpen(clientExRate);
                mdw.setMaxSizeInBytes(clientMaxSize);
                mdw.setRandomIOExceptionRate(clientExRate);
                mdw.setCheckIndexOnClose(false);
                clientMaxSize *= 2;
                clientExRate /= 2;
                return mdw;
            }
            if (failures.get() > 0 && random().nextBoolean()) {
                // handler should fail
                handlerDir.setMaxSizeInBytes(handlerMaxSize);
                handlerDir.setRandomIOExceptionRateOnOpen(handlerExRate);
                handlerDir.setRandomIOExceptionRate(handlerExRate);
                handlerMaxSize *= 2;
                handlerExRate /= 2;
            } else {
                // disable errors
                handlerDir.setMaxSizeInBytes(0);
                handlerDir.setRandomIOExceptionRate(0.0);
                handlerDir.setRandomIOExceptionRateOnOpen(0.0);
            }
            return dir;
        }
    };
    handler = new IndexReplicationHandler(handlerDir, new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            if (random().nextDouble() < 0.2 && failures.get() > 0) {
                throw new RuntimeException("random exception from callback");
            }
            return null;
        }
    });
    // wrap handleUpdateException so we can act on the thrown exception
    client = new ReplicationClient(replicator, handler, sourceDirFactory) {

        @SuppressWarnings("synthetic-access")
        @Override
        protected void handleUpdateException(Throwable t) {
            if (t instanceof IOException) {
                if (VERBOSE) {
                    System.out.println("hit exception during update: " + t);
                    t.printStackTrace(System.out);
                }
                try {
                    // test that the index can be read and also some basic statistics
                    DirectoryReader reader = DirectoryReader.open(handlerDir.getDelegate());
                    try {
                        int numDocs = reader.numDocs();
                        int version = Integer.parseInt(reader.getIndexCommit().getUserData().get(VERSION_ID), 16);
                        assertEquals(numDocs, version);
                    } finally {
                        reader.close();
                    }
                    // verify index consistency
                    TestUtil.checkIndex(handlerDir.getDelegate());
                } catch (IOException e) {
                    // exceptions here are bad, don't ignore them
                    throw new RuntimeException(e);
                } finally {
                    // count-down number of failures
                    failures.decrementAndGet();
                    assert failures.get() >= 0 : "handler failed too many times: " + failures.get();
                    if (VERBOSE) {
                        if (failures.get() == 0) {
                            System.out.println("no more failures expected");
                        } else {
                            System.out.println("num failures left: " + failures.get());
                        }
                    }
                }
            } else {
                if (t instanceof RuntimeException)
                    throw (RuntimeException) t;
                throw new RuntimeException(t);
            }
        }
    };
    client.startUpdateThread(10, "index");
    final Directory baseHandlerDir = handlerDir.getDelegate();
    int numRevisions = atLeast(20);
    for (int i = 2; i < numRevisions; i++) {
        replicator.publish(createRevision(i));
        assertHandlerRevision(i, baseHandlerDir);
    }
    // disable errors -- maybe randomness didn't exhaust all allowed failures,
    // and we don't want e.g. CheckIndex to hit false errors. 
    handlerDir.setMaxSizeInBytes(0);
    handlerDir.setRandomIOExceptionRate(0.0);
    handlerDir.setRandomIOExceptionRateOnOpen(0.0);
}
Also used : MockDirectoryWrapper(org.apache.lucene.store.MockDirectoryWrapper) SourceDirectoryFactory(org.apache.lucene.replicator.ReplicationClient.SourceDirectoryFactory) DirectoryReader(org.apache.lucene.index.DirectoryReader) IOException(java.io.IOException) Callable(java.util.concurrent.Callable) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Directory(org.apache.lucene.store.Directory) Test(org.junit.Test)

Aggregations

IOException (java.io.IOException)2 Callable (java.util.concurrent.Callable)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 DirectoryReader (org.apache.lucene.index.DirectoryReader)2 SourceDirectoryFactory (org.apache.lucene.replicator.ReplicationClient.SourceDirectoryFactory)2 Directory (org.apache.lucene.store.Directory)2 MockDirectoryWrapper (org.apache.lucene.store.MockDirectoryWrapper)2 Test (org.junit.Test)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 PrintStream (java.io.PrintStream)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 CheckIndex (org.apache.lucene.index.CheckIndex)1