Exemple #1
0
        /// <summary>
        /// Create a new <see cref="BackupMetadataFile"/> and write it to the given file.
        /// </summary>
        /// <returns>Task that represents the asynchronous operation.</returns>
        public static async Task <BackupMetadataFile> CreateAsync(
            string fileName,
            BackupOption backupOption,
            Guid parentBackupId,
            Guid backupId,
            Guid partitionId,
            long replicaId,
            Epoch startingEpoch,
            long startingLsn,
            Epoch backupEpoch,
            long backupLsn,
            CancellationToken cancellationToken)
        {
            // Create the file with asynchronous flag and 4096 cache size (C# default).
            // MCoskun: Default IoPriorityHint is used.
            // Reason: Backup is a user operation.
            using (var filestream = FabricFile.Open(
                       fileName,
                       FileMode.CreateNew,
                       FileAccess.Write,
                       FileShare.Read,
                       4096,
                       FileOptions.Asynchronous))
            {
                Utility.SetIoPriorityHint(filestream.SafeFileHandle, Kernel32Types.PRIORITY_HINT.IoPriorityHintLow);

                var backupMetadataFile = new BackupMetadataFile(fileName);
                backupMetadataFile.properties = new BackupMetadataFileProperties()
                {
                    BackupOption   = backupOption,
                    ParentBackupId = parentBackupId,
                    BackupId       = backupId,
                    PartitionId    = partitionId,
                    ReplicaId      = replicaId,
                    StartingEpoch  = startingEpoch,
                    StartingLsn    = startingLsn,
                    BackupEpoch    = backupEpoch,
                    BackupLsn      = backupLsn,
                };

                // Write the properties.
                var propertiesHandle =
                    await FileBlock.WriteBlockAsync(filestream, writer => backupMetadataFile.properties.Write(writer)).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                // Write the footer.
                backupMetadataFile.footer = new FileFooter(propertiesHandle, Version);
                await FileBlock.WriteBlockAsync(filestream, writer => backupMetadataFile.footer.Write(writer)).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                // Flush to underlying stream.
                await filestream.FlushAsync(cancellationToken).ConfigureAwait(false);

                return(backupMetadataFile);
            }
        }
        /// <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="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>
        /// Create a new <see cref="StateManagerFile"/> and write it to the given file.
        /// </summary>
        /// <param name="filePath">Path to the checkpoint file.</param>
        /// <param name="partitionId">Service partition Id.</param>
        /// <param name="replicaId">Service replica Id.</param>
        /// <param name="metadataList">The state providers' metadata.</param>
        /// <param name="allowPrepareCheckpointLSNToBeInvalid">
        /// Allow the prepare checkpoint LSN to be invalid. If it is invalid, do not write it.
        /// </param>
        /// <param name="prepareCheckpointLSN">The PrepareCheckpointLSN.</param>
        /// <param name="cancellationToken">Token used to signal cancellation.</param>
        /// <returns>The new <see cref="BackupLogFile"/>.</returns>
        public static async Task <StateManagerFile> CreateAsync(
            string filePath,
            Guid partitionId,
            long replicaId,
            List <SerializableMetadata> metadataList,
            bool allowPrepareCheckpointLSNToBeInvalid,
            long prepareCheckpointLSN,
            CancellationToken cancellationToken)
        {
            // #12249219: Without the "allowPrepareCheckpointLSNToBeInvalid" being set to true in the backup code path,
            // It is possible for all backups before the first checkpoint after the upgrade to fail.
            // If the code has the PrepareCheckpointLSN property, it must be larger than or equal to ZeroLSN(0).
            Utility.Assert(
                allowPrepareCheckpointLSNToBeInvalid || prepareCheckpointLSN >= StateManagerConstants.ZeroLSN,
                "{0}:{1} CreateAsync: In the write path, prepareCheckpointLSN must be larger or equal to 0. PrepareCheckpointLSN: {2}.",
                partitionId,
                replicaId,
                prepareCheckpointLSN);

            // Create the file with asynchronous flag and 4096 cache size (C# default).
            // MCoskun: Default IoPriorityHint is used.
            // Reason: Used during backup and checkpoint (user operation and life-cycle operation respectively).
            using (var filestream = FabricFile.Open(
                       filePath,
                       FileMode.Create,
                       FileAccess.Write,
                       FileShare.Write,
                       4096,
                       FileOptions.Asynchronous))
            {
                var stateManagerFile = new StateManagerFile(filePath);
                stateManagerFile.StateProviderMetadata = metadataList;

                bool shouldNotWritePrepareCheckpointLSN = prepareCheckpointLSN == StateManagerConstants.InvalidLSN ? true : false;

                stateManagerFile.properties             = new StateManagerFileProperties(shouldNotWritePrepareCheckpointLSN);
                stateManagerFile.properties.PartitionId = partitionId;
                stateManagerFile.properties.ReplicaId   = replicaId;

                if (shouldNotWritePrepareCheckpointLSN == false)
                {
                    stateManagerFile.properties.PrepareCheckpointLSN = prepareCheckpointLSN;
                }

                // Write the state provider metadata.
                var blocks = await stateManagerFile.WriteMetadataAsync(filestream, metadataList, cancellationToken).ConfigureAwait(false);

                stateManagerFile.properties.MetadataHandle = new BlockHandle(offset: 0, size: filestream.Position);

                cancellationToken.ThrowIfCancellationRequested();

                // Write the blocks and update the properties.
                stateManagerFile.properties.BlocksHandle =
                    await FileBlock.WriteBlockAsync(filestream, (sectionWriter) => blocks.Write(sectionWriter)).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                // Write the properties.
                var propertiesHandle =
                    await FileBlock.WriteBlockAsync(filestream, writer => stateManagerFile.properties.Write(writer)).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                // Write the footer.
                stateManagerFile.footer = new FileFooter(propertiesHandle, Version);
                await FileBlock.WriteBlockAsync(filestream, writer => stateManagerFile.footer.Write(writer)).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                // Ensure we fully flush the data to disk before returning.
                await filestream.FlushAsync().ConfigureAwait(false);

                stateManagerFile.FileSize = filestream.Length;
                return(stateManagerFile);
            }
        }
