/// <summary> /// Abort callback for a range partition service /// </summary> /// <param name="isInbound">Is Inbound/Outbound Session</param> /// <param name="sourceServiceInstanceName">Service instance name</param> /// <param name="partitionKey">Partition key range</param> /// <param name="session">Aborted session</param> public void SessionAbortedByPartner( bool isInbound, Uri sourceServiceInstanceName, IntegerPartitionKeyRange partitionKey, IReliableMessagingSession session) { string sessionKind = isInbound ? "Inbound" : "Outbound"; string partnerKind = isInbound ? "Source" : "Target"; LogHelper.Log("{0} Session Aborted for Int64 Partition {1} {2}:{3}-{4}", sessionKind, partnerKind, sourceServiceInstanceName, partitionKey.IntegerKeyLow, partitionKey.IntegerKeyHigh); }
/// <summary> /// Creates a new PartitionKey specifing its service instance name, partition range and numbered kind. /// </summary> /// <param name="serviceInstanceName">Service name of the role</param> /// <param name="lowKey">Partition range - Low key</param> /// <param name="highKey">Partition range - High key</param> public PartitionKey(Uri serviceInstanceName, long lowKey, long highKey) { //Set service and partition info. this.ServiceInstanceName = serviceInstanceName; this.serviceInstanceString = this.ServiceInstanceName.OriginalString; this.partitionRange = new IntegerPartitionKeyRange { IntegerKeyLow = lowKey, IntegerKeyHigh = highKey }; this.Kind = PartitionKind.Numbered; }
/// <summary> /// Callback offering a session. /// Use the instance number (in URI segment - 3) to assign the callback session to the right global partition object. /// Three overloads for singleton, numbered and named partition types /// </summary> /// <param name="sourceServiceInstanceName"></param> /// <param name="partitionKey">Numbered partition types</param> /// <param name="session"></param> /// <returns> true to grant permission and false to deny</returns> public bool AcceptInboundSession( Uri sourceServiceInstanceName, IntegerPartitionKeyRange partitionKey, IReliableMessagingSession session) { string key = sourceServiceInstanceName + ":" + partitionKey.IntegerKeyLow + ":" + partitionKey.IntegerKeyHigh; if (!this.myPartitionRecord.InboundSessions.ContainsKey(key)) { this.myPartitionRecord.InboundSessions.Add(key, session); } return(true); }
/// <summary> /// Creates an instance of the partition instance /// </summary> /// <param name="name">Name of the partition instance</param> /// <param name="type">Type of the partition</param> /// <param name="stringPartitionKey">Name of the partition if Named partition type</param> /// <param name="intPartitionKey">Range of the partition if range partition type</param> public PartitionRecord(Uri name, PartitionKeyType type, string stringPartitionKey, IntegerPartitionKeyRange intPartitionKey) { this.InstanceName = name; this.PartitionType = type; this.StringPartitionPartitionKey = stringPartitionKey; this.Int64PartitionPartitionKey = intPartitionKey; this.InboundSessions = new Dictionary <string, IReliableMessagingSession>(); }
public void SessionAbortedByPartner(bool isInbound, Uri sourceServiceInstanceName, IntegerPartitionKeyRange range, IReliableMessagingSession session) { this.SessionAbortedByPartner(isInbound, new PartitionKey(sourceServiceInstanceName, range.IntegerKeyLow, range.IntegerKeyHigh), session); }
/// <summary> /// Manages the Inbound Session Callback for a numbered service type. /// </summary> /// <param name="sourceServiceInstanceName">The inbound source service name</param> /// <param name="keyRange">The key range of the inbound source service partition</param> /// <param name="session">The inbound reliable messaging session</param> /// <returns>true if accepted, false otherwise</returns> public bool AcceptInboundSession(Uri sourceServiceInstanceName, IntegerPartitionKeyRange keyRange, IReliableMessagingSession session) { var key = new PartitionKey(sourceServiceInstanceName, keyRange.IntegerKeyLow, keyRange.IntegerKeyHigh); return(this.AcceptInboundSession(key, session)); }
/// <summary> /// Create and Initialize partitions for the given service instance . /// </summary> /// <param name="instance">Initialize partitions for this service instance</param> /// <param name="isRandomPartitionType">true - if the partition type is selected randomly - String or Int64</param> /// <param name="type">Set the partition type to this parameter, if isRandomPartitionType is false. /// Singleton type is not allowed as we will set this type if instance partitions count = 1</param> /// <param name="int64PartitionKeyLowValMultiplier"></param> static void InitializePartitions(InstanceRecord instance, bool isRandomPartitionType, PartitionKeyType type, int int64PartitionKeyLowValMultiplier) { // Singletone is not a valid type VS.Assert.IsTrue(type != PartitionKeyType.Singleton, "unexpected partition key type {0} in StartSessionManagersForServiceInstance", type); // Ensure we have a valid partitions count > 0 Uri instanceName = instance.InstanceName; int partitionCount = instance.CountOfPartitions; VS.Assert.IsTrue(partitionCount > 0, "unexpected partitionCount {0} in StartSessionManagersForServiceInstance", partitionCount); // singleton case if (partitionCount == 1) { PartitionRecord newPartition = new PartitionRecord( instanceName, PartitionKeyType.Singleton, null, new IntegerPartitionKeyRange()); instance.Partitions[0] = newPartition; return; } bool stringPartitions = false; // randomly allocate string or int64 partition type. if (isRandomPartitionType) { stringPartitions = (RandGen.Next() % 2) == 0; // decide if we have string or int64 partitions } else { if (type == PartitionKeyType.StringKey) { stringPartitions = true; } } for (int i = 0; i < partitionCount; i++) { PartitionRecord newPartition; if (stringPartitions) { // string partition key string partitionKey = i.ToString(CultureInfo.InvariantCulture); newPartition = new PartitionRecord( instanceName, PartitionKeyType.StringKey, partitionKey, new IntegerPartitionKeyRange()); instance.Partitions[i] = newPartition; LogHelper.Log("Created; Instance: {0} StringPartition: {1}", instanceName, partitionKey); } // numerical partition key -- single number range IntegerPartitionKeyRange partitionInt64Key = new IntegerPartitionKeyRange { IntegerKeyLow = i * int64PartitionKeyLowValMultiplier, IntegerKeyHigh = i * int64PartitionKeyLowValMultiplier + (RandGen.Next() % (int64PartitionKeyLowValMultiplier - 1)) }; newPartition = new PartitionRecord( instanceName, PartitionKeyType.Int64Key, null, partitionInt64Key); instance.Partitions[i] = newPartition; LogHelper.Log("Created; Instance: {0} Int64Partition: {1}-{2}", instanceName, partitionInt64Key.IntegerKeyLow, partitionInt64Key.IntegerKeyHigh); } }
/// <summary> /// Setup a session from source partition to target partition. /// </summary> /// <param name="sessionTest"></param> /// <param name="sourcePartition"></param> /// <param name="targetPartition"></param> private void SetupSessionTest(SessionTest sessionTest, PartitionRecord sourcePartition, PartitionRecord targetPartition) { VS.Assert.IsFalse(sourcePartition == targetPartition, "sourcePartition {0} equals targetPartition {1} in SetupSessionTests", sourcePartition, targetPartition); IReliableSessionManager sourceSessionManager = sourcePartition.SessionManager; Uri targetSvcInstance = targetPartition.InstanceName; string targetEndpoint = targetPartition.Endpoint; Task <IReliableMessagingSession> newOutboundSessionTask = null; bool testSkipped = false; try { // Setup the outbound session from source to target partition switch (targetPartition.PartitionType) { case PartitionKeyType.Singleton: newOutboundSessionTask = sourceSessionManager.CreateOutboundSessionAsync(targetSvcInstance, targetEndpoint, new CancellationToken()); break; case PartitionKeyType.StringKey: string targetStringKey = targetPartition.StringPartitionPartitionKey; newOutboundSessionTask = sourceSessionManager.CreateOutboundSessionAsync(targetSvcInstance, targetStringKey, targetEndpoint, new CancellationToken()); break; case PartitionKeyType.Int64Key: IntegerPartitionKeyRange targetInt64Key = targetPartition.Int64PartitionPartitionKey; long rangeSize = targetInt64Key.IntegerKeyHigh - targetInt64Key.IntegerKeyLow + 1; long targetPartitionNumber = targetInt64Key.IntegerKeyLow + (RandGen.Next() % rangeSize); newOutboundSessionTask = sourceSessionManager.CreateOutboundSessionAsync(targetSvcInstance, targetPartitionNumber, targetEndpoint, new CancellationToken()); break; } VS.Assert.IsNotNull(newOutboundSessionTask, "Null newOutboundSessionTask in SetupSessionTests"); newOutboundSessionTask.Wait(); sessionTest.OutboundSession = newOutboundSessionTask.Result; } catch (System.AggregateException e) { Exception inner = e.InnerException.InnerException; VS.Assert.AreEqual(inner.GetType(), typeof(System.Runtime.InteropServices.COMException), "Unexpected AggregateException {0} from CreateOutboundSessionAsync", inner.GetType().ToString()); // Due to random nature of source and target selection, it might be possible we create a duplicate selection. // in this case, we skip the test. System.Runtime.InteropServices.COMException realException = (System.Runtime.InteropServices.COMException)inner; uint hresult = (uint)realException.ErrorCode; uint expectedError = (uint)NativeTypes.FABRIC_ERROR_CODE.FABRIC_E_RELIABLE_SESSION_ALREADY_EXISTS; VS.Assert.AreEqual(expectedError, hresult, "Unexpected error HRESULT code {0} from CreateOutboundSessionAsync", hresult); testSkipped = true; LogHelper.Log("Test# skipped due to {0} exception ", hresult); } if (testSkipped) { sessionTest.SkipTest = true; } else { // initialize snapshot test and open the session for message communication. sessionTest.OutboundSession.OpenAsync(new CancellationToken()).Wait(); sessionTest.InboundSession = targetPartition.InboundSessions[sourcePartition.PartitionKey]; sessionTest.SnapshotOutbound = sessionTest.OutboundSession.GetDataSnapshot(); sessionTest.SnapshotInbound = sessionTest.InboundSession.GetDataSnapshot(); VS.Assert.IsFalse(sessionTest.InboundSession == sessionTest.OutboundSession, "sourcePartition equals targetPartition in SetupSessionTests"); } }