Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / tools / monkeydoc / Lucene.Net / Lucene.Net / Index / MultiReader.cs
1 /* 
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  * 
9  * http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 using System;
19
20 using Document = Mono.Lucene.Net.Documents.Document;
21 using FieldSelector = Mono.Lucene.Net.Documents.FieldSelector;
22 using MultiTermDocs = Mono.Lucene.Net.Index.DirectoryReader.MultiTermDocs;
23 using MultiTermEnum = Mono.Lucene.Net.Index.DirectoryReader.MultiTermEnum;
24 using MultiTermPositions = Mono.Lucene.Net.Index.DirectoryReader.MultiTermPositions;
25 using DefaultSimilarity = Mono.Lucene.Net.Search.DefaultSimilarity;
26
27 namespace Mono.Lucene.Net.Index
28 {
29         
30         /// <summary>An IndexReader which reads multiple indexes, appending their content.
31         /// 
32         /// </summary>
33         /// <version>  $Id: MultiReader.java 782406 2009-06-07 16:31:18Z mikemccand $
34         /// </version>
35         public class MultiReader:IndexReader, System.ICloneable
36         {
37                 protected internal IndexReader[] subReaders;
38                 private int[] starts; // 1st docno for each segment
39                 private bool[] decrefOnClose; // remember which subreaders to decRef on close
40                 private System.Collections.IDictionary normsCache = new System.Collections.Hashtable();
41                 private int maxDoc = 0;
42                 private int numDocs = - 1;
43                 private bool hasDeletions = false;
44                 
45                 /// <summary> <p/>Construct a MultiReader aggregating the named set of (sub)readers.
46                 /// Directory locking for delete, undeleteAll, and setNorm operations is
47                 /// left to the subreaders. <p/>
48                 /// <p/>Note that all subreaders are closed if this Multireader is closed.<p/>
49                 /// </summary>
50                 /// <param name="subReaders">set of (sub)readers
51                 /// </param>
52                 /// <throws>  IOException </throws>
53                 public MultiReader(IndexReader[] subReaders)
54                 {
55                         Initialize(subReaders, true);
56                 }
57                 
58                 /// <summary> <p/>Construct a MultiReader aggregating the named set of (sub)readers.
59                 /// Directory locking for delete, undeleteAll, and setNorm operations is
60                 /// left to the subreaders. <p/>
61                 /// </summary>
62                 /// <param name="closeSubReaders">indicates whether the subreaders should be closed
63                 /// when this MultiReader is closed
64                 /// </param>
65                 /// <param name="subReaders">set of (sub)readers
66                 /// </param>
67                 /// <throws>  IOException </throws>
68                 public MultiReader(IndexReader[] subReaders, bool closeSubReaders)
69                 {
70                         Initialize(subReaders, closeSubReaders);
71                 }
72                 
73                 private void  Initialize(IndexReader[] subReaders, bool closeSubReaders)
74                 {
75                         this.subReaders = new IndexReader[subReaders.Length];
76                         subReaders.CopyTo(this.subReaders, 0);
77                         starts = new int[subReaders.Length + 1]; // build starts array
78                         decrefOnClose = new bool[subReaders.Length];
79                         for (int i = 0; i < subReaders.Length; i++)
80                         {
81                                 starts[i] = maxDoc;
82                                 maxDoc += subReaders[i].MaxDoc(); // compute maxDocs
83                                 
84                                 if (!closeSubReaders)
85                                 {
86                                         subReaders[i].IncRef();
87                                         decrefOnClose[i] = true;
88                                 }
89                                 else
90                                 {
91                                         decrefOnClose[i] = false;
92                                 }
93                                 
94                                 if (subReaders[i].HasDeletions())
95                                         hasDeletions = true;
96                         }
97                         starts[subReaders.Length] = maxDoc;
98                 }
99                 
100                 /// <summary> Tries to reopen the subreaders.
101                 /// <br/>
102                 /// If one or more subreaders could be re-opened (i. e. subReader.reopen() 
103                 /// returned a new instance != subReader), then a new MultiReader instance 
104                 /// is returned, otherwise this instance is returned.
105                 /// <p/>
106                 /// A re-opened instance might share one or more subreaders with the old 
107                 /// instance. Index modification operations result in undefined behavior
108                 /// when performed before the old instance is closed.
109                 /// (see {@link IndexReader#Reopen()}).
110                 /// <p/>
111                 /// If subreaders are shared, then the reference count of those
112                 /// readers is increased to ensure that the subreaders remain open
113                 /// until the last referring reader is closed.
114                 /// 
115                 /// </summary>
116                 /// <throws>  CorruptIndexException if the index is corrupt </throws>
117                 /// <throws>  IOException if there is a low-level IO error  </throws>
118                 public override IndexReader Reopen()
119                 {
120                         lock (this)
121                         {
122                                 return DoReopen(false);
123                         }
124                 }
125                 
126                 /// <summary> Clones the subreaders.
127                 /// (see {@link IndexReader#clone()}).
128                 /// <br/>
129                 /// <p/>
130                 /// If subreaders are shared, then the reference count of those
131                 /// readers is increased to ensure that the subreaders remain open
132                 /// until the last referring reader is closed.
133                 /// </summary>
134                 public override System.Object Clone()
135                 {
136                         try
137                         {
138                                 return DoReopen(true);
139                         }
140                         catch (System.Exception ex)
141                         {
142                                 throw new System.SystemException(ex.Message, ex);
143                         }
144                 }
145                 
146                 /// <summary> If clone is true then we clone each of the subreaders</summary>
147                 /// <param name="doClone">
148                 /// </param>
149                 /// <returns> New IndexReader, or same one (this) if
150                 /// reopen/clone is not necessary
151                 /// </returns>
152                 /// <throws>  CorruptIndexException </throws>
153                 /// <throws>  IOException </throws>
154                 protected internal virtual IndexReader DoReopen(bool doClone)
155                 {
156                         EnsureOpen();
157                         
158                         bool reopened = false;
159                         IndexReader[] newSubReaders = new IndexReader[subReaders.Length];
160                         
161                         bool success = false;
162                         try
163                         {
164                                 for (int i = 0; i < subReaders.Length; i++)
165                                 {
166                                         if (doClone)
167                                                 newSubReaders[i] = (IndexReader) subReaders[i].Clone();
168                                         else
169                                                 newSubReaders[i] = subReaders[i].Reopen();
170                                         // if at least one of the subreaders was updated we remember that
171                                         // and return a new MultiReader
172                                         if (newSubReaders[i] != subReaders[i])
173                                         {
174                                                 reopened = true;
175                                         }
176                                 }
177                                 success = true;
178                         }
179                         finally
180                         {
181                                 if (!success && reopened)
182                                 {
183                                         for (int i = 0; i < newSubReaders.Length; i++)
184                                         {
185                                                 if (newSubReaders[i] != subReaders[i])
186                                                 {
187                                                         try
188                                                         {
189                                                                 newSubReaders[i].Close();
190                                                         }
191                                                         catch (System.IO.IOException ignore)
192                                                         {
193                                                                 // keep going - we want to clean up as much as possible
194                                                         }
195                                                 }
196                                         }
197                                 }
198                         }
199                         
200                         if (reopened)
201                         {
202                                 bool[] newDecrefOnClose = new bool[subReaders.Length];
203                                 for (int i = 0; i < subReaders.Length; i++)
204                                 {
205                                         if (newSubReaders[i] == subReaders[i])
206                                         {
207                                                 newSubReaders[i].IncRef();
208                                                 newDecrefOnClose[i] = true;
209                                         }
210                                 }
211                                 MultiReader mr = new MultiReader(newSubReaders);
212                                 mr.decrefOnClose = newDecrefOnClose;
213                                 mr.SetDisableFakeNorms(GetDisableFakeNorms());
214                                 return mr;
215                         }
216                         else
217                         {
218                                 return this;
219                         }
220                 }
221                 
222                 public override TermFreqVector[] GetTermFreqVectors(int n)
223                 {
224                         EnsureOpen();
225                         int i = ReaderIndex(n); // find segment num
226                         return subReaders[i].GetTermFreqVectors(n - starts[i]); // dispatch to segment
227                 }
228                 
229                 public override TermFreqVector GetTermFreqVector(int n, System.String field)
230                 {
231                         EnsureOpen();
232                         int i = ReaderIndex(n); // find segment num
233                         return subReaders[i].GetTermFreqVector(n - starts[i], field);
234                 }
235                 
236                 
237                 public override void  GetTermFreqVector(int docNumber, System.String field, TermVectorMapper mapper)
238                 {
239                         EnsureOpen();
240                         int i = ReaderIndex(docNumber); // find segment num
241                         subReaders[i].GetTermFreqVector(docNumber - starts[i], field, mapper);
242                 }
243                 
244                 public override void  GetTermFreqVector(int docNumber, TermVectorMapper mapper)
245                 {
246                         EnsureOpen();
247                         int i = ReaderIndex(docNumber); // find segment num
248                         subReaders[i].GetTermFreqVector(docNumber - starts[i], mapper);
249                 }
250                 
251                 public override bool IsOptimized()
252                 {
253                         return false;
254                 }
255                 
256                 public override int NumDocs()
257                 {
258                         // Don't call ensureOpen() here (it could affect performance)
259             // NOTE: multiple threads may wind up init'ing
260             // numDocs... but that's harmless
261                         if (numDocs == - 1)
262                         {
263                                 // check cache
264                                 int n = 0; // cache miss--recompute
265                                 for (int i = 0; i < subReaders.Length; i++)
266                                         n += subReaders[i].NumDocs(); // sum from readers
267                                 numDocs = n;
268                         }
269                         return numDocs;
270                 }
271                 
272                 public override int MaxDoc()
273                 {
274                         // Don't call ensureOpen() here (it could affect performance)
275                         return maxDoc;
276                 }
277                 
278                 // inherit javadoc
279                 public override Document Document(int n, FieldSelector fieldSelector)
280                 {
281                         EnsureOpen();
282                         int i = ReaderIndex(n); // find segment num
283                         return subReaders[i].Document(n - starts[i], fieldSelector); // dispatch to segment reader
284                 }
285                 
286                 public override bool IsDeleted(int n)
287                 {
288                         // Don't call ensureOpen() here (it could affect performance)
289                         int i = ReaderIndex(n); // find segment num
290                         return subReaders[i].IsDeleted(n - starts[i]); // dispatch to segment reader
291                 }
292                 
293                 public override bool HasDeletions()
294                 {
295                         // Don't call ensureOpen() here (it could affect performance)
296                         return hasDeletions;
297                 }
298                 
299                 protected internal override void  DoDelete(int n)
300                 {
301                         numDocs = - 1; // invalidate cache
302                         int i = ReaderIndex(n); // find segment num
303                         subReaders[i].DeleteDocument(n - starts[i]); // dispatch to segment reader
304                         hasDeletions = true;
305                 }
306                 
307                 protected internal override void  DoUndeleteAll()
308                 {
309                         for (int i = 0; i < subReaders.Length; i++)
310                                 subReaders[i].UndeleteAll();
311                         
312                         hasDeletions = false;
313                         numDocs = - 1; // invalidate cache
314                 }
315                 
316                 private int ReaderIndex(int n)
317                 {
318                         // find reader for doc n:
319                         return DirectoryReader.ReaderIndex(n, this.starts, this.subReaders.Length);
320                 }
321                 
322                 public override bool HasNorms(System.String field)
323                 {
324                         EnsureOpen();
325                         for (int i = 0; i < subReaders.Length; i++)
326                         {
327                                 if (subReaders[i].HasNorms(field))
328                                         return true;
329                         }
330                         return false;
331                 }
332                 
333                 private byte[] ones;
334                 private byte[] FakeNorms()
335                 {
336                         if (ones == null)
337                                 ones = SegmentReader.CreateFakeNorms(MaxDoc());
338                         return ones;
339                 }
340                 
341                 public override byte[] Norms(System.String field)
342                 {
343                         lock (this)
344                         {
345                                 EnsureOpen();
346                                 byte[] bytes = (byte[]) normsCache[field];
347                                 if (bytes != null)
348                                         return bytes; // cache hit
349                                 if (!HasNorms(field))
350                                         return GetDisableFakeNorms()?null:FakeNorms();
351                                 
352                                 bytes = new byte[MaxDoc()];
353                                 for (int i = 0; i < subReaders.Length; i++)
354                                         subReaders[i].Norms(field, bytes, starts[i]);
355                                 normsCache[field] = bytes; // update cache
356                                 return bytes;
357                         }
358                 }
359                 
360                 public override void  Norms(System.String field, byte[] result, int offset)
361                 {
362                         lock (this)
363                         {
364                                 EnsureOpen();
365                                 byte[] bytes = (byte[]) normsCache[field];
366                                 for (int i = 0; i < subReaders.Length; i++)
367                                 // read from segments
368                                         subReaders[i].Norms(field, result, offset + starts[i]);
369                                 
370                                 if (bytes == null && !HasNorms(field))
371                                 {
372                     for (int i = offset; i < result.Length; i++)
373                     {
374                         result[i] = (byte) DefaultSimilarity.EncodeNorm(1.0f);
375                     }
376                                 }
377                                 else if (bytes != null)
378                                 {
379                                         // cache hit
380                                         Array.Copy(bytes, 0, result, offset, MaxDoc());
381                                 }
382                                 else
383                                 {
384                                         for (int i = 0; i < subReaders.Length; i++)
385                                         {
386                                                 // read from segments
387                                                 subReaders[i].Norms(field, result, offset + starts[i]);
388                                         }
389                                 }
390                         }
391                 }
392                 
393                 protected internal override void  DoSetNorm(int n, System.String field, byte value_Renamed)
394                 {
395                         lock (normsCache.SyncRoot)
396                         {
397                                 normsCache.Remove(field); // clear cache
398                         }
399                         int i = ReaderIndex(n); // find segment num
400                         subReaders[i].SetNorm(n - starts[i], field, value_Renamed); // dispatch
401                 }
402                 
403                 public override TermEnum Terms()
404                 {
405                         EnsureOpen();
406                         return new MultiTermEnum(this, subReaders, starts, null);
407                 }
408                 
409                 public override TermEnum Terms(Term term)
410                 {
411                         EnsureOpen();
412                         return new MultiTermEnum(this, subReaders, starts, term);
413                 }
414                 
415                 public override int DocFreq(Term t)
416                 {
417                         EnsureOpen();
418                         int total = 0; // sum freqs in segments
419                         for (int i = 0; i < subReaders.Length; i++)
420                                 total += subReaders[i].DocFreq(t);
421                         return total;
422                 }
423                 
424                 public override TermDocs TermDocs()
425                 {
426                         EnsureOpen();
427                         return new MultiTermDocs(this, subReaders, starts);
428                 }
429                 
430                 public override TermPositions TermPositions()
431                 {
432                         EnsureOpen();
433                         return new MultiTermPositions(this, subReaders, starts);
434                 }
435                 
436                 /// <deprecated> 
437                 /// </deprecated>
438         [Obsolete]
439                 protected internal override void  DoCommit()
440                 {
441                         DoCommit(null);
442                 }
443
444         protected internal override void DoCommit(System.Collections.Generic.IDictionary<string, string> commitUserData)
445                 {
446                         for (int i = 0; i < subReaders.Length; i++)
447                                 subReaders[i].Commit(commitUserData);
448                 }
449                 
450                 protected internal override void  DoClose()
451                 {
452                         lock (this)
453                         {
454                                 for (int i = 0; i < subReaders.Length; i++)
455                                 {
456                                         if (decrefOnClose[i])
457                                         {
458                                                 subReaders[i].DecRef();
459                                         }
460                                         else
461                                         {
462                                                 subReaders[i].Close();
463                                         }
464                                 }
465                         }
466
467             // NOTE: only needed in case someone had asked for
468             // FieldCache for top-level reader (which is generally
469             // not a good idea):
470             Mono.Lucene.Net.Search.FieldCache_Fields.DEFAULT.Purge(this);
471                 }
472
473         public override System.Collections.Generic.ICollection<string> GetFieldNames(IndexReader.FieldOption fieldNames)
474                 {
475                         EnsureOpen();
476                         return DirectoryReader.GetFieldNames(fieldNames, this.subReaders);
477                 }
478                 
479                 /// <summary> Checks recursively if all subreaders are up to date. </summary>
480                 public override bool IsCurrent()
481                 {
482                         for (int i = 0; i < subReaders.Length; i++)
483                         {
484                                 if (!subReaders[i].IsCurrent())
485                                 {
486                                         return false;
487                                 }
488                         }
489                         
490                         // all subreaders are up to date
491                         return true;
492                 }
493                 
494                 /// <summary>Not implemented.</summary>
495                 /// <throws>  UnsupportedOperationException </throws>
496                 public override long GetVersion()
497                 {
498                         throw new System.NotSupportedException("MultiReader does not support this method.");
499                 }
500                 
501                 public override IndexReader[] GetSequentialSubReaders()
502                 {
503                         return subReaders;
504                 }
505         }
506 }