Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / tools / monkeydoc / Lucene.Net / Lucene.Net / Index / ParallelReader.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 FieldSelectorResult = Mono.Lucene.Net.Documents.FieldSelectorResult;
23 using Fieldable = Mono.Lucene.Net.Documents.Fieldable;
24
25 namespace Mono.Lucene.Net.Index
26 {
27         
28         
29         /// <summary>An IndexReader which reads multiple, parallel indexes.  Each index added
30         /// must have the same number of documents, but typically each contains
31         /// different fields.  Each document contains the union of the fields of all
32         /// documents with the same document number.  When searching, matches for a
33         /// query term are from the first index added that has the field.
34         /// 
35         /// <p/>This is useful, e.g., with collections that have large fields which
36         /// change rarely and small fields that change more frequently.  The smaller
37         /// fields may be re-indexed in a new index and both indexes may be searched
38         /// together.
39         /// 
40         /// <p/><strong>Warning:</strong> It is up to you to make sure all indexes
41         /// are created and modified the same way. For example, if you add
42         /// documents to one index, you need to add the same documents in the
43         /// same order to the other indexes. <em>Failure to do so will result in
44         /// undefined behavior</em>.
45         /// </summary>
46         public class ParallelReader:IndexReader, System.ICloneable
47         {
48                 private System.Collections.ArrayList readers = new System.Collections.ArrayList();
49                 private System.Collections.IList decrefOnClose = new System.Collections.ArrayList(); // remember which subreaders to decRef on close
50                 internal bool incRefReaders = false;
51                 private System.Collections.SortedList fieldToReader = new System.Collections.SortedList();
52                 private System.Collections.IDictionary readerToFields = new System.Collections.Hashtable();
53                 private System.Collections.IList storedFieldReaders = new System.Collections.ArrayList();
54                 
55                 private int maxDoc;
56                 private int numDocs;
57                 private bool hasDeletions;
58                 
59                 /// <summary>Construct a ParallelReader. 
60                 /// <p/>Note that all subreaders are closed if this ParallelReader is closed.<p/>
61                 /// </summary>
62                 public ParallelReader():this(true)
63                 {
64                 }
65                 
66                 /// <summary>Construct a ParallelReader. </summary>
67                 /// <param name="closeSubReaders">indicates whether the subreaders should be closed
68                 /// when this ParallelReader is closed
69                 /// </param>
70                 public ParallelReader(bool closeSubReaders):base()
71                 {
72                         this.incRefReaders = !closeSubReaders;
73                 }
74                 
75                 /// <summary>Add an IndexReader.</summary>
76                 /// <throws>  IOException if there is a low-level IO error </throws>
77                 public virtual void  Add(IndexReader reader)
78                 {
79                         EnsureOpen();
80                         Add(reader, false);
81                 }
82                 
83                 /// <summary>Add an IndexReader whose stored fields will not be returned.  This can
84                 /// accellerate search when stored fields are only needed from a subset of
85                 /// the IndexReaders.
86                 /// 
87                 /// </summary>
88                 /// <throws>  IllegalArgumentException if not all indexes contain the same number </throws>
89                 /// <summary>     of documents
90                 /// </summary>
91                 /// <throws>  IllegalArgumentException if not all indexes have the same value </throws>
92                 /// <summary>     of {@link IndexReader#MaxDoc()}
93                 /// </summary>
94                 /// <throws>  IOException if there is a low-level IO error </throws>
95                 public virtual void  Add(IndexReader reader, bool ignoreStoredFields)
96                 {
97                         
98                         EnsureOpen();
99                         if (readers.Count == 0)
100                         {
101                                 this.maxDoc = reader.MaxDoc();
102                                 this.numDocs = reader.NumDocs();
103                                 this.hasDeletions = reader.HasDeletions();
104                         }
105                         
106                         if (reader.MaxDoc() != maxDoc)
107                         // check compatibility
108                                 throw new System.ArgumentException("All readers must have same maxDoc: " + maxDoc + "!=" + reader.MaxDoc());
109                         if (reader.NumDocs() != numDocs)
110                                 throw new System.ArgumentException("All readers must have same numDocs: " + numDocs + "!=" + reader.NumDocs());
111                         
112                         System.Collections.Generic.ICollection<string> fields = reader.GetFieldNames(IndexReader.FieldOption.ALL);
113                         readerToFields[reader] = fields;
114                         System.Collections.IEnumerator i = fields.GetEnumerator();
115                         while (i.MoveNext())
116                         {
117                                 // update fieldToReader map
118                                 System.String field = (System.String) i.Current;
119                                 if (fieldToReader[field] == null)
120                                         fieldToReader[field] = reader;
121                         }
122                         
123                         if (!ignoreStoredFields)
124                                 storedFieldReaders.Add(reader); // add to storedFieldReaders
125                         readers.Add(reader);
126                         
127                         if (incRefReaders)
128                         {
129                                 reader.IncRef();
130                         }
131                         decrefOnClose.Add(incRefReaders);
132                 }
133                 
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> Tries to reopen the subreaders.
147                 /// <br/>
148                 /// If one or more subreaders could be re-opened (i. e. subReader.reopen() 
149                 /// returned a new instance != subReader), then a new ParallelReader instance 
150                 /// is returned, otherwise this instance is returned.
151                 /// <p/>
152                 /// A re-opened instance might share one or more subreaders with the old 
153                 /// instance. Index modification operations result in undefined behavior
154                 /// when performed before the old instance is closed.
155                 /// (see {@link IndexReader#Reopen()}).
156                 /// <p/>
157                 /// If subreaders are shared, then the reference count of those
158                 /// readers is increased to ensure that the subreaders remain open
159                 /// until the last referring reader is closed.
160                 /// 
161                 /// </summary>
162                 /// <throws>  CorruptIndexException if the index is corrupt </throws>
163                 /// <throws>  IOException if there is a low-level IO error  </throws>
164                 public override IndexReader Reopen()
165                 {
166                         lock (this)
167                         {
168                                 return DoReopen(false);
169                         }
170                 }
171                 
172                 protected internal virtual IndexReader DoReopen(bool doClone)
173                 {
174                         EnsureOpen();
175                         
176                         bool reopened = false;
177                         System.Collections.IList newReaders = new System.Collections.ArrayList();
178                         
179                         bool success = false;
180                         
181                         try
182                         {
183                                 for (int i = 0; i < readers.Count; i++)
184                                 {
185                                         IndexReader oldReader = (IndexReader) readers[i];
186                                         IndexReader newReader = null;
187                                         if (doClone)
188                                         {
189                                                 newReader = (IndexReader) oldReader.Clone();
190                                         }
191                                         else
192                                         {
193                                                 newReader = oldReader.Reopen();
194                                         }
195                                         newReaders.Add(newReader);
196                                         // if at least one of the subreaders was updated we remember that
197                                         // and return a new ParallelReader
198                                         if (newReader != oldReader)
199                                         {
200                                                 reopened = true;
201                                         }
202                                 }
203                                 success = true;
204                         }
205                         finally
206                         {
207                                 if (!success && reopened)
208                                 {
209                                         for (int i = 0; i < newReaders.Count; i++)
210                                         {
211                                                 IndexReader r = (IndexReader) newReaders[i];
212                                                 if (r != readers[i])
213                                                 {
214                                                         try
215                                                         {
216                                                                 r.Close();
217                                                         }
218                                                         catch (System.IO.IOException ignore)
219                                                         {
220                                                                 // keep going - we want to clean up as much as possible
221                                                         }
222                                                 }
223                                         }
224                                 }
225                         }
226                         
227                         if (reopened)
228                         {
229                                 System.Collections.IList newDecrefOnClose = new System.Collections.ArrayList();
230                                 ParallelReader pr = new ParallelReader();
231                                 for (int i = 0; i < readers.Count; i++)
232                                 {
233                                         IndexReader oldReader = (IndexReader) readers[i];
234                                         IndexReader newReader = (IndexReader) newReaders[i];
235                                         if (newReader == oldReader)
236                                         {
237                                                 newDecrefOnClose.Add(true);
238                                                 newReader.IncRef();
239                                         }
240                                         else
241                                         {
242                                                 // this is a new subreader instance, so on close() we don't
243                                                 // decRef but close it 
244                                                 newDecrefOnClose.Add(false);
245                                         }
246                                         pr.Add(newReader, !storedFieldReaders.Contains(oldReader));
247                                 }
248                                 pr.decrefOnClose = newDecrefOnClose;
249                                 pr.incRefReaders = incRefReaders;
250                                 return pr;
251                         }
252                         else
253                         {
254                                 // No subreader was refreshed
255                                 return this;
256                         }
257                 }
258                 
259                 
260                 public override int NumDocs()
261                 {
262                         // Don't call ensureOpen() here (it could affect performance)
263                         return numDocs;
264                 }
265                 
266                 public override int MaxDoc()
267                 {
268                         // Don't call ensureOpen() here (it could affect performance)
269                         return maxDoc;
270                 }
271                 
272                 public override bool HasDeletions()
273                 {
274                         // Don't call ensureOpen() here (it could affect performance)
275                         return hasDeletions;
276                 }
277                 
278                 // check first reader
279                 public override bool IsDeleted(int n)
280                 {
281                         // Don't call ensureOpen() here (it could affect performance)
282                         if (readers.Count > 0)
283                                 return ((IndexReader) readers[0]).IsDeleted(n);
284                         return false;
285                 }
286                 
287                 // delete in all readers
288                 protected internal override void  DoDelete(int n)
289                 {
290                         for (int i = 0; i < readers.Count; i++)
291                         {
292                                 ((IndexReader) readers[i]).DeleteDocument(n);
293                         }
294                         hasDeletions = true;
295                 }
296                 
297                 // undeleteAll in all readers
298                 protected internal override void  DoUndeleteAll()
299                 {
300                         for (int i = 0; i < readers.Count; i++)
301                         {
302                                 ((IndexReader) readers[i]).UndeleteAll();
303                         }
304                         hasDeletions = false;
305                 }
306                 
307                 // append fields from storedFieldReaders
308                 public override Document Document(int n, FieldSelector fieldSelector)
309                 {
310                         EnsureOpen();
311                         Document result = new Document();
312                         for (int i = 0; i < storedFieldReaders.Count; i++)
313                         {
314                                 IndexReader reader = (IndexReader) storedFieldReaders[i];
315                                 
316                                 bool include = (fieldSelector == null);
317                                 if (!include)
318                                 {
319                                         System.Collections.IEnumerator it = ((System.Collections.ICollection) readerToFields[reader]).GetEnumerator();
320                                         while (it.MoveNext())
321                                         {
322                                                 if (fieldSelector.Accept((System.String) it.Current) != FieldSelectorResult.NO_LOAD)
323                                                 {
324                                                         include = true;
325                                                         break;
326                                                 }
327                                         }
328                                 }
329                                 if (include)
330                                 {
331                                         System.Collections.IEnumerator fieldIterator = reader.Document(n, fieldSelector).GetFields().GetEnumerator();
332                                         while (fieldIterator.MoveNext())
333                                         {
334                                                 result.Add((Fieldable) fieldIterator.Current);
335                                         }
336                                 }
337                         }
338                         return result;
339                 }
340                 
341                 // get all vectors
342                 public override TermFreqVector[] GetTermFreqVectors(int n)
343                 {
344                         EnsureOpen();
345                         System.Collections.ArrayList results = new System.Collections.ArrayList();
346             System.Collections.IEnumerator i = new System.Collections.Hashtable(fieldToReader).GetEnumerator();
347                         while (i.MoveNext())
348                         {
349                                 System.Collections.DictionaryEntry e = (System.Collections.DictionaryEntry) i.Current;
350                                 System.String field = (System.String) e.Key;
351                                 IndexReader reader = (IndexReader) e.Value;
352                                 TermFreqVector vector = reader.GetTermFreqVector(n, field);
353                                 if (vector != null)
354                                         results.Add(vector);
355                         }
356                         return (TermFreqVector[]) results.ToArray(typeof(TermFreqVector));
357                 }
358                 
359                 public override TermFreqVector GetTermFreqVector(int n, System.String field)
360                 {
361                         EnsureOpen();
362                         IndexReader reader = ((IndexReader) fieldToReader[field]);
363                         return reader == null?null:reader.GetTermFreqVector(n, field);
364                 }
365                 
366                 
367                 public override void  GetTermFreqVector(int docNumber, System.String field, TermVectorMapper mapper)
368                 {
369                         EnsureOpen();
370                         IndexReader reader = ((IndexReader) fieldToReader[field]);
371                         if (reader != null)
372                         {
373                                 reader.GetTermFreqVector(docNumber, field, mapper);
374                         }
375                 }
376                 
377                 public override void  GetTermFreqVector(int docNumber, TermVectorMapper mapper)
378                 {
379                         EnsureOpen();
380
381             System.Collections.IEnumerator i = new System.Collections.Hashtable(fieldToReader).GetEnumerator();
382                         while (i.MoveNext())
383                         {
384                                 System.Collections.DictionaryEntry e = (System.Collections.DictionaryEntry) i.Current;
385                                 System.String field = (System.String) e.Key;
386                                 IndexReader reader = (IndexReader) e.Value;
387                                 reader.GetTermFreqVector(docNumber, field, mapper);
388                         }
389                 }
390                 
391                 public override bool HasNorms(System.String field)
392                 {
393                         EnsureOpen();
394                         IndexReader reader = ((IndexReader) fieldToReader[field]);
395                         return reader == null?false:reader.HasNorms(field);
396                 }
397                 
398                 public override byte[] Norms(System.String field)
399                 {
400                         EnsureOpen();
401                         IndexReader reader = ((IndexReader) fieldToReader[field]);
402                         return reader == null?null:reader.Norms(field);
403                 }
404                 
405                 public override void  Norms(System.String field, byte[] result, int offset)
406                 {
407                         EnsureOpen();
408                         IndexReader reader = ((IndexReader) fieldToReader[field]);
409                         if (reader != null)
410                                 reader.Norms(field, result, offset);
411                 }
412                 
413                 protected internal override void  DoSetNorm(int n, System.String field, byte value_Renamed)
414                 {
415                         IndexReader reader = ((IndexReader) fieldToReader[field]);
416                         if (reader != null)
417                                 reader.DoSetNorm(n, field, value_Renamed);
418                 }
419                 
420                 public override TermEnum Terms()
421                 {
422                         EnsureOpen();
423                         return new ParallelTermEnum(this);
424                 }
425                 
426                 public override TermEnum Terms(Term term)
427                 {
428                         EnsureOpen();
429                         return new ParallelTermEnum(this, term);
430                 }
431                 
432                 public override int DocFreq(Term term)
433                 {
434                         EnsureOpen();
435                         IndexReader reader = ((IndexReader) fieldToReader[term.Field()]);
436                         return reader == null?0:reader.DocFreq(term);
437                 }
438                 
439                 public override TermDocs TermDocs(Term term)
440                 {
441                         EnsureOpen();
442                         return new ParallelTermDocs(this, term);
443                 }
444                 
445                 public override TermDocs TermDocs()
446                 {
447                         EnsureOpen();
448                         return new ParallelTermDocs(this);
449                 }
450                 
451                 public override TermPositions TermPositions(Term term)
452                 {
453                         EnsureOpen();
454                         return new ParallelTermPositions(this, term);
455                 }
456                 
457                 public override TermPositions TermPositions()
458                 {
459                         EnsureOpen();
460                         return new ParallelTermPositions(this);
461                 }
462                 
463                 /// <summary> Checks recursively if all subreaders are up to date. </summary>
464                 public override bool IsCurrent()
465                 {
466                         for (int i = 0; i < readers.Count; i++)
467                         {
468                                 if (!((IndexReader) readers[i]).IsCurrent())
469                                 {
470                                         return false;
471                                 }
472                         }
473                         
474                         // all subreaders are up to date
475                         return true;
476                 }
477                 
478                 /// <summary> Checks recursively if all subindexes are optimized </summary>
479                 public override bool IsOptimized()
480                 {
481                         for (int i = 0; i < readers.Count; i++)
482                         {
483                                 if (!((IndexReader) readers[i]).IsOptimized())
484                                 {
485                                         return false;
486                                 }
487                         }
488                         
489                         // all subindexes are optimized
490                         return true;
491                 }
492                 
493                 
494                 /// <summary>Not implemented.</summary>
495                 /// <throws>  UnsupportedOperationException </throws>
496                 public override long GetVersion()
497                 {
498                         throw new System.NotSupportedException("ParallelReader does not support this method.");
499                 }
500                 
501                 // for testing
502                 public /*internal*/ virtual IndexReader[] GetSubReaders()
503                 {
504                         return (IndexReader[]) readers.ToArray(typeof(IndexReader));
505                 }
506                 
507                 /// <deprecated> 
508                 /// </deprecated>
509         [Obsolete]
510                 protected internal override void  DoCommit()
511                 {
512                         DoCommit(null);
513                 }
514
515         protected internal override void DoCommit(System.Collections.Generic.IDictionary<string, string> commitUserData)
516                 {
517                         for (int i = 0; i < readers.Count; i++)
518                                 ((IndexReader) readers[i]).Commit(commitUserData);
519                 }
520                 
521                 protected internal override void  DoClose()
522                 {
523                         lock (this)
524                         {
525                                 for (int i = 0; i < readers.Count; i++)
526                                 {
527                                         if (((System.Boolean) decrefOnClose[i]))
528                                         {
529                                                 ((IndexReader) readers[i]).DecRef();
530                                         }
531                                         else
532                                         {
533                                                 ((IndexReader) readers[i]).Close();
534                                         }
535                                 }
536                         }
537
538             Mono.Lucene.Net.Search.FieldCache_Fields.DEFAULT.Purge(this);
539                 }
540
541         public override System.Collections.Generic.ICollection<string> GetFieldNames(IndexReader.FieldOption fieldNames)
542                 {
543                         EnsureOpen();
544             System.Collections.Generic.List<string> fieldSet = new System.Collections.Generic.List<string>();
545                         for (int i = 0; i < readers.Count; i++)
546                         {
547                                 IndexReader reader = ((IndexReader) readers[i]);
548                                 System.Collections.Generic.ICollection<string> names = reader.GetFieldNames(fieldNames);
549                 fieldSet.AddRange(names);
550                         }
551                         return fieldSet;
552                 }
553                 
554                 private class ParallelTermEnum:TermEnum
555                 {
556                         private void  InitBlock(ParallelReader enclosingInstance)
557                         {
558                                 this.enclosingInstance = enclosingInstance;
559                         }
560                         private ParallelReader enclosingInstance;
561                         public ParallelReader Enclosing_Instance
562                         {
563                                 get
564                                 {
565                                         return enclosingInstance;
566                                 }
567                                 
568                         }
569                         private System.String field;
570                         private System.Collections.IEnumerator fieldIterator;
571                         private TermEnum termEnum;
572                         
573                         public ParallelTermEnum(ParallelReader enclosingInstance)
574                         {
575                                 InitBlock(enclosingInstance);
576                                 try
577                                 {
578                                         field = ((System.String) Enclosing_Instance.fieldToReader.GetKey(0));
579                                 }
580                                 catch (ArgumentOutOfRangeException e)
581                                 {
582                                         // No fields, so keep field == null, termEnum == null
583                                         return;
584                                 }
585                                 if (field != null)
586                                         termEnum = ((IndexReader) Enclosing_Instance.fieldToReader[field]).Terms();
587                         }
588                         
589                         public ParallelTermEnum(ParallelReader enclosingInstance, Term term)
590                         {
591                                 InitBlock(enclosingInstance);
592                                 field = term.Field();
593                                 IndexReader reader = ((IndexReader) Enclosing_Instance.fieldToReader[field]);
594                                 if (reader != null)
595                                         termEnum = reader.Terms(term);
596                         }
597                         
598                         public override bool Next()
599                         {
600                                 if (termEnum == null)
601                                         return false;
602                                 
603                                 // another term in this field?
604                                 if (termEnum.Next() && (System.Object) termEnum.Term().Field() == (System.Object) field)
605                                         return true; // yes, keep going
606                                 
607                                 termEnum.Close(); // close old termEnum
608                                 
609                                 // find the next field with terms, if any
610                                 if (fieldIterator == null)
611                                 {
612                     System.Collections.Comparer comparer = System.Collections.Comparer.Default;
613                     System.Collections.SortedList newList = new System.Collections.SortedList();
614                     if (Enclosing_Instance.fieldToReader != null)
615                     {
616                         if (Enclosing_Instance.fieldToReader.Count > 0)
617                         {
618                             int index = 0;
619                             while (comparer.Compare(Enclosing_Instance.fieldToReader.GetKey(index), field) < 0)
620                                 index++;
621                             for (; index < Enclosing_Instance.fieldToReader.Count; index++)
622                             {
623                                 newList.Add(Enclosing_Instance.fieldToReader.GetKey(index), Enclosing_Instance.fieldToReader[Enclosing_Instance.fieldToReader.GetKey(index)]);
624                             }
625                         }
626                     }
627
628                     fieldIterator = newList.Keys.GetEnumerator();
629                     fieldIterator.MoveNext();
630                                         System.Object generatedAux = fieldIterator.Current; // Skip field to get next one
631                                 }
632                                 while (fieldIterator.MoveNext())
633                                 {
634                                         field = ((System.String) fieldIterator.Current);
635                                         termEnum = ((IndexReader) Enclosing_Instance.fieldToReader[field]).Terms(new Term(field));
636                                         Term term = termEnum.Term();
637                                         if (term != null && (System.Object) term.Field() == (System.Object) field)
638                                                 return true;
639                                         else
640                                                 termEnum.Close();
641                                 }
642                                 
643                                 return false; // no more fields
644                         }
645                         
646                         public override Term Term()
647                         {
648                                 if (termEnum == null)
649                                         return null;
650                                 
651                                 return termEnum.Term();
652                         }
653                         
654                         public override int DocFreq()
655                         {
656                                 if (termEnum == null)
657                                         return 0;
658                                 
659                                 return termEnum.DocFreq();
660                         }
661                         
662                         public override void  Close()
663                         {
664                                 if (termEnum != null)
665                                         termEnum.Close();
666                         }
667                 }
668                 
669                 // wrap a TermDocs in order to support seek(Term)
670                 private class ParallelTermDocs : TermDocs
671                 {
672                         private void  InitBlock(ParallelReader enclosingInstance)
673                         {
674                                 this.enclosingInstance = enclosingInstance;
675                         }
676                         private ParallelReader enclosingInstance;
677                         public ParallelReader Enclosing_Instance
678                         {
679                                 get
680                                 {
681                                         return enclosingInstance;
682                                 }
683                                 
684                         }
685                         protected internal TermDocs termDocs;
686                         
687                         public ParallelTermDocs(ParallelReader enclosingInstance)
688                         {
689                                 InitBlock(enclosingInstance);
690                         }
691                         public ParallelTermDocs(ParallelReader enclosingInstance, Term term)
692                         {
693                                 InitBlock(enclosingInstance);
694                                 if (term == null)
695                                         termDocs = (Enclosing_Instance.readers.Count == 0)?null:((IndexReader) Enclosing_Instance.readers[0]).TermDocs(null);
696                                 else
697                                         Seek(term);
698                         }
699                         
700                         public virtual int Doc()
701                         {
702                                 return termDocs.Doc();
703                         }
704                         public virtual int Freq()
705                         {
706                                 return termDocs.Freq();
707                         }
708                         
709                         public virtual void  Seek(Term term)
710                         {
711                                 IndexReader reader = ((IndexReader) Enclosing_Instance.fieldToReader[term.Field()]);
712                                 termDocs = reader != null?reader.TermDocs(term):null;
713                         }
714                         
715                         public virtual void  Seek(TermEnum termEnum)
716                         {
717                                 Seek(termEnum.Term());
718                         }
719                         
720                         public virtual bool Next()
721                         {
722                                 if (termDocs == null)
723                                         return false;
724                                 
725                                 return termDocs.Next();
726                         }
727                         
728                         public virtual int Read(int[] docs, int[] freqs)
729                         {
730                                 if (termDocs == null)
731                                         return 0;
732                                 
733                                 return termDocs.Read(docs, freqs);
734                         }
735                         
736                         public virtual bool SkipTo(int target)
737                         {
738                                 if (termDocs == null)
739                                         return false;
740                                 
741                                 return termDocs.SkipTo(target);
742                         }
743                         
744                         public virtual void  Close()
745                         {
746                                 if (termDocs != null)
747                                         termDocs.Close();
748                         }
749                 }
750                 
751                 private class ParallelTermPositions:ParallelTermDocs, TermPositions
752                 {
753                         private void  InitBlock(ParallelReader enclosingInstance)
754                         {
755                                 this.enclosingInstance = enclosingInstance;
756                         }
757                         private ParallelReader enclosingInstance;
758                         public new ParallelReader Enclosing_Instance
759                         {
760                                 get
761                                 {
762                                         return enclosingInstance;
763                                 }
764                                 
765                         }
766                         
767                         public ParallelTermPositions(ParallelReader enclosingInstance):base(enclosingInstance)
768                         {
769                                 InitBlock(enclosingInstance);
770                         }
771                         public ParallelTermPositions(ParallelReader enclosingInstance, Term term):base(enclosingInstance)
772                         {
773                                 InitBlock(enclosingInstance);
774                                 Seek(term);
775                         }
776                         
777                         public override void  Seek(Term term)
778                         {
779                                 IndexReader reader = ((IndexReader) Enclosing_Instance.fieldToReader[term.Field()]);
780                                 termDocs = reader != null?reader.TermPositions(term):null;
781                         }
782                         
783                         public virtual int NextPosition()
784                         {
785                                 // It is an error to call this if there is no next position, e.g. if termDocs==null
786                                 return ((TermPositions) termDocs).NextPosition();
787                         }
788                         
789                         public virtual int GetPayloadLength()
790                         {
791                                 return ((TermPositions) termDocs).GetPayloadLength();
792                         }
793                         
794                         public virtual byte[] GetPayload(byte[] data, int offset)
795                         {
796                                 return ((TermPositions) termDocs).GetPayload(data, offset);
797                         }
798                         
799                         
800                         // TODO: Remove warning after API has been finalized
801                         public virtual bool IsPayloadAvailable()
802                         {
803                                 return ((TermPositions) termDocs).IsPayloadAvailable();
804                         }
805                 }
806         }
807 }