| using J2N.Text; |
| using Lucene.Net.Facet.Taxonomy.Directory; |
| using Lucene.Net.Facet.Taxonomy.WriterCache; |
| using Lucene.Net.Index; |
| using Lucene.Net.Store; |
| using System; |
| using System.Collections.Generic; |
| using System.Diagnostics; |
| using System.Globalization; |
| using System.IO; |
| using System.Linq; |
| using Directory = Lucene.Net.Store.Directory; |
| |
| namespace Lucene.Net.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. |
| */ |
| |
| /// <summary> |
| /// A <see cref="IRevision"/> of a single index and taxonomy index files which comprises |
| /// the list of files from both indexes. This revision should be used whenever a |
| /// pair of search and taxonomy indexes need to be replicated together to |
| /// guarantee consistency of both on the replicating (client) side. |
| /// </summary> |
| /// <remarks> |
| /// @lucene.experimental |
| /// </remarks> |
| /// <seealso cref="IndexRevision"/> |
| public class IndexAndTaxonomyRevision : IRevision |
| { |
| /// <summary> |
| /// A <see cref="DirectoryTaxonomyWriter"/> which sets the underlying |
| /// <see cref="Index.IndexWriter"/>'s <see cref="IndexDeletionPolicy"/> to |
| /// <see cref="SnapshotDeletionPolicy"/>. |
| /// </summary> |
| public class SnapshotDirectoryTaxonomyWriter : DirectoryTaxonomyWriter |
| { |
| private SnapshotDeletionPolicy sdp; |
| private IndexWriter writer; |
| |
| /// <summary> |
| /// <see cref="DirectoryTaxonomyWriter(Directory, OpenMode, ITaxonomyWriterCache)"/> |
| /// </summary> |
| /// <exception cref="IOException"></exception> |
| public SnapshotDirectoryTaxonomyWriter(Directory directory, OpenMode openMode, ITaxonomyWriterCache cache) |
| : base(directory, openMode, cache) |
| { |
| } |
| |
| /// <summary> |
| /// <see cref="DirectoryTaxonomyWriter(Directory, OpenMode)"/> |
| /// </summary> |
| /// <exception cref="IOException"></exception> |
| public SnapshotDirectoryTaxonomyWriter(Directory directory, OpenMode openMode = OpenMode.CREATE_OR_APPEND) |
| : base(directory, openMode) |
| { |
| } |
| |
| protected override IndexWriterConfig CreateIndexWriterConfig(OpenMode openMode) |
| { |
| IndexWriterConfig conf = base.CreateIndexWriterConfig(openMode); |
| conf.IndexDeletionPolicy = sdp = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy); |
| return conf; |
| } |
| |
| protected override IndexWriter OpenIndexWriter(Directory directory, IndexWriterConfig config) |
| { |
| return writer = base.OpenIndexWriter(directory, config); |
| } |
| |
| /// <summary> |
| /// Gets the <see cref="SnapshotDeletionPolicy"/> used by the underlying <see cref="Index.IndexWriter"/>. |
| /// </summary> |
| public virtual SnapshotDeletionPolicy DeletionPolicy { get { return sdp; } } |
| |
| /// <summary> |
| /// Gets the <see cref="Index.IndexWriter"/> used by this <see cref="DirectoryTaxonomyWriter"/>. |
| /// </summary> |
| public virtual IndexWriter IndexWriter { get { return writer; } } |
| } |
| |
| public const string INDEX_SOURCE = "index"; |
| public const string TAXONOMY_SOURCE = "taxonomy"; |
| |
| private readonly IndexWriter indexWriter; |
| private readonly SnapshotDirectoryTaxonomyWriter taxonomyWriter; |
| private readonly IndexCommit indexCommit, taxonomyCommit; |
| private readonly SnapshotDeletionPolicy indexSdp, taxonomySdp; |
| private readonly string version; |
| private readonly IDictionary<string, IList<RevisionFile>> sourceFiles; |
| |
| /// <summary> |
| /// Returns a map of the revision files from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes. |
| /// </summary> |
| /// <exception cref="IOException"></exception> |
| public static IDictionary<string, IList<RevisionFile>> RevisionFiles(IndexCommit indexCommit, IndexCommit taxonomyCommit) |
| { |
| return new Dictionary<string, IList<RevisionFile>>{ |
| { INDEX_SOURCE, IndexRevision.RevisionFiles(indexCommit).Values.First() }, |
| { TAXONOMY_SOURCE, IndexRevision.RevisionFiles(taxonomyCommit).Values.First() } |
| }; |
| } |
| |
| /// <summary> |
| /// Returns a <see cref="string"/> representation of a revision's version from the given |
| /// <see cref="IndexCommit"/>s of the search and taxonomy indexes. |
| /// </summary> |
| /// <returns>a <see cref="string"/> representation of a revision's version from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes.</returns> |
| public static string RevisionVersion(IndexCommit indexCommit, IndexCommit taxonomyCommit) |
| { |
| return string.Format("{0:X}:{1:X}", indexCommit.Generation, taxonomyCommit.Generation); |
| } |
| |
| /// <summary> |
| /// Constructor over the given <see cref="IndexWriter"/>. Uses the last |
| /// <see cref="IndexCommit"/> found in the <see cref="Directory"/> managed by the given |
| /// writer. |
| /// </summary> |
| /// <exception cref="IOException"></exception> |
| public IndexAndTaxonomyRevision(IndexWriter indexWriter, SnapshotDirectoryTaxonomyWriter taxonomyWriter) |
| { |
| this.indexSdp = indexWriter.Config.IndexDeletionPolicy as SnapshotDeletionPolicy; |
| if (indexSdp == null) |
| throw new ArgumentException("IndexWriter must be created with SnapshotDeletionPolicy", "indexWriter"); |
| |
| this.indexWriter = indexWriter; |
| this.taxonomyWriter = taxonomyWriter; |
| this.taxonomySdp = taxonomyWriter.DeletionPolicy; |
| this.indexCommit = indexSdp.Snapshot(); |
| this.taxonomyCommit = taxonomySdp.Snapshot(); |
| this.version = RevisionVersion(indexCommit, taxonomyCommit); |
| this.sourceFiles = RevisionFiles(indexCommit, taxonomyCommit); |
| } |
| |
| /// <summary> |
| /// Compares this <see cref="IndexAndTaxonomyRevision"/> to the given <see cref="version"/>. |
| /// </summary> |
| public virtual int CompareTo(string version) |
| { |
| string[] parts = version.Split(':').TrimEnd(); |
| long indexGen = long.Parse(parts[0], NumberStyles.HexNumber); |
| long taxonomyGen = long.Parse(parts[1], NumberStyles.HexNumber); |
| long indexCommitGen = indexCommit.Generation; |
| long taxonomyCommitGen = taxonomyCommit.Generation; |
| |
| if (indexCommitGen < indexGen) |
| return -1; |
| |
| if (indexCommitGen > indexGen) |
| return 1; |
| |
| return taxonomyCommitGen < taxonomyGen ? -1 : (taxonomyCommitGen > taxonomyGen ? 1 : 0); |
| } |
| |
| public virtual int CompareTo(IRevision other) |
| { |
| if (other == null) |
| throw new ArgumentNullException("other"); |
| |
| IndexAndTaxonomyRevision itr = other as IndexAndTaxonomyRevision; |
| if(itr == null) |
| throw new ArgumentException(string.Format("Cannot compare IndexAndTaxonomyRevision to a {0}", other.GetType()), "other"); |
| |
| int cmp = indexCommit.CompareTo(itr.indexCommit); |
| return cmp != 0 ? cmp : taxonomyCommit.CompareTo(itr.taxonomyCommit); |
| } |
| |
| public virtual string Version { get { return version; } } |
| |
| public virtual IDictionary<string, IList<RevisionFile>> SourceFiles { get { return sourceFiles; } } |
| |
| /// <exception cref="IOException"></exception> |
| public virtual Stream Open(string source, string fileName) |
| { |
| Debug.Assert(source.Equals(INDEX_SOURCE, StringComparison.Ordinal) || source.Equals(TAXONOMY_SOURCE, StringComparison.Ordinal), string.Format("invalid source; expected=({0} or {1}) got={2}", INDEX_SOURCE, TAXONOMY_SOURCE, source)); |
| IndexCommit commit = source.Equals(INDEX_SOURCE, StringComparison.Ordinal) ? indexCommit : taxonomyCommit; |
| return new IndexInputStream(commit.Directory.OpenInput(fileName, IOContext.READ_ONCE)); |
| } |
| |
| /// <exception cref="IOException"></exception> |
| public virtual void Release() |
| { |
| try |
| { |
| indexSdp.Release(indexCommit); |
| } |
| finally |
| { |
| taxonomySdp.Release(taxonomyCommit); |
| } |
| |
| try |
| { |
| indexWriter.DeleteUnusedFiles(); |
| } |
| finally |
| { |
| taxonomyWriter.IndexWriter.DeleteUnusedFiles(); |
| } |
| } |
| } |
| } |