~ubuntu-branches/ubuntu/trusty/pylucene/trusty

« back to all changes in this revision

Viewing changes to lucene-java-3.5.0/lucene/src/java/org/apache/lucene/index/TermsHashPerField.java

  • Committer: Package Import Robot
  • Author(s): Dmitry Nezhevenko
  • Date: 2012-04-23 16:43:55 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120423164355-grqtepnwtecdjfk2
Tags: 3.5.0-1
* New maintainer (closes: 670179)
* New upstream release
* Switch to dpkg-source 3.0 (quilt) format
* Switch to machine-readable debian/copyright
* Bump debian/compat to 8, drop debian/pycompat
* Switch from cdbs to dh
* Add watch file
* Build for all supported versions of python2 (closes: 581198, 632240)
* Rename binary package to python-lucene (closes: 581197)
* Add -dbg package

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 java.io.IOException;
 
21
import java.util.Arrays;
 
22
 
 
23
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
 
24
import org.apache.lucene.document.Fieldable;
 
25
import org.apache.lucene.util.UnicodeUtil;
 
26
import org.apache.lucene.util.RamUsageEstimator;
 
27
import org.apache.lucene.util.SorterTemplate;
 
28
 
 
29
final class TermsHashPerField extends InvertedDocConsumerPerField {
 
30
 
 
31
  final TermsHashConsumerPerField consumer;
 
32
 
 
33
  final TermsHashPerField nextPerField;
 
34
  final TermsHashPerThread perThread;
 
35
  final DocumentsWriter.DocState docState;
 
36
  final FieldInvertState fieldState;
 
37
  CharTermAttribute termAtt;
 
38
  
 
39
  // Copied from our perThread
 
40
  final CharBlockPool charPool;
 
41
  final IntBlockPool intPool;
 
42
  final ByteBlockPool bytePool;
 
43
 
 
44
  final int streamCount;
 
45
  final int numPostingInt;
 
46
 
 
47
  final FieldInfo fieldInfo;
 
48
 
 
49
  boolean postingsCompacted;
 
50
  int numPostings;
 
51
  private int postingsHashSize = 4;
 
52
  private int postingsHashHalfSize = postingsHashSize/2;
 
53
  private int postingsHashMask = postingsHashSize-1;
 
54
  private int[] postingsHash;
 
55
 
 
56
  ParallelPostingsArray postingsArray;
 
57
  
 
58
  public TermsHashPerField(DocInverterPerField docInverterPerField, final TermsHashPerThread perThread, final TermsHashPerThread nextPerThread, final FieldInfo fieldInfo) {
 
59
    this.perThread = perThread;
 
60
    intPool = perThread.intPool;
 
61
    charPool = perThread.charPool;
 
62
    bytePool = perThread.bytePool;
 
63
    docState = perThread.docState;
 
64
 
 
65
    postingsHash = new int[postingsHashSize];
 
66
    Arrays.fill(postingsHash, -1);
 
67
    bytesUsed(postingsHashSize * RamUsageEstimator.NUM_BYTES_INT);
 
68
 
 
69
    fieldState = docInverterPerField.fieldState;
 
70
    this.consumer = perThread.consumer.addField(this, fieldInfo);
 
71
    initPostingsArray();
 
72
 
 
73
    streamCount = consumer.getStreamCount();
 
74
    numPostingInt = 2*streamCount;
 
75
    this.fieldInfo = fieldInfo;
 
76
    if (nextPerThread != null)
 
77
      nextPerField = (TermsHashPerField) nextPerThread.addField(docInverterPerField, fieldInfo);
 
78
    else
 
79
      nextPerField = null;
 
80
  }
 
81
 
 
82
  private void initPostingsArray() {
 
83
    postingsArray = consumer.createPostingsArray(2);
 
84
    bytesUsed(postingsArray.size * postingsArray.bytesPerPosting());
 
85
  }
 
86
 
 
87
  // sugar: just forwards to DW
 
88
  private void bytesUsed(long size) {
 
89
    if (perThread.termsHash.trackAllocations) {
 
90
      perThread.termsHash.docWriter.bytesUsed(size);
 
91
    }
 
92
  }
 
93
  
 
94
  void shrinkHash(int targetSize) {
 
95
    assert postingsCompacted || numPostings == 0;
 
96
 
 
97
    final int newSize = 4;
 
98
    if (newSize != postingsHash.length) {
 
99
      final long previousSize = postingsHash.length;
 
100
      postingsHash = new int[newSize];
 
101
      bytesUsed((newSize-previousSize)*RamUsageEstimator.NUM_BYTES_INT);
 
102
      Arrays.fill(postingsHash, -1);
 
103
      postingsHashSize = newSize;
 
104
      postingsHashHalfSize = newSize/2;
 
105
      postingsHashMask = newSize-1;
 
106
    }
 
107
 
 
108
    // Fully free the postings array on each flush:
 
109
    if (postingsArray != null) {
 
110
      bytesUsed(-postingsArray.bytesPerPosting() * postingsArray.size);
 
111
      postingsArray = null;
 
112
    }
 
113
  }
 
114
 
 
115
  public void reset() {
 
116
    if (!postingsCompacted)
 
117
      compactPostings();
 
118
    assert numPostings <= postingsHash.length;
 
119
    if (numPostings > 0) {
 
120
      Arrays.fill(postingsHash, 0, numPostings, -1);
 
121
      numPostings = 0;
 
122
    }
 
123
    postingsCompacted = false;
 
124
    if (nextPerField != null)
 
125
      nextPerField.reset();
 
126
  }
 
127
 
 
128
  @Override
 
129
  synchronized public void abort() {
 
130
    reset();
 
131
    if (nextPerField != null)
 
132
      nextPerField.abort();
 
133
  }
 
134
  
 
135
  private final void growParallelPostingsArray() {
 
136
    int oldSize = postingsArray.size;
 
137
    this.postingsArray = this.postingsArray.grow();
 
138
    bytesUsed(postingsArray.bytesPerPosting() * (postingsArray.size - oldSize));
 
139
  }
 
140
 
 
141
  public void initReader(ByteSliceReader reader, int termID, int stream) {
 
142
    assert stream < streamCount;
 
143
    int intStart = postingsArray.intStarts[termID];
 
144
    final int[] ints = intPool.buffers[intStart >> DocumentsWriter.INT_BLOCK_SHIFT];
 
145
    final int upto = intStart & DocumentsWriter.INT_BLOCK_MASK;
 
146
    reader.init(bytePool,
 
147
                postingsArray.byteStarts[termID]+stream*ByteBlockPool.FIRST_LEVEL_SIZE,
 
148
                ints[upto+stream]);
 
149
  }
 
150
 
 
151
  private void compactPostings() {
 
152
    int upto = 0;
 
153
    for(int i=0;i<postingsHashSize;i++) {
 
154
      if (postingsHash[i] != -1) {
 
155
        if (upto < i) {
 
156
          postingsHash[upto] = postingsHash[i];
 
157
          postingsHash[i] = -1;
 
158
        }
 
159
        upto++;
 
160
      }
 
161
    }
 
162
 
 
163
    assert upto == numPostings: "upto=" + upto + " numPostings=" + numPostings;
 
164
    postingsCompacted = true;
 
165
  }
 
166
 
 
167
  /** Collapse the hash table & sort in-place. */
 
168
  public int[] sortPostings() {
 
169
    compactPostings();
 
170
    final int[] postingsHash = this.postingsHash;
 
171
    new SorterTemplate() {
 
172
      @Override
 
173
      protected void swap(int i, int j) {
 
174
        final int o = postingsHash[i];
 
175
        postingsHash[i] = postingsHash[j];
 
176
        postingsHash[j] = o;
 
177
      }
 
178
      
 
179
      @Override
 
180
      protected int compare(int i, int j) {
 
181
        final int term1 = postingsHash[i], term2 = postingsHash[j];
 
182
        if (term1 == term2)
 
183
          return 0;
 
184
        final int textStart1 = postingsArray.textStarts[term1],
 
185
          textStart2 = postingsArray.textStarts[term2];
 
186
        final char[] text1 = charPool.buffers[textStart1 >> DocumentsWriter.CHAR_BLOCK_SHIFT];
 
187
        final int pos1 = textStart1 & DocumentsWriter.CHAR_BLOCK_MASK;
 
188
        final char[] text2 = charPool.buffers[textStart2 >> DocumentsWriter.CHAR_BLOCK_SHIFT];
 
189
        final int pos2 = textStart2 & DocumentsWriter.CHAR_BLOCK_MASK;
 
190
        return comparePostings(text1, pos1, text2, pos2);
 
191
      }
 
192
 
 
193
      @Override
 
194
      protected void setPivot(int i) {
 
195
        pivotTerm = postingsHash[i];
 
196
        final int textStart = postingsArray.textStarts[pivotTerm];
 
197
        pivotBuf = charPool.buffers[textStart >> DocumentsWriter.CHAR_BLOCK_SHIFT];
 
198
        pivotBufPos = textStart & DocumentsWriter.CHAR_BLOCK_MASK;
 
199
      }
 
200
  
 
201
      @Override
 
202
      protected int comparePivot(int j) {
 
203
        final int term = postingsHash[j];
 
204
        if (pivotTerm == term)
 
205
          return 0;
 
206
        final int textStart = postingsArray.textStarts[term];
 
207
        final char[] text = charPool.buffers[textStart >> DocumentsWriter.CHAR_BLOCK_SHIFT];
 
208
        final int pos = textStart & DocumentsWriter.CHAR_BLOCK_MASK;
 
209
        return comparePostings(pivotBuf, pivotBufPos, text, pos);
 
210
      }
 
211
      
 
212
      private int pivotTerm, pivotBufPos;
 
213
      private char[] pivotBuf;
 
214
 
 
215
      /** Compares term text for two Posting instance and
 
216
       *  returns -1 if p1 < p2; 1 if p1 > p2; else 0. */
 
217
      private int comparePostings(final char[] text1, int pos1, final char[] text2, int pos2) {
 
218
        assert text1 != text2 || pos1 != pos2;
 
219
 
 
220
        while(true) {
 
221
          final char c1 = text1[pos1++];
 
222
          final char c2 = text2[pos2++];
 
223
          if (c1 != c2) {
 
224
            if (0xffff == c2)
 
225
              return 1;
 
226
            else if (0xffff == c1)
 
227
              return -1;
 
228
            else
 
229
              return c1-c2;
 
230
          } else
 
231
            // This method should never compare equal postings
 
232
            // unless p1==p2
 
233
            assert c1 != 0xffff;
 
234
        }
 
235
      }
 
236
    }.quickSort(0, numPostings-1);
 
237
    return postingsHash;
 
238
  }
 
239
 
 
240
  /** Test whether the text for current RawPostingList p equals
 
241
   *  current tokenText. */
 
242
  private boolean postingEquals(final int termID, final char[] tokenText, final int tokenTextLen) {
 
243
    final int textStart = postingsArray.textStarts[termID];
 
244
    
 
245
    final char[] text = perThread.charPool.buffers[textStart >> DocumentsWriter.CHAR_BLOCK_SHIFT];
 
246
    assert text != null;
 
247
    int pos = textStart & DocumentsWriter.CHAR_BLOCK_MASK;
 
248
 
 
249
    int tokenPos = 0;
 
250
    for(;tokenPos<tokenTextLen;pos++,tokenPos++)
 
251
      if (tokenText[tokenPos] != text[pos])
 
252
        return false;
 
253
    return 0xffff == text[pos];
 
254
  }
 
255
  
 
256
  private boolean doCall;
 
257
  private boolean doNextCall;
 
258
 
 
259
  @Override
 
260
  void start(Fieldable f) {
 
261
    termAtt = fieldState.attributeSource.addAttribute(CharTermAttribute.class);
 
262
    consumer.start(f);
 
263
    if (nextPerField != null) {
 
264
      nextPerField.start(f);
 
265
    }
 
266
  }
 
267
  
 
268
  @Override
 
269
  boolean start(Fieldable[] fields, int count) throws IOException {
 
270
    doCall = consumer.start(fields, count);
 
271
    if (postingsArray == null) {
 
272
      initPostingsArray();
 
273
    }
 
274
 
 
275
    if (nextPerField != null)
 
276
      doNextCall = nextPerField.start(fields, count);
 
277
    return doCall || doNextCall;
 
278
  }
 
279
 
 
280
  // Secondary entry point (for 2nd & subsequent TermsHash),
 
281
  // because token text has already been "interned" into
 
282
  // textStart, so we hash by textStart
 
283
  public void add(int textStart) throws IOException {
 
284
    int code = textStart;
 
285
 
 
286
    int hashPos = code & postingsHashMask;
 
287
 
 
288
    assert !postingsCompacted;
 
289
 
 
290
    // Locate RawPostingList in hash
 
291
    int termID = postingsHash[hashPos];
 
292
 
 
293
    if (termID != -1 && postingsArray.textStarts[termID] != textStart) {
 
294
      // Conflict: keep searching different locations in
 
295
      // the hash table.
 
296
      final int inc = ((code>>8)+code)|1;
 
297
      do {
 
298
        code += inc;
 
299
        hashPos = code & postingsHashMask;
 
300
        termID = postingsHash[hashPos];
 
301
      } while (termID != -1 && postingsArray.textStarts[termID] != textStart);
 
302
    }
 
303
 
 
304
    if (termID == -1) {
 
305
 
 
306
      // First time we are seeing this token since we last
 
307
      // flushed the hash.
 
308
 
 
309
      // New posting
 
310
      termID = numPostings++;
 
311
      if (termID >= postingsArray.size) {
 
312
        growParallelPostingsArray();
 
313
      }
 
314
 
 
315
      assert termID >= 0;
 
316
 
 
317
      postingsArray.textStarts[termID] = textStart;
 
318
          
 
319
      assert postingsHash[hashPos] == -1;
 
320
      postingsHash[hashPos] = termID;
 
321
 
 
322
      if (numPostings == postingsHashHalfSize)
 
323
        rehashPostings(2*postingsHashSize);
 
324
 
 
325
      // Init stream slices
 
326
      if (numPostingInt + intPool.intUpto > DocumentsWriter.INT_BLOCK_SIZE)
 
327
        intPool.nextBuffer();
 
328
 
 
329
      if (DocumentsWriter.BYTE_BLOCK_SIZE - bytePool.byteUpto < numPostingInt*ByteBlockPool.FIRST_LEVEL_SIZE)
 
330
        bytePool.nextBuffer();
 
331
 
 
332
      intUptos = intPool.buffer;
 
333
      intUptoStart = intPool.intUpto;
 
334
      intPool.intUpto += streamCount;
 
335
 
 
336
      postingsArray.intStarts[termID] = intUptoStart + intPool.intOffset;
 
337
 
 
338
      for(int i=0;i<streamCount;i++) {
 
339
        final int upto = bytePool.newSlice(ByteBlockPool.FIRST_LEVEL_SIZE);
 
340
        intUptos[intUptoStart+i] = upto + bytePool.byteOffset;
 
341
      }
 
342
      postingsArray.byteStarts[termID] = intUptos[intUptoStart];
 
343
 
 
344
      consumer.newTerm(termID);
 
345
 
 
346
    } else {
 
347
      int intStart = postingsArray.intStarts[termID];
 
348
      intUptos = intPool.buffers[intStart >> DocumentsWriter.INT_BLOCK_SHIFT];
 
349
      intUptoStart = intStart & DocumentsWriter.INT_BLOCK_MASK;
 
350
      consumer.addTerm(termID);
 
351
    }
 
352
  }
 
353
 
 
354
  // Primary entry point (for first TermsHash)
 
355
  @Override
 
356
  void add() throws IOException {
 
357
 
 
358
    assert !postingsCompacted;
 
359
 
 
360
    // We are first in the chain so we must "intern" the
 
361
    // term text into textStart address
 
362
 
 
363
    // Get the text of this term.
 
364
    final char[] tokenText = termAtt.buffer();
 
365
    final int tokenTextLen = termAtt.length();
 
366
 
 
367
    // Compute hashcode & replace any invalid UTF16 sequences
 
368
    int downto = tokenTextLen;
 
369
    int code = 0;
 
370
    while (downto > 0) {
 
371
      char ch = tokenText[--downto];
 
372
 
 
373
      if (ch >= UnicodeUtil.UNI_SUR_LOW_START && ch <= UnicodeUtil.UNI_SUR_LOW_END) {
 
374
        if (0 == downto) {
 
375
          // Unpaired
 
376
          ch = tokenText[downto] = UnicodeUtil.UNI_REPLACEMENT_CHAR;
 
377
        } else {
 
378
          final char ch2 = tokenText[downto-1];
 
379
          if (ch2 >= UnicodeUtil.UNI_SUR_HIGH_START && ch2 <= UnicodeUtil.UNI_SUR_HIGH_END) {
 
380
            // OK: high followed by low.  This is a valid
 
381
            // surrogate pair.
 
382
            code = ((code*31) + ch)*31+ch2;
 
383
            downto--;
 
384
            continue;
 
385
          } else {
 
386
            // Unpaired
 
387
            ch = tokenText[downto] = UnicodeUtil.UNI_REPLACEMENT_CHAR;
 
388
          }            
 
389
        }
 
390
      } else if (ch >= UnicodeUtil.UNI_SUR_HIGH_START && (ch <= UnicodeUtil.UNI_SUR_HIGH_END ||
 
391
                                                          ch == 0xffff)) {
 
392
        // Unpaired or 0xffff
 
393
        ch = tokenText[downto] = UnicodeUtil.UNI_REPLACEMENT_CHAR;
 
394
      }
 
395
 
 
396
      code = (code*31) + ch;
 
397
    }
 
398
 
 
399
    int hashPos = code & postingsHashMask;
 
400
 
 
401
    // Locate RawPostingList in hash
 
402
    int termID = postingsHash[hashPos];
 
403
 
 
404
    if (termID != -1 && !postingEquals(termID, tokenText, tokenTextLen)) {
 
405
      // Conflict: keep searching different locations in
 
406
      // the hash table.
 
407
      final int inc = ((code>>8)+code)|1;
 
408
      do {
 
409
        code += inc;
 
410
        hashPos = code & postingsHashMask;
 
411
        termID = postingsHash[hashPos];
 
412
      } while (termID != -1 && !postingEquals(termID, tokenText, tokenTextLen));
 
413
    }
 
414
 
 
415
    if (termID == -1) {
 
416
 
 
417
      // First time we are seeing this token since we last
 
418
      // flushed the hash.
 
419
      final int textLen1 = 1+tokenTextLen;
 
420
      if (textLen1 + charPool.charUpto > DocumentsWriter.CHAR_BLOCK_SIZE) {
 
421
        if (textLen1 > DocumentsWriter.CHAR_BLOCK_SIZE) {
 
422
          // Just skip this term, to remain as robust as
 
423
          // possible during indexing.  A TokenFilter
 
424
          // can be inserted into the analyzer chain if
 
425
          // other behavior is wanted (pruning the term
 
426
          // to a prefix, throwing an exception, etc).
 
427
 
 
428
          if (docState.maxTermPrefix == null)
 
429
            docState.maxTermPrefix = new String(tokenText, 0, 30);
 
430
 
 
431
          consumer.skippingLongTerm();
 
432
          return;
 
433
        }
 
434
        charPool.nextBuffer();
 
435
      }
 
436
 
 
437
      // New posting
 
438
      termID = numPostings++;
 
439
      if (termID >= postingsArray.size) {
 
440
        growParallelPostingsArray();
 
441
      }
 
442
 
 
443
      assert termID != -1;
 
444
 
 
445
      final char[] text = charPool.buffer;
 
446
      final int textUpto = charPool.charUpto;
 
447
      postingsArray.textStarts[termID] = textUpto + charPool.charOffset;
 
448
      charPool.charUpto += textLen1;
 
449
      System.arraycopy(tokenText, 0, text, textUpto, tokenTextLen);
 
450
      text[textUpto+tokenTextLen] = 0xffff;
 
451
          
 
452
      assert postingsHash[hashPos] == -1;
 
453
      postingsHash[hashPos] = termID;
 
454
 
 
455
      if (numPostings == postingsHashHalfSize) {
 
456
        rehashPostings(2*postingsHashSize);
 
457
        bytesUsed(2*numPostings * RamUsageEstimator.NUM_BYTES_INT);
 
458
      }
 
459
 
 
460
      // Init stream slices
 
461
      if (numPostingInt + intPool.intUpto > DocumentsWriter.INT_BLOCK_SIZE)
 
462
        intPool.nextBuffer();
 
463
 
 
464
      if (DocumentsWriter.BYTE_BLOCK_SIZE - bytePool.byteUpto < numPostingInt*ByteBlockPool.FIRST_LEVEL_SIZE)
 
465
        bytePool.nextBuffer();
 
466
 
 
467
      intUptos = intPool.buffer;
 
468
      intUptoStart = intPool.intUpto;
 
469
      intPool.intUpto += streamCount;
 
470
 
 
471
      postingsArray.intStarts[termID] = intUptoStart + intPool.intOffset;
 
472
 
 
473
      for(int i=0;i<streamCount;i++) {
 
474
        final int upto = bytePool.newSlice(ByteBlockPool.FIRST_LEVEL_SIZE);
 
475
        intUptos[intUptoStart+i] = upto + bytePool.byteOffset;
 
476
      }
 
477
      postingsArray.byteStarts[termID] = intUptos[intUptoStart];
 
478
      
 
479
      consumer.newTerm(termID);
 
480
 
 
481
    } else {
 
482
      final int intStart = postingsArray.intStarts[termID];
 
483
      intUptos = intPool.buffers[intStart >> DocumentsWriter.INT_BLOCK_SHIFT];
 
484
      intUptoStart = intStart & DocumentsWriter.INT_BLOCK_MASK;
 
485
      consumer.addTerm(termID);
 
486
    }
 
487
 
 
488
    if (doNextCall)
 
489
      nextPerField.add(postingsArray.textStarts[termID]);
 
490
  }
 
491
 
 
492
  int[] intUptos;
 
493
  int intUptoStart;
 
494
 
 
495
  void writeByte(int stream, byte b) {
 
496
    int upto = intUptos[intUptoStart+stream];
 
497
    byte[] bytes = bytePool.buffers[upto >> DocumentsWriter.BYTE_BLOCK_SHIFT];
 
498
    assert bytes != null;
 
499
    int offset = upto & DocumentsWriter.BYTE_BLOCK_MASK;
 
500
    if (bytes[offset] != 0) {
 
501
      // End of slice; allocate a new one
 
502
      offset = bytePool.allocSlice(bytes, offset);
 
503
      bytes = bytePool.buffer;
 
504
      intUptos[intUptoStart+stream] = offset + bytePool.byteOffset;
 
505
    }
 
506
    bytes[offset] = b;
 
507
    (intUptos[intUptoStart+stream])++;
 
508
  }
 
509
 
 
510
  public void writeBytes(int stream, byte[] b, int offset, int len) {
 
511
    // TODO: optimize
 
512
    final int end = offset + len;
 
513
    for(int i=offset;i<end;i++)
 
514
      writeByte(stream, b[i]);
 
515
  }
 
516
 
 
517
  void writeVInt(int stream, int i) {
 
518
    assert stream < streamCount;
 
519
    while ((i & ~0x7F) != 0) {
 
520
      writeByte(stream, (byte)((i & 0x7f) | 0x80));
 
521
      i >>>= 7;
 
522
    }
 
523
    writeByte(stream, (byte) i);
 
524
  }
 
525
 
 
526
  @Override
 
527
  void finish() throws IOException {
 
528
    try {
 
529
      consumer.finish();
 
530
    } finally {
 
531
      if (nextPerField != null) {
 
532
        nextPerField.finish();
 
533
      }
 
534
    }
 
535
  }
 
536
 
 
537
  /** Called when postings hash is too small (> 50%
 
538
   *  occupied) or too large (< 20% occupied). */
 
539
  void rehashPostings(final int newSize) {
 
540
 
 
541
    final int newMask = newSize-1;
 
542
 
 
543
    int[] newHash = new int[newSize];
 
544
    Arrays.fill(newHash, -1);
 
545
    for(int i=0;i<postingsHashSize;i++) {
 
546
      int termID = postingsHash[i];
 
547
      if (termID != -1) {
 
548
        int code;
 
549
        if (perThread.primary) {
 
550
          final int textStart = postingsArray.textStarts[termID];
 
551
          final int start = textStart & DocumentsWriter.CHAR_BLOCK_MASK;
 
552
          final char[] text = charPool.buffers[textStart >> DocumentsWriter.CHAR_BLOCK_SHIFT];
 
553
          int pos = start;
 
554
          while(text[pos] != 0xffff)
 
555
            pos++;
 
556
          code = 0;
 
557
          while (pos > start)
 
558
            code = (code*31) + text[--pos];
 
559
        } else
 
560
          code = postingsArray.textStarts[termID];
 
561
 
 
562
        int hashPos = code & newMask;
 
563
        assert hashPos >= 0;
 
564
        if (newHash[hashPos] != -1) {
 
565
          final int inc = ((code>>8)+code)|1;
 
566
          do {
 
567
            code += inc;
 
568
            hashPos = code & newMask;
 
569
          } while (newHash[hashPos] != -1);
 
570
        }
 
571
        newHash[hashPos] = termID;
 
572
      }
 
573
    }
 
574
 
 
575
    postingsHashMask = newMask;
 
576
    postingsHash = newHash;
 
577
 
 
578
    postingsHashSize = newSize;
 
579
    postingsHashHalfSize = newSize >> 1;
 
580
  }
 
581
}