PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Raven.Database/Server/RavenFS/Util/StorageStream.cs

https://github.com/nwendel/ravendb
C# | 244 lines | 213 code | 31 blank | 0 comment | 33 complexity | 616419a015ee8e26abbd458dd32d7fa8 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, CC-BY-SA-3.0
  1. using System;
  2. using System.Collections.Specialized;
  3. using System.IO;
  4. using System.Linq;
  5. using Raven.Database.Server.RavenFS.Infrastructure;
  6. using Raven.Database.Server.RavenFS.Search;
  7. using Raven.Database.Server.RavenFS.Storage;
  8. using Raven.Database.Server.RavenFS.Storage.Esent;
  9. using Raven.Json.Linq;
  10. using Raven.Abstractions.FileSystem;
  11. namespace Raven.Database.Server.RavenFS.Util
  12. {
  13. public class StorageStream : Stream
  14. {
  15. private const int PagesBatchSize = 64;
  16. private long currentOffset;
  17. private long currentPageFrameOffset;
  18. private bool disposed;
  19. private FileAndPagesInformation fileAndPages;
  20. private FileHeader fileHeader;
  21. protected byte[] InnerBuffer;
  22. protected int InnerBufferOffset = 0;
  23. private int writtingPagePosition;
  24. protected StorageStream(ITransactionalStorage transactionalStorage, string fileName,
  25. StorageStreamAccess storageStreamAccess,
  26. RavenJObject metadata, IndexStorage indexStorage, StorageOperationsTask operations)
  27. {
  28. TransactionalStorage = transactionalStorage;
  29. StorageStreamAccess = storageStreamAccess;
  30. Name = fileName;
  31. switch (storageStreamAccess)
  32. {
  33. case StorageStreamAccess.Read:
  34. TransactionalStorage.Batch(accessor => fileHeader = accessor.ReadFile(fileName));
  35. if (fileHeader.TotalSize == null)
  36. {
  37. throw new FileNotFoundException("File is not uploaded yet");
  38. }
  39. Metadata = fileHeader.Metadata;
  40. Seek(0, SeekOrigin.Begin);
  41. break;
  42. case StorageStreamAccess.CreateAndWrite:
  43. TransactionalStorage.Batch(accessor =>
  44. {
  45. operations.IndicateFileToDelete(fileName);
  46. accessor.PutFile(fileName, null, metadata);
  47. indexStorage.Index(fileName, metadata);
  48. });
  49. Metadata = metadata;
  50. break;
  51. default:
  52. throw new ArgumentOutOfRangeException("storageStreamAccess", storageStreamAccess, "Unknown value");
  53. }
  54. }
  55. public ITransactionalStorage TransactionalStorage { get; private set; }
  56. public StorageStreamAccess StorageStreamAccess { get; private set; }
  57. public string Name { get; private set; }
  58. public RavenJObject Metadata { get; private set; }
  59. private long CurrentPageFrameSize
  60. {
  61. get { return fileAndPages.Pages.Sum(item => item.Size); }
  62. }
  63. public override bool CanRead
  64. {
  65. get { return StorageStreamAccess == StorageStreamAccess.Read && fileHeader.TotalSize.HasValue; }
  66. }
  67. public override bool CanSeek
  68. {
  69. get { return StorageStreamAccess == StorageStreamAccess.Read && fileHeader.TotalSize.HasValue; }
  70. }
  71. public override bool CanWrite
  72. {
  73. get { return StorageStreamAccess == StorageStreamAccess.CreateAndWrite; }
  74. }
  75. public override long Length
  76. {
  77. get { return fileHeader.TotalSize ?? 0; }
  78. }
  79. public override long Position
  80. {
  81. get { return currentOffset; }
  82. set { Seek(value, SeekOrigin.Begin); }
  83. }
  84. public static StorageStream Reading(ITransactionalStorage transactionalStorage, string fileName)
  85. {
  86. return new StorageStream(transactionalStorage, fileName, StorageStreamAccess.Read, null, null, null);
  87. }
  88. public static StorageStream CreatingNewAndWritting(ITransactionalStorage transactionalStorage,
  89. IndexStorage indexStorage, StorageOperationsTask operations,
  90. string fileName, RavenJObject metadata)
  91. {
  92. if (indexStorage == null)
  93. throw new ArgumentNullException("indexStorage", "indexStorage == null");
  94. return new StorageStream(transactionalStorage, fileName, StorageStreamAccess.CreateAndWrite, metadata, indexStorage, operations);
  95. }
  96. public override long Seek(long offset, SeekOrigin origin)
  97. {
  98. switch (origin)
  99. {
  100. case SeekOrigin.Begin:
  101. break;
  102. case SeekOrigin.Current:
  103. offset = currentOffset + offset;
  104. break;
  105. case SeekOrigin.End:
  106. offset = Length - offset - 1;
  107. break;
  108. default:
  109. throw new ArgumentOutOfRangeException("origin");
  110. }
  111. MovePageFrame(offset);
  112. return currentOffset;
  113. }
  114. private void MovePageFrame(long offset)
  115. {
  116. offset = Math.Min(Length, offset);
  117. if (offset < currentPageFrameOffset || fileAndPages == null)
  118. {
  119. TransactionalStorage.Batch(accessor => fileAndPages = accessor.GetFile(Name, 0, PagesBatchSize));
  120. currentPageFrameOffset = 0;
  121. }
  122. while (currentPageFrameOffset + CurrentPageFrameSize - 1 < offset)
  123. {
  124. var lastPageFrameSize = CurrentPageFrameSize;
  125. var nextPageIndex = fileAndPages.Start + fileAndPages.Pages.Count;
  126. TransactionalStorage.Batch(accessor => fileAndPages = accessor.GetFile(Name, nextPageIndex, PagesBatchSize));
  127. if (fileAndPages.Pages.Count < 1)
  128. {
  129. fileAndPages.Start = 0;
  130. break;
  131. }
  132. currentPageFrameOffset += lastPageFrameSize;
  133. }
  134. currentOffset = offset;
  135. }
  136. public override void SetLength(long value)
  137. {
  138. throw new NotSupportedException();
  139. }
  140. public override int Read(byte[] buffer, int offset, int count)
  141. {
  142. if (currentOffset >= Length)
  143. {
  144. return 0;
  145. }
  146. var innerBuffer = new byte[StorageConstants.MaxPageSize];
  147. var pageOffset = currentPageFrameOffset;
  148. var length = 0L;
  149. var startingOffset = currentOffset;
  150. foreach (var page in fileAndPages.Pages)
  151. {
  152. if (pageOffset <= currentOffset && currentOffset < pageOffset + page.Size)
  153. {
  154. var pageLength = 0;
  155. TransactionalStorage.Batch(accessor => pageLength = accessor.ReadPage(page.Id, innerBuffer));
  156. var sourceIndex = currentOffset - pageOffset;
  157. length = Math.Min(innerBuffer.Length - sourceIndex,
  158. Math.Min(pageLength, Math.Min(buffer.Length - offset, Math.Min(pageLength - sourceIndex, count))));
  159. Array.Copy(innerBuffer, sourceIndex, buffer, offset, length);
  160. break;
  161. }
  162. pageOffset += page.Size;
  163. }
  164. MovePageFrame(currentOffset + length);
  165. return Convert.ToInt32(currentOffset - startingOffset);
  166. }
  167. public override void Flush()
  168. {
  169. if (InnerBuffer != null && InnerBufferOffset > 0)
  170. {
  171. ConcurrencyAwareExecutor.Execute(() => TransactionalStorage.Batch(
  172. accessor =>
  173. {
  174. var hashKey = accessor.InsertPage(InnerBuffer, InnerBufferOffset);
  175. accessor.AssociatePage(Name, hashKey, writtingPagePosition, InnerBufferOffset);
  176. writtingPagePosition++;
  177. }));
  178. InnerBuffer = null;
  179. InnerBufferOffset = 0;
  180. }
  181. }
  182. public override void Write(byte[] buffer, int offset, int count)
  183. {
  184. var innerOffset = 0;
  185. while (innerOffset < count)
  186. {
  187. if (InnerBuffer == null)
  188. InnerBuffer = new byte[StorageConstants.MaxPageSize];
  189. var toCopy = Math.Min(StorageConstants.MaxPageSize - InnerBufferOffset, count - innerOffset);
  190. if (toCopy == 0)
  191. throw new Exception("Impossible");
  192. Array.Copy(buffer, offset + innerOffset, InnerBuffer, InnerBufferOffset, toCopy);
  193. InnerBufferOffset += toCopy;
  194. if (InnerBufferOffset == StorageConstants.MaxPageSize)
  195. Flush();
  196. innerOffset += toCopy;
  197. }
  198. }
  199. protected override void Dispose(bool disposing)
  200. {
  201. if (!disposed)
  202. {
  203. if (disposing)
  204. {
  205. Flush();
  206. if (StorageStreamAccess == StorageStreamAccess.CreateAndWrite)
  207. TransactionalStorage.Batch(accessor => accessor.CompleteFileUpload(Name));
  208. }
  209. disposed = true;
  210. }
  211. }
  212. }
  213. }