/// <summary> /// Read a single state provider metadata from the stream. /// </summary> /// <param name="reader">Stream to read from.</param> /// <param name="traceType">Tracing type information.</param> /// <param name="deserializeTypes">Should the types be deserialized.</param> /// <returns>The read state provider metadata.</returns> private static SerializableMetadata ReadMetadata(InMemoryBinaryReader reader, string traceType, bool deserializeTypes = true) { var startPosition = reader.BaseStream.Position; var recordSize = reader.ReadInt32(); var name = reader.ReadUri(); Utility.Assert(name != null, "{0}: Name for the State Provider cannot be null.", traceType); string typeName = null; var type = reader.ReadType(out typeName); Utility.Assert(type != null, SR.Assert_SM_TypeNotFound, traceType, typeName, name.ToString()); var createLsn = reader.ReadInt64(); var deleteLsn = reader.ReadInt64(); var initializationParameters = reader.ReadNullableBytes(); var metadataMode = (MetadataMode)reader.ReadInt32(); var stateProviderId = reader.ReadInt64(); var parentStateProviderId = reader.ReadInt64(); var endPosition = reader.BaseStream.Position; var readRecordSize = checked ((int)(endPosition - startPosition)); if (readRecordSize != recordSize) { throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_Corrupt_RecordSize)); } if (deserializeTypes) { // Re-create the state provider metadata. return(new SerializableMetadata( name, type, initializationParameters, stateProviderId, parentStateProviderId, metadataMode, createLsn, deleteLsn)); } // Test only. return(new SerializableMetadata( name, typeName, initializationParameters, stateProviderId, parentStateProviderId, metadataMode, createLsn, deleteLsn)); }
/// <summary> /// Reads the state provider metadata from the next chunk of copy data. /// </summary> /// <param name="operationData">The next chunk of copy data.</param> /// <param name="traceType">Tracing type information.</param> /// <returns>The copied set of state providers' metadata.</returns> internal static IEnumerable <SerializableMetadata> ReadCopyData(OperationData operationData, string traceType) { if (operationData == null) { throw new ArgumentNullException("operationData"); } if (operationData.Count <= 0) { throw new ArgumentException("OperationData contains zero data.", "operationData"); } // The state manager currently sends a single array segment per operation data. var itemData = operationData[0]; var operationType = (StateManagerCopyOperation)itemData.Array[itemData.Offset + itemData.Count - 1]; using (var itemStream = new MemoryStream(itemData.Array, itemData.Offset, itemData.Count - 1)) using (var itemReader = new InMemoryBinaryReader(itemStream)) { if (operationType == StateManagerCopyOperation.Version) { // Verify the copy protocol version is known. var copyProtocolVersion = itemReader.ReadInt32(); if (copyProtocolVersion != CopyProtocolVersion) { throw new InvalidDataException( string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_UnknownCopyProtocol_OneArg, copyProtocolVersion)); } } else if (operationType == StateManagerCopyOperation.StateProviderMetadata) { // Read the chunk of state provider metadata. while (itemStream.Position < itemStream.Length) { yield return(ReadMetadata(itemReader, traceType, true)); } } else { throw new InvalidDataException( string.Format(CultureInfo.CurrentCulture, SR.Error_SMFile_UnknownSMCopyOperation_OneArg, operationType)); } } }
/// <summary> /// Deserialize the header for the OperationData /// </summary> internal void DeserializeContext( OperationData operationData, int version, string traceType) { Utility.Assert( operationData != null, "{0}: DeserializeContext: Null named operation data during create", this.TraceType); Utility.Assert( operationData.Count > 0, "{0}:DeserializeContext: Named operation data should have atleast one buffer during create", this.TraceType); var headerBufferSPtr = operationData[operationData.Count - 1]; bool isStateProviderDataNull; using (InMemoryBinaryReader reader = new InMemoryBinaryReader(new MemoryStream( headerBufferSPtr.Array, headerBufferSPtr.Offset, headerBufferSPtr.Count))) { this.Version = reader.ReadInt32(); if (this.Version != version) { FabricEvents.Events.OnApplyVersionError(traceType, this.Version, version); throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, "Unsupported version {0} on deserialization, current version is {1}", this.Version, version)); } this.StateProviderId = reader.ReadInt64(); isStateProviderDataNull = reader.ReadBoolean(); } // Remove state manager metadata from data. operationData.RemoveAt(operationData.Count - 1); this.OperationData = isStateProviderDataNull ? null : operationData; }
/// <summary> /// Deserializes replication metadata. /// </summary> public static void DeserializeMetadataForUndoOperation( InMemoryBinaryReader metaDataReader, string traceType, int currentVersion, out long stateProviderId, out Uri stateProviderName, out StateManagerApplyType applyType) { try { // Read meta data. int version; DeserializeMetadata( metaDataReader, traceType, currentVersion, out stateProviderId, out stateProviderName, out applyType, out version); Utility.Assert(applyType != StateManagerApplyType.Invalid, "Invalid apply type"); if (applyType == StateManagerApplyType.Delete) { applyType = StateManagerApplyType.Insert; } else { applyType = StateManagerApplyType.Delete; } } catch (Exception e) { StateManagerStructuredEvents.TraceException( traceType, "ReplicationMetadata.Deserialize", string.Empty, e); throw; } }
/// <summary> /// Deserializes replication metadata. /// </summary> private static void DeserializeMetadata( InMemoryBinaryReader metaDataReader, string traceType, int currentVersion, out long stateProviderId, out Uri stateProviderName, out StateManagerApplyType applyType, out int version) { try { version = metaDataReader.ReadInt32(); if (version != currentVersion) { var errorMessage = string.Format( CultureInfo.InvariantCulture, SR.Error_Unsupported_Version_Deserialization, version, currentVersion); FabricEvents.Events.ReplicationMetadataDeserializeError(traceType, errorMessage); throw new NotSupportedException(errorMessage); } stateProviderId = metaDataReader.ReadInt64(); stateProviderName = metaDataReader.ReadUri(); applyType = (StateManagerApplyType)metaDataReader.ReadByte(); Utility.Assert(applyType != StateManagerApplyType.Invalid, "Invalid apply type"); } catch (Exception e) { StateManagerStructuredEvents.TraceException( traceType, "ReplicationMetadata.Deserialize", string.Empty, e); throw; } }
/// <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> /// Deserializes replication metadata and the redodata. /// </summary> public static ReplicationMetadata Deserialize( InMemoryBinaryReader metaDataReader, InMemoryBinaryReader redoDataReader, string traceType, int currentVersion) { try { // Read meta data first long stateProviderId; Uri name; StateManagerApplyType operationType; int version; DeserializeMetadata( metaDataReader, traceType, currentVersion, out stateProviderId, out name, out operationType, out version); if (redoDataReader == null) { return(new ReplicationMetadata( name, stateProviderId, DynamicStateManager.StateManagerId, version, operationType)); } // Read Data Next string typeName; Type type = redoDataReader.ReadType(out typeName); Utility.Assert(type != null, SR.Assert_SM_TypeNotFound, traceType, typeName, name.ToString()); byte[] initializationParameters = redoDataReader.ReadNullableBytes(); long parentStateProviderId = redoDataReader.ReadInt64(); // Since this is used in redo only scenarios, it is safe to assuem apply type is same as the original opeartion type. ReplicationMetadata replicationMetadata = new ReplicationMetadata( name, type, initializationParameters, stateProviderId, parentStateProviderId, version, operationType); return(replicationMetadata); } catch (Exception e) { StateManagerStructuredEvents.TraceException( traceType, "ReplicationMetadata.Deserialize", string.Empty, e); throw; } }