blob: 3a242f3862ae85094c53b53f8d65644d5957d5b4 [file] [log] [blame]
using J2N.Collections.Generic.Extensions;
using Lucene.Net.Diagnostics;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Lucene.Net.Index
{
/*
* 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 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;
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>
internal class FrozenBufferedUpdates
{
/// <summary>Query we often undercount (say 24 bytes), plus int.</summary>
internal static readonly int BYTES_PER_DEL_QUERY = RamUsageEstimator.NUM_BYTES_OBJECT_REF + RamUsageEstimator.NUM_BYTES_INT32 + 24;
/// <summary>Terms, in sorted order:</summary>
internal readonly PrefixCodedTerms terms;
internal int termCount; // just for debugging
/// <summary>Parallel array of deleted query, and the docIDUpto for each</summary>
internal readonly Query[] queries;
internal readonly int[] queryLimits;
/// <summary>numeric DV update term and their updates</summary>
internal readonly NumericDocValuesUpdate[] numericDVUpdates;
/// <summary>binary DV update term and their updates</summary>
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;
if (Debugging.AssertsEnabled) Debugging.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;
if (ent.Value.HasValue)
{
queryLimits[upto] = ent.Value.Value;
}
else
{
// LUCENENET NOTE: According to this: http://stackoverflow.com/a/13914344
// we are supposed to throw an exception in this case, rather than
// silently fail.
throw new NullReferenceException();
}
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.GetSizeInBytes();
}
}
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.GetSizeInBytes();
}
}
binaryDVUpdates = allBinaryUpdates.ToArray();
bytesUsed = (int)terms.GetSizeInBytes() + 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;
}
public virtual long DelGen
{
set
{
if (Debugging.AssertsEnabled) Debugging.Assert(this.gen == -1);
this.gen = value;
}
get
{
if (Debugging.AssertsEnabled) Debugging.Assert(gen != -1);
return gen;
}
}
// LUCENENET NOTE: This was termsIterable() in Lucene
public virtual IEnumerable<Term> GetTermsEnumerable()
{
return new IterableAnonymousClass(this);
}
private class IterableAnonymousClass : IEnumerable<Term>
{
private readonly FrozenBufferedUpdates outerInstance;
public IterableAnonymousClass(FrozenBufferedUpdates outerInstance)
{
this.outerInstance = outerInstance;
}
public virtual IEnumerator<Term> GetEnumerator()
{
return outerInstance.terms.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
// LUCENENET NOTE: This was queriesIterable() in Lucene
public virtual IEnumerable<QueryAndLimit> GetQueriesEnumerable()
{
return new IterableAnonymousClass2(this);
}
private class IterableAnonymousClass2 : IEnumerable<QueryAndLimit>
{
private readonly FrozenBufferedUpdates outerInstance;
public IterableAnonymousClass2(FrozenBufferedUpdates outerInstance)
{
this.outerInstance = outerInstance;
}
public virtual IEnumerator<QueryAndLimit> GetEnumerator()
{
return new IteratorAnonymousClass(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class IteratorAnonymousClass : IEnumerator<QueryAndLimit>
{
private readonly IterableAnonymousClass2 outerInstance;
private readonly int upto;
private int i;
private QueryAndLimit current;
public IteratorAnonymousClass(IterableAnonymousClass2 outerInstance)
{
this.outerInstance = outerInstance;
upto = this.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 => current;
object System.Collections.IEnumerator.Current => Current;
public virtual void Reset()
{
throw new NotSupportedException();
}
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;
}
}
}