/* * 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 { /// 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. /// class BufferedDeletes { internal int numTerms; internal IDictionary terms = null; internal IDictionary queries = new HashMap(); internal List docIDs = new List(); internal long bytesUsed; internal bool doTermSort; public BufferedDeletes(bool doTermSort) { this.doTermSort = doTermSort; if (doTermSort) { //TODO: Used in place of TreeMap terms = new SortedDictionary(); } else { terms = new HashMap(); } } // 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 in @in.terms) { terms[term.Key] = term.Value; } foreach (KeyValuePair 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 newDeleteTerms; // Remap delete-by-term if (terms.Count > 0) { if (doTermSort) { newDeleteTerms = new SortedDictionary(); } else { newDeleteTerms = new HashMap(); } 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 newDeleteDocIDs; if (docIDs.Count > 0) { newDeleteDocIDs = new List(docIDs.Count); foreach(int num in docIDs) { newDeleteDocIDs.Add(mapper.Remap(num)); } } else newDeleteDocIDs = null; // Remap delete-by-query HashMap newDeleteQueries; if (queries.Count > 0) { newDeleteQueries = new HashMap(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; } } } }