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
RAMDirectory.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 Lucene.Net.Support;
20 
21 namespace Lucene.Net.Store
22 {
23 
24  /// <summary> A memory-resident <see cref="Directory"/> implementation. Locking
25  /// implementation is by default the <see cref="SingleInstanceLockFactory"/>
26  /// but can be changed with <see cref="Directory.SetLockFactory"/>.
27  /// </summary>
28  [Serializable]
29  public class RAMDirectory:Directory
30  {
31 
32  private const long serialVersionUID = 1L;
33 
34  internal protected HashMap<string, RAMFile> fileMap = new HashMap<string, RAMFile>();
35  internal protected long internalSizeInBytes = 0;
36 
37  // *****
38  // Lock acquisition sequence: RAMDirectory, then RAMFile
39  // *****
40 
41  /// <summary>Constructs an empty <see cref="Directory"/>. </summary>
42  public RAMDirectory()
43  {
44  SetLockFactory(new SingleInstanceLockFactory());
45  }
46 
47  /// <summary> Creates a new <c>RAMDirectory</c> instance from a different
48  /// <c>Directory</c> implementation. This can be used to load
49  /// a disk-based index into memory.
50  /// <p/>
51  /// This should be used only with indices that can fit into memory.
52  /// <p/>
53  /// Note that the resulting <c>RAMDirectory</c> instance is fully
54  /// independent from the original <c>Directory</c> (it is a
55  /// complete copy). Any subsequent changes to the
56  /// original <c>Directory</c> will not be visible in the
57  /// <c>RAMDirectory</c> instance.
58  ///
59  /// </summary>
60  /// <param name="dir">a <c>Directory</c> value
61  /// </param>
62  /// <exception cref="System.IO.IOException">if an error occurs
63  /// </exception>
64  public RAMDirectory(Directory dir):this(dir, false)
65  {
66  }
67 
68  private RAMDirectory(Directory dir, bool closeDir):this()
69  {
70  Directory.Copy(dir, this, closeDir);
71  }
72 
73  //https://issues.apache.org/jira/browse/LUCENENET-174
74  [System.Runtime.Serialization.OnDeserialized]
75  void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
76  {
77  if (interalLockFactory == null)
78  {
79  SetLockFactory(new SingleInstanceLockFactory());
80  }
81  }
82 
83  public override System.String[] ListAll()
84  {
85  lock (this)
86  {
87  EnsureOpen();
88  // TODO: may have better performance if our HashMap implmented KeySet() instead of generating one via HashSet
89  System.Collections.Generic.ISet<string> fileNames = Support.Compatibility.SetFactory.CreateHashSet(fileMap.Keys);
90  System.String[] result = new System.String[fileNames.Count];
91  int i = 0;
92  foreach(string filename in fileNames)
93  {
94  result[i++] = filename;
95  }
96  return result;
97  }
98  }
99 
100  /// <summary>Returns true iff the named file exists in this directory. </summary>
101  public override bool FileExists(System.String name)
102  {
103  EnsureOpen();
104  RAMFile file;
105  lock (this)
106  {
107  file = fileMap[name];
108  }
109  return file != null;
110  }
111 
112  /// <summary>Returns the time the named file was last modified.</summary>
113  /// <throws> IOException if the file does not exist </throws>
114  public override long FileModified(System.String name)
115  {
116  EnsureOpen();
117  RAMFile file;
118  lock (this)
119  {
120  file = fileMap[name];
121  }
122  if (file == null)
123  throw new System.IO.FileNotFoundException(name);
124 
125  // RAMOutputStream.Flush() was changed to use DateTime.UtcNow.
126  // Convert it back to local time before returning (previous behavior)
127  return new DateTime(file.LastModified*TimeSpan.TicksPerMillisecond, DateTimeKind.Utc).ToLocalTime().Ticks/
128  TimeSpan.TicksPerMillisecond;
129  }
130 
131  /// <summary>Set the modified time of an existing file to now.</summary>
132  /// <throws> IOException if the file does not exist </throws>
133  public override void TouchFile(System.String name)
134  {
135  EnsureOpen();
136  RAMFile file;
137  lock (this)
138  {
139  file = fileMap[name];
140  }
141  if (file == null)
142  throw new System.IO.FileNotFoundException(name);
143 
144  long ts2, ts1 = System.DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
145  do
146  {
147  try
148  {
149  System.Threading.Thread.Sleep(new System.TimeSpan((System.Int64) 10000 * 0 + 100 * 1));
150  }
151  catch (System.Threading.ThreadInterruptedException ie)
152  {
153  // In 3.0 we will change this to throw
154  // InterruptedException instead
156  throw new System.SystemException(ie.Message, ie);
157  }
158  ts2 = System.DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
159  }
160  while (ts1 == ts2);
161 
162  file.LastModified = ts2;
163  }
164 
165  /// <summary>Returns the length in bytes of a file in the directory.</summary>
166  /// <throws> IOException if the file does not exist </throws>
167  public override long FileLength(System.String name)
168  {
169  EnsureOpen();
170  RAMFile file;
171  lock (this)
172  {
173  file = fileMap[name];
174  }
175  if (file == null)
176  throw new System.IO.FileNotFoundException(name);
177  return file.Length;
178  }
179 
180  /// <summary>Return total size in bytes of all files in this
181  /// directory. This is currently quantized to
182  /// RAMOutputStream.BUFFER_SIZE.
183  /// </summary>
184  public long SizeInBytes()
185  {
186  lock (this)
187  {
188  EnsureOpen();
189  return internalSizeInBytes;
190  }
191  }
192 
193  /// <summary>Removes an existing file in the directory.</summary>
194  /// <throws> IOException if the file does not exist </throws>
195  public override void DeleteFile(System.String name)
196  {
197  lock (this)
198  {
199  EnsureOpen();
200  RAMFile file = fileMap[name];
201  if (file != null)
202  {
203  fileMap.Remove(name);
204  file.directory = null;
205  internalSizeInBytes -= file.sizeInBytes;
206  }
207  else
208  throw new System.IO.FileNotFoundException(name);
209  }
210  }
211 
212  /// <summary>Creates a new, empty file in the directory with the given name. Returns a stream writing this file. </summary>
213  public override IndexOutput CreateOutput(System.String name)
214  {
215  EnsureOpen();
216  RAMFile file = new RAMFile(this);
217  lock (this)
218  {
219  RAMFile existing = fileMap[name];
220  if (existing != null)
221  {
222  internalSizeInBytes -= existing.sizeInBytes;
223  existing.directory = null;
224  }
225  fileMap[name] = file;
226  }
227  return new RAMOutputStream(file);
228  }
229 
230  /// <summary>Returns a stream reading an existing file. </summary>
231  public override IndexInput OpenInput(System.String name)
232  {
233  EnsureOpen();
234  RAMFile file;
235  lock (this)
236  {
237  file = fileMap[name];
238  }
239  if (file == null)
240  throw new System.IO.FileNotFoundException(name);
241  return new RAMInputStream(file);
242  }
243 
244  /// <summary>Closes the store to future operations, releasing associated memory. </summary>
245  protected override void Dispose(bool disposing)
246  {
247  isOpen = false;
248  fileMap = null;
249  }
250 
251  //public HashMap<string, RAMFile> fileMap_ForNUnit
252  //{
253  // get { return fileMap; }
254  //}
255 
256  //public long sizeInBytes_ForNUnitTest
257  //{
258  // get { return sizeInBytes; }
259  // set { sizeInBytes = value; }
260  //}
261  }
262 }