LUCENE-8309: Live docs are no longer backed by mutable bits.

This commit is contained in:
Adrien Grand 2018-05-16 17:26:02 +02:00
parent 6d69824a6b
commit 35a815b955
6 changed files with 99 additions and 11 deletions

View File

@ -115,6 +115,10 @@ API Changes
* LUCENE-8303: LiveDocsFormat is now only responsible for (de)serialization of * LUCENE-8303: LiveDocsFormat is now only responsible for (de)serialization of
live docs. (Adrien Grand) live docs. (Adrien Grand)
Changes in Runtime Behavior
* LUCENE-8309: Live docs are no longer backed by a FixedBitSet. (Adrien Grand)
New Features New Features
* LUCENE-8200: Allow doc-values to be updated atomically together * LUCENE-8200: Allow doc-values to be updated atomically together

View File

@ -80,7 +80,7 @@ public final class Lucene50LiveDocsFormat extends LiveDocsFormat {
throw new CorruptIndexException("bits.deleted=" + (fbs.length() - fbs.cardinality()) + throw new CorruptIndexException("bits.deleted=" + (fbs.length() - fbs.cardinality()) +
" info.delcount=" + info.getDelCount(), input); " info.delcount=" + info.getDelCount(), input);
} }
return fbs; return fbs.asReadOnlyBits();
} catch (Throwable exception) { } catch (Throwable exception) {
priorE = exception; priorE = exception;
} finally { } finally {

View File

@ -76,7 +76,7 @@ class PendingDeletes {
writeableLiveDocs = new FixedBitSet(info.info.maxDoc()); writeableLiveDocs = new FixedBitSet(info.info.maxDoc());
writeableLiveDocs.set(0, info.info.maxDoc()); writeableLiveDocs.set(0, info.info.maxDoc());
} }
liveDocs = writeableLiveDocs; liveDocs = writeableLiveDocs.asReadOnlyBits();
} }
return writeableLiveDocs; return writeableLiveDocs;
} }

View File

@ -515,6 +515,12 @@ public final class FixedBitSet extends BitSet implements Bits, Accountable {
* Make a copy of the given bits. * Make a copy of the given bits.
*/ */
public static FixedBitSet copyOf(Bits bits) { public static FixedBitSet copyOf(Bits bits) {
if (bits instanceof FixedBits) {
// restore the original FixedBitSet
FixedBits fixedBits = (FixedBits) bits;
bits = new FixedBitSet(fixedBits.bits, fixedBits.length);
}
if (bits instanceof FixedBitSet) { if (bits instanceof FixedBitSet) {
return ((FixedBitSet)bits).clone(); return ((FixedBitSet)bits).clone();
} else { } else {
@ -529,4 +535,16 @@ public final class FixedBitSet extends BitSet implements Bits, Accountable {
return bitSet; return bitSet;
} }
} }
/**
* Convert this instance to read-only {@link Bits}.
* This is useful in the case that this {@link FixedBitSet} is returned as a
* {@link Bits} instance, to make sure that consumers may not get write access
* back by casting to a {@link FixedBitSet}.
* NOTE: Changes to this {@link FixedBitSet} will be reflected on the returned
* {@link Bits}.
*/
public Bits asReadOnlyBits() {
return new FixedBits(bits, numBits);
}
} }

View File

@ -0,0 +1,47 @@
/*
* 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.
*/
package org.apache.lucene.util;
/**
* Immutable twin of FixedBitSet.
*/
final class FixedBits implements Bits {
final long[] bits;
final int length;
FixedBits(long[] bits, int length) {
this.bits = bits;
this.length = length;
}
@Override
public boolean get(int index) {
assert index >= 0 && index < length: "index=" + index + ", numBits=" + length;
int i = index >> 6; // div 64
// signed shift will keep a negative index and force an
// array-index-out-of-bounds-exception, removing the need for an explicit check.
long bitmask = 1L << index;
return (bits[i] & bitmask) != 0;
}
@Override
public int length() {
return length;
}
}

View File

@ -503,11 +503,14 @@ public class TestFixedBitSet extends BaseBitSetTestCase<FixedBitSet> {
for (int e : bits) { for (int e : bits) {
fixedBitSet.set(e); fixedBitSet.set(e);
} }
FixedBitSet mutableCopy = FixedBitSet.copyOf(fixedBitSet); for (boolean readOnly : new boolean[] {false, true}) {
assertNotSame(mutableCopy, fixedBitSet); Bits bitsToCopy = readOnly ? fixedBitSet.asReadOnlyBits() : fixedBitSet;
FixedBitSet mutableCopy = FixedBitSet.copyOf(bitsToCopy);
assertNotSame(mutableCopy, bitsToCopy);
assertEquals(mutableCopy, fixedBitSet); assertEquals(mutableCopy, fixedBitSet);
}
FixedBitSet mutableCopy1 = FixedBitSet.copyOf(new Bits() { final Bits bitsToCopy = new Bits() {
@Override @Override
public boolean get(int index) { public boolean get(int index) {
@ -518,11 +521,27 @@ public class TestFixedBitSet extends BaseBitSetTestCase<FixedBitSet> {
public int length() { public int length() {
return fixedBitSet.length(); return fixedBitSet.length();
} }
}); };
FixedBitSet mutableCopy = FixedBitSet.copyOf(bitsToCopy);
assertNotSame(mutableCopy, mutableCopy1); assertNotSame(bitsToCopy, mutableCopy);
assertNotSame(fixedBitSet, mutableCopy1); assertNotSame(fixedBitSet, mutableCopy);
assertEquals(mutableCopy1, mutableCopy); assertEquals(mutableCopy, fixedBitSet);
assertEquals(mutableCopy1, fixedBitSet); }
public void testAsBits() {
FixedBitSet set = new FixedBitSet(10);
set.set(3);
set.set(4);
set.set(9);
Bits bits = set.asReadOnlyBits();
assertFalse(bits instanceof FixedBitSet);
assertEquals(set.length(), bits.length());
for (int i = 0; i < set.length(); ++i) {
assertEquals(set.get(i), bits.get(i));
}
// Further changes are reflected
set.set(5);
assertTrue(bits.get(5));
} }
} }