/// <summary> /// Open an existing <see cref="StateManagerFile"/> from the given file path. /// </summary> /// <param name="filePath">Path to the checkpoint file.</param> /// <param name="traceType">Tracing information.</param> /// <param name="deserializeTypes">Should the type information be deserialized.</param> /// <param name="cancellationToken">Token used to signal cancellation.</param> /// <returns>The opened <see cref="StateManagerFile"/>.</returns> internal static async Task <StateManagerFile> OpenAsync( string filePath, string traceType, bool deserializeTypes, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(filePath)) { throw new ArgumentException(SR.Error_FilePath_Null_NoArgs); } if (!FabricFile.Exists(filePath)) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Error_FilePath_Null, filePath)); } // Open the file with asynchronous flag and 4096 cache size (C# default). // MCoskun: Default IoPriorityHint is used. // Reason: Used during open, restore and complete checkpoint. using (var filestream = FabricFile.Open( filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous)) { var stateManagerFile = new StateManagerFile(filePath); // Read and validate the Footer section. The footer is always at the end of the stream, minus space for the checksum. var footerHandle = new BlockHandle( filestream.Length - FileFooter.SerializedSize - sizeof(ulong), FileFooter.SerializedSize); stateManagerFile.footer = await FileBlock.ReadBlockAsync( filestream, footerHandle, (reader, handle) => FileFooter.Read(reader, handle)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Verify we know how to deserialize this version of the state manager checkpoint file. if (stateManagerFile.footer.Version != Version) { throw new InvalidDataException( string.Format( CultureInfo.CurrentCulture, "StateManager checkpoint file cannot be deserialized (unknown version number: {0}, expected version number: {1})", stateManagerFile.footer.Version, Version)); } // Read and validate the properties section. var propertiesHandle = stateManagerFile.footer.PropertiesHandle; stateManagerFile.properties = await FileBlock.ReadBlockAsync( filestream, propertiesHandle, (reader, handle) => FileProperties.Read <StateManagerFileProperties>(reader, handle)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Read the state provider metadata. stateManagerFile.StateProviderMetadata = await stateManagerFile.ReadMetadataAsync(filestream, traceType, deserializeTypes, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); stateManagerFile.FileSize = filestream.Length; return(stateManagerFile); } }
/// <summary> /// Read the list of state providers' metadata from the <see cref="StateManagerFile"/>. /// </summary> /// <param name="stream">Stream to read from.</param> /// <param name="traceType">Tracing type information.</param> /// <param name="deserializeTypes">Should the types be deserialized.</param> /// <param name="cancellationToken">Token used to signal cancellation.</param> /// <returns>The list of state providers' metadata read.</returns> private async Task <List <SerializableMetadata> > ReadMetadataAsync( Stream stream, string traceType, bool deserializeTypes, CancellationToken cancellationToken) { var metadataList = new List <SerializableMetadata>((int)this.properties.StateProviderCount); // Read the blocks, to improve sequential reads. var blocks = await FileBlock.ReadBlockAsync( stream, this.properties.BlocksHandle, (sectionReader, sectionHandle) => StateManagerFileBlocks.Read(sectionReader, sectionHandle)).ConfigureAwait(false); // Currently, we expect the block sizes to always be present. if (blocks == null || blocks.RecordBlockSizes == null) { throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_Corrupt_BlockSizesMissing)); } var recordBlockSizes = blocks.RecordBlockSizes; // Read blocks from the file. Each state provider metadata is checksummed individually. using (var itemStream = new MemoryStream(DesiredBlockSize * 2)) using (var itemReader = new InMemoryBinaryReader(itemStream)) { stream.Position = this.properties.MetadataHandle.Offset; var endOffset = this.properties.MetadataHandle.EndOffset; // Each block has one or more state provider metadata records. foreach (var recordBlockSize in recordBlockSizes) { if (stream.Position + recordBlockSize > endOffset) { throw new InvalidDataException( string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_Corrupt_BlockExtendPastFile)); } // Read the block into memory. itemStream.Position = 0; itemStream.SetLength(recordBlockSize); await stream.ReadAsync(itemStream.GetBuffer(), 0, recordBlockSize, cancellationToken).ConfigureAwait(false); // Read to the end of the metadata section. var endBlockOffset = itemStream.Length; while (itemStream.Position < endBlockOffset) { var position = itemStream.Position; // Read the record size and validate it is not obviously corrupted. if (position + sizeof(int) > endBlockOffset) { throw new InvalidDataException( string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_Corrupt_MissingRecordSize)); } var recordSize = itemReader.ReadInt32(); var recordSizeWithChecksum = recordSize + sizeof(ulong); // We need to do extra validation on the recordSize, because we haven't validated the bits // against the checksum and we need the recordSize to locate the checksum. if (recordSize < 0) { throw new InvalidDataException( string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_Corrupt_NegativeRecordSize)); } if (position + recordSize > endBlockOffset) { throw new InvalidDataException( string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_Corrupt_RecordExtendsPastFile)); } if (position + recordSizeWithChecksum > endBlockOffset) { throw new InvalidDataException( string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_Corrupt_MissingChecksum)); } // Compute the checksum. var computedChecksum = CRC64.ToCRC64( itemStream.GetBuffer(), checked ((int)position), recordSize); // Read the checksum (checksum is after the record bytes). itemStream.Position = position + recordSize; var checksum = itemReader.ReadUInt64(); // Verify the checksum. if (checksum != computedChecksum) { throw new InvalidDataException( string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_Corrupt_MismatchedChecksum)); } // Read and re-create the state provider metadata, now that the checksum is validated. itemStream.Position = position; var metadata = ReadMetadata(itemReader, traceType, deserializeTypes); metadataList.Add(metadata); itemStream.Position = position + recordSizeWithChecksum; } } } // Post-validation. if (metadataList.Count != (int)this.Properties.StateProviderCount) { throw new InvalidDataException( string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_Corrupt_MetadataCountMismatch)); } return(metadataList); }
/// <summary> /// Open an existing <see cref="BackupLogFile"/> from the given file path. /// </summary> /// <param name="fileName">Path to the backup log file.</param> /// <param name="cancellationToken">Token used to signal cancellation.</param> /// <returns>The opened <see cref="BackupLogFile"/>.</returns> public static async Task <BackupLogFile> OpenAsync(string fileName, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(fileName)) { throw new ArgumentException(SR.Error_FilePath_Null_NoArgs); } if (!FabricFile.Exists(fileName)) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Error_FilePath_Null, fileName)); } // Open the file with asynchronous flag and 4096 cache size (C# default). // MCoskun: Uses default IOPriorityHint since this operation is called during Restore. using (var filestream = FabricFile.Open( fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous)) { var backupLogFile = new BackupLogFile(fileName); backupLogFile.Size = filestream.Length; // Read and validate the Footer section. The footer is always at the end of the stream, minus space for the checksum. var footerHandle = new BlockHandle( filestream.Length - FileFooter.SerializedSize - sizeof(ulong), FileFooter.SerializedSize); backupLogFile.footer = await FileBlock.ReadBlockAsync( filestream, footerHandle, (reader, handle) => FileFooter.Read(reader, handle)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Verify we know how to deserialize this version of the backup log file. if (backupLogFile.footer.Version != Version) { throw new InvalidDataException( string.Format( CultureInfo.CurrentCulture, SR.Error_BackupLogFile_Deserialized, backupLogFile.footer.Version, Version)); } // Read and validate the properties section. var propertiesHandle = backupLogFile.footer.PropertiesHandle; backupLogFile.properties = await FileBlock.ReadBlockAsync( filestream, propertiesHandle, (reader, handle) => FileProperties.Read <BackupLogFileProperties>(reader, handle)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); return(backupLogFile); } }