Exemple #5
0
        /// <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);
            }
        }
Exemple #6
0
        /// <summary>
        /// Create a new <see cref="BackupLogFile"/> and write it to the given file.
        /// </summary>
        /// <param name="fileName">Name of the backup file.</param>
        /// <param name="logRecords">The log records.</param>
        /// <param name="lastBackupLogRecord"></param>
        /// <param name="cancellationToken">Token used to signal cancellation.</param>
        /// <returns>The new <see cref="BackupLogFile"/>.</returns>
        public static async Task <BackupLogFile> CreateAsync(
            string fileName,
            IAsyncEnumerator <LogRecord> logRecords,
            BackupLogRecord lastBackupLogRecord,
            CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            var backupLogFile = new BackupLogFile(fileName);

            backupLogFile.properties = new BackupLogFileProperties();

            // Create the file with asynchronous flag and 4096 cache size (C# default).
            using (var filestream = FabricFile.Open(
                       fileName,
                       FileMode.CreateNew,
                       FileAccess.Write,
                       FileShare.Write,
                       4096,
                       FileOptions.Asynchronous))
            {
                Utility.SetIoPriorityHint(filestream.SafeFileHandle, Kernel32Types.PRIORITY_HINT.IoPriorityHintLow);

                var incrementalBackupRecords = logRecords as IncrementalBackupLogRecordAsyncEnumerator;
                if (incrementalBackupRecords == null)
                {
                    await backupLogFile.WriteLogRecordsAsync(filestream, logRecords, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    await backupLogFile.WriteLogRecordsAsync(filestream, incrementalBackupRecords, cancellationToken).ConfigureAwait(false);

                    await incrementalBackupRecords.VerifyDrainedAsync().ConfigureAwait(false);

                    Utility.Assert(backupLogFile.Count == incrementalBackupRecords.Count, "Unexpected count");

                    backupLogFile.properties.IndexingRecordEpoch = incrementalBackupRecords.StartingEpoch;
                    backupLogFile.properties.IndexingRecordLsn   = incrementalBackupRecords.StartingLsn;

                    if (incrementalBackupRecords.HighestBackedupEpoch == LoggingReplicator.InvalidEpoch)
                    {
                        backupLogFile.properties.LastBackedUpEpoch = lastBackupLogRecord.HighestBackedUpEpoch;
                    }
                    else
                    {
                        backupLogFile.properties.LastBackedUpEpoch = incrementalBackupRecords.HighestBackedupEpoch;
                    }

                    backupLogFile.properties.LastBackedUpLsn = incrementalBackupRecords.HighestBackedupLsn;
                }

                // Write the log records.
                backupLogFile.properties.RecordsHandle = new BlockHandle(offset: 0, size: filestream.Position);

                cancellationToken.ThrowIfCancellationRequested();

                // Write the properties.
                var propertiesHandle =
                    await FileBlock.WriteBlockAsync(filestream, writer => backupLogFile.properties.Write(writer)).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                // Write the footer.
                backupLogFile.footer = new FileFooter(propertiesHandle, Version);
                await FileBlock.WriteBlockAsync(filestream, writer => backupLogFile.footer.Write(writer)).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                // Store the size.
                backupLogFile.Size = filestream.Length;
            }

            stopwatch.Stop();
            backupLogFile.WriteTimeInMilliseconds = stopwatch.ElapsedMilliseconds;

            return(backupLogFile);
        }