/*
* 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.
*/
using System;
using IndexOutput = Lucene.Net.Store.IndexOutput;
using UnicodeUtil = Lucene.Net.Util.UnicodeUtil;
namespace Lucene.Net.Index
{
/// Consumes doc and freq, writing them using the current
/// index file format
///
sealed class FormatPostingsDocsWriter : FormatPostingsDocsConsumer, IDisposable
{
internal IndexOutput out_Renamed;
internal FormatPostingsTermsWriter parent;
internal FormatPostingsPositionsWriter posWriter;
internal DefaultSkipListWriter skipListWriter;
internal int skipInterval;
internal int totalNumDocs;
internal bool omitTermFreqAndPositions;
internal bool storePayloads;
internal long freqStart;
internal FieldInfo fieldInfo;
internal FormatPostingsDocsWriter(SegmentWriteState state, FormatPostingsTermsWriter parent):base()
{
this.parent = parent;
System.String fileName = IndexFileNames.SegmentFileName(parent.parent.segment, IndexFileNames.FREQ_EXTENSION);
state.flushedFiles.Add(fileName);
out_Renamed = parent.parent.dir.CreateOutput(fileName);
totalNumDocs = parent.parent.totalNumDocs;
// TODO: abstraction violation
skipInterval = parent.parent.termsOut.skipInterval;
skipListWriter = parent.parent.skipListWriter;
skipListWriter.SetFreqOutput(out_Renamed);
posWriter = new FormatPostingsPositionsWriter(state, this);
}
internal void SetField(FieldInfo fieldInfo)
{
this.fieldInfo = fieldInfo;
omitTermFreqAndPositions = fieldInfo.omitTermFreqAndPositions;
storePayloads = fieldInfo.storePayloads;
posWriter.SetField(fieldInfo);
}
internal int lastDocID;
internal int df;
/// Adds a new doc in this term. If this returns null
/// then we just skip consuming positions/payloads.
///
internal override FormatPostingsPositionsConsumer AddDoc(int docID, int termDocFreq)
{
int delta = docID - lastDocID;
if (docID < 0 || (df > 0 && delta <= 0))
throw new CorruptIndexException("docs out of order (" + docID + " <= " + lastDocID + " )");
if ((++df % skipInterval) == 0)
{
// TODO: abstraction violation
skipListWriter.SetSkipData(lastDocID, storePayloads, posWriter.lastPayloadLength);
skipListWriter.BufferSkip(df);
}
System.Diagnostics.Debug.Assert(docID < totalNumDocs, "docID=" + docID + " totalNumDocs=" + totalNumDocs);
lastDocID = docID;
if (omitTermFreqAndPositions)
out_Renamed.WriteVInt(delta);
else if (1 == termDocFreq)
out_Renamed.WriteVInt((delta << 1) | 1);
else
{
out_Renamed.WriteVInt(delta << 1);
out_Renamed.WriteVInt(termDocFreq);
}
return posWriter;
}
private TermInfo termInfo = new TermInfo(); // minimize consing
internal UnicodeUtil.UTF8Result utf8 = new UnicodeUtil.UTF8Result();
/// Called when we are done adding docs to this term
internal override void Finish()
{
long skipPointer = skipListWriter.WriteSkip(out_Renamed);
// TODO: this is abstraction violation -- we should not
// peek up into parents terms encoding format
termInfo.Set(df, parent.freqStart, parent.proxStart, (int) (skipPointer - parent.freqStart));
// TODO: we could do this incrementally
UnicodeUtil.UTF16toUTF8(parent.currentTerm, parent.currentTermStart, utf8);
if (df > 0)
{
parent.termsOut.Add(fieldInfo.number, utf8.result, utf8.length, termInfo);
}
lastDocID = 0;
df = 0;
}
public void Dispose()
{
// Move to protected method if class becomes unsealed
out_Renamed.Dispose();
posWriter.Dispose();
}
}
}