Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
SegmentInfo.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using System.Collections.Generic;
20 using Lucene.Net.Support;
21 using Directory = Lucene.Net.Store.Directory;
22 using IndexInput = Lucene.Net.Store.IndexInput;
23 using IndexOutput = Lucene.Net.Store.IndexOutput;
24 using BitVector = Lucene.Net.Util.BitVector;
25 
26 namespace Lucene.Net.Index
27 {
28 
29  /// <summary> Information about a segment such as it's name, directory, and files related
30  /// to the segment.
31  ///
32  /// * <p/><b>NOTE:</b> This API is new and still experimental
33  /// (subject to change suddenly in the next release)<p/>
34  /// </summary>
35  public sealed class SegmentInfo : System.ICloneable
36  {
37 
38  internal const int NO = - 1; // e.g. no norms; no deletes;
39  internal const int YES = 1; // e.g. have norms; have deletes;
40  internal const int CHECK_DIR = 0; // e.g. must check dir to see if there are norms/deletions
41  internal const int WITHOUT_GEN = 0; // a file name that has no GEN in it.
42 
43  public System.String name; // unique name in dir
44  public int docCount; // number of docs in seg
45  public Directory dir; // where segment resides
46 
47  private bool preLockless; // true if this is a segments file written before
48  // lock-less commits (2.1)
49 
50  private long delGen; // current generation of del file; NO if there
51  // are no deletes; CHECK_DIR if it's a pre-2.1 segment
52  // (and we must check filesystem); YES or higher if
53  // there are deletes at generation N
54 
55  private long[] normGen; // current generation of each field's norm file.
56  // If this array is null, for lockLess this means no
57  // separate norms. For preLockLess this means we must
58  // check filesystem. If this array is not null, its
59  // values mean: NO says this field has no separate
60  // norms; CHECK_DIR says it is a preLockLess segment and
61  // filesystem must be checked; >= YES says this field
62  // has separate norms with the specified generation
63 
64  private sbyte isCompoundFile; // NO if it is not; YES if it is; CHECK_DIR if it's
65  // pre-2.1 (ie, must check file system to see
66  // if <name>.cfs and <name>.nrm exist)
67 
68  private bool hasSingleNormFile; // true if this segment maintains norms in a single file;
69  // false otherwise
70  // this is currently false for segments populated by DocumentWriter
71  // and true for newly created merged segments (both
72  // compound and non compound).
73 
74  private IList<string> files; // cached list of files that this segment uses
75  // in the Directory
76 
77  internal long sizeInBytes = - 1; // total byte size of all of our files (computed on demand)
78 
79  private int docStoreOffset; // if this segment shares stored fields & vectors, this
80  // offset is where in that file this segment's docs begin
81  private System.String docStoreSegment; // name used to derive fields/vectors file we share with
82  // other segments
83  private bool docStoreIsCompoundFile; // whether doc store files are stored in compound file (*.cfx)
84 
85  private int delCount; // How many deleted docs in this segment, or -1 if not yet known
86  // (if it's an older index)
87 
88  private bool hasProx; // True if this segment has any fields with omitTermFreqAndPositions==false
89 
90  private IDictionary<string, string> diagnostics;
91 
92  public override System.String ToString()
93  {
94  return "si: " + dir.ToString() + " " + name + " docCount: " + docCount + " delCount: " + delCount + " delFileName: " + GetDelFileName();
95  }
96 
97  public SegmentInfo(System.String name, int docCount, Directory dir)
98  {
99  this.name = name;
100  this.docCount = docCount;
101  this.dir = dir;
102  delGen = NO;
103  isCompoundFile = (sbyte) (CHECK_DIR);
104  preLockless = true;
105  hasSingleNormFile = false;
106  docStoreOffset = - 1;
107  docStoreSegment = name;
108  docStoreIsCompoundFile = false;
109  delCount = 0;
110  hasProx = true;
111  }
112 
113  public SegmentInfo(System.String name, int docCount, Directory dir, bool isCompoundFile, bool hasSingleNormFile):this(name, docCount, dir, isCompoundFile, hasSingleNormFile, - 1, null, false, true)
114  {
115  }
116 
117  public SegmentInfo(System.String name, int docCount, Directory dir, bool isCompoundFile, bool hasSingleNormFile, int docStoreOffset, System.String docStoreSegment, bool docStoreIsCompoundFile, bool hasProx):this(name, docCount, dir)
118  {
119  this.isCompoundFile = (sbyte) (isCompoundFile?YES:NO);
120  this.hasSingleNormFile = hasSingleNormFile;
121  preLockless = false;
122  this.docStoreOffset = docStoreOffset;
123  this.docStoreSegment = docStoreSegment;
124  this.docStoreIsCompoundFile = docStoreIsCompoundFile;
125  this.hasProx = hasProx;
126  delCount = 0;
127  System.Diagnostics.Debug.Assert(docStoreOffset == - 1 || docStoreSegment != null, "dso=" + docStoreOffset + " dss=" + docStoreSegment + " docCount=" + docCount);
128  }
129 
130  /// <summary> Copy everything from src SegmentInfo into our instance.</summary>
131  internal void Reset(SegmentInfo src)
132  {
133  ClearFiles();
134  name = src.name;
135  docCount = src.docCount;
136  dir = src.dir;
137  preLockless = src.preLockless;
138  delGen = src.delGen;
139  docStoreOffset = src.docStoreOffset;
140  docStoreIsCompoundFile = src.docStoreIsCompoundFile;
141  if (src.normGen == null)
142  {
143  normGen = null;
144  }
145  else
146  {
147  normGen = new long[src.normGen.Length];
148  Array.Copy(src.normGen, 0, normGen, 0, src.normGen.Length);
149  }
150  isCompoundFile = src.isCompoundFile;
151  hasSingleNormFile = src.hasSingleNormFile;
152  delCount = src.delCount;
153  }
154 
155  public IDictionary<string, string> Diagnostics
156  {
157  get { return diagnostics; }
158  internal set { this.diagnostics = value; }
159  }
160 
161  /// <summary> Construct a new SegmentInfo instance by reading a
162  /// previously saved SegmentInfo from input.
163  ///
164  /// </summary>
165  /// <param name="dir">directory to load from
166  /// </param>
167  /// <param name="format">format of the segments info file
168  /// </param>
169  /// <param name="input">input handle to read segment info from
170  /// </param>
171  internal SegmentInfo(Directory dir, int format, IndexInput input)
172  {
173  this.dir = dir;
174  name = input.ReadString();
175  docCount = input.ReadInt();
176  if (format <= SegmentInfos.FORMAT_LOCKLESS)
177  {
178  delGen = input.ReadLong();
180  {
181  docStoreOffset = input.ReadInt();
182  if (docStoreOffset != - 1)
183  {
184  docStoreSegment = input.ReadString();
185  docStoreIsCompoundFile = (1 == input.ReadByte());
186  }
187  else
188  {
189  docStoreSegment = name;
190  docStoreIsCompoundFile = false;
191  }
192  }
193  else
194  {
195  docStoreOffset = - 1;
196  docStoreSegment = name;
197  docStoreIsCompoundFile = false;
198  }
199  if (format <= SegmentInfos.FORMAT_SINGLE_NORM_FILE)
200  {
201  hasSingleNormFile = (1 == input.ReadByte());
202  }
203  else
204  {
205  hasSingleNormFile = false;
206  }
207  int numNormGen = input.ReadInt();
208  if (numNormGen == NO)
209  {
210  normGen = null;
211  }
212  else
213  {
214  normGen = new long[numNormGen];
215  for (int j = 0; j < numNormGen; j++)
216  {
217  normGen[j] = input.ReadLong();
218  }
219  }
220  isCompoundFile = (sbyte) input.ReadByte();
221  preLockless = (isCompoundFile == CHECK_DIR);
222  if (format <= SegmentInfos.FORMAT_DEL_COUNT)
223  {
224  delCount = input.ReadInt();
225  System.Diagnostics.Debug.Assert(delCount <= docCount);
226  }
227  else
228  delCount = - 1;
229  if (format <= SegmentInfos.FORMAT_HAS_PROX)
230  hasProx = input.ReadByte() == 1;
231  else
232  hasProx = true;
233 
234  if (format <= SegmentInfos.FORMAT_DIAGNOSTICS)
235  {
236  diagnostics = input.ReadStringStringMap();
237  }
238  else
239  {
240  diagnostics = new Dictionary<string,string>();
241  }
242  }
243  else
244  {
245  delGen = CHECK_DIR;
246  normGen = null;
247  isCompoundFile = (sbyte) (CHECK_DIR);
248  preLockless = true;
249  hasSingleNormFile = false;
250  docStoreOffset = - 1;
251  docStoreIsCompoundFile = false;
252  docStoreSegment = null;
253  delCount = - 1;
254  hasProx = true;
255  diagnostics = new Dictionary<string,string>();
256  }
257  }
258 
259  internal void SetNumFields(int numFields)
260  {
261  if (normGen == null)
262  {
263  // normGen is null if we loaded a pre-2.1 segment
264  // file, or, if this segments file hasn't had any
265  // norms set against it yet:
266  normGen = new long[numFields];
267 
268  if (preLockless)
269  {
270  // Do nothing: thus leaving normGen[k]==CHECK_DIR (==0), so that later we know
271  // we have to check filesystem for norm files, because this is prelockless.
272  }
273  else
274  {
275  // This is a FORMAT_LOCKLESS segment, which means
276  // there are no separate norms:
277  for (int i = 0; i < numFields; i++)
278  {
279  normGen[i] = NO;
280  }
281  }
282  }
283  }
284 
285  /// <summary>Returns total size in bytes of all of files used by
286  /// this segment.
287  /// </summary>
288  public long SizeInBytes()
289  {
290  if (sizeInBytes == - 1)
291  {
292  IList<string> files = Files();
293  int size = files.Count;
294  sizeInBytes = 0;
295  for (int i = 0; i < size; i++)
296  {
297  System.String fileName = files[i];
298  // We don't count bytes used by a shared doc store
299  // against this segment:
300  if (docStoreOffset == - 1 || !IndexFileNames.IsDocStoreFile(fileName))
301  sizeInBytes += dir.FileLength(fileName);
302  }
303  }
304  return sizeInBytes;
305  }
306 
307  public bool HasDeletions()
308  {
309  // Cases:
310  //
311  // delGen == NO: this means this segment was written
312  // by the LOCKLESS code and for certain does not have
313  // deletions yet
314  //
315  // delGen == CHECK_DIR: this means this segment was written by
316  // pre-LOCKLESS code which means we must check
317  // directory to see if .del file exists
318  //
319  // delGen >= YES: this means this segment was written by
320  // the LOCKLESS code and for certain has
321  // deletions
322  //
323  if (delGen == NO)
324  {
325  return false;
326  }
327  else if (delGen >= YES)
328  {
329  return true;
330  }
331  else
332  {
333  return dir.FileExists(GetDelFileName());
334  }
335  }
336 
337  internal void AdvanceDelGen()
338  {
339  // delGen 0 is reserved for pre-LOCKLESS format
340  if (delGen == NO)
341  {
342  delGen = YES;
343  }
344  else
345  {
346  delGen++;
347  }
348  ClearFiles();
349  }
350 
351  internal void ClearDelGen()
352  {
353  delGen = NO;
354  ClearFiles();
355  }
356 
357  public System.Object Clone()
358  {
359  SegmentInfo si = new SegmentInfo(name, docCount, dir);
360  si.isCompoundFile = isCompoundFile;
361  si.delGen = delGen;
362  si.delCount = delCount;
363  si.hasProx = hasProx;
364  si.preLockless = preLockless;
365  si.hasSingleNormFile = hasSingleNormFile;
366  si.diagnostics = new HashMap<string, string>(this.diagnostics);
367  if (this.diagnostics != null)
368  {
369  si.diagnostics = new System.Collections.Generic.Dictionary<string, string>();
370  foreach (string o in diagnostics.Keys)
371  {
372  si.diagnostics.Add(o,diagnostics[o]);
373  }
374  }
375  if (normGen != null)
376  {
377  si.normGen = new long[normGen.Length];
378  normGen.CopyTo(si.normGen, 0);
379  }
380  si.docStoreOffset = docStoreOffset;
381  si.docStoreSegment = docStoreSegment;
382  si.docStoreIsCompoundFile = docStoreIsCompoundFile;
383  if (this.files != null)
384  {
385  si.files = new System.Collections.Generic.List<string>();
386  foreach (string file in files)
387  {
388  si.files.Add(file);
389  }
390  }
391 
392  return si;
393  }
394 
395  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
396  public System.String GetDelFileName()
397  {
398  if (delGen == NO)
399  {
400  // In this case we know there is no deletion filename
401  // against this segment
402  return null;
403  }
404  else
405  {
406  // If delGen is CHECK_DIR, it's the pre-lockless-commit file format
407  return IndexFileNames.FileNameFromGeneration(name, "." + IndexFileNames.DELETES_EXTENSION, delGen);
408  }
409  }
410 
411  /// <summary> Returns true if this field for this segment has saved a separate norms file (_&lt;segment&gt;_N.sX).
412  ///
413  /// </summary>
414  /// <param name="fieldNumber">the field index to check
415  /// </param>
416  public bool HasSeparateNorms(int fieldNumber)
417  {
418  if ((normGen == null && preLockless) || (normGen != null && normGen[fieldNumber] == CHECK_DIR))
419  {
420  // Must fallback to directory file exists check:
421  System.String fileName = name + ".s" + fieldNumber;
422  return dir.FileExists(fileName);
423  }
424  else if (normGen == null || normGen[fieldNumber] == NO)
425  {
426  return false;
427  }
428  else
429  {
430  return true;
431  }
432  }
433 
434  /// <summary> Returns true if any fields in this segment have separate norms.</summary>
435  public bool HasSeparateNorms()
436  {
437  if (normGen == null)
438  {
439  if (!preLockless)
440  {
441  // This means we were created w/ LOCKLESS code and no
442  // norms are written yet:
443  return false;
444  }
445  else
446  {
447  // This means this segment was saved with pre-LOCKLESS
448  // code. So we must fallback to the original
449  // directory list check:
450  System.String[] result = dir.ListAll();
451  if (result == null)
452  {
453  throw new System.IO.IOException("cannot read directory " + dir + ": ListAll() returned null");
454  }
455 
457  System.String pattern;
458  pattern = name + ".s";
459  int patternLength = pattern.Length;
460  for (int i = 0; i < result.Length; i++)
461  {
462  string fileName = result[i];
463  if (filter.Accept(null, fileName) && fileName.StartsWith(pattern) && char.IsDigit(fileName[patternLength]))
464  return true;
465  }
466  return false;
467  }
468  }
469  else
470  {
471  // This means this segment was saved with LOCKLESS
472  // code so we first check whether any normGen's are >= 1
473  // (meaning they definitely have separate norms):
474  for (int i = 0; i < normGen.Length; i++)
475  {
476  if (normGen[i] >= YES)
477  {
478  return true;
479  }
480  }
481  // Next we look for any == 0. These cases were
482  // pre-LOCKLESS and must be checked in directory:
483  for (int i = 0; i < normGen.Length; i++)
484  {
485  if (normGen[i] == CHECK_DIR)
486  {
487  if (HasSeparateNorms(i))
488  {
489  return true;
490  }
491  }
492  }
493  }
494 
495  return false;
496  }
497 
498  /// <summary> Increment the generation count for the norms file for
499  /// this field.
500  ///
501  /// </summary>
502  /// <param name="fieldIndex">field whose norm file will be rewritten
503  /// </param>
504  internal void AdvanceNormGen(int fieldIndex)
505  {
506  if (normGen[fieldIndex] == NO)
507  {
508  normGen[fieldIndex] = YES;
509  }
510  else
511  {
512  normGen[fieldIndex]++;
513  }
514  ClearFiles();
515  }
516 
517  /// <summary> Get the file name for the norms file for this field.
518  ///
519  /// </summary>
520  /// <param name="number">field index
521  /// </param>
522  public System.String GetNormFileName(int number)
523  {
524  System.String prefix;
525 
526  long gen;
527  if (normGen == null)
528  {
529  gen = CHECK_DIR;
530  }
531  else
532  {
533  gen = normGen[number];
534  }
535 
536  if (HasSeparateNorms(number))
537  {
538  // case 1: separate norm
539  prefix = ".s";
540  return IndexFileNames.FileNameFromGeneration(name, prefix + number, gen);
541  }
542 
543  if (hasSingleNormFile)
544  {
545  // case 2: lockless (or nrm file exists) - single file for all norms
546  prefix = "." + IndexFileNames.NORMS_EXTENSION;
547  return IndexFileNames.FileNameFromGeneration(name, prefix, WITHOUT_GEN);
548  }
549 
550  // case 3: norm file for each field
551  prefix = ".f";
552  return IndexFileNames.FileNameFromGeneration(name, prefix + number, WITHOUT_GEN);
553  }
554 
555  /// <summary> Returns true if this segment is stored as a compound
556  /// file; else, false.
557  /// </summary>
558  internal void SetUseCompoundFile(bool value)
559  {
560  if (value)
561  {
562  this.isCompoundFile = (sbyte) (YES);
563  }
564  else
565  {
566  this.isCompoundFile = (sbyte) (NO);
567  }
568  ClearFiles();
569  }
570 
571  /// <summary> Returns true if this segment is stored as a compound
572  /// file; else, false.
573  /// </summary>
574  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
575  public bool GetUseCompoundFile()
576  {
577  if (isCompoundFile == NO)
578  {
579  return false;
580  }
581  if (isCompoundFile == YES)
582  {
583  return true;
584  }
585  return dir.FileExists(name + "." + IndexFileNames.COMPOUND_FILE_EXTENSION);
586  }
587 
588  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
589  public int GetDelCount()
590  {
591  if (delCount == - 1)
592  {
593  if (HasDeletions())
594  {
595  System.String delFileName = GetDelFileName();
596  delCount = new BitVector(dir, delFileName).Count();
597  }
598  else
599  delCount = 0;
600  }
601  System.Diagnostics.Debug.Assert(delCount <= docCount);
602  return delCount;
603  }
604 
605  internal void SetDelCount(int delCount)
606  {
607  this.delCount = delCount;
608  System.Diagnostics.Debug.Assert(delCount <= docCount);
609  }
610 
611  public int DocStoreOffset
612  {
613  get { return docStoreOffset; }
614  internal set
615  {
616  docStoreOffset = value;
617  ClearFiles();
618  }
619  }
620 
621  public bool DocStoreIsCompoundFile
622  {
623  get { return docStoreIsCompoundFile; }
624  internal set
625  {
626  docStoreIsCompoundFile = value;
627  ClearFiles();
628  }
629  }
630 
631  public string DocStoreSegment
632  {
633  get { return docStoreSegment; }
634  }
635 
636  internal void SetDocStore(int offset, System.String segment, bool isCompoundFile)
637  {
638  docStoreOffset = offset;
639  docStoreSegment = segment;
640  docStoreIsCompoundFile = isCompoundFile;
641  }
642 
643  /// <summary> Save this segment's info.</summary>
644  internal void Write(IndexOutput output)
645  {
646  output.WriteString(name);
647  output.WriteInt(docCount);
648  output.WriteLong(delGen);
649  output.WriteInt(docStoreOffset);
650  if (docStoreOffset != - 1)
651  {
652  output.WriteString(docStoreSegment);
653  output.WriteByte((byte) (docStoreIsCompoundFile?1:0));
654  }
655 
656  output.WriteByte((byte) (hasSingleNormFile?1:0));
657  if (normGen == null)
658  {
659  output.WriteInt(NO);
660  }
661  else
662  {
663  output.WriteInt(normGen.Length);
664  for (int j = 0; j < normGen.Length; j++)
665  {
666  output.WriteLong(normGen[j]);
667  }
668  }
669  output.WriteByte((byte) isCompoundFile);
670  output.WriteInt(delCount);
671  output.WriteByte((byte) (hasProx?1:0));
672  output.WriteStringStringMap(diagnostics);
673  }
674 
675  public bool HasProx
676  {
677  get { return hasProx; }
678  internal set
679  {
680  this.hasProx = value;
681  ClearFiles();
682  }
683  }
684 
685  private void AddIfExists(IList<string> files, System.String fileName)
686  {
687  if (dir.FileExists(fileName))
688  files.Add(fileName);
689  }
690 
691  /*
692  * Return all files referenced by this SegmentInfo. The
693  * returns List is a locally cached List so you should not
694  * modify it.
695  */
696 
697  public IList<string> Files()
698  {
699 
700  if (files != null)
701  {
702  // Already cached:
703  return files;
704  }
705 
706  var fileList = new System.Collections.Generic.List<string>();
707 
708  bool useCompoundFile = GetUseCompoundFile();
709 
710  if (useCompoundFile)
711  {
712  fileList.Add(name + "." + IndexFileNames.COMPOUND_FILE_EXTENSION);
713  }
714  else
715  {
716  System.String[] exts = IndexFileNames.NON_STORE_INDEX_EXTENSIONS;
717  for (int i = 0; i < exts.Length; i++)
718  AddIfExists(fileList, name + "." + exts[i]);
719  }
720 
721  if (docStoreOffset != - 1)
722  {
723  // We are sharing doc stores (stored fields, term
724  // vectors) with other segments
725  System.Diagnostics.Debug.Assert(docStoreSegment != null);
726  if (docStoreIsCompoundFile)
727  {
728  fileList.Add(docStoreSegment + "." + IndexFileNames.COMPOUND_FILE_STORE_EXTENSION);
729  }
730  else
731  {
732  System.String[] exts = IndexFileNames.STORE_INDEX_EXTENSIONS;
733  for (int i = 0; i < exts.Length; i++)
734  AddIfExists(fileList, docStoreSegment + "." + exts[i]);
735  }
736  }
737  else if (!useCompoundFile)
738  {
739  // We are not sharing, and, these files were not
740  // included in the compound file
741  System.String[] exts = IndexFileNames.STORE_INDEX_EXTENSIONS;
742  for (int i = 0; i < exts.Length; i++)
743  AddIfExists(fileList, name + "." + exts[i]);
744  }
745 
746  System.String delFileName = IndexFileNames.FileNameFromGeneration(name, "." + IndexFileNames.DELETES_EXTENSION, delGen);
747  if (delFileName != null && (delGen >= YES || dir.FileExists(delFileName)))
748  {
749  fileList.Add(delFileName);
750  }
751 
752  // Careful logic for norms files
753  if (normGen != null)
754  {
755  for (int i = 0; i < normGen.Length; i++)
756  {
757  long gen = normGen[i];
758  if (gen >= YES)
759  {
760  // Definitely a separate norm file, with generation:
762  }
763  else if (NO == gen)
764  {
765  // No separate norms but maybe plain norms
766  // in the non compound file case:
767  if (!hasSingleNormFile && !useCompoundFile)
768  {
769  System.String fileName = name + "." + IndexFileNames.PLAIN_NORMS_EXTENSION + i;
770  if (dir.FileExists(fileName))
771  {
772  fileList.Add(fileName);
773  }
774  }
775  }
776  else if (CHECK_DIR == gen)
777  {
778  // Pre-2.1: we have to check file existence
779  System.String fileName = null;
780  if (useCompoundFile)
781  {
782  fileName = name + "." + IndexFileNames.SEPARATE_NORMS_EXTENSION + i;
783  }
784  else if (!hasSingleNormFile)
785  {
786  fileName = name + "." + IndexFileNames.PLAIN_NORMS_EXTENSION + i;
787  }
788  if (fileName != null && dir.FileExists(fileName))
789  {
790  fileList.Add(fileName);
791  }
792  }
793  }
794  }
795  else if (preLockless || (!hasSingleNormFile && !useCompoundFile))
796  {
797  // Pre-2.1: we have to scan the dir to find all
798  // matching _X.sN/_X.fN files for our segment:
799  System.String prefix;
800  if (useCompoundFile)
801  prefix = name + "." + IndexFileNames.SEPARATE_NORMS_EXTENSION;
802  else
803  prefix = name + "." + IndexFileNames.PLAIN_NORMS_EXTENSION;
804  int prefixLength = prefix.Length;
805  System.String[] allFiles = dir.ListAll();
807  for (int i = 0; i < allFiles.Length; i++)
808  {
809  System.String fileName = allFiles[i];
810  if (filter.Accept(null, fileName) && fileName.Length > prefixLength && System.Char.IsDigit(fileName[prefixLength]) && fileName.StartsWith(prefix))
811  {
812  fileList.Add(fileName);
813  }
814  }
815  }
816  //System.Diagnostics.Debug.Assert();
817  files = fileList;
818  return files;
819  }
820 
821  /* Called whenever any change is made that affects which
822  * files this segment has. */
823  private void ClearFiles()
824  {
825  files = null;
826  sizeInBytes = - 1;
827  }
828 
829  /// <summary>Used for debugging </summary>
830  public System.String SegString(Directory dir)
831  {
832  System.String cfs;
833  try
834  {
835  if (GetUseCompoundFile())
836  cfs = "c";
837  else
838  cfs = "C";
839  }
840  catch (System.IO.IOException)
841  {
842  cfs = "?";
843  }
844 
845  System.String docStore;
846 
847  if (docStoreOffset != - 1)
848  docStore = "->" + docStoreSegment;
849  else
850  docStore = "";
851 
852  return name + ":" + cfs + (this.dir == dir?"":"x") + docCount + docStore;
853  }
854 
855  /// <summary>We consider another SegmentInfo instance equal if it
856  /// has the same dir and same name.
857  /// </summary>
858  public override bool Equals(System.Object obj)
859  {
860  if (this == obj) return true;
861 
862  if (obj is SegmentInfo)
863  {
864  SegmentInfo other = (SegmentInfo) obj;
865  return other.dir == dir && other.name.Equals(name);
866  }
867  return false;
868  }
869 
870  public override int GetHashCode()
871  {
872  return dir.GetHashCode() + name.GetHashCode();
873  }
874  }
875 }