public ActivationAddress AddSingleActivation(GrainId grain, ActivationId act, SiloAddress silo) { SingleInstance = true; if (Instances.Count > 0) { var item = Instances.First(); return(ActivationAddress.GetAddress(item.Value.SiloAddress, grain, item.Key)); } else { Instances.Add(act, new ActivationInfo(silo)); VersionTag = rand.Next(); return(ActivationAddress.GetAddress(silo, grain, act)); } }
public Dictionary <SiloAddress, List <ActivationAddress> > Merge(GrainId grain, IGrainInfo other) { bool modified = false; foreach (var pair in other.Instances) { if (Instances.ContainsKey(pair.Key)) { continue; } Instances[pair.Key] = new ActivationInfo(pair.Value.SiloAddress, pair.Value.RegistrationStatus); modified = true; } if (modified) { VersionTag = rand.Next(); } if (SingleInstance && (Instances.Count > 0)) { // Grain is supposed to be in single activation mode, but we have two activations!! // Eventually we should somehow delegate handling this to the silo, but for now, we'll arbitrarily pick one value. var orderedActivations = Instances.OrderBy(pair => pair.Key); var activationToKeep = orderedActivations.First(); var activationsToDrop = orderedActivations.Skip(1); Instances.Clear(); Instances.Add(activationToKeep.Key, activationToKeep.Value); var mapping = new Dictionary <SiloAddress, List <ActivationAddress> >(); foreach (var activationPair in activationsToDrop) { var activation = ActivationAddress.GetAddress(activationPair.Value.SiloAddress, grain, activationPair.Key); List <ActivationAddress> activationsToRemoveOnSilo; if (!mapping.TryGetValue(activation.Silo, out activationsToRemoveOnSilo)) { activationsToRemoveOnSilo = mapping[activation.Silo] = new List <ActivationAddress>(1); } activationsToRemoveOnSilo.Add(activation); } return(mapping); } return(null); }
public void Serialize_ActivationAddress() { GrainId grain = LegacyGrainId.NewId(); var addr = ActivationAddress.GetAddress(null, grain, default); object deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, addr, false); Assert.IsAssignableFrom <ActivationAddress>(deserialized); Assert.True(((ActivationAddress)deserialized).Activation.IsDefault); //Activation no longer null after copy Assert.Null(((ActivationAddress)deserialized).Silo); //Silo no longer null after copy Assert.Equal(grain, ((ActivationAddress)deserialized).Grain); //Grain different after copy deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, addr); Assert.IsAssignableFrom <ActivationAddress>(deserialized); //ActivationAddress full serialization loop as wrong type Assert.True(((ActivationAddress)deserialized).Activation.IsDefault); //Activation no longer null after full serialization loop Assert.Null(((ActivationAddress)deserialized).Silo); //Silo no longer null after full serialization loop Assert.Equal(grain, ((ActivationAddress)deserialized).Grain); //Grain different after copy }
/// <summary> Read an <c>ActivationAddress</c> value from the stream. </summary> /// <returns>Data from current position in stream, converted to the appropriate output type.</returns> internal ActivationAddress ReadActivationAddress() { var silo = ReadSiloAddress(); var grain = ReadGrainId(); var act = ReadActivationId(); if (silo.Equals(SiloAddress.Zero)) { silo = null; } if (act.Equals(ActivationId.Zero)) { act = null; } return(ActivationAddress.GetAddress(silo, grain, act)); }
/// <summary> Read an <c>ActivationAddress</c> value from the stream. </summary> /// <returns>Data from current position in stream, converted to the appropriate output type.</returns> internal static ActivationAddress ReadActivationAddress <TReader>(this TReader @this) where TReader : IBinaryTokenStreamReader { var silo = @this.ReadSiloAddress(); var grain = @this.ReadGrainId(); var act = @this.ReadActivationId(); if (silo.Equals(SiloAddress.Zero)) { silo = null; } if (act.Equals(ActivationId.Zero)) { act = null; } return(ActivationAddress.GetAddress(silo, grain, act)); }
private PlacementResult SelectActivationCore(PlacementStrategy strategy, GrainId target, IPlacementRuntime context) { if (target.IsClient()) { throw new InvalidOperationException("Cannot use StatelessWorkerStrategy to route messages to client grains."); } // If there are available (not busy with a request) activations, it returns the first one. // If all are busy and the number of local activations reached or exceeded MaxLocal, it randomly returns one of them. // Otherwise, it requests creation of a new activation. List <ActivationData> local; if (context.LocalSiloStatus.IsTerminating()) { return(null); } if (!context.LocalLookup(target, out local) || local.Count == 0) { return(null); } var placement = (StatelessWorkerPlacement)strategy; foreach (var activation in local) { ActivationData info; if (!context.TryGetActivationData(activation.ActivationId, out info) || info.State != ActivationState.Valid || !info.IsInactive) { continue; } return(PlacementResult.IdentifySelection(ActivationAddress.GetAddress(context.LocalSilo, target, activation.ActivationId))); } if (local.Count >= placement.MaxLocal) { var id = local[local.Count == 1 ? 0 : random.Next(local.Count)].ActivationId; return(PlacementResult.IdentifySelection(ActivationAddress.GetAddress(context.LocalSilo, target, id))); } return(null); }
private async Task RunBatchedValidation(SiloAddress silo, List <KeyValuePair <GrainId, IGrainInfo> > list) { var multiClusterConfig = this.multiClusterOracle.GetMultiClusterConfiguration(); string clusterId = null; // If this silo is a part of a multi-cluster, try to find out which cluster the target silo belongs to. // The check here is a simple ping used to check if the remote silo is available and, if so, which cluster // it belongs to. // This is a used to determine whether or not the local silo should invalidate directory cache entries // pointing to the remote silo. // A preferable approach would be to flow cluster membership or grain directory information from the remote // cluster to the local one. That would avoid heuristic checks such as this. Additionally, information // about which cluster a particular silo belongs (or belonged) to could be maintained. That would allow // us to skip this first step. if (multiClusterConfig != null) { try { var validator = this.grainFactory.GetSystemTarget <IClusterGrainDirectory>( Constants.ClusterDirectoryServiceId, silo); clusterId = await validator.Ping(); } catch (Exception exception) { // A failure here may indicate a transient error, but for simplicity we will continue as though // the remote silo is no longer a part of the multi-cluster. this.logger.LogWarning("Failed to ping remote silo {Silo}: {Exception}", silo, exception); } } // if the silo could not be contacted or is not part of the multicluster, unregister if (clusterId == null || !multiClusterConfig.Clusters.Contains(clusterId)) { this.logger.Debug("GSIP:M removing {Count} cache entries pointing to {Silo}", list.Count, silo); var registrar = this.registrarManager.GetRegistrar(GlobalSingleInstanceRegistration.Singleton); foreach (var kvp in list) { registrar.InvalidateCache(ActivationAddress.GetAddress(silo, kvp.Key, kvp.Value.Instances.FirstOrDefault().Key)); } } }
/// <summary> /// Returns a list of activations (along with the version number of the list) for the given grain. /// If the grain is not found, null is returned. /// </summary> /// <param name="grain"></param> /// <returns></returns> internal AddressesAndTag LookUpGrain(GrainId grain) { var result = new AddressesAndTag(); lock (lockable) { if (partitionData.ContainsKey(grain)) { result.Addresses = new List <ActivationAddress>(); result.VersionTag = partitionData[grain].VersionTag; foreach (var route in partitionData[grain].Instances.Where(route => IsValidSilo(route.Value.SiloAddress))) { result.Addresses.Add(ActivationAddress.GetAddress(route.Value.SiloAddress, grain, route.Key, route.Value.RegistrationStatus)); } } } return(result); }
public bool Merge(GrainId grain, IGrainInfo other) { bool modified = false; foreach (var pair in other.Instances) { if (Instances.ContainsKey(pair.Key)) { continue; } Instances[pair.Key] = new ActivationInfo(pair.Value.SiloAddress); modified = true; } if (modified) { VersionTag = rand.Next(); } if (SingleInstance && (Instances.Count > 0)) { // Grain is supposed to be in single activation mode, but we have two activations!! // Eventually we should somehow delegate handling this to the silo, but for now, we'll arbitrarily pick one value. var orderedActivations = Instances.OrderBy(pair => pair.Key); var activationToKeep = orderedActivations.First(); var activationsToDrop = orderedActivations.Skip(1); Instances.Clear(); Instances.Add(activationToKeep.Key, activationToKeep.Value); var list = new List <ActivationAddress>(1); foreach (var activation in activationsToDrop.Select(keyValuePair => ActivationAddress.GetAddress(keyValuePair.Value.SiloAddress, grain, keyValuePair.Key))) { list.Add(activation); CatalogFactory.GetSystemTarget(Constants.CatalogId, activation.Silo). DeleteActivations(list).Ignore(); list.Clear(); } return(true); } return(false); }
public bool TryLocalLookup(GrainId grainId, out List <ActivationAddress> addresses) { if (grainId.IsClient) { return(this.inClusterGrainLocator.TryLocalLookup(grainId, out addresses)); } if (this.cache.LookUp(grainId, out var results)) { // IGrainDirectory only supports single activation var result = results[0]; addresses = new List <ActivationAddress>() { ActivationAddress.GetAddress(result.Item1, grainId, result.Item2) }; return(true); } addresses = null; return(false); }
/// <summary> /// Returns the activation of a single-activation grain, if present. /// </summary> internal GrainDirectoryEntryStatus TryGetActivation(GrainId grain, out ActivationAddress address, out int version) { lock (lockable) { IGrainInfo graininfo; if (partitionData.TryGetValue(grain, out graininfo)) { var first = graininfo.Instances.FirstOrDefault(); if (first.Value != null) { address = ActivationAddress.GetAddress(first.Value.SiloAddress, grain, first.Key); version = graininfo.VersionTag; return(first.Value.RegistrationStatus); } } } address = null; version = 0; return(GrainDirectoryEntryStatus.Invalid); }
private void HandleMessage(Message message) { // when we receive the first message, we update the // clientId for this client because it may have been modified to // include the cluster name if (!firstMessageReceived) { firstMessageReceived = true; if (!handshakeClientId.Equals(message.TargetGrain)) { clientId = message.TargetGrain; transport.UpdateClientId(clientId); CurrentActivationAddress = ActivationAddress.GetAddress(transport.MyAddress, clientId, CurrentActivationAddress.Activation); } else { clientId = handshakeClientId; } } switch (message.Direction) { case Message.Directions.Response: { ReceiveResponse(message); break; } case Message.Directions.OneWay: case Message.Directions.Request: { this.localObjects.Dispatch(message); break; } default: logger.Error(ErrorCode.Runtime_Error_100327, $"Message not supported: {message}."); break; } }
/// <summary> /// Returns a list of activations (along with the version number of the list) for the given grain. /// If the grain is not found, null is returned. /// </summary> /// <param name="grain"></param> /// <returns></returns> internal AddressesAndTag LookUpActivations(GrainId grain) { var result = new AddressesAndTag(); lock (lockable) { IGrainInfo graininfo; if (partitionData.TryGetValue(grain, out graininfo)) { result.Addresses = new List <ActivationAddress>(); result.VersionTag = partitionData[grain].VersionTag; foreach (var route in partitionData[grain].Instances) { if (IsValidSilo(route.Value.SiloAddress)) { result.Addresses.Add(ActivationAddress.GetAddress(route.Value.SiloAddress, grain, route.Key)); } } } } return(result); }
internal List <ActivationAddress> ToListOfActivations(bool singleActivation) { var result = new List <ActivationAddress>(); lock (lockable) { foreach (var pair in partitionData) { var grain = pair.Key; if (pair.Value.SingleInstance == singleActivation) { result.AddRange(pair.Value.Instances.Select(activationPair => ActivationAddress.GetAddress(activationPair.Value.SiloAddress, grain, activationPair.Key)) .Where(addr => IsValidSilo(addr.Silo))); } } } return(result); }
private void RunClientMessagePump(CancellationToken ct) { if (StatisticsCollector.CollectThreadTimeTrackingStats) { incomingMessagesThreadTimeTracking.OnStartExecution(); } while (listenForMessages) { var message = transport.WaitMessage(Message.Categories.Application, ct); if (message == null) // if wait was cancelled { break; } #if TRACK_DETAILED_STATS if (StatisticsCollector.CollectThreadTimeTrackingStats) { incomingMessagesThreadTimeTracking.OnStartProcessing(); } #endif // when we receive the first message, we update the // clientId for this client because it may have been modified to // include the cluster name if (!firstMessageReceived) { firstMessageReceived = true; if (!handshakeClientId.Equals(message.TargetGrain)) { clientId = message.TargetGrain; transport.UpdateClientId(clientId); CurrentActivationAddress = ActivationAddress.GetAddress(transport.MyAddress, clientId, CurrentActivationAddress.Activation); } else { clientId = handshakeClientId; } } switch (message.Direction) { case Message.Directions.Response: { ReceiveResponse(message); break; } case Message.Directions.OneWay: case Message.Directions.Request: { this.DispatchToLocalObject(message); break; } default: logger.Error(ErrorCode.Runtime_Error_100327, String.Format("Message not supported: {0}.", message)); break; } #if TRACK_DETAILED_STATS if (StatisticsCollector.CollectThreadTimeTrackingStats) { incomingMessagesThreadTimeTracking.OnStopProcessing(); incomingMessagesThreadTimeTracking.IncrementNumberOfProcessed(); } #endif } if (StatisticsCollector.CollectThreadTimeTrackingStats) { incomingMessagesThreadTimeTracking.OnStopExecution(); } }
public async Task <List <ActivationAddress> > FullLookup(GrainId grain) { fullLookups.Increment(); SiloAddress silo = CalculateTargetSilo(grain, false); // No need to check that silo != null since we're passing excludeThisSiloIfStopping = false if (log.IsVerbose) { log.Verbose("Silo {0} fully lookups for {1}-->{2} ({3}-->{4})", MyAddress, grain, silo, grain.GetUniformHashCode(), silo.GetConsistentHashCode()); } // We assyme that getting here means the grain was not found locally (i.e., in TryFullLookup()). // We still check if we own the grain locally to avoid races between the time TryFullLookup() and FullLookup() were called. if (silo.Equals(MyAddress)) { LocalDirectoryLookups.Increment(); var localResult = DirectoryPartition.LookUpGrain(grain); if (localResult == null) { // it can happen that we cannot find the grain in our partition if there were // some recent changes in the membership if (log.IsVerbose2) { log.Verbose2("FullLookup mine {0}=none", grain); } return(new List <ActivationAddress>()); } var a = localResult.Item1.Select(t => ActivationAddress.GetAddress(t.Item1, grain, t.Item2)).Where(addr => IsValidSilo(addr.Silo)).ToList(); if (log.IsVerbose2) { log.Verbose2("FullLookup mine {0}={1}", grain, a.ToStrings()); } LocalDirectorySuccesses.Increment(); return(a); } // Just a optimization. Why sending a message to someone we know is not valid. if (!IsValidSilo(silo)) { throw new OrleansException(String.Format("Current directory at {0} is not stable to perform the lookup for grain {1} (it maps to {2}, which is not a valid silo). Retry later.", MyAddress, grain, silo)); } RemoteLookupsSent.Increment(); Tuple <List <Tuple <SiloAddress, ActivationId> >, int> result = await GetDirectoryReference(silo).LookUp(grain, NUM_RETRIES); // update the cache List <Tuple <SiloAddress, ActivationId> > entries = result.Item1.Where(t => IsValidSilo(t.Item1)).ToList(); List <ActivationAddress> addresses = entries.Select(t => ActivationAddress.GetAddress(t.Item1, grain, t.Item2)).ToList(); if (log.IsVerbose2) { log.Verbose2("FullLookup remote {0}={1}", grain, addresses.ToStrings()); } if (entries.Count > 0) { DirectoryCache.AddOrUpdate(grain, entries, result.Item2); } return(addresses); }