PageRenderTime 158ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/eLMM/VirusCount/Escience/SharedFile.cs

#
C# | 320 lines | 236 code | 35 blank | 49 comment | 14 complexity | 8ee96436bd19661a982a9d7baacf5fbe MD5 | raw file
  1. //*********************************************************
  2. //
  3. // Copyright (c) Microsoft. All rights reserved.
  4. // This code is licensed under the Apache License, Version 2.0.
  5. // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
  6. // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
  7. // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
  8. // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
  9. //
  10. //*********************************************************
  11. using System;
  12. using System.Collections.Generic;
  13. using System.IO;
  14. using System.Linq;
  15. using Bio.Util;
  16. using MBT.Escience.Parse;
  17. namespace MBT.Escience
  18. {
  19. public class SharedFile : IDisposable
  20. {
  21. //readonly FileInfo _sharedFileInfo;
  22. string _filename;
  23. //string _uniqFilename;
  24. FileStream _filestream;
  25. StreamWriter _writer;
  26. StreamReader _reader;
  27. object _lockObj = new object();
  28. Random _rand;
  29. //long _locklength;
  30. volatile bool _disposed = false;
  31. volatile bool _haveLock = false;
  32. public SharedFile(string filename)
  33. {
  34. //Helper.CheckCondition(!uniqID.Contains("\\"), "uniqID cannot contain backslashes");
  35. //_sharedFileInfo = new FileInfo(filename);
  36. _filename = filename;
  37. CreateFileIfNotCreated(filename);
  38. //_uniqFilename = string.Format("{0}_{1}_{2}.txt", filename, uniqID, System.Guid.NewGuid().ToString());
  39. _rand = new Random(System.Guid.NewGuid().GetHashCode());
  40. }
  41. [Obsolete("uniqID is no longer used. You should switch to the other constructor.")]
  42. public SharedFile(string filename, string uniqID) : this(filename) { }
  43. public bool ObtainLock()
  44. {
  45. if (!_haveLock)
  46. {
  47. //Console.WriteLine("Lock requested.");
  48. _filestream = ObtainLockInternal();
  49. if (_filestream != null) // will be null if disposed while obtaining lock. checking if(_disposed) is not threadsafe. so check for null.
  50. {
  51. //Console.WriteLine("Lock obtained.");
  52. }
  53. }
  54. return _haveLock;
  55. }
  56. private const int _slowest = 45 * 1000;
  57. private const int _threshold = 20 * 1000;
  58. private const int _increment = 1000;
  59. private const int _fastest = 250;
  60. private int _sleepTimer = _slowest;
  61. private FileStream ObtainLockInternal()
  62. {
  63. while (!_disposed)
  64. {
  65. try
  66. {
  67. lock (_lockObj)
  68. {
  69. if (!_disposed)
  70. {
  71. //File.Move(_filename, _uniqFilename);
  72. _filestream = File.Open(_filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
  73. //_locklength = _filestream.Length;
  74. //_filestream.Lock(0, _locklength); // this should be unnecessary, but whatever.
  75. _sleepTimer = Math.Max(_sleepTimer < _threshold ? _sleepTimer - _increment : _sleepTimer / 2, _fastest);
  76. _reader = new StreamReader(_filestream);
  77. _writer = new StreamWriter(_filestream);
  78. _haveLock = true;
  79. return _filestream;
  80. }
  81. }
  82. }
  83. catch (UnauthorizedAccessException) { }
  84. catch (FileLoadException) { }
  85. catch (IOException) { }
  86. catch (Exception e)
  87. {
  88. Console.WriteLine("Error obtaining lock: " + e.Message);
  89. Console.WriteLine(e.StackTrace);
  90. throw;
  91. }
  92. // if we get here, it's because one of the lock-based exceptions was thrown. Reset clock and try again.
  93. //Console.WriteLine("File {0} is already locked. Sleeping and will try again.", _filename);
  94. System.Threading.Thread.Sleep(_rand.Next(_sleepTimer));
  95. _sleepTimer = (int)Math.Min(2 * _sleepTimer, _slowest);
  96. }
  97. Console.WriteLine("SharedFile is disposed. Cannot obtain another lock on disposed object. Returning null.");
  98. return null;
  99. }
  100. private static void CreateFileIfNotCreated(string filename)
  101. {
  102. Random rand = new Random(System.Guid.NewGuid().GetHashCode());
  103. for (int i = 0; !File.Exists(filename); i++)
  104. {
  105. try
  106. {
  107. using (FileStream fs = File.Create(filename))
  108. {
  109. return;
  110. }
  111. }
  112. catch (IOException e)
  113. {
  114. if (i >= 20)
  115. throw new IOException("Could not create SharedFile. Tried 20 times to no avail.", e);
  116. else
  117. System.Threading.Thread.Sleep(rand.Next(1000, 5000));
  118. }
  119. }
  120. }
  121. public void ReleaseLock()
  122. {
  123. lock (_lockObj)
  124. {
  125. if (_haveLock)
  126. {
  127. _writer.Flush();
  128. //_filestream.Dispose();
  129. ReleaseLockInternal();
  130. _filestream = null;
  131. _writer = null;
  132. _reader = null; ;
  133. _haveLock = false;
  134. //Console.WriteLine("Lock released.");
  135. }
  136. else
  137. {
  138. //Console.WriteLine("Release lock called, but we don't have a lock.");
  139. }
  140. }
  141. }
  142. private void ReleaseLockInternal()
  143. {
  144. //_filestream.Unlock(0, _locklength); // this should be unnecessary, but whatever.
  145. _filestream.Dispose();
  146. //Console.WriteLine("Releasing file lock. Does {0} still exist? {1}", _filename, File.Exists(_filename));
  147. //File.Move(_uniqFilename, _filename);
  148. }
  149. public string ReadAll()
  150. {
  151. lock (_lockObj)
  152. {
  153. Helper.CheckCondition(_haveLock, "You must obtain a lock before reading the file.");
  154. _filestream.Position = 0;
  155. string completeStream = _reader.ReadToEnd();
  156. return completeStream;
  157. }
  158. }
  159. public IEnumerable<string> ReadLines()
  160. {
  161. lock (_lockObj)
  162. {
  163. Helper.CheckCondition(_haveLock, "You must obtain a lock before reading the file.");
  164. _filestream.Position = 0;
  165. string line;
  166. while (null != (line = _reader.ReadLine()))
  167. {
  168. yield return line;
  169. }
  170. }
  171. }
  172. //public List<string> ReadLines()
  173. //{
  174. // lock (_lockObj)
  175. // {
  176. // Helper.CheckCondition(_haveLock, "You must obtain a lock before reading the file.");
  177. // _filestream.Position = 0;
  178. // List<string> lines = new List<string>();
  179. // string line;
  180. // while (null != (line = _reader.ReadLine()))
  181. // {
  182. // lines.Add(line);
  183. // }
  184. // return lines;
  185. // }
  186. //}
  187. public void Clear()
  188. {
  189. lock (_lockObj)
  190. {
  191. Helper.CheckCondition(_haveLock, "You must obtain a lock before clearing the file.");
  192. _filestream.SetLength(0);
  193. _filestream.Position = 0;
  194. }
  195. }
  196. public void Write(object o)
  197. {
  198. Write(o.ToString());
  199. }
  200. public void Write(string formatString, params object[] args)
  201. {
  202. Write(string.Format(formatString, args));
  203. }
  204. public void WriteLine(object o)
  205. {
  206. WriteLine(o.ToString());
  207. }
  208. public void WriteLine(string formatString, params object[] args)
  209. {
  210. WriteLine(string.Format(formatString, args));
  211. }
  212. public void WriteLine(string s)
  213. {
  214. Write(s + "\n");
  215. }
  216. public void WriteAggregate(string key, object value)
  217. {
  218. WriteLine("AGGREGATE_{0}: {1}", key, value.ToString());
  219. }
  220. public void Write(string s)
  221. {
  222. //!!! THIS WAS COMMENTED OUT. I DON'T THINK IT SHOULD HAVE BEEN, IF YOU HAVE TROUBLE, COMMENT OUT THE LOCK
  223. lock (_lockObj)
  224. {
  225. Helper.CheckCondition(_haveLock, "You must obtain a lock before writing to the file.");
  226. _filestream.Position = _filestream.Length;
  227. _writer.Write(s);
  228. _writer.Flush();
  229. }
  230. }
  231. public List<T> ExtractAggregate<T>(string key)
  232. {
  233. var lines = ReadLines().ToList();
  234. Clear();
  235. List<T> values = new List<T>();
  236. string keyc = "AGGREGATE_" + key + ": ";
  237. foreach (string line in lines)
  238. {
  239. if (line.StartsWith(keyc))
  240. {
  241. T value = MBT.Escience.Parse.Parser.Parse<T>(line.Substring(keyc.Length));
  242. values.Add(value);
  243. }
  244. else
  245. {
  246. WriteLine(line);
  247. }
  248. }
  249. return values;
  250. }
  251. /// <summary>
  252. /// Will try really hard to be the next one to get a lock on the file and delete it. If currently has the lock, it must release it, in which case someone else could grab it before
  253. /// we get the chance to delete it.
  254. /// </summary>
  255. public void Delete()
  256. {
  257. lock (_lockObj)
  258. {
  259. if (_haveLock)
  260. ReleaseLock();
  261. while (true)
  262. {
  263. try
  264. {
  265. File.Delete(_filename);
  266. Dispose();
  267. return;
  268. }
  269. catch (IOException) { }
  270. }
  271. }
  272. }
  273. public void Dispose()
  274. {
  275. lock (_lockObj)
  276. {
  277. if (!_disposed)
  278. {
  279. _disposed = true;
  280. ReleaseLock();
  281. }
  282. }
  283. }
  284. }
  285. }