blob: af8584e40959a594cab20aa9d3624ed3bfd3f9ef [file] [log] [blame]
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Lucene.Net.Index
{
using Lucene.Net.Support;
using System;
using ArrayUtil = Lucene.Net.Util.ArrayUtil;
using BinaryDocValuesUpdate = Lucene.Net.Index.DocValuesUpdate.BinaryDocValuesUpdate;
using NumericDocValuesUpdate = Lucene.Net.Index.DocValuesUpdate.NumericDocValuesUpdate;
using Query = Lucene.Net.Search.Query;
/*
* 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 QueryAndLimit = Lucene.Net.Index.BufferedUpdatesStream.QueryAndLimit;
using RamUsageEstimator = Lucene.Net.Util.RamUsageEstimator;
/// <summary>
/// Holds buffered deletes and updates by term or query, once pushed. Pushed
/// deletes/updates are write-once, so we shift to more memory efficient data
/// structure to hold them. We don't hold docIDs because these are applied on
/// flush.
/// </summary>
public class FrozenBufferedUpdates
{
/* Query we often undercount (say 24 bytes), plus int. */
internal static readonly int BYTES_PER_DEL_QUERY = RamUsageEstimator.NUM_BYTES_OBJECT_REF + RamUsageEstimator.NUM_BYTES_INT + 24;
// Terms, in sorted order:
internal readonly PrefixCodedTerms Terms;
internal int termCount; // just for debugging
// Parallel array of deleted query, and the docIDUpto for each
internal readonly Query[] Queries;
internal readonly int?[] QueryLimits;
// numeric DV update term and their updates
internal readonly NumericDocValuesUpdate[] NumericDVUpdates;
// binary DV update term and their updates
internal readonly BinaryDocValuesUpdate[] BinaryDVUpdates;
internal readonly int BytesUsed;
internal readonly int NumTermDeletes;
private long Gen = -1; // assigned by BufferedDeletesStream once pushed
internal readonly bool IsSegmentPrivate; // set to true iff this frozen packet represents
// a segment private deletes. in that case is should
// only have Queries
public FrozenBufferedUpdates(BufferedUpdates deletes, bool isSegmentPrivate)
{
this.IsSegmentPrivate = isSegmentPrivate;
Debug.Assert(!isSegmentPrivate || deletes.Terms.Count == 0, "segment private package should only have del queries");
Term[] termsArray = deletes.Terms.Keys.ToArray(/*new Term[deletes.Terms.Count]*/);
termCount = termsArray.Length;
ArrayUtil.TimSort(termsArray);
PrefixCodedTerms.Builder builder = new PrefixCodedTerms.Builder();
foreach (Term term in termsArray)
{
builder.Add(term);
}
Terms = builder.Finish();
Queries = new Query[deletes.Queries.Count];
QueryLimits = new int?[deletes.Queries.Count];
int upto = 0;
foreach (KeyValuePair<Query, int?> ent in deletes.Queries)
{
Queries[upto] = ent.Key;
QueryLimits[upto] = ent.Value;
upto++;
}
// TODO if a Term affects multiple fields, we could keep the updates key'd by Term
// so that it maps to all fields it affects, sorted by their docUpto, and traverse
// that Term only once, applying the update to all fields that still need to be
// updated.
IList<NumericDocValuesUpdate> allNumericUpdates = new List<NumericDocValuesUpdate>();
int numericUpdatesSize = 0;
foreach (var numericUpdates in deletes.NumericUpdates.Values)
{
foreach (NumericDocValuesUpdate update in numericUpdates.Values)
{
allNumericUpdates.Add(update);
numericUpdatesSize += update.SizeInBytes();
}
}
NumericDVUpdates = allNumericUpdates.ToArray();
// TODO if a Term affects multiple fields, we could keep the updates key'd by Term
// so that it maps to all fields it affects, sorted by their docUpto, and traverse
// that Term only once, applying the update to all fields that still need to be
// updated.
IList<BinaryDocValuesUpdate> allBinaryUpdates = new List<BinaryDocValuesUpdate>();
int binaryUpdatesSize = 0;
foreach (var binaryUpdates in deletes.BinaryUpdates.Values)
{
foreach (BinaryDocValuesUpdate update in binaryUpdates.Values)
{
allBinaryUpdates.Add(update);
binaryUpdatesSize += update.SizeInBytes();
}
}
BinaryDVUpdates = allBinaryUpdates.ToArray();
BytesUsed = (int)Terms.SizeInBytes + Queries.Length * BYTES_PER_DEL_QUERY + numericUpdatesSize + NumericDVUpdates.Length * RamUsageEstimator.NUM_BYTES_OBJECT_REF + binaryUpdatesSize + BinaryDVUpdates.Length * RamUsageEstimator.NUM_BYTES_OBJECT_REF;
NumTermDeletes = deletes.NumTermDeletes.Get();
}
public virtual long DelGen
{
set
{
Debug.Assert(this.Gen == -1);
this.Gen = value;
}
get
{
Debug.Assert(Gen != -1);
return Gen;
}
}
public virtual IEnumerable<Term> TermsIterable()
{
return new IterableAnonymousInnerClassHelper(this);
}
private class IterableAnonymousInnerClassHelper : IEnumerable<Term>
{
private readonly FrozenBufferedUpdates OuterInstance;
public IterableAnonymousInnerClassHelper(FrozenBufferedUpdates outerInstance)
{
this.OuterInstance = outerInstance;
}
public virtual IEnumerator<Term> GetEnumerator()
{
return OuterInstance.Terms.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public virtual IEnumerable<QueryAndLimit> QueriesIterable()
{
return new IterableAnonymousInnerClassHelper2(this);
}
private class IterableAnonymousInnerClassHelper2 : IEnumerable<QueryAndLimit>
{
private readonly FrozenBufferedUpdates OuterInstance;
public IterableAnonymousInnerClassHelper2(FrozenBufferedUpdates outerInstance)
{
this.OuterInstance = outerInstance;
}
public virtual IEnumerator<QueryAndLimit> GetEnumerator()
{
return new IteratorAnonymousInnerClassHelper(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class IteratorAnonymousInnerClassHelper : IEnumerator<QueryAndLimit>
{
private readonly IterableAnonymousInnerClassHelper2 OuterInstance;
private int upto, i;
private QueryAndLimit current;
public IteratorAnonymousInnerClassHelper(IterableAnonymousInnerClassHelper2 outerInstance)
{
this.OuterInstance = outerInstance;
upto = OuterInstance.OuterInstance.Queries.Length;
i = 0;
}
public virtual bool MoveNext()
{
if (i < upto)
{
current = new QueryAndLimit(OuterInstance.OuterInstance.Queries[i], OuterInstance.OuterInstance.QueryLimits[i]);
i++;
return true;
}
return false;
}
public virtual QueryAndLimit Current
{
get
{
return current;
}
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public virtual void Reset()
{
throw new NotImplementedException();
}
public void Dispose()
{
}
}
}
public override string ToString()
{
string s = "";
if (NumTermDeletes != 0)
{
s += " " + NumTermDeletes + " deleted terms (unique count=" + termCount + ")";
}
if (Queries.Length != 0)
{
s += " " + Queries.Length + " deleted queries";
}
if (BytesUsed != 0)
{
s += " bytesUsed=" + BytesUsed;
}
return s;
}
public virtual bool Any()
{
return termCount > 0 || Queries.Length > 0 || NumericDVUpdates.Length > 0 || BinaryDVUpdates.Length > 0;
}
//For debugging only
public int TermCount
{
get { return termCount; }
}
public object Queries_Nunit()
{
return Queries.Clone();
}
}
}