blob: 53b3efa96d72c97aac396d1ac9108b9ebc31648b [file] [log] [blame]
using System.Collections.Generic;
namespace Lucene.Net.Index
{
using Lucene.Net.Support;
/*
* 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 Directory = Lucene.Net.Store.Directory;
/// <summary>
/// Embeds a [read-only] SegmentInfo and adds per-commit
/// fields.
///
/// @lucene.experimental
/// </summary>
public class SegmentCommitInfo
{
/// <summary>
/// The <seealso cref="SegmentInfo"/> that we wrap. </summary>
public readonly SegmentInfo Info;
// How many deleted docs in the segment:
private int DelCount_Renamed;
// Generation number of the live docs file (-1 if there
// are no deletes yet):
private long DelGen_Renamed;
// Normally 1+delGen, unless an exception was hit on last
// attempt to write:
private long NextWriteDelGen;
// Generation number of the FieldInfos (-1 if there are no updates)
private long FieldInfosGen_Renamed;
// Normally 1 + fieldInfosGen, unless an exception was hit on last attempt to
// write
private long NextWriteFieldInfosGen;
// Track the per-generation updates files
private readonly IDictionary<long, ISet<string>> GenUpdatesFiles_Renamed = new Dictionary<long, ISet<string>>();
private long SizeInBytes_Renamed = -1;
/// <summary>
/// Sole constructor.
/// </summary>
/// <param name="info">
/// <seealso cref="SegmentInfo"/> that we wrap </param>
/// <param name="delCount">
/// number of deleted documents in this segment </param>
/// <param name="delGen">
/// deletion generation number (used to name deletion files) </param>
/// <param name="fieldInfosGen">
/// FieldInfos generation number (used to name field-infos files)
/// </param>
public SegmentCommitInfo(SegmentInfo info, int delCount, long delGen, long fieldInfosGen)
{
this.Info = info;
this.DelCount_Renamed = delCount;
this.DelGen_Renamed = delGen;
if (delGen == -1)
{
NextWriteDelGen = 1;
}
else
{
NextWriteDelGen = delGen + 1;
}
this.FieldInfosGen_Renamed = fieldInfosGen;
if (fieldInfosGen == -1)
{
NextWriteFieldInfosGen = 1;
}
else
{
NextWriteFieldInfosGen = fieldInfosGen + 1;
}
}
/// <summary>
/// Returns the per generation updates files. </summary>
public virtual IDictionary<long, ISet<string>> UpdatesFiles
{
get
{
return CollectionsHelper.UnmodifiableMap(GenUpdatesFiles_Renamed);
}
}
/// <summary>
/// Sets the updates file names per generation. Does not deep clone the map. </summary>
public virtual IDictionary<long, ISet<string>> GenUpdatesFiles
{
set
{
this.GenUpdatesFiles_Renamed.Clear();
this.GenUpdatesFiles_Renamed.PutAll(value);
}
}
/// <summary>
/// Called when we succeed in writing deletes </summary>
internal virtual void AdvanceDelGen()
{
DelGen_Renamed = NextWriteDelGen;
NextWriteDelGen = DelGen_Renamed + 1;
SizeInBytes_Renamed = -1;
}
/// <summary>
/// Called if there was an exception while writing
/// deletes, so that we don't try to write to the same
/// file more than once.
/// </summary>
internal virtual void AdvanceNextWriteDelGen()
{
NextWriteDelGen++;
}
/// <summary>
/// Called when we succeed in writing a new FieldInfos generation. </summary>
internal virtual void AdvanceFieldInfosGen()
{
FieldInfosGen_Renamed = NextWriteFieldInfosGen;
NextWriteFieldInfosGen = FieldInfosGen_Renamed + 1;
SizeInBytes_Renamed = -1;
}
/// <summary>
/// Called if there was an exception while writing a new generation of
/// FieldInfos, so that we don't try to write to the same file more than once.
/// </summary>
internal virtual void AdvanceNextWriteFieldInfosGen()
{
NextWriteFieldInfosGen++;
}
/// <summary>
/// Returns total size in bytes of all files for this
/// segment.
/// <p><b>NOTE:</b> this value is not correct for 3.0 segments
/// that have shared docstores. To get the correct value, upgrade!
/// </summary>
public virtual long SizeInBytes()
{
if (SizeInBytes_Renamed == -1)
{
long sum = 0;
foreach (string fileName in Files())
{
sum += Info.Dir.FileLength(fileName);
}
SizeInBytes_Renamed = sum;
}
return SizeInBytes_Renamed;
}
/// <summary>
/// Returns all files in use by this segment. </summary>
public virtual ICollection<string> Files()
{
// Start from the wrapped info's files:
ISet<string> files = new HashSet<string>(Info.Files);
// TODO we could rely on TrackingDir.getCreatedFiles() (like we do for
// updates) and then maybe even be able to remove LiveDocsFormat.files().
// Must separately add any live docs files:
Info.Codec.LiveDocsFormat().Files(this, files);
// Must separately add any field updates files
foreach (ISet<string> updateFiles in GenUpdatesFiles_Renamed.Values)
{
CollectionsHelper.AddAll(files, updateFiles);
}
return files;
}
// NOTE: only used in-RAM by IW to track buffered deletes;
// this is never written to/read from the Directory
private long BufferedDeletesGen_Renamed;
internal virtual long BufferedDeletesGen
{
get
{
return BufferedDeletesGen_Renamed;
}
set
{
BufferedDeletesGen_Renamed = value;
SizeInBytes_Renamed = -1;
}
}
/// <summary>
/// Returns true if there are any deletions for the
/// segment at this commit.
/// </summary>
public virtual bool HasDeletions()
{
return DelGen_Renamed != -1;
}
/// <summary>
/// Returns true if there are any field updates for the segment in this commit. </summary>
public virtual bool HasFieldUpdates()
{
return FieldInfosGen_Renamed != -1;
}
/// <summary>
/// Returns the next available generation number of the FieldInfos files. </summary>
public virtual long NextFieldInfosGen
{
get
{
return NextWriteFieldInfosGen;
}
}
/// <summary>
/// Returns the generation number of the field infos file or -1 if there are no
/// field updates yet.
/// </summary>
public virtual long FieldInfosGen
{
get
{
return FieldInfosGen_Renamed;
}
}
/// <summary>
/// Returns the next available generation number
/// of the live docs file.
/// </summary>
public virtual long NextDelGen
{
get
{
return NextWriteDelGen;
}
}
/// <summary>
/// Returns generation number of the live docs file
/// or -1 if there are no deletes yet.
/// </summary>
public virtual long DelGen
{
get
{
return DelGen_Renamed;
}
}
/// <summary>
/// Returns the number of deleted docs in the segment.
/// </summary>
public virtual int DelCount
{
get
{
return DelCount_Renamed;
}
set
{
if (value < 0 || value > Info.DocCount)
{
throw new System.ArgumentException("invalid delCount=" + value + " (docCount=" + Info.DocCount + ")");
}
this.DelCount_Renamed = value;
}
}
/// <summary>
/// Returns a description of this segment. </summary>
public virtual string ToString(Directory dir, int pendingDelCount)
{
string s = Info.ToString(dir, DelCount_Renamed + pendingDelCount);
if (DelGen_Renamed != -1)
{
s += ":delGen=" + DelGen_Renamed;
}
if (FieldInfosGen_Renamed != -1)
{
s += ":fieldInfosGen=" + FieldInfosGen_Renamed;
}
return s;
}
public override string ToString()
{
return ToString(Info.Dir, 0);
}
public virtual object Clone()
{
SegmentCommitInfo other = new SegmentCommitInfo(Info, DelCount_Renamed, DelGen_Renamed, FieldInfosGen_Renamed);
// Not clear that we need to carry over nextWriteDelGen
// (i.e. do we ever clone after a failed write and
// before the next successful write?), but just do it to
// be safe:
other.NextWriteDelGen = NextWriteDelGen;
other.NextWriteFieldInfosGen = NextWriteFieldInfosGen;
// deep clone
foreach (KeyValuePair<long, ISet<string>> e in GenUpdatesFiles_Renamed)
{
other.GenUpdatesFiles_Renamed[e.Key] = new HashSet<string>(e.Value);
}
return other;
}
}
}