blob: 5b10ce739c28ab28c7217a56e01d6a3948bed6a9 [file] [log] [blame]
/*
* 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.Collections.Generic;
using Lucene.Net.Search;
using Lucene.Net.Support;
namespace Lucene.Net.Index
{
/// <summary>Holds buffered deletes, by docID, term or query. We
/// hold two instances of this class: one for the deletes
/// prior to the last flush, the other for deletes after
/// the last flush. This is so if we need to abort
/// (discard all buffered docs) we can also discard the
/// buffered deletes yet keep the deletes done during
/// previously flushed segments.
/// </summary>
class BufferedDeletes
{
internal int numTerms;
internal IDictionary<Term,Num> terms = null;
internal IDictionary<Query, int> queries = new HashMap<Query, int>();
internal List<int> docIDs = new List<int>();
internal long bytesUsed;
internal bool doTermSort;
public BufferedDeletes(bool doTermSort)
{
this.doTermSort = doTermSort;
if (doTermSort)
{
//TODO: Used in place of TreeMap
terms = new SortedDictionary<Term, Num>();
}
else
{
terms = new HashMap<Term, Num>();
}
}
// Number of documents a delete term applies to.
internal sealed class Num
{
internal int num;
internal Num(int num)
{
this.num = num;
}
internal int GetNum()
{
return num;
}
internal void SetNum(int num)
{
// Only record the new number if it's greater than the
// current one. This is important because if multiple
// threads are replacing the same doc at nearly the
// same time, it's possible that one thread that got a
// higher docID is scheduled before the other
// threads.
if (num > this.num)
this.num = num;
}
}
internal virtual int Size()
{
// We use numTerms not terms.size() intentionally, so
// that deletes by the same term multiple times "count",
// ie if you ask to flush every 1000 deletes then even
// dup'd terms are counted towards that 1000
return numTerms + queries.Count + docIDs.Count;
}
internal virtual void Update(BufferedDeletes @in)
{
numTerms += @in.numTerms;
bytesUsed += @in.bytesUsed;
foreach (KeyValuePair<Term, Num> term in @in.terms)
{
terms[term.Key] = term.Value;
}
foreach (KeyValuePair<Query, int> term in @in.queries)
{
queries[term.Key] = term.Value;
}
docIDs.AddRange(@in.docIDs);
@in.Clear();
}
internal virtual void Clear()
{
terms.Clear();
queries.Clear();
docIDs.Clear();
numTerms = 0;
bytesUsed = 0;
}
internal virtual void AddBytesUsed(long b)
{
bytesUsed += b;
}
internal virtual bool Any()
{
return terms.Count > 0 || docIDs.Count > 0 || queries.Count > 0;
}
// Remaps all buffered deletes based on a completed
// merge
internal virtual void Remap(MergeDocIDRemapper mapper, SegmentInfos infos, int[][] docMaps, int[] delCounts, MergePolicy.OneMerge merge, int mergeDocCount)
{
lock (this)
{
IDictionary<Term, Num> newDeleteTerms;
// Remap delete-by-term
if (terms.Count > 0)
{
if (doTermSort)
{
newDeleteTerms = new SortedDictionary<Term, Num>();
}
else
{
newDeleteTerms = new HashMap<Term, Num>();
}
foreach(var entry in terms)
{
Num num = entry.Value;
newDeleteTerms[entry.Key] = new Num(mapper.Remap(num.GetNum()));
}
}
else
newDeleteTerms = null;
// Remap delete-by-docID
List<int> newDeleteDocIDs;
if (docIDs.Count > 0)
{
newDeleteDocIDs = new List<int>(docIDs.Count);
foreach(int num in docIDs)
{
newDeleteDocIDs.Add(mapper.Remap(num));
}
}
else
newDeleteDocIDs = null;
// Remap delete-by-query
HashMap<Query, int> newDeleteQueries;
if (queries.Count > 0)
{
newDeleteQueries = new HashMap<Query, int>(queries.Count);
foreach(var entry in queries)
{
int num = entry.Value;
newDeleteQueries[entry.Key] = mapper.Remap(num);
}
}
else
newDeleteQueries = null;
if (newDeleteTerms != null)
terms = newDeleteTerms;
if (newDeleteDocIDs != null)
docIDs = newDeleteDocIDs;
if (newDeleteQueries != null)
queries = newDeleteQueries;
}
}
}
}