/
SegmentCommitInfo.cs
292 lines (252 loc) · 10.2 KB
/
SegmentCommitInfo.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
using J2N.Collections.Generic.Extensions;
using Lucene.Net.Support;
using System;
using System.Collections.Generic;
using JCG = J2N.Collections.Generic;
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 Directory = Lucene.Net.Store.Directory;
/// <summary>
/// Embeds a [read-only] <see cref="SegmentInfo"/> and adds per-commit
/// fields.
/// <para/>
/// @lucene.experimental
/// </summary>
public class SegmentCommitInfo
{
/// <summary>
/// The <see cref="SegmentInfo"/> that we wrap. </summary>
public SegmentInfo Info { get; private set; }
// How many deleted docs in the segment:
private int delCount;
// Generation number of the live docs file (-1 if there
// are no deletes yet):
private long delGen;
// 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;
// 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 = new Dictionary<long, ISet<string>>();
private long sizeInBytes = -1; // LUCENENET NOTE: This was volatile in the original, but long cannot be volatile in .NET
/// <summary>
/// Sole constructor.
/// </summary>
/// <param name="info">
/// <see 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">
/// <see cref="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 = delCount;
this.delGen = delGen;
if (delGen == -1)
{
nextWriteDelGen = 1;
}
else
{
nextWriteDelGen = delGen + 1;
}
this.fieldInfosGen = 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 => genUpdatesFiles.AsReadOnly();
/// <summary>
/// Sets the updates file names per generation. Does not deep clone the map. </summary>
public virtual void SetGenUpdatesFiles(IDictionary<long, ISet<string>> genUpdatesFiles)
{
this.genUpdatesFiles.Clear();
this.genUpdatesFiles.PutAll(genUpdatesFiles);
}
/// <summary>
/// Called when we succeed in writing deletes </summary>
internal virtual void AdvanceDelGen()
{
delGen = nextWriteDelGen;
nextWriteDelGen = delGen + 1;
sizeInBytes = -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 <see cref="FieldInfos"/> generation. </summary>
internal virtual void AdvanceFieldInfosGen()
{
fieldInfosGen = nextWriteFieldInfosGen;
nextWriteFieldInfosGen = fieldInfosGen + 1;
sizeInBytes = -1;
}
/// <summary>
/// Called if there was an exception while writing a new generation of
/// <see cref="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.
/// <para/><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 GetSizeInBytes()
{
if (sizeInBytes == -1)
{
long sum = 0;
foreach (string fileName in GetFiles())
{
sum += Info.Dir.FileLength(fileName);
}
sizeInBytes = sum;
}
return sizeInBytes;
}
/// <summary>
/// Returns all files in use by this segment. </summary>
public virtual ICollection<string> GetFiles()
{
// Start from the wrapped info's files:
ISet<string> files = new JCG.HashSet<string>(Info.GetFiles());
// 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.Values)
{
files.UnionWith(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;
internal virtual long BufferedDeletesGen => bufferedDeletesGen;
internal void SetBufferedDeletesGen(long value)
{
bufferedDeletesGen = value;
sizeInBytes = -1;
}
/// <summary>
/// Returns <c>true</c> if there are any deletions for the
/// segment at this commit.
/// </summary>
public virtual bool HasDeletions => delGen != -1;
/// <summary>
/// Returns <c>true</c> if there are any field updates for the segment in this commit. </summary>
public virtual bool HasFieldUpdates => fieldInfosGen != -1;
/// <summary>
/// Returns the next available generation number of the <see cref="FieldInfos"/> files. </summary>
public virtual long NextFieldInfosGen => 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 => fieldInfosGen;
/// <summary>
/// Returns the next available generation number
/// of the live docs file.
/// </summary>
public virtual long NextDelGen => nextWriteDelGen;
/// <summary>
/// Returns generation number of the live docs file
/// or -1 if there are no deletes yet.
/// </summary>
public virtual long DelGen => delGen;
/// <summary>
/// Returns the number of deleted docs in the segment.
/// </summary>
public virtual int DelCount
{
get => delCount;
internal set
{
if (value < 0 || value > Info.DocCount)
{
throw new ArgumentOutOfRangeException(nameof(DelCount), "invalid delCount=" + value + " (docCount=" + Info.DocCount + ")"); // LUCENENET specific - changed from IllegalArgumentException to ArgumentOutOfRangeException (.NET convention)
}
this.delCount = value;
}
}
/// <summary>
/// Returns a description of this segment. </summary>
public virtual string ToString(Directory dir, int pendingDelCount)
{
string s = Info.ToString(dir, delCount + pendingDelCount);
if (delGen != -1)
{
s += ":delGen=" + delGen;
}
if (fieldInfosGen != -1)
{
s += ":fieldInfosGen=" + fieldInfosGen;
}
return s;
}
public override string ToString()
{
return ToString(Info.Dir, 0);
}
public virtual object Clone()
{
SegmentCommitInfo other = new SegmentCommitInfo(Info, delCount, delGen, fieldInfosGen);
// 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)
{
other.genUpdatesFiles[e.Key] = new JCG.HashSet<string>(e.Value);
}
return other;
}
}
}