package org.apache.lucene.codecs.asserting; /* * 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. */ import java.io.IOException; import java.util.Iterator; import java.util.NoSuchElementException; import org.apache.lucene.codecs.DocValuesConsumer; import org.apache.lucene.codecs.DocValuesFormat; import org.apache.lucene.codecs.DocValuesProducer; import org.apache.lucene.codecs.lucene45.Lucene45DocValuesFormat; import org.apache.lucene.index.AssertingAtomicReader; import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.NumericDocValues; import org.apache.lucene.index.SegmentReadState; import org.apache.lucene.index.SegmentWriteState; import org.apache.lucene.index.SortedDocValues; import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.util.Bits; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.util.LongBitSet; /** * Just like {@link Lucene45DocValuesFormat} but with additional asserts. */ public class AssertingDocValuesFormat extends DocValuesFormat { private final DocValuesFormat in = new Lucene45DocValuesFormat(); public AssertingDocValuesFormat() { super("Asserting"); } @Override public DocValuesConsumer fieldsConsumer(SegmentWriteState state) throws IOException { DocValuesConsumer consumer = in.fieldsConsumer(state); assert consumer != null; return new AssertingDocValuesConsumer(consumer, state.segmentInfo.getDocCount()); } @Override public DocValuesProducer fieldsProducer(SegmentReadState state) throws IOException { assert state.fieldInfos.hasDocValues(); DocValuesProducer producer = in.fieldsProducer(state); assert producer != null; return new AssertingDocValuesProducer(producer, state.segmentInfo.getDocCount()); } static class AssertingDocValuesConsumer extends DocValuesConsumer { private final DocValuesConsumer in; private final int maxDoc; AssertingDocValuesConsumer(DocValuesConsumer in, int maxDoc) { this.in = in; this.maxDoc = maxDoc; } @Override public void addNumericField(FieldInfo field, Iterable<Number> values) throws IOException { int count = 0; for (Number v : values) { count++; } assert count == maxDoc; checkIterator(values.iterator(), maxDoc, true); in.addNumericField(field, values); } @Override public void addBinaryField(FieldInfo field, Iterable<BytesRef> values) throws IOException { int count = 0; for (BytesRef b : values) { assert b == null || b.isValid(); count++; } assert count == maxDoc; checkIterator(values.iterator(), maxDoc, true); in.addBinaryField(field, values); } @Override public void addSortedField(FieldInfo field, Iterable<BytesRef> values, Iterable<Number> docToOrd) throws IOException { int valueCount = 0; BytesRef lastValue = null; for (BytesRef b : values) { assert b != null; assert b.isValid(); if (valueCount > 0) { assert b.compareTo(lastValue) > 0; } lastValue = BytesRef.deepCopyOf(b); valueCount++; } assert valueCount <= maxDoc; FixedBitSet seenOrds = new FixedBitSet(valueCount); int count = 0; for (Number v : docToOrd) { assert v != null; int ord = v.intValue(); assert ord >= -1 && ord < valueCount; if (ord >= 0) { seenOrds.set(ord); } count++; } assert count == maxDoc; assert seenOrds.cardinality() == valueCount; checkIterator(values.iterator(), valueCount, false); checkIterator(docToOrd.iterator(), maxDoc, false); in.addSortedField(field, values, docToOrd); } @Override public void addSortedSetField(FieldInfo field, Iterable<BytesRef> values, Iterable<Number> docToOrdCount, Iterable<Number> ords) throws IOException { long valueCount = 0; BytesRef lastValue = null; for (BytesRef b : values) { assert b != null; assert b.isValid(); if (valueCount > 0) { assert b.compareTo(lastValue) > 0; } lastValue = BytesRef.deepCopyOf(b); valueCount++; } int docCount = 0; long ordCount = 0; LongBitSet seenOrds = new LongBitSet(valueCount); Iterator<Number> ordIterator = ords.iterator(); for (Number v : docToOrdCount) { assert v != null; int count = v.intValue(); assert count >= 0; docCount++; ordCount += count; long lastOrd = -1; for (int i = 0; i < count; i++) { Number o = ordIterator.next(); assert o != null; long ord = o.longValue(); assert ord >= 0 && ord < valueCount; assert ord > lastOrd : "ord=" + ord + ",lastOrd=" + lastOrd; seenOrds.set(ord); lastOrd = ord; } } assert ordIterator.hasNext() == false; assert docCount == maxDoc; assert seenOrds.cardinality() == valueCount; checkIterator(values.iterator(), valueCount, false); checkIterator(docToOrdCount.iterator(), maxDoc, false); checkIterator(ords.iterator(), ordCount, false); in.addSortedSetField(field, values, docToOrdCount, ords); } @Override public void close() throws IOException { in.close(); } } static class AssertingNormsConsumer extends DocValuesConsumer { private final DocValuesConsumer in; private final int maxDoc; AssertingNormsConsumer(DocValuesConsumer in, int maxDoc) { this.in = in; this.maxDoc = maxDoc; } @Override public void addNumericField(FieldInfo field, Iterable<Number> values) throws IOException { int count = 0; for (Number v : values) { assert v != null; count++; } assert count == maxDoc; checkIterator(values.iterator(), maxDoc, false); in.addNumericField(field, values); } @Override public void close() throws IOException { in.close(); } @Override public void addBinaryField(FieldInfo field, Iterable<BytesRef> values) throws IOException { throw new IllegalStateException(); } @Override public void addSortedField(FieldInfo field, Iterable<BytesRef> values, Iterable<Number> docToOrd) throws IOException { throw new IllegalStateException(); } @Override public void addSortedSetField(FieldInfo field, Iterable<BytesRef> values, Iterable<Number> docToOrdCount, Iterable<Number> ords) throws IOException { throw new IllegalStateException(); } } private static <T> void checkIterator(Iterator<T> iterator, long expectedSize, boolean allowNull) { for (long i = 0; i < expectedSize; i++) { boolean hasNext = iterator.hasNext(); assert hasNext; T v = iterator.next(); assert allowNull || v != null; try { iterator.remove(); throw new AssertionError("broken iterator (supports remove): " + iterator); } catch (UnsupportedOperationException expected) { // ok } } assert !iterator.hasNext(); try { iterator.next(); throw new AssertionError("broken iterator (allows next() when hasNext==false) " + iterator); } catch (NoSuchElementException expected) { // ok } } static class AssertingDocValuesProducer extends DocValuesProducer { private final DocValuesProducer in; private final int maxDoc; AssertingDocValuesProducer(DocValuesProducer in, int maxDoc) { this.in = in; this.maxDoc = maxDoc; } @Override public NumericDocValues getNumeric(FieldInfo field) throws IOException { assert field.getDocValuesType() == FieldInfo.DocValuesType.NUMERIC || field.getNormType() == FieldInfo.DocValuesType.NUMERIC; NumericDocValues values = in.getNumeric(field); assert values != null; return new AssertingAtomicReader.AssertingNumericDocValues(values, maxDoc); } @Override public BinaryDocValues getBinary(FieldInfo field) throws IOException { assert field.getDocValuesType() == FieldInfo.DocValuesType.BINARY; BinaryDocValues values = in.getBinary(field); assert values != null; return new AssertingAtomicReader.AssertingBinaryDocValues(values, maxDoc); } @Override public SortedDocValues getSorted(FieldInfo field) throws IOException { assert field.getDocValuesType() == FieldInfo.DocValuesType.SORTED; SortedDocValues values = in.getSorted(field); assert values != null; return new AssertingAtomicReader.AssertingSortedDocValues(values, maxDoc); } @Override public SortedSetDocValues getSortedSet(FieldInfo field) throws IOException { assert field.getDocValuesType() == FieldInfo.DocValuesType.SORTED_SET; SortedSetDocValues values = in.getSortedSet(field); assert values != null; return new AssertingAtomicReader.AssertingSortedSetDocValues(values, maxDoc); } @Override public Bits getDocsWithField(FieldInfo field) throws IOException { assert field.getDocValuesType() != null; Bits bits = in.getDocsWithField(field); assert bits != null; assert bits.length() == maxDoc; return new AssertingAtomicReader.AssertingBits(bits); } @Override public void close() throws IOException { in.close(); } @Override public long ramBytesUsed() { return in.ramBytesUsed(); } } }