| using J2N.Collections.Generic.Extensions; |
| using System; |
| using System.Collections.Generic; |
| using Lucene.Net.Diagnostics; |
| using System.Text; |
| using System.Text.RegularExpressions; |
| |
| namespace Lucene.Net.Index |
| { |
| /* |
| * 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. |
| */ |
| |
| using Codec = Lucene.Net.Codecs.Codec; |
| using Directory = Lucene.Net.Store.Directory; |
| using Lucene3xSegmentInfoFormat = Lucene.Net.Codecs.Lucene3x.Lucene3xSegmentInfoFormat; |
| using TrackingDirectoryWrapper = Lucene.Net.Store.TrackingDirectoryWrapper; |
| |
| /// <summary> |
| /// Information about a segment such as it's name, directory, and files related |
| /// to the segment. |
| /// <para/> |
| /// @lucene.experimental |
| /// </summary> |
| public sealed class SegmentInfo |
| { |
| // TODO: remove these from this class, for now this is the representation |
| /// <summary> |
| /// Used by some member fields to mean not present (e.g., |
| /// norms, deletions). |
| /// </summary> |
| public static readonly int NO = -1; // e.g. no norms; no deletes; |
| |
| /// <summary> |
| /// Used by some member fields to mean present (e.g., |
| /// norms, deletions). |
| /// </summary> |
| public static readonly int YES = 1; // e.g. have norms; have deletes; |
| |
| /// <summary> |
| /// Unique segment name in the directory. </summary> |
| public string Name { get; private set; } |
| |
| private int docCount; // number of docs in seg |
| |
| /// <summary> |
| /// Where this segment resides. </summary> |
| public Directory Dir { get; private set; } |
| |
| private bool isCompoundFile; |
| |
| private Codec codec; |
| |
| private IDictionary<string, string> diagnostics; |
| |
| [Obsolete("not used anymore")] |
| private IDictionary<string, string> attributes; |
| |
| // Tracks the Lucene version this segment was created with, since 3.1. Null |
| // indicates an older than 3.0 index, and it's used to detect a too old index. |
| // The format expected is "x.y" - "2.x" for pre-3.0 indexes (or null), and |
| // specific versions afterwards ("3.0", "3.1" etc.). |
| // see Constants.LUCENE_MAIN_VERSION. |
| private string version; |
| |
| /// <summary> |
| /// Gets or Sets diagnostics saved into the segment when it was written. |
| /// </summary> |
| public IDictionary<string, string> Diagnostics |
| { |
| get => diagnostics; |
| set => this.diagnostics = value; |
| } |
| |
| /// <summary> |
| /// Construct a new complete <see cref="SegmentInfo"/> instance from input. |
| /// <para>Note: this is public only to allow access from |
| /// the codecs package.</para> |
| /// </summary> |
| public SegmentInfo(Directory dir, string version, string name, int docCount, bool isCompoundFile, Codec codec, IDictionary<string, string> diagnostics) |
| : this(dir, version, name, docCount, isCompoundFile, codec, diagnostics, null) |
| { |
| } |
| |
| /// <summary> |
| /// Construct a new complete <see cref="SegmentInfo"/> instance from input. |
| /// <para>Note: this is public only to allow access from |
| /// the codecs package.</para> |
| /// </summary> |
| public SegmentInfo(Directory dir, string version, string name, int docCount, bool isCompoundFile, Codec codec, IDictionary<string, string> diagnostics, IDictionary<string, string> attributes) |
| { |
| if (Debugging.AssertsEnabled) Debugging.Assert(!(dir is TrackingDirectoryWrapper)); |
| this.Dir = dir; |
| this.version = version; |
| this.Name = name; |
| this.docCount = docCount; |
| this.isCompoundFile = isCompoundFile; |
| this.codec = codec; |
| this.diagnostics = diagnostics; |
| #pragma warning disable 612, 618 |
| this.attributes = attributes; |
| #pragma warning restore 612, 618 |
| } |
| |
| [Obsolete("separate norms are not supported in >= 4.0")] |
| internal bool HasSeparateNorms => GetAttribute(Lucene3xSegmentInfoFormat.NORMGEN_KEY) != null; |
| |
| /// <summary> |
| /// Gets or Sets whether this segment is stored as a compound file. |
| /// <c>true</c> if this is a compound file; |
| /// else, <c>false</c> |
| /// </summary> |
| public bool UseCompoundFile |
| { |
| get => isCompoundFile; |
| set => this.isCompoundFile = value; |
| } |
| |
| /// <summary> |
| /// Gets or Sets <see cref="Codecs.Codec"/> that wrote this segment. |
| /// Setter can only be called once. </summary> |
| public Codec Codec |
| { |
| get => codec; |
| set |
| { |
| if (Debugging.AssertsEnabled) Debugging.Assert(this.codec == null); |
| if (value == null) |
| { |
| throw new ArgumentException("codec must be non-null"); |
| } |
| this.codec = value; |
| } |
| } |
| |
| /// <summary> |
| /// Returns number of documents in this segment (deletions |
| /// are not taken into account). |
| /// </summary> |
| public int DocCount |
| { |
| get |
| { |
| if (this.docCount == -1) |
| { |
| throw new InvalidOperationException("docCount isn't set yet"); |
| } |
| return docCount; |
| } |
| internal set // NOTE: leave package private |
| { |
| if (this.docCount != -1) |
| { |
| throw new InvalidOperationException("docCount was already set"); |
| } |
| this.docCount = value; |
| } |
| } |
| |
| /// <summary> |
| /// Return all files referenced by this <see cref="SegmentInfo"/>. </summary> |
| public ISet<string> GetFiles() |
| { |
| if (setFiles == null) |
| { |
| throw new InvalidOperationException("files were not computed yet"); |
| } |
| return setFiles.AsReadOnly(); |
| } |
| |
| public override string ToString() |
| { |
| return ToString(Dir, 0); |
| } |
| |
| /// <summary> |
| /// Used for debugging. Format may suddenly change. |
| /// |
| /// <para>Current format looks like |
| /// <c>_a(3.1):c45/4</c>, which means the segment's |
| /// name is <c>_a</c>; it was created with Lucene 3.1 (or |
| /// '?' if it's unknown); it's using compound file |
| /// format (would be <c>C</c> if not compound); it |
| /// has 45 documents; it has 4 deletions (this part is |
| /// left off when there are no deletions).</para> |
| /// </summary> |
| public string ToString(Directory dir, int delCount) |
| { |
| StringBuilder s = new StringBuilder(); |
| s.Append(Name).Append('(').Append(version == null ? "?" : version).Append(')').Append(':'); |
| char cfs = UseCompoundFile ? 'c' : 'C'; |
| s.Append(cfs); |
| |
| if (this.Dir != dir) |
| { |
| s.Append('x'); |
| } |
| s.Append(docCount); |
| |
| if (delCount != 0) |
| { |
| s.Append('/').Append(delCount); |
| } |
| |
| // TODO: we could append toString of attributes() here? |
| |
| return s.ToString(); |
| } |
| |
| /// <summary> |
| /// We consider another <see cref="SegmentInfo"/> instance equal if it |
| /// has the same dir and same name. |
| /// </summary> |
| public override bool Equals(object obj) |
| { |
| if (this == obj) |
| { |
| return true; |
| } |
| if (obj is SegmentInfo) |
| { |
| SegmentInfo other = (SegmentInfo)obj; |
| return other.Dir == Dir && other.Name.Equals(Name, StringComparison.Ordinal); |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| public override int GetHashCode() |
| { |
| return Dir.GetHashCode() + Name.GetHashCode(); |
| } |
| |
| /// <summary> |
| /// Used by DefaultSegmentInfosReader to upgrade a 3.0 segment to record its |
| /// version is "3.0". this method can be removed when we're not required to |
| /// support 3x indexes anymore, e.g. in 5.0. |
| /// <para/> |
| /// <b>NOTE:</b> this method is used for internal purposes only - you should |
| /// not modify the version of a <see cref="SegmentInfo"/>, or it may result in unexpected |
| /// exceptions thrown when you attempt to open the index. |
| /// <para/> |
| /// @lucene.internal |
| /// </summary> |
| public string Version |
| { |
| get => version; |
| set => this.version = value; |
| } |
| |
| private ISet<string> setFiles; |
| |
| /// <summary> |
| /// Sets the files written for this segment. </summary> |
| public void SetFiles(ISet<string> files) |
| { |
| CheckFileNames(files); |
| setFiles = files; |
| } |
| |
| /// <summary> |
| /// Add these files to the set of files written for this |
| /// segment. |
| /// </summary> |
| public void AddFiles(ICollection<string> files) |
| { |
| CheckFileNames(files); |
| setFiles.UnionWith(files); |
| } |
| |
| /// <summary> |
| /// Add this file to the set of files written for this |
| /// segment. |
| /// </summary> |
| public void AddFile(string file) |
| { |
| CheckFileNames(new[] { file }); |
| setFiles.Add(file); |
| } |
| |
| private void CheckFileNames(ICollection<string> files) |
| { |
| Regex r = IndexFileNames.CODEC_FILE_PATTERN; |
| foreach (string file in files) |
| { |
| if (!r.IsMatch(file)) |
| { |
| throw new ArgumentException("invalid codec filename '" + file + "', must match: " + IndexFileNames.CODEC_FILE_PATTERN.ToString()); |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Get a codec attribute value, or null if it does not exist |
| /// </summary> |
| [Obsolete("no longer supported")] |
| public string GetAttribute(string key) |
| { |
| if (attributes == null) |
| { |
| return null; |
| } |
| else |
| { |
| string attribute; |
| attributes.TryGetValue(key, out attribute); |
| return attribute; |
| } |
| } |
| |
| /// <summary> |
| /// Puts a codec attribute value. |
| /// <para/> |
| /// This is a key-value mapping for the field that the codec can use to store |
| /// additional metadata, and will be available to the codec when reading the |
| /// segment via <see cref="GetAttribute(string)"/> |
| /// <para/> |
| /// If a value already exists for the field, it will be replaced with the new |
| /// value. |
| /// </summary> |
| [Obsolete("no longer supported")] |
| public string PutAttribute(string key, string value) |
| { |
| if (attributes == null) |
| { |
| attributes = new Dictionary<string, string>(); |
| } |
| return attributes[key] = value; |
| } |
| |
| /// <summary> |
| /// Returns the internal codec attributes map. May be null if no mappings exist. |
| /// </summary> |
| [Obsolete("no longer supported")] |
| public IDictionary<string, string> Attributes => attributes; |
| } |
| } |