Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
FieldsWriter.cs
Go to the documentation of this file.
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 using System.Linq;
20 using Lucene.Net.Documents;
21 using Document = Lucene.Net.Documents.Document;
22 using Directory = Lucene.Net.Store.Directory;
23 using IndexInput = Lucene.Net.Store.IndexInput;
24 using IndexOutput = Lucene.Net.Store.IndexOutput;
25 using RAMOutputStream = Lucene.Net.Store.RAMOutputStream;
26 
27 namespace Lucene.Net.Index
28 {
29 
30  sealed class FieldsWriter : IDisposable
31  {
32  internal const byte FIELD_IS_TOKENIZED = (0x1);
33  internal const byte FIELD_IS_BINARY = (0x2);
34  [Obsolete("Kept for backwards-compatibility with <3.0 indexes; will be removed in 4.0")]
35  internal const byte FIELD_IS_COMPRESSED = (0x4);
36 
37  // Original format
38  internal const int FORMAT = 0;
39 
40  // Changed strings to UTF8
41  internal const int FORMAT_VERSION_UTF8_LENGTH_IN_BYTES = 1;
42 
43  // Lucene 3.0: Removal of compressed fields
44  internal static int FORMAT_LUCENE_3_0_NO_COMPRESSED_FIELDS = 2;
45 
46  // NOTE: if you introduce a new format, make it 1 higher
47  // than the current one, and always change this if you
48  // switch to a new format!
49  internal static readonly int FORMAT_CURRENT = FORMAT_LUCENE_3_0_NO_COMPRESSED_FIELDS;
50 
51  private readonly FieldInfos fieldInfos;
52 
53  private IndexOutput fieldsStream;
54 
55  private IndexOutput indexStream;
56 
57  private readonly bool doClose;
58 
59  internal FieldsWriter(Directory d, System.String segment, FieldInfos fn)
60  {
61  fieldInfos = fn;
62 
63  bool success = false;
64  String fieldsName = segment + "." + IndexFileNames.FIELDS_EXTENSION;
65  try
66  {
67  fieldsStream = d.CreateOutput(fieldsName);
68  fieldsStream.WriteInt(FORMAT_CURRENT);
69  success = true;
70  }
71  finally
72  {
73  if (!success)
74  {
75  try
76  {
77  Dispose();
78  }
79  catch (System.Exception)
80  {
81  // Suppress so we keep throwing the original exception
82  }
83  try
84  {
85  d.DeleteFile(fieldsName);
86  }
87  catch (System.Exception)
88  {
89  // Suppress so we keep throwing the original exception
90  }
91  }
92  }
93 
94  success = false;
95  String indexName = segment + "." + IndexFileNames.FIELDS_INDEX_EXTENSION;
96  try
97  {
98  indexStream = d.CreateOutput(indexName);
99  indexStream.WriteInt(FORMAT_CURRENT);
100  success = true;
101  }
102  finally
103  {
104  if (!success)
105  {
106  try
107  {
108  Dispose();
109  }
110  catch (System.IO.IOException)
111  {
112  }
113  try
114  {
115  d.DeleteFile(fieldsName);
116  }
117  catch (System.Exception)
118  {
119  // Suppress so we keep throwing the original exception
120  }
121  try
122  {
123  d.DeleteFile(indexName);
124  }
125  catch (System.Exception)
126  {
127  // Suppress so we keep throwing the original exception
128  }
129  }
130  }
131 
132  doClose = true;
133  }
134 
135  internal FieldsWriter(IndexOutput fdx, IndexOutput fdt, FieldInfos fn)
136  {
137  fieldInfos = fn;
138  fieldsStream = fdt;
139  indexStream = fdx;
140  doClose = false;
141  }
142 
143  internal void SetFieldsStream(IndexOutput stream)
144  {
145  this.fieldsStream = stream;
146  }
147 
148  // Writes the contents of buffer into the fields stream
149  // and adds a new entry for this document into the index
150  // stream. This assumes the buffer was already written
151  // in the correct fields format.
152  internal void FlushDocument(int numStoredFields, RAMOutputStream buffer)
153  {
154  indexStream.WriteLong(fieldsStream.FilePointer);
155  fieldsStream.WriteVInt(numStoredFields);
156  buffer.WriteTo(fieldsStream);
157  }
158 
159  internal void SkipDocument()
160  {
161  indexStream.WriteLong(fieldsStream.FilePointer);
162  fieldsStream.WriteVInt(0);
163  }
164 
165  internal void Flush()
166  {
167  indexStream.Flush();
168  fieldsStream.Flush();
169  }
170 
171  public void Dispose()
172  {
173  // Move to protected method if class becomes unsealed
174  if (doClose)
175  {
176  try
177  {
178  if (fieldsStream != null)
179  {
180  try
181  {
182  fieldsStream.Close();
183  }
184  finally
185  {
186  fieldsStream = null;
187  }
188  }
189  }
190  catch (System.IO.IOException)
191  {
192  try
193  {
194  if (indexStream != null)
195  {
196  try
197  {
198  indexStream.Close();
199  }
200  finally
201  {
202  indexStream = null;
203  }
204  }
205  }
206  catch (System.IO.IOException)
207  {
208  // Ignore so we throw only first IOException hit
209  }
210  throw;
211  }
212  finally
213  {
214  if (indexStream != null)
215  {
216  try
217  {
218  indexStream.Close();
219  }
220  finally
221  {
222  indexStream = null;
223  }
224  }
225  }
226  }
227  }
228 
229  internal void WriteField(FieldInfo fi, IFieldable field)
230  {
231  fieldsStream.WriteVInt(fi.number);
232  byte bits = 0;
233  if (field.IsTokenized)
234  bits |= FieldsWriter.FIELD_IS_TOKENIZED;
235  if (field.IsBinary)
236  bits |= FieldsWriter.FIELD_IS_BINARY;
237 
238  fieldsStream.WriteByte(bits);
239 
240  // compression is disabled for the current field
241  if (field.IsBinary)
242  {
243  byte[] data = field.GetBinaryValue();
244  int len = field.BinaryLength;
245  int offset = field.BinaryOffset;
246 
247  fieldsStream.WriteVInt(len);
248  fieldsStream.WriteBytes(data, offset, len);
249  }
250  else
251  {
252  fieldsStream.WriteString(field.StringValue);
253  }
254  }
255 
256  /// <summary>Bulk write a contiguous series of documents. The
257  /// lengths array is the length (in bytes) of each raw
258  /// document. The stream IndexInput is the
259  /// fieldsStream from which we should bulk-copy all
260  /// bytes.
261  /// </summary>
262  internal void AddRawDocuments(IndexInput stream, int[] lengths, int numDocs)
263  {
264  long position = fieldsStream.FilePointer;
265  long start = position;
266  for (int i = 0; i < numDocs; i++)
267  {
268  indexStream.WriteLong(position);
269  position += lengths[i];
270  }
271  fieldsStream.CopyBytes(stream, position - start);
272  System.Diagnostics.Debug.Assert(fieldsStream.FilePointer == position);
273  }
274 
275  internal void AddDocument(Document doc)
276  {
277  indexStream.WriteLong(fieldsStream.FilePointer);
278 
279  System.Collections.Generic.IList<IFieldable> fields = doc.GetFields();
280  int storedCount = fields.Count(field => field.IsStored);
281  fieldsStream.WriteVInt(storedCount);
282 
283  foreach(IFieldable field in fields)
284  {
285  if (field.IsStored)
286  WriteField(fieldInfos.FieldInfo(field.Name), field);
287  }
288  }
289  }
290 }