~slub.team/goobi-indexserver/3.x

« back to all changes in this revision

Viewing changes to lucene/src/java/org/apache/lucene/index/SegmentInfo.java

  • Committer: Sebastian Meyer
  • Date: 2012-08-03 09:12:40 UTC
  • Revision ID: sebastian.meyer@slub-dresden.de-20120803091240-x6861b0vabq1xror
Remove Lucene and Solr source code and add patches instead
Fix Bug #985487: Auto-suggestion for the search interface

Show diffs side-by-side

added added

removed removed

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