private static async Task FlushMemoryBufferAsync(Stream fileStream, InMemoryBinaryWriter memoryBuffer) { // Write the chunk length at the beginning of the stream. var chunkSize = checked ((int)memoryBuffer.BaseStream.Position); memoryBuffer.BaseStream.Position = 0; var propertyChunkMetadata = new PropertyChunkMetadata(chunkSize); propertyChunkMetadata.Write(memoryBuffer); // Move to end. memoryBuffer.BaseStream.Position = chunkSize; // Checksum the chunk. var checksum = memoryBuffer.GetChecksum(); memoryBuffer.Write(checksum); // Write to disk. await memoryBuffer.WriteAsync(fileStream).ConfigureAwait(false); // Reset the memory buffer. memoryBuffer.BaseStream.Position = 0; }
/// <summary> /// Read all file metadata from the metadata file. /// </summary> /// <param name="metadataTable">The metadata table.</param> /// <param name="filestream">The file stream to read from.</param> /// <param name="properties">The metadata manager file properties.</param> /// <param name="traceType">Tracing information.</param> /// <returns></returns> private static async Task <int> ReadDiskMetadataAsync( Dictionary <uint, FileMetadata> metadataTable, Stream filestream, MetadataManagerFileProperties properties, string traceType) { var startOffset = properties.MetadataHandle.Offset; var endOffset = properties.MetadataHandle.EndOffset; var metadataCount = 0; var fileId = 0; // No metadata to read (there are no metadata chunks). if (startOffset + sizeof(int) >= endOffset) { return(fileId); } filestream.Position = startOffset; using (var metadataStream = new MemoryStream(capacity: 64 * 1024)) using (var metadataReader = new InMemoryBinaryReader(metadataStream)) { // Read the first key chunk size into memory. metadataStream.SetLength(64 * 1024); await filestream.ReadAsync(metadataStream.GetBuffer(), 0, PropertyChunkMetadata.Size).ConfigureAwait(false); var propertyChunkMetadata = PropertyChunkMetadata.Read(metadataReader); var chunkSize = propertyChunkMetadata.BlockSize; filestream.Position -= PropertyChunkMetadata.Size; while (filestream.Position + chunkSize + sizeof(ulong) <= endOffset) { // Consistency checks. if (chunkSize < 0) { throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, SR.Error_Metadata_Corrupt_NegativeSize_OneArgs, chunkSize)); } // Read the entire chunk (plus the checksum and next chunk size) into memory. metadataStream.SetLength(chunkSize + sizeof(ulong) + sizeof(int)); await filestream.ReadAsync(metadataStream.GetBuffer(), 0, chunkSize + sizeof(ulong) + sizeof(int)).ConfigureAwait(false); // Read the checksum. metadataStream.Position = chunkSize; var checksum = metadataReader.ReadUInt64(); // Re-compute the checksum. var expectedChecksum = CRC64.ToCRC64(metadataStream.GetBuffer(), 0, chunkSize); if (checksum != expectedChecksum) { throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, SR.Error_Metadata_Corrupt_ChecksumMismatch_TwoArgs, checksum, expectedChecksum)); } // Deserialize the value into memory. metadataStream.Position = sizeof(int); metadataReader.ReadPaddingUntilAligned(true); while (metadataStream.Position < chunkSize) { var fileMetadata = FileMetadata.Read(metadataReader, traceType); if (metadataTable.ContainsKey(fileMetadata.FileId)) { throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, SR.Error_DuplicateFileId_Found_OneArgs, fileMetadata.FileId)); } metadataTable.Add(fileMetadata.FileId, fileMetadata); metadataCount++; } // Read the next chunk size. chunkSize = BitConverter.ToInt32(metadataStream.GetBuffer(), chunkSize + sizeof(ulong)); filestream.Position -= sizeof(int); } // Consistency checks. if (filestream.Position != endOffset) { throw new InvalidDataException(SR.Error_Metadata_Corrupt_IncorrectSize); } if (metadataCount != properties.FileCount) { throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, SR.Error_Metadata_Corrupt_FileCountMismatch_TwoArgs, metadataCount, properties.FileCount)); } return(fileId); } }