You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2017/08/18 08:04:49 UTC
[02/20] lucenenet git commit: LUCENENET-565: Porting of Lucene
Replicator - Commit is for Review with comments about original Java Source
for assistance.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
new file mode 100644
index 0000000..645888a
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
@@ -0,0 +1,518 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Lucene.Net.Documents;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Facet.Taxonomy.Directory;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Search;
+using Lucene.Net.Store;
+using Lucene.Net.Support;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Tests.Replicator
+{
+ [TestFixture]
+ public class IndexAndTaxonomyReplicationClientTest : ReplicatorTestCase
+ {
+ private class IndexAndTaxonomyReadyCallback : IDisposable
+ {
+ private Directory indexDir, taxoDir;
+ private DirectoryReader indexReader;
+ private DirectoryTaxonomyReader taxoReader;
+ private FacetsConfig config;
+ private long lastIndexGeneration = -1;
+
+ public IndexAndTaxonomyReadyCallback(MockDirectoryWrapper indexDir, MockDirectoryWrapper taxoDir)
+ {
+ this.indexDir = indexDir;
+ this.taxoDir = taxoDir;
+ config = new FacetsConfig();
+ config.SetHierarchical("A", true);
+ if (DirectoryReader.IndexExists(indexDir))
+ {
+ indexReader = DirectoryReader.Open(indexDir);
+ lastIndexGeneration = indexReader.IndexCommit.Generation;
+ taxoReader = new DirectoryTaxonomyReader(taxoDir);
+ }
+ }
+
+ public bool? Call()
+ {
+ if (indexReader == null)
+ {
+ indexReader = DirectoryReader.Open(indexDir);
+ lastIndexGeneration = indexReader.IndexCommit.Generation;
+ taxoReader = new DirectoryTaxonomyReader(taxoDir);
+ }
+ else
+ {
+ // verify search index
+ DirectoryReader newReader = DirectoryReader.OpenIfChanged(indexReader);
+ assertNotNull("should not have reached here if no changes were made to the index", newReader);
+ long newGeneration = newReader.IndexCommit.Generation;
+ assertTrue("expected newer generation; current=" + lastIndexGeneration + " new=" + newGeneration, newGeneration > lastIndexGeneration);
+ indexReader.Dispose();
+ indexReader = newReader;
+ lastIndexGeneration = newGeneration;
+ TestUtil.CheckIndex(indexDir);
+
+ // verify taxonomy index
+ DirectoryTaxonomyReader newTaxoReader = TaxonomyReader.OpenIfChanged(taxoReader);
+ if (newTaxoReader != null)
+ {
+ taxoReader.Dispose();
+ taxoReader = newTaxoReader;
+ }
+ TestUtil.CheckIndex(taxoDir);
+
+ // verify faceted search
+ int id = int.Parse(indexReader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber);
+ IndexSearcher searcher = new IndexSearcher(indexReader);
+ FacetsCollector fc = new FacetsCollector();
+ searcher.Search(new MatchAllDocsQuery(), fc);
+ Facets facets = new FastTaxonomyFacetCounts(taxoReader, config, fc);
+ assertEquals(1, (int)facets.GetSpecificValue("A", id.ToString("X")));
+
+ DrillDownQuery drillDown = new DrillDownQuery(config);
+ drillDown.Add("A", id.ToString("X"));
+ TopDocs docs = searcher.Search(drillDown, 10);
+ assertEquals(1, docs.TotalHits);
+ }
+ return null;
+ }
+
+ public void Dispose()
+ {
+ IOUtils.Dispose(indexReader, taxoReader);
+ }
+ }
+
+ private Directory publishIndexDir, publishTaxoDir;
+ private MockDirectoryWrapper handlerIndexDir, handlerTaxoDir;
+ private IReplicator replicator;
+ private ISourceDirectoryFactory sourceDirFactory;
+ private ReplicationClient client;
+ private IReplicationHandler handler;
+ private IndexWriter publishIndexWriter;
+ private IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter publishTaxoWriter;
+ private FacetsConfig config;
+ private IndexAndTaxonomyReadyCallback callback;
+ private DirectoryInfo clientWorkDir;
+
+ private const string VERSION_ID = "version";
+
+ private void AssertHandlerRevision(int expectedId, Directory dir)
+ {
+ //JAVA: private void assertHandlerRevision(int expectedID, Directory dir) throws IOException {
+ //JAVA: // loop as long as client is alive. test-framework will terminate us if
+ //JAVA: // there's a serious bug, e.g. client doesn't really update. otherwise,
+ //JAVA: // introducing timeouts is not good, can easily lead to false positives.
+ //JAVA: while (client.isUpdateThreadAlive()) {
+ //JAVA: // give client a chance to update
+ //JAVA: try {
+ //JAVA: Thread.sleep(100);
+ //JAVA: } catch (InterruptedException e) {
+ //JAVA: throw new ThreadInterruptedException(e);
+ //JAVA: }
+ //JAVA:
+ //JAVA: try {
+ //JAVA: DirectoryReader reader = DirectoryReader.open(dir);
+ //JAVA: try {
+ //JAVA: int handlerID = Integer.parseInt(reader.getIndexCommit().getUserData().get(VERSION_ID), 16);
+ //JAVA: if (expectedID == handlerID) {
+ //JAVA: return;
+ //JAVA: }
+ //JAVA: } finally {
+ //JAVA: reader.close();
+ //JAVA: }
+ //JAVA: } catch (Exception e) {
+ //JAVA: // we can hit IndexNotFoundException or e.g. EOFException (on
+ //JAVA: // segments_N) because it is being copied at the same time it is read by
+ //JAVA: // DirectoryReader.open().
+ //JAVA: }
+ //JAVA: }
+ //JAVA: }
+
+ // loop as long as client is alive. test-framework will terminate us if
+ // there's a serious bug, e.g. client doesn't really update. otherwise,
+ // introducing timeouts is not good, can easily lead to false positives.
+ while (client.IsUpdateThreadAlive)
+ {
+ Thread.Sleep(100);
+
+ try
+ {
+ DirectoryReader reader = DirectoryReader.Open(dir);
+ try
+ {
+ int handlerId = int.Parse(reader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber);
+ if (expectedId == handlerId)
+ {
+ return;
+ }
+ }
+ finally
+ {
+ reader.Dispose();
+ }
+ }
+ catch (Exception)
+ {
+ // we can hit IndexNotFoundException or e.g. EOFException (on
+ // segments_N) because it is being copied at the same time it is read by
+ // DirectoryReader.open().
+ }
+ }
+ }
+
+ private IRevision CreateRevision(int id)
+ {
+ //JAVA: private Revision createRevision(final int id) throws IOException {
+ //JAVA: publishIndexWriter.addDocument(newDocument(publishTaxoWriter, id));
+ //JAVA: publishIndexWriter.setCommitData(new HashMap<String, String>() {{
+ //JAVA: put(VERSION_ID, Integer.toString(id, 16));
+ //JAVA: }});
+ //JAVA: publishIndexWriter.commit();
+ //JAVA: publishTaxoWriter.commit();
+ //JAVA: return new IndexAndTaxonomyRevision(publishIndexWriter, publishTaxoWriter);
+ //JAVA: }
+ publishIndexWriter.AddDocument(NewDocument(publishTaxoWriter, id));
+ publishIndexWriter.SetCommitData(new Dictionary<string, string>{
+ { VERSION_ID, id.ToString("X") }
+ });
+ publishIndexWriter.Commit();
+ publishTaxoWriter.Commit();
+ return new IndexAndTaxonomyRevision(publishIndexWriter, publishTaxoWriter);
+ }
+
+ private Document NewDocument(ITaxonomyWriter taxoWriter, int id)
+ {
+ Document doc = new Document();
+ doc.Add(new FacetField("A", id.ToString("X")));
+ return config.Build(taxoWriter, doc);
+ }
+
+ public override void SetUp()
+ {
+ base.SetUp();
+
+ publishIndexDir = NewDirectory();
+ publishTaxoDir = NewDirectory();
+ handlerIndexDir = NewMockDirectory();
+ handlerTaxoDir = NewMockDirectory();
+ clientWorkDir = CreateTempDir("replicationClientTest");
+ sourceDirFactory = new PerSessionDirectoryFactory(clientWorkDir.FullName);
+ replicator = new LocalReplicator();
+ callback = new IndexAndTaxonomyReadyCallback(handlerIndexDir, handlerTaxoDir);
+ handler = new IndexAndTaxonomyReplicationHandler(handlerIndexDir, handlerTaxoDir, callback.Call);
+ client = new ReplicationClient(replicator, handler, sourceDirFactory);
+
+ IndexWriterConfig conf = NewIndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ publishIndexWriter = new IndexWriter(publishIndexDir, conf);
+ publishTaxoWriter = new IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter(publishTaxoDir);
+ config = new FacetsConfig();
+ config.SetHierarchical("A", true);
+ }
+
+ public override void TearDown()
+ {
+ IOUtils.Dispose(client, callback, publishIndexWriter, publishTaxoWriter, replicator, publishIndexDir, publishTaxoDir,
+ handlerIndexDir, handlerTaxoDir);
+ base.TearDown();
+ }
+
+ [Test]
+ public void TestNoUpdateThread()
+ {
+ assertNull("no version expected at start", handler.CurrentVersion);
+
+ // Callback validates the replicated index
+ replicator.Publish(CreateRevision(1));
+ client.UpdateNow();
+
+ // make sure updating twice, when in fact there's nothing to update, works
+ client.UpdateNow();
+
+ replicator.Publish(CreateRevision(2));
+ client.UpdateNow();
+
+ // Publish two revisions without update, handler should be upgraded to latest
+ replicator.Publish(CreateRevision(3));
+ replicator.Publish(CreateRevision(4));
+ client.UpdateNow();
+ }
+
+ [Test]
+ public void TestRestart()
+ {
+ replicator.Publish(CreateRevision(1));
+ client.UpdateNow();
+
+ replicator.Publish(CreateRevision(2));
+ client.UpdateNow();
+
+ client.StopUpdateThread();
+ client.Dispose();
+ client = new ReplicationClient(replicator, handler, sourceDirFactory);
+
+ // Publish two revisions without update, handler should be upgraded to latest
+ replicator.Publish(CreateRevision(3));
+ replicator.Publish(CreateRevision(4));
+ client.UpdateNow();
+ }
+
+ [Test]
+ public void TestUpdateThread()
+ {
+ client.StartUpdateThread(10, "indexTaxo");
+
+ replicator.Publish(CreateRevision(1));
+ AssertHandlerRevision(1, handlerIndexDir);
+
+ replicator.Publish(CreateRevision(2));
+ AssertHandlerRevision(2, handlerIndexDir);
+
+ // Publish two revisions without update, handler should be upgraded to latest
+ replicator.Publish(CreateRevision(3));
+ replicator.Publish(CreateRevision(4));
+ AssertHandlerRevision(4, handlerIndexDir);
+ }
+
+ [Test]
+ public void TestRecreateTaxonomy()
+ {
+ replicator.Publish(CreateRevision(1));
+ client.UpdateNow();
+
+ // recreate index and taxonomy
+ Directory newTaxo = NewDirectory();
+ new DirectoryTaxonomyWriter(newTaxo).Dispose();
+ publishTaxoWriter.ReplaceTaxonomy(newTaxo);
+ publishIndexWriter.DeleteAll();
+ replicator.Publish(CreateRevision(2));
+
+ client.UpdateNow();
+ newTaxo.Dispose();
+ }
+
+ //JAVA: /*
+ //JAVA: * This test verifies that the client and handler do not end up in a corrupt
+ //JAVA: * index if exceptions are thrown at any point during replication. Either when
+ //JAVA: * a client copies files from the server to the temporary space, or when the
+ //JAVA: * handler copies them to the index directory.
+ //JAVA: */
+ [Test]
+ public void TestConsistencyOnExceptions()
+ {
+ // so the handler's index isn't empty
+ replicator.Publish(CreateRevision(1));
+ client.UpdateNow();
+ client.Dispose();
+ callback.Dispose();
+
+ // Replicator violates write-once policy. It may be that the
+ // handler copies files to the index dir, then fails to copy a
+ // file and reverts the copy operation. On the next attempt, it
+ // will copy the same file again. There is nothing wrong with this
+ // in a real system, but it does violate write-once, and MDW
+ // doesn't like it. Disabling it means that we won't catch cases
+ // where the handler overwrites an existing index file, but
+ // there's nothing currently we can do about it, unless we don't
+ // use MDW.
+ handlerIndexDir.PreventDoubleWrite=(false);
+ handlerTaxoDir.PreventDoubleWrite = (false);
+
+ // wrap sourceDirFactory to return a MockDirWrapper so we can simulate errors
+ ISourceDirectoryFactory @in = sourceDirFactory;
+ AtomicInt32 failures = new AtomicInt32(AtLeast(10));
+
+ sourceDirFactory = new SourceDirectoryFactoryAnonymousInnerClass(this, @in, failures);
+ handler = new IndexAndTaxonomyReplicationHandler(handlerIndexDir, handlerTaxoDir, () =>
+ {
+ if (Random().NextDouble() < 0.2 && failures.Get() > 0)
+ throw new Exception("random exception from callback");
+ return null;
+ });
+ client = new ReplicationClientAnonymousInnerClass(this, replicator, handler, @in, failures);
+ client.StartUpdateThread(10, "indexAndTaxo");
+
+ Directory baseHandlerIndexDir = handlerIndexDir.Delegate;
+ int numRevisions = AtLeast(20) + 2;
+ for (int i = 2; i < numRevisions; 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.MaxSizeInBytes=(0);
+ handlerIndexDir.RandomIOExceptionRate=(0.0);
+ handlerIndexDir.RandomIOExceptionRateOnOpen=(0.0);
+ handlerTaxoDir.MaxSizeInBytes=(0);
+ handlerTaxoDir.RandomIOExceptionRate=(0.0);
+ handlerTaxoDir.RandomIOExceptionRateOnOpen=(0.0);
+ }
+
+ private class SourceDirectoryFactoryAnonymousInnerClass : ISourceDirectoryFactory
+ {
+ private long clientMaxSize = 100, handlerIndexMaxSize = 100, handlerTaxoMaxSize = 100;
+ private double clientExRate = 1.0, handlerIndexExRate = 1.0, handlerTaxoExRate = 1.0;
+
+ private readonly IndexAndTaxonomyReplicationClientTest test;
+ private readonly ISourceDirectoryFactory @in;
+ private readonly AtomicInt32 failures;
+
+ public SourceDirectoryFactoryAnonymousInnerClass(IndexAndTaxonomyReplicationClientTest test, ISourceDirectoryFactory @in, AtomicInt32 failures)
+ {
+ this.test = test;
+ this.@in = @in;
+ this.failures = failures;
+ }
+
+ public void CleanupSession(string sessionId)
+ {
+ @in.CleanupSession(sessionId);
+ }
+
+ public Directory GetDirectory(string sessionId, string source)
+ {
+ 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.RandomIOExceptionRateOnOpen = clientExRate;
+ mdw.MaxSizeInBytes = clientMaxSize;
+ mdw.RandomIOExceptionRate = clientExRate;
+ mdw.CheckIndexOnClose = false;
+ clientMaxSize *= 2;
+ clientExRate /= 2;
+ return mdw;
+ }
+
+ if (failures.Get() > 0 && Random().nextBoolean())
+ { // handler should fail
+ if (Random().nextBoolean())
+ { // index dir fail
+ test.handlerIndexDir.MaxSizeInBytes=(handlerIndexMaxSize);
+ test.handlerIndexDir.RandomIOExceptionRate = (handlerIndexExRate);
+ test.handlerIndexDir.RandomIOExceptionRateOnOpen = (handlerIndexExRate);
+ handlerIndexMaxSize *= 2;
+ handlerIndexExRate /= 2;
+ }
+ else
+ { // taxo dir fail
+ test.handlerTaxoDir.MaxSizeInBytes = (handlerTaxoMaxSize);
+ test.handlerTaxoDir.RandomIOExceptionRate = (handlerTaxoExRate);
+ test.handlerTaxoDir.RandomIOExceptionRateOnOpen = (handlerTaxoExRate);
+ test.handlerTaxoDir.CheckIndexOnClose = (false);
+ handlerTaxoMaxSize *= 2;
+ handlerTaxoExRate /= 2;
+ }
+ }
+ else
+ {
+ // disable all errors
+ test.handlerIndexDir.MaxSizeInBytes = (0);
+ test.handlerIndexDir.RandomIOExceptionRate = (0.0);
+ test.handlerIndexDir.RandomIOExceptionRateOnOpen = (0.0);
+ test.handlerTaxoDir.MaxSizeInBytes = (0);
+ test.handlerTaxoDir.RandomIOExceptionRate = (0.0);
+ test.handlerTaxoDir.RandomIOExceptionRateOnOpen = (0.0);
+ }
+ return dir;
+ }
+ }
+
+
+
+ private class ReplicationClientAnonymousInnerClass : ReplicationClient
+ {
+ private readonly IndexAndTaxonomyReplicationClientTest test;
+ private readonly AtomicInt32 failures;
+
+ public ReplicationClientAnonymousInnerClass(IndexAndTaxonomyReplicationClientTest test, IReplicator replicator, IReplicationHandler handler, ISourceDirectoryFactory factory, AtomicInt32 failures)
+ : base(replicator, handler, factory)
+ {
+ this.test = test;
+ this.failures = failures;
+ }
+
+ protected override void HandleUpdateException(Exception exception)
+ {
+ if (exception is IOException)
+ {
+ try
+ {
+ if (VERBOSE)
+ {
+ Console.WriteLine("hit exception during update: " + exception);
+ }
+
+ // test that the index can be read and also some basic statistics
+ DirectoryReader reader = DirectoryReader.Open(test.handlerIndexDir.Delegate);
+ try
+ {
+ int numDocs = reader.NumDocs;
+ int version = int.Parse(reader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber);
+ assertEquals(numDocs, version);
+ }
+ finally
+ {
+ reader.Dispose();
+ }
+ // verify index consistency
+ TestUtil.CheckIndex(test.handlerIndexDir.Delegate);
+
+ // verify taxonomy index is fully consistent (since we only add one
+ // category to all documents, there's nothing much more to validate
+ TestUtil.CheckIndex(test.handlerTaxoDir.Delegate);
+ }
+ //TODO: Java had this, but considering what it does do we need it?
+ //JAVA: catch (IOException e)
+ //JAVA: {
+ //JAVA: throw new RuntimeException(e);
+ //JAVA: }
+ finally
+ {
+ // count-down number of failures
+ failures.DecrementAndGet();
+ Debug.Assert(failures.Get() >= 0, "handler failed too many times: " + failures.Get());
+ if (VERBOSE)
+ {
+ if (failures.Get() == 0)
+ {
+ Console.WriteLine("no more failures expected");
+ }
+ else
+ {
+ Console.WriteLine("num failures left: " + failures.Get());
+ }
+ }
+ }
+ }
+ else
+ {
+ //JAVA: if (t instanceof RuntimeException) throw (RuntimeException) t;
+ //JAVA: throw new RuntimeException(t);
+ throw exception;
+ }
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
new file mode 100644
index 0000000..dd20864
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
@@ -0,0 +1,188 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Lucene.Net.Documents;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using NUnit.Framework;
+
+namespace Lucene.Net.Tests.Replicator
+{
+ /*
+ * 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.
+ */
+
+ public class IndexAndTaxonomyRevisionTest : ReplicatorTestCase
+ {
+ private Document NewDocument(ITaxonomyWriter taxoWriter)
+ {
+ FacetsConfig config = new FacetsConfig();
+ Document doc = new Document();
+ doc.Add(new FacetField("A", "1"));
+ return config.Build(taxoWriter, doc);
+ }
+
+ [Test]
+ public void TestNoCommit()
+ {
+ Directory indexDir = NewDirectory();
+ IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ IndexWriter indexWriter = new IndexWriter(indexDir, conf);
+
+ Directory taxoDir = NewDirectory();
+ IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter taxoWriter = new IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter(taxoDir);
+ try
+ {
+ assertNotNull(new IndexAndTaxonomyRevision(indexWriter, taxoWriter));
+ fail("should have failed when there are no commits to snapshot");
+ }
+ catch (System.InvalidOperationException)
+ {
+ // expected
+ }
+ finally
+ {
+ IOUtils.Dispose(indexWriter, taxoWriter, taxoDir, indexDir);
+ }
+ }
+
+ [Test]
+ public void TestRevisionRelease()
+ {
+ Directory indexDir = NewDirectory();
+ IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ IndexWriter indexWriter = new IndexWriter(indexDir, conf);
+
+ Directory taxoDir = NewDirectory();
+ IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter taxoWriter = new IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter(taxoDir);
+ try
+ {
+ indexWriter.AddDocument(NewDocument(taxoWriter));
+ indexWriter.Commit();
+ taxoWriter.Commit();
+ IRevision rev1 = new IndexAndTaxonomyRevision(indexWriter, taxoWriter);
+ // releasing that revision should not delete the files
+ rev1.Release();
+ assertTrue(SlowFileExists(indexDir, IndexFileNames.SEGMENTS + "_1"));
+ assertTrue(SlowFileExists(taxoDir, IndexFileNames.SEGMENTS + "_1"));
+
+ rev1 = new IndexAndTaxonomyRevision(indexWriter, taxoWriter); // create revision again, so the files are snapshotted
+ indexWriter.AddDocument(NewDocument(taxoWriter));
+ indexWriter.Commit();
+ taxoWriter.Commit();
+ assertNotNull(new IndexAndTaxonomyRevision(indexWriter, taxoWriter));
+ rev1.Release(); // this release should trigger the delete of segments_1
+ assertFalse(SlowFileExists(indexDir, IndexFileNames.SEGMENTS + "_1"));
+ }
+ finally
+ {
+ IOUtils.Dispose(indexWriter, taxoWriter, taxoDir, indexDir);
+ }
+ }
+
+ [Test]
+ public void TestSegmentsFileLast()
+ {
+ Directory indexDir = NewDirectory();
+ IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ IndexWriter indexWriter = new IndexWriter(indexDir, conf);
+
+ Directory taxoDir = NewDirectory();
+ IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter taxoWriter = new IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter(taxoDir);
+ try
+ {
+ indexWriter.AddDocument(NewDocument(taxoWriter));
+ indexWriter.Commit();
+ taxoWriter.Commit();
+ IRevision rev = new IndexAndTaxonomyRevision(indexWriter, taxoWriter);
+ var sourceFiles = rev.SourceFiles;
+ assertEquals(2, sourceFiles.Count);
+ foreach (var files in sourceFiles.Values)
+ {
+ string lastFile = files.Last().FileName;
+ assertTrue(lastFile.StartsWith(IndexFileNames.SEGMENTS, StringComparison.Ordinal) && !lastFile.Equals(IndexFileNames.SEGMENTS_GEN));
+ }
+ }
+ finally
+ {
+ IOUtils.Dispose(indexWriter, taxoWriter, taxoDir, indexDir);
+ }
+ }
+
+ [Test]
+ public void TestOpen()
+ {
+ Directory indexDir = NewDirectory();
+ IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ IndexWriter indexWriter = new IndexWriter(indexDir, conf);
+
+ Directory taxoDir = NewDirectory();
+ IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter taxoWriter = new IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter(taxoDir);
+ try
+ {
+ indexWriter.AddDocument(NewDocument(taxoWriter));
+ indexWriter.Commit();
+ taxoWriter.Commit();
+ IRevision rev = new IndexAndTaxonomyRevision(indexWriter, taxoWriter);
+ foreach (var e in rev.SourceFiles)
+ {
+ string source = e.Key;
+ Directory dir = source.Equals(IndexAndTaxonomyRevision.INDEX_SOURCE) ? indexDir : taxoDir;
+ foreach (RevisionFile file in e.Value)
+ {
+ IndexInput src = dir.OpenInput(file.FileName, IOContext.READ_ONCE);
+ System.IO.Stream @in = rev.Open(source, file.FileName);
+ assertEquals(src.Length, @in.Length);
+ byte[] srcBytes = new byte[(int)src.Length];
+ byte[] inBytes = new byte[(int)src.Length];
+ int offset = 0;
+ if (Random().nextBoolean())
+ {
+ int skip = Random().Next(10);
+ if (skip >= src.Length)
+ {
+ skip = 0;
+ }
+ //JAVA: in.skip(skip);
+ byte[] skips = new byte[skip];
+ @in.Read(skips, 0, skip);
+ src.Seek(skip);
+ offset = skip;
+ }
+ src.ReadBytes(srcBytes, offset, srcBytes.Length - offset);
+ @in.Read(inBytes, offset, inBytes.Length - offset);
+ assertArrayEquals(srcBytes, inBytes);
+ IOUtils.Dispose(src, @in);
+ }
+ }
+ }
+ finally
+ {
+ IOUtils.Dispose(indexWriter, taxoWriter, taxoDir, indexDir);
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
new file mode 100644
index 0000000..6a56c77
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
@@ -0,0 +1,513 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Threading;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Store;
+using Lucene.Net.Support;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Tests.Replicator
+{
+ [TestFixture]
+ public class IndexReplicationClientTest : ReplicatorTestCase
+ {
+ private class IndexReadyCallback : IDisposable
+ {
+ private readonly Directory indexDir;
+ private DirectoryReader reader;
+ private long lastGeneration = -1;
+
+ public IndexReadyCallback(Directory indexDir)
+ {
+ //JAVA: public IndexReadyCallback(Directory indexDir) throws IOException {
+ //JAVA: this.indexDir = indexDir;
+ //JAVA: if (DirectoryReader.indexExists(indexDir)) {
+ //JAVA: reader = DirectoryReader.open(indexDir);
+ //JAVA: lastGeneration = reader.getIndexCommit().getGeneration();
+ //JAVA: }
+ //JAVA: }
+
+ this.indexDir = indexDir;
+ if (DirectoryReader.IndexExists(indexDir))
+ {
+ reader = DirectoryReader.Open(indexDir);
+ lastGeneration = reader.IndexCommit.Generation;
+ }
+ }
+
+ public bool? Call()
+ {
+ //JAVA: public Boolean call() throws Exception {
+ //JAVA: if (reader == null) {
+ //JAVA: reader = DirectoryReader.open(indexDir);
+ //JAVA: lastGeneration = reader.getIndexCommit().getGeneration();
+ //JAVA: } else {
+ //JAVA: DirectoryReader newReader = DirectoryReader.openIfChanged(reader);
+ //JAVA: assertNotNull("should not have reached here if no changes were made to the index", newReader);
+ //JAVA: long newGeneration = newReader.getIndexCommit().getGeneration();
+ //JAVA: assertTrue("expected newer generation; current=" + lastGeneration + " new=" + newGeneration, newGeneration > lastGeneration);
+ //JAVA: reader.close();
+ //JAVA: reader = newReader;
+ //JAVA: lastGeneration = newGeneration;
+ //JAVA: TestUtil.checkIndex(indexDir);
+ //JAVA: }
+ //JAVA: return null;
+ //JAVA: }
+ if (reader == null)
+ {
+ reader = DirectoryReader.Open(indexDir);
+ lastGeneration = reader.IndexCommit.Generation;
+ }
+ else
+ {
+ DirectoryReader newReader = DirectoryReader.OpenIfChanged(reader);
+ assertNotNull("should not have reached here if no changes were made to the index", newReader);
+ long newGeneration = newReader.IndexCommit.Generation;
+ assertTrue("expected newer generation; current=" + lastGeneration + " new=" + newGeneration, newGeneration > lastGeneration);
+ reader.Dispose();
+ reader = newReader;
+ lastGeneration = newGeneration;
+ TestUtil.CheckIndex(indexDir);
+ }
+ return null;
+ }
+ public void Dispose()
+ {
+ IOUtils.Dispose(reader);
+ }
+ }
+
+
+ private MockDirectoryWrapper publishDir, handlerDir;
+ private IReplicator replicator;
+ private ISourceDirectoryFactory sourceDirFactory;
+ private ReplicationClient client;
+ private IReplicationHandler handler;
+ private IndexWriter publishWriter;
+ private IndexReadyCallback callback;
+ //JAVA: private IndexReadyCallback callback;
+
+ private const string VERSION_ID = "version";
+
+ private void AssertHandlerRevision(int expectedId, Directory dir)
+ {
+ //JAVA: private void assertHandlerRevision(int expectedID, Directory dir) throws IOException {
+ //JAVA: // loop as long as client is alive. test-framework will terminate us if
+ //JAVA: // there's a serious bug, e.g. client doesn't really update. otherwise,
+ //JAVA: // introducing timeouts is not good, can easily lead to false positives.
+ //JAVA: while (client.isUpdateThreadAlive()) {
+ //JAVA: // give client a chance to update
+ //JAVA: try {
+ //JAVA: Thread.sleep(100);
+ //JAVA: } catch (InterruptedException e) {
+ //JAVA: throw new ThreadInterruptedException(e);
+ //JAVA: }
+ //JAVA:
+ //JAVA: try {
+ //JAVA: DirectoryReader reader = DirectoryReader.open(dir);
+ //JAVA: try {
+ //JAVA: int handlerID = Integer.parseInt(reader.getIndexCommit().getUserData().get(VERSION_ID), 16);
+ //JAVA: if (expectedID == handlerID) {
+ //JAVA: return;
+ //JAVA: } else if (VERBOSE) {
+ //JAVA: System.out.println("expectedID=" + expectedID + " actual=" + handlerID + " generation=" + reader.getIndexCommit().getGeneration());
+ //JAVA: }
+ //JAVA: } finally {
+ //JAVA: reader.close();
+ //JAVA: }
+ //JAVA: } catch (Exception e) {
+ //JAVA: // we can hit IndexNotFoundException or e.g. EOFException (on
+ //JAVA: // segments_N) because it is being copied at the same time it is read by
+ //JAVA: // DirectoryReader.open().
+ //JAVA: }
+ //JAVA: }
+ //JAVA: }
+
+ // loop as long as client is alive. test-framework will terminate us if
+ // there's a serious bug, e.g. client doesn't really update. otherwise,
+ // introducing timeouts is not good, can easily lead to false positives.
+ while (client.IsUpdateThreadAlive)
+ {
+ // give client a chance to update
+ Thread.Sleep(100);
+ try
+ {
+ DirectoryReader reader = DirectoryReader.Open(dir);
+ try
+ {
+ int handlerId = int.Parse(reader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber);
+ if (expectedId == handlerId)
+ {
+ return;
+ }
+ else if (VERBOSE)
+ {
+ Console.WriteLine("expectedID=" + expectedId + " actual=" + handlerId + " generation=" + reader.IndexCommit.Generation);
+ }
+ }
+ finally
+ {
+ reader.Dispose();
+ }
+ }
+ catch (Exception)
+ {
+ // we can hit IndexNotFoundException or e.g. EOFException (on
+ // segments_N) because it is being copied at the same time it is read by
+ // DirectoryReader.open().
+ }
+ }
+ }
+
+ private IRevision CreateRevision(int id)
+ {
+ //JAVA: private Revision createRevision(final int id) throws IOException {
+ //JAVA: publishWriter.addDocument(new Document());
+ //JAVA: publishWriter.setCommitData(new HashMap<String, String>() {{
+ //JAVA: put(VERSION_ID, Integer.toString(id, 16));
+ //JAVA: }});
+ //JAVA: publishWriter.commit();
+ //JAVA: return new IndexRevision(publishWriter);
+ //JAVA: }
+ publishWriter.AddDocument(new Document());
+ publishWriter.SetCommitData(new Dictionary<string, string>{
+ { VERSION_ID, id.ToString("X") }
+ });
+ publishWriter.Commit();
+ return new IndexRevision(publishWriter);
+ }
+
+ public override void SetUp()
+ {
+ //JAVA: public void setUp() throws Exception {
+ //JAVA: super.setUp();
+ //JAVA: publishDir = newMockDirectory();
+ //JAVA: handlerDir = newMockDirectory();
+ //JAVA: sourceDirFactory = new PerSessionDirectoryFactory(createTempDir("replicationClientTest"));
+ //JAVA: replicator = new LocalReplicator();
+ //JAVA: callback = new IndexReadyCallback(handlerDir);
+ //JAVA: handler = new IndexReplicationHandler(handlerDir, callback);
+ //JAVA: client = new ReplicationClient(replicator, handler, sourceDirFactory);
+ //JAVA:
+ //JAVA: IndexWriterConfig conf = newIndexWriterConfig(TEST_VERSION_CURRENT, null);
+ //JAVA: conf.setIndexDeletionPolicy(new SnapshotDeletionPolicy(conf.getIndexDeletionPolicy()));
+ //JAVA: publishWriter = new IndexWriter(publishDir, conf);
+ //JAVA: }
+ base.SetUp();
+
+ publishDir = NewMockDirectory();
+ handlerDir = NewMockDirectory();
+ sourceDirFactory = new PerSessionDirectoryFactory(CreateTempDir("replicationClientTest").FullName);
+ replicator = new LocalReplicator();
+ callback = new IndexReadyCallback(handlerDir);
+ handler = new IndexReplicationHandler(handlerDir, callback.Call);
+ client = new ReplicationClient(replicator, handler, sourceDirFactory);
+
+ IndexWriterConfig conf = NewIndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ publishWriter = new IndexWriter(publishDir, conf);
+ }
+
+ public override void TearDown()
+ {
+ //JAVA: public void tearDown() throws Exception {
+ //JAVA: IOUtils.close(client, callback, publishWriter, replicator, publishDir, handlerDir);
+ //JAVA: super.tearDown();
+ //JAVA: }
+ IOUtils.Dispose(client, callback, publishWriter, replicator, publishDir, handlerDir);
+ base.TearDown();
+ }
+
+ [Test]
+ public void TestNoUpdateThread()
+ {
+ //JAVA: public void testNoUpdateThread() throws Exception {
+ //JAVA: assertNull("no version expected at start", handler.currentVersion());
+ //JAVA:
+ //JAVA: // Callback validates the replicated index
+ //JAVA: replicator.publish(createRevision(1));
+ //JAVA: client.updateNow();
+ //JAVA:
+ //JAVA: replicator.publish(createRevision(2));
+ //JAVA: client.updateNow();
+ //JAVA:
+ //JAVA: // Publish two revisions without update, handler should be upgraded to latest
+ //JAVA: replicator.publish(createRevision(3));
+ //JAVA: replicator.publish(createRevision(4));
+ //JAVA: client.updateNow();
+ //JAVA: }
+ assertNull("no version expected at start", handler.CurrentVersion);
+
+ // Callback validates the replicated ind
+ replicator.Publish(CreateRevision(1));
+ client.UpdateNow();
+
+ replicator.Publish(CreateRevision(2));
+ client.UpdateNow();
+
+ // Publish two revisions without update,
+ replicator.Publish(CreateRevision(3));
+ replicator.Publish(CreateRevision(4));
+ client.UpdateNow();
+ }
+
+
+ [Test]
+ public void TestUpdateThread()
+ {
+ //JAVA: public void testUpdateThread() throws Exception {
+ //JAVA: client.startUpdateThread(10, "index");
+ //JAVA:
+ //JAVA: replicator.publish(createRevision(1));
+ //JAVA: assertHandlerRevision(1, handlerDir);
+ //JAVA:
+ //JAVA: replicator.publish(createRevision(2));
+ //JAVA: assertHandlerRevision(2, handlerDir);
+ //JAVA:
+ //JAVA: // Publish two revisions without update, handler should be upgraded to latest
+ //JAVA: replicator.publish(createRevision(3));
+ //JAVA: replicator.publish(createRevision(4));
+ //JAVA: assertHandlerRevision(4, handlerDir);
+ //JAVA: }
+
+ client.StartUpdateThread(10, "index");
+
+ replicator.Publish(CreateRevision(1));
+ AssertHandlerRevision(1, handlerDir);
+
+ replicator.Publish(CreateRevision(2));
+ AssertHandlerRevision(2, handlerDir);
+
+ // Publish two revisions without update, handler should be upgraded to latest
+ replicator.Publish(CreateRevision(3));
+ replicator.Publish(CreateRevision(4));
+ AssertHandlerRevision(4, handlerDir);
+ }
+
+ [Test]
+ public void TestRestart()
+ {
+ //JAVA: public void testRestart() throws Exception {
+ //JAVA: replicator.publish(createRevision(1));
+ //JAVA: client.updateNow();
+ //JAVA:
+ //JAVA: replicator.publish(createRevision(2));
+ //JAVA: client.updateNow();
+ //JAVA:
+ //JAVA: client.stopUpdateThread();
+ //JAVA: client.close();
+ //JAVA: client = new ReplicationClient(replicator, handler, sourceDirFactory);
+ //JAVA:
+ //JAVA: // Publish two revisions without update, handler should be upgraded to latest
+ //JAVA: replicator.publish(createRevision(3));
+ //JAVA: replicator.publish(createRevision(4));
+ //JAVA: client.updateNow();
+ //JAVA: }
+ replicator.Publish(CreateRevision(1));
+ client.UpdateNow();
+
+ replicator.Publish(CreateRevision(2));
+ client.UpdateNow();
+
+ client.StopUpdateThread();
+ client.Dispose();
+ client = new ReplicationClient(replicator, handler, sourceDirFactory);
+
+ // Publish two revisions without update, handler should be upgraded to latest
+ replicator.Publish(CreateRevision(3));
+ replicator.Publish(CreateRevision(4));
+ client.UpdateNow();
+ }
+
+ //JAVA: /*
+ //JAVA: * This test verifies that the client and handler do not end up in a corrupt
+ //JAVA: * index if exceptions are thrown at any point during replication. Either when
+ //JAVA: * a client copies files from the server to the temporary space, or when the
+ //JAVA: * handler copies them to the index directory.
+ //JAVA: */
+ [Test]
+ public void TestConsistencyOnExceptions()
+ {
+ // so the handler's index isn't empty
+ replicator.Publish(CreateRevision(1));
+ client.UpdateNow();
+ client.Dispose();
+ callback.Dispose();
+
+ // Replicator violates write-once policy. It may be that the
+ // handler copies files to the index dir, then fails to copy a
+ // file and reverts the copy operation. On the next attempt, it
+ // will copy the same file again. There is nothing wrong with this
+ // in a real system, but it does violate write-once, and MDW
+ // doesn't like it. Disabling it means that we won't catch cases
+ // where the handler overwrites an existing index file, but
+ // there's nothing currently we can do about it, unless we don't
+ // use MDW.
+ //JAVA: handlerDir.setPreventDoubleWrite(false);
+ handlerDir.PreventDoubleWrite = false;
+
+ // wrap sourceDirFactory to return a MockDirWrapper so we can simulate errors
+ ISourceDirectoryFactory @in = sourceDirFactory;
+ AtomicInt32 failures = new AtomicInt32(AtLeast(10));
+
+ // wrap sourceDirFactory to return a MockDirWrapper so we can simulate errors
+ sourceDirFactory = new SourceDirectoryFactoryAnonymousInnerClass(this, @in, failures);
+ handler = new IndexReplicationHandler(handlerDir, () =>
+ {
+ if (Random().NextDouble() < 0.2 && failures.Get() > 0)
+ throw new Exception("random exception from callback");
+ return null;
+ });
+ client = new ReplicationClientAnonymousInnerClass(this, replicator, handler, sourceDirFactory, failures);
+ client.StartUpdateThread(10, "index");
+
+ Directory baseHandlerDir = handlerDir.Delegate;
+ 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.MaxSizeInBytes = 0;
+ handlerDir.RandomIOExceptionRate=0.0;
+ handlerDir.RandomIOExceptionRateOnOpen=0.0;
+ }
+
+ private class SourceDirectoryFactoryAnonymousInnerClass : ISourceDirectoryFactory
+ {
+ private long clientMaxSize = 100, handlerMaxSize = 100;
+ private double clientExRate = 1.0, handlerExRate = 1.0;
+
+ private readonly IndexReplicationClientTest test;
+ private readonly ISourceDirectoryFactory @in;
+ private readonly AtomicInt32 failures;
+
+ public SourceDirectoryFactoryAnonymousInnerClass(IndexReplicationClientTest test, ISourceDirectoryFactory @in, AtomicInt32 failures)
+ {
+ this.test = test;
+ this.@in = @in;
+ this.failures = failures;
+ }
+
+ public void CleanupSession(string sessionId)
+ {
+ @in.CleanupSession(sessionId);
+ }
+
+ public Directory GetDirectory(string sessionId, string source)
+ {
+ 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.RandomIOExceptionRateOnOpen = clientExRate;
+ mdw.MaxSizeInBytes = clientMaxSize;
+ mdw.RandomIOExceptionRate = clientExRate;
+ mdw.CheckIndexOnClose = false;
+ clientMaxSize *= 2;
+ clientExRate /= 2;
+ return mdw;
+ }
+
+ if (failures.Get() > 0 && Random().nextBoolean())
+ { // handler should fail
+ test.handlerDir.MaxSizeInBytes = handlerMaxSize;
+ test.handlerDir.RandomIOExceptionRateOnOpen = handlerExRate;
+ test.handlerDir.RandomIOExceptionRate = handlerExRate;
+ handlerMaxSize *= 2;
+ handlerExRate /= 2;
+ }
+ else
+ {
+ // disable errors
+ test.handlerDir.MaxSizeInBytes = 0;
+ test.handlerDir.RandomIOExceptionRate = 0;
+ test.handlerDir.RandomIOExceptionRateOnOpen = 0.0;
+ }
+ return dir;
+ }
+ }
+
+ private class ReplicationClientAnonymousInnerClass : ReplicationClient
+ {
+ private readonly IndexReplicationClientTest test;
+ private readonly AtomicInt32 failures;
+
+ public ReplicationClientAnonymousInnerClass(IndexReplicationClientTest test, IReplicator replicator, IReplicationHandler handler, ISourceDirectoryFactory factory, AtomicInt32 failures)
+ : base(replicator, handler, factory)
+ {
+ this.test = test;
+ this.failures = failures;
+ }
+
+ protected override void HandleUpdateException(Exception exception)
+ {
+ if (exception is IOException)
+ {
+ if (VERBOSE)
+ {
+ Console.WriteLine("hit exception during update: " + exception);
+ }
+
+ try
+ {
+ // test that the index can be read and also some basic statistics
+ DirectoryReader reader = DirectoryReader.Open(test.handlerDir.Delegate);
+ try
+ {
+ int numDocs = reader.NumDocs;
+ int version = int.Parse(reader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber);
+ assertEquals(numDocs, version);
+ }
+ finally
+ {
+ reader.Dispose();
+ }
+ // verify index consistency
+ TestUtil.CheckIndex(test.handlerDir.Delegate);
+ }
+ //TODO: Java had this, but considering what it does do we need it?
+ //JAVA: catch (IOException e)
+ //JAVA: {
+ //JAVA: // exceptions here are bad, don't ignore them
+ //JAVA: throw new RuntimeException(e);
+ //JAVA: }
+ finally
+ {
+ // count-down number of failures
+ failures.DecrementAndGet();
+ Debug.Assert(failures.Get() >= 0, "handler failed too many times: " + failures.Get());
+ if (VERBOSE)
+ {
+ if (failures.Get() == 0)
+ {
+ Console.WriteLine("no more failures expected");
+ }
+ else
+ {
+ Console.WriteLine("num failures left: " + failures.Get());
+ }
+ }
+ }
+ } else {
+ //JAVA: if (t instanceof RuntimeException) throw (RuntimeException) t;
+ //JAVA: throw new RuntimeException(t);
+ throw exception;
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs b/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
new file mode 100644
index 0000000..de4dbb4
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
@@ -0,0 +1,177 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Linq;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using NUnit.Framework;
+
+namespace Lucene.Net.Tests.Replicator
+{
+ /*
+ * 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.
+ */
+
+ public class IndexRevisionTest : ReplicatorTestCase
+ {
+ [Test]
+ public void TestNoSnapshotDeletionPolicy()
+ {
+ Directory dir = NewDirectory();
+ IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new KeepOnlyLastCommitDeletionPolicy();
+ IndexWriter writer = new IndexWriter(dir, conf);
+ try
+ {
+ assertNotNull(new IndexRevision(writer));
+ fail("should have failed when IndexDeletionPolicy is not Snapshot");
+ }
+ catch (ArgumentException)
+ {
+ // expected
+ }
+ finally
+ {
+ IOUtils.Dispose(writer, dir);
+ }
+ }
+
+ [Test]
+ public void TestNoCommit()
+ {
+ Directory dir = NewDirectory();
+ IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ IndexWriter writer = new IndexWriter(dir, conf);
+ try
+ {
+ assertNotNull(new IndexRevision(writer));
+ fail("should have failed when there are no commits to snapshot");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+ finally
+ {
+ IOUtils.Dispose(writer, dir);
+ }
+ }
+
+ [Test]
+ public void TestRevisionRelease()
+ {
+ Directory dir = NewDirectory();
+ IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ IndexWriter writer = new IndexWriter(dir, conf);
+ try
+ {
+ writer.AddDocument(new Document());
+ writer.Commit();
+ IRevision rev1 = new IndexRevision(writer);
+ // releasing that revision should not delete the files
+ rev1.Release();
+ assertTrue(SlowFileExists(dir, IndexFileNames.SEGMENTS + "_1"));
+
+ rev1 = new IndexRevision(writer); // create revision again, so the files are snapshotted
+ writer.AddDocument(new Document());
+ writer.Commit();
+ assertNotNull(new IndexRevision(writer));
+ rev1.Release(); // this release should trigger the delete of segments_1
+ assertFalse(SlowFileExists(dir, IndexFileNames.SEGMENTS + "_1"));
+ }
+ finally
+ {
+ IOUtils.Dispose(writer, dir);
+ }
+ }
+
+ [Test]
+ public void TestSegmentsFileLast()
+ {
+ Directory dir = NewDirectory();
+ IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ IndexWriter writer = new IndexWriter(dir, conf);
+ try
+ {
+ writer.AddDocument(new Document());
+ writer.Commit();
+ IRevision rev = new IndexRevision(writer);
+ var sourceFiles = rev.SourceFiles;
+ assertEquals(1, sourceFiles.Count);
+ var files = sourceFiles.Values.First();
+ string lastFile = files.Last().FileName;
+ assertTrue(lastFile.StartsWith(IndexFileNames.SEGMENTS, StringComparison.Ordinal) && !lastFile.Equals(IndexFileNames.SEGMENTS_GEN));
+ }
+ finally
+ {
+ IOUtils.Dispose(writer, dir);
+ }
+ }
+
+ [Test]
+ public void TestOpen()
+ {
+ Directory dir = NewDirectory();
+ IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ IndexWriter writer = new IndexWriter(dir, conf);
+ try
+ {
+ writer.AddDocument(new Document());
+ writer.Commit();
+ IRevision rev = new IndexRevision(writer);
+ var sourceFiles = rev.SourceFiles;
+ string source = sourceFiles.Keys.First();
+ foreach (RevisionFile file in sourceFiles.Values.First())
+ {
+ IndexInput src = dir.OpenInput(file.FileName, IOContext.READ_ONCE);
+ System.IO.Stream @in = rev.Open(source, file.FileName);
+ assertEquals(src.Length, @in.Length);
+ byte[] srcBytes = new byte[(int) src.Length];
+ byte[] inBytes = new byte[(int) src.Length];
+ int offset = 0;
+ if (Random().nextBoolean())
+ {
+ int skip = Random().Next(10);
+ if (skip >= src.Length)
+ {
+ skip = 0;
+ }
+ //JAVA: in.skip(skip);
+ byte[] skips = new byte[skip];
+ @in.Read(skips, 0, skip);
+ src.Seek(skip);
+ offset = skip;
+ }
+ src.ReadBytes(srcBytes, offset, srcBytes.Length - offset);
+ @in.Read(inBytes, offset, inBytes.Length - offset);
+ assertArrayEquals(srcBytes, inBytes);
+ IOUtils.Dispose(src, @in);
+ }
+ }
+ finally
+ {
+ IOUtils.Dispose(writer, dir);
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
new file mode 100644
index 0000000..9946457
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
@@ -0,0 +1,225 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Support;
+using Lucene.Net.Support.C5;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Tests.Replicator
+{
+ /*
+ * 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.
+ */
+
+ public class LocalReplicatorTest : ReplicatorTestCase
+ {
+ private const string VERSION_ID = "version";
+
+ private LocalReplicator replicator;
+ private Directory sourceDirectory;
+ private IndexWriter sourceWriter;
+
+ public override void SetUp()
+ {
+ base.SetUp();
+
+ sourceDirectory = NewDirectory();
+ IndexWriterConfig conf = NewIndexWriterConfig(TEST_VERSION_CURRENT, null);
+ conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+ sourceWriter = new IndexWriter(sourceDirectory, conf);
+ replicator = new LocalReplicator();
+ }
+
+ public override void TearDown()
+ {
+ IOUtils.Dispose(replicator, sourceWriter, sourceDirectory);
+ base.TearDown();
+ }
+
+ private IRevision CreateRevision(int id)
+ {
+ sourceWriter.AddDocument(new Document());
+ //JAVA: sourceWriter.setCommitData(new HashMap<String, String>() {{
+ //JAVA: put(VERSION_ID, Integer.toString(id, 16));
+ //JAVA: }
+ sourceWriter.SetCommitData(new Dictionary<string, string> {
+ { VERSION_ID, id.ToString() }
+ });
+ sourceWriter.Commit();
+ return new IndexRevision(sourceWriter);
+ }
+
+ [Test]
+ public void TestCheckForUpdateNoRevisions()
+ {
+ assertNull(replicator.CheckForUpdate(null));
+ }
+
+ [Test]
+ public void TestObtainFileAlreadyClosed()
+ {
+ replicator.Publish(CreateRevision(1));
+ SessionToken res = replicator.CheckForUpdate(null);
+ assertNotNull(res);
+ assertEquals(1, res.SourceFiles.Count);
+ System.Collections.Generic.KeyValuePair<string, System.Collections.Generic.IList<RevisionFile>> entry = res.SourceFiles.First();
+ replicator.Dispose();
+ try
+ {
+ replicator.ObtainFile(res.Id, entry.Key, entry.Value.First().FileName);
+ fail("should have failed on AlreadyClosedException");
+ }
+ catch (ObjectDisposedException)
+ {
+ // expected
+ }
+ }
+
+ [Test]
+ public void TestPublishAlreadyClosed()
+ {
+ replicator.Dispose();
+ try
+ {
+ replicator.Publish(CreateRevision(2));
+ fail("should have failed on AlreadyClosedException");
+ }
+ catch (ObjectDisposedException)
+ {
+ // expected
+ }
+ }
+
+ [Test]
+ public void TestUpdateAlreadyClosed()
+ {
+ replicator.Dispose();
+ try
+ {
+ replicator.CheckForUpdate(null);
+ fail("should have failed on AlreadyClosedException");
+ }
+ catch (ObjectDisposedException)
+ {
+ // expected
+ }
+ }
+
+ [Test]
+ public void TestPublishSameRevision()
+ {
+ IRevision rev = CreateRevision(1);
+ replicator.Publish(rev);
+ SessionToken res = replicator.CheckForUpdate(null);
+ assertNotNull(res);
+ assertEquals(rev.Version, res.Version);
+ replicator.Release(res.Id);
+ replicator.Publish(new IndexRevision(sourceWriter));
+ res = replicator.CheckForUpdate(res.Version);
+ assertNull(res);
+
+ // now make sure that publishing same revision doesn't leave revisions
+ // "locked", i.e. that replicator releases revisions even when they are not
+ // kept
+ replicator.Publish(CreateRevision(2));
+ assertEquals(1, DirectoryReader.ListCommits(sourceDirectory).size());
+ }
+
+ [Test]
+ public void TestPublishOlderRev()
+ {
+ replicator.Publish(CreateRevision(1));
+ IRevision old = new IndexRevision(sourceWriter);
+ replicator.Publish(CreateRevision(2));
+ try
+ {
+ replicator.Publish(old);
+ fail("should have failed to publish an older revision");
+ }
+ catch (System.ArgumentException)
+ {
+ // expected
+ }
+ assertEquals(1, DirectoryReader.ListCommits(sourceDirectory).size());
+ }
+
+ [Test]
+ public void TestObtainMissingFile()
+ {
+ replicator.Publish(CreateRevision(1));
+ SessionToken res = replicator.CheckForUpdate(null);
+ try
+ {
+ replicator.ObtainFile(res.Id, res.SourceFiles.Keys.First(), "madeUpFile");
+ fail("should have failed obtaining an unrecognized file");
+ }
+ //JAVA: } catch (FileNotFoundException | NoSuchFileException e) { -> Could not find a "NoSuchFileException" ?NoSuchItemException
+ catch (Exception e) when (e is FileNotFoundException)//|| e is NoSuchItemException)
+ {
+ // expected
+ }
+ }
+
+ [Test]
+ public void TestSessionExpiration()
+ {
+ replicator.Publish(CreateRevision(1));
+ SessionToken session = replicator.CheckForUpdate(null);
+ replicator.ExpirationThreshold = 5; // expire quickly
+ Thread.Sleep(50); // sufficient for expiration
+ try
+ {
+ replicator.ObtainFile(session.Id, session.SourceFiles.Keys.First(), session.SourceFiles.Values.First().First().FileName);
+ fail("should have failed to obtain a file for an expired session");
+ }
+ catch (SessionExpiredException)
+ {
+ // expected
+ }
+ }
+
+ [Test]
+ public void TestUpdateToLatest()
+ {
+ replicator.Publish(CreateRevision(1));
+ IRevision rev = CreateRevision(2);
+ replicator.Publish(rev);
+ SessionToken res = replicator.CheckForUpdate(null);
+ assertNotNull(res);
+ assertEquals(0, rev.CompareTo(res.Version));
+ }
+
+ [Test]
+ public void TestRevisionRelease()
+ {
+ replicator.Publish(CreateRevision(1));
+ assertTrue(SlowFileExists(sourceDirectory, IndexFileNames.SEGMENTS + "_1"));
+ replicator.Publish(CreateRevision(2));
+ // now the files of revision 1 can be deleted
+ assertTrue(SlowFileExists(sourceDirectory, IndexFileNames.SEGMENTS + "_2"));
+ assertFalse("segments_1 should not be found in index directory after revision is released", SlowFileExists(sourceDirectory, IndexFileNames.SEGMENTS + "_1"));
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
new file mode 100644
index 0000000..60adc6e
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{418E9D8E-2369-4B52-8D2F-5A987213999B}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Lucene.Net.Tests.Replicator</RootNamespace>
+ <AssemblyName>Lucene.Net.Tests.Replicator</AssemblyName>
+ <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.AspNetCore.Hosting, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.AspNetCore.Hosting.1.0.3\lib\net451\Microsoft.AspNetCore.Hosting.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.AspNetCore.Hosting.Abstractions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.AspNetCore.Hosting.Abstractions.1.0.3\lib\net451\Microsoft.AspNetCore.Hosting.Abstractions.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.AspNetCore.Hosting.Server.Abstractions.1.0.3\lib\net451\Microsoft.AspNetCore.Hosting.Server.Abstractions.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.AspNetCore.Http, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.AspNetCore.Http.1.0.3\lib\net451\Microsoft.AspNetCore.Http.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.AspNetCore.Http.Abstractions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.AspNetCore.Http.Abstractions.1.0.3\lib\net451\Microsoft.AspNetCore.Http.Abstractions.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.AspNetCore.Http.Extensions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.AspNetCore.Http.Extensions.1.0.3\lib\net451\Microsoft.AspNetCore.Http.Extensions.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.AspNetCore.Http.Features, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.AspNetCore.Http.Features.1.0.3\lib\net451\Microsoft.AspNetCore.Http.Features.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.AspNetCore.TestHost, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.AspNetCore.TestHost.1.0.3\lib\net451\Microsoft.AspNetCore.TestHost.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.AspNetCore.WebUtilities, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.AspNetCore.WebUtilities.1.0.3\lib\net451\Microsoft.AspNetCore.WebUtilities.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.Configuration, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.Configuration.1.0.2\lib\netstandard1.1\Microsoft.Extensions.Configuration.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.Configuration.Abstractions.1.0.2\lib\netstandard1.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.Configuration.EnvironmentVariables, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.Configuration.EnvironmentVariables.1.0.2\lib\net451\Microsoft.Extensions.Configuration.EnvironmentVariables.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.DependencyInjection, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.DependencyInjection.1.0.2\lib\netstandard1.1\Microsoft.Extensions.DependencyInjection.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.1.0.2\lib\netstandard1.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.FileProviders.Abstractions, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.FileProviders.Abstractions.1.0.1\lib\netstandard1.0\Microsoft.Extensions.FileProviders.Abstractions.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.FileProviders.Physical, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.FileProviders.Physical.1.0.1\lib\net451\Microsoft.Extensions.FileProviders.Physical.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.FileSystemGlobbing, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.FileSystemGlobbing.1.0.1\lib\net451\Microsoft.Extensions.FileSystemGlobbing.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.Logging, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.Logging.1.0.2\lib\netstandard1.1\Microsoft.Extensions.Logging.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.Logging.Abstractions.1.0.2\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.ObjectPool, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.ObjectPool.1.0.1\lib\net451\Microsoft.Extensions.ObjectPool.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.Options, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.Options.1.0.2\lib\netstandard1.0\Microsoft.Extensions.Options.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.PlatformAbstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.PlatformAbstractions.1.0.0\lib\net451\Microsoft.Extensions.PlatformAbstractions.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.Primitives, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.Primitives.1.0.1\lib\netstandard1.0\Microsoft.Extensions.Primitives.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Net.Http.Headers, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Net.Http.Headers.1.0.3\lib\netstandard1.1\Microsoft.Net.Http.Headers.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Buffers, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Buffers.4.0.0\lib\netstandard1.1\System.Buffers.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.ComponentModel.Composition" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Diagnostics.DiagnosticSource.4.0.0\lib\portable-net45+win8+wpa81\System.Diagnostics.DiagnosticSource.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.Reflection.Metadata, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Runtime.InteropServices.RuntimeInformation.4.0.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.Text.Encodings.Web, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Text.Encodings.Web.4.0.1\lib\netstandard1.0\System.Text.Encodings.Web.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\CommonAssemblyInfo.cs">
+ <Link>Properties\CommonAssemblyInfo.cs</Link>
+ </Compile>
+ <Compile Include="Http\HttpReplicatorTest.cs" />
+ <Compile Include="Http\ReplicationServlet.cs" />
+ <Compile Include="IndexAndTaxonomyReplicationClientTest.cs" />
+ <Compile Include="IndexAndTaxonomyRevisionTest.cs" />
+ <Compile Include="IndexReplicationClientTest.cs" />
+ <Compile Include="IndexRevisionTest.cs" />
+ <Compile Include="LocalReplicatorTest.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="ReplicatorTestCase.cs" />
+ <Compile Include="SessionTokenTest.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Lucene.Net.Facet\Lucene.Net.Facet.csproj">
+ <Project>{48F7884A-9454-4E88-8413-9D35992CB440}</Project>
+ <Name>Lucene.Net.Facet</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Lucene.Net.Replicator.AspNetCore\Lucene.Net.Replicator.AspNetCore.csproj">
+ <Project>{763ccb5a-e397-456a-af47-7c6e228b1852}</Project>
+ <Name>Lucene.Net.Replicator.AspNetCore</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Lucene.Net.Replicator\Lucene.Net.Replicator.csproj">
+ <Project>{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}</Project>
+ <Name>Lucene.Net.Replicator</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Lucene.Net.TestFramework\Lucene.Net.TestFramework.csproj">
+ <Project>{B2C0D749-CE34-4F62-A15E-00CB2FF5DDB3}</Project>
+ <Name>Lucene.Net.TestFramework</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Lucene.Net\Lucene.Net.csproj">
+ <Project>{5D4AD9BE-1FFB-41AB-9943-25737971BF57}</Project>
+ <Name>Lucene.Net</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file