public Task UnregisterManyAsync(List <ActivationAddress> addresses) { unregistrationsManyIssued.Increment(); return(Task.WhenAll( addresses.GroupBy(a => CalculateTargetSilo(a.Grain)) .Select(g => { if (g.Key == null) { // We don't know about any other silos, and we're stopping, so throw throw new InvalidOperationException("Grain directory is stopping"); } foreach (var addr in g) { InvalidateCacheEntry(addr); } if (MyAddress.Equals(g.Key)) { // if I am the owner, remove the old activation locally foreach (var addr in g) { UnregistrationsLocal.Increment(); DirectoryPartition.RemoveActivation(addr.Grain, addr.Activation, true); } return TaskDone.Done; } UnregistrationsManyRemoteSent.Increment(); // otherwise, notify the owner return GetDirectoryReference(g.Key).UnregisterMany(g.ToList(), NUM_RETRIES); }))); }
/// Adjust local cache following the removal of a silo by droping: /// 1) entries that point to activations located on the removed silo /// 2) entries for grains that are now owned by this silo (me) /// 3) entries for grains that were owned by this removed silo - we currently do NOT do that. /// If we did 3, we need to do that BEFORE we change the membershipRingList (based on old Membership). /// We don't do that since first cache refresh handles that. /// Second, since Membership events are not guaranteed to be ordered, we may remove a cache entry that does not really point to a failed silo. /// To do that properly, we need to store for each cache entry who was the directory owner that registered this activation (the original partition owner). protected void AdjustLocalCache(SiloAddress removedSilo) { // remove all records of activations located on the removed silo foreach (Tuple <GrainId, List <Tuple <SiloAddress, ActivationId> >, int> tuple in DirectoryCache.KeyValues) { // 2) remove entries owned by me (they should be retrieved from my directory partition) if (MyAddress.Equals(CalculateTargetSilo(tuple.Item1))) { DirectoryCache.Remove(tuple.Item1); } // 1) remove entries that point to activations located on the removed silo if (tuple.Item2.RemoveAll(tuple2 => tuple2.Item1.Equals(removedSilo)) <= 0) { continue; } if (tuple.Item2.Count > 0) { DirectoryCache.AddOrUpdate(tuple.Item1, tuple.Item2, tuple.Item3); } else { DirectoryCache.Remove(tuple.Item1); } } }
/// Adjust local cache following the removal of a silo by droping: /// 1) entries that point to activations located on the removed silo /// 2) entries for grains that are now owned by this silo (me) /// 3) entries for grains that were owned by this removed silo - we currently do NOT do that. /// If we did 3, we need to do that BEFORE we change the membershipRingList (based on old Membership). /// We don't do that since first cache refresh handles that. /// Second, since Membership events are not guaranteed to be ordered, we may remove a cache entry that does not really point to a failed silo. /// To do that properly, we need to store for each cache entry who was the directory owner that registered this activation (the original partition owner). protected void AdjustLocalCache(SiloAddress removedSilo) { // remove all records of activations located on the removed silo foreach (Tuple <GrainId, IReadOnlyList <Tuple <SiloAddress, ActivationId> >, int> tuple in DirectoryCache.KeyValues) { // 2) remove entries now owned by me (they should be retrieved from my directory partition) if (MyAddress.Equals(CalculateTargetSilo(tuple.Item1))) { DirectoryCache.Remove(tuple.Item1); } // 1) remove entries that point to activations located on the removed silo RemoveActivations(DirectoryCache, tuple.Item1, tuple.Item2, tuple.Item3, t => t.Item1.Equals(removedSilo)); } }
/// <summary> /// For testing purposes only. /// Returns the directory information held by the local silo for the provided grain ID. /// The result will be null if no information is held. /// </summary> /// <param name="grain"></param> /// <param name="isPrimary"></param> /// <returns></returns> public List <ActivationAddress> GetLocalDataForGrain(GrainId grain, out bool isPrimary) { var primary = CalculateTargetSilo(grain); List <ActivationAddress> backupData = HandoffManager.GetHandedOffInfo(grain); if (MyAddress.Equals(primary)) { log.Assert(ErrorCode.DirectoryBothPrimaryAndBackupForGrain, backupData == null, "Silo contains both primary and backup directory data for grain " + grain); isPrimary = true; return(GetLocalDirectoryData(grain)); } isPrimary = false; return(backupData); }
/// Adjust local cache following the removal of a silo by dropping: /// 1) entries that point to activations located on the removed silo /// 2) entries for grains that are now owned by this silo (me) /// 3) entries for grains that were owned by this removed silo - we currently do NOT do that. /// If we did 3, we need to do that BEFORE we change the membershipRingList (based on old Membership). /// We don't do that since first cache refresh handles that. /// Second, since Membership events are not guaranteed to be ordered, we may remove a cache entry that does not really point to a failed silo. /// To do that properly, we need to store for each cache entry who was the directory owner that registered this activation (the original partition owner). protected void AdjustLocalCache(SiloAddress silo, bool dead) { // remove all records of activations located on the removed silo foreach (var tuple in DirectoryCache.KeyValues) { var activationAddress = tuple.ActivationAddress; // 2) remove entries now owned by me (they should be retrieved from my directory partition) if (MyAddress.Equals(CalculateGrainDirectoryPartition(activationAddress.GrainId))) { DirectoryCache.Remove(activationAddress.GrainId); } // 1) remove entries that point to activations located on the removed silo // For dead silos, remove any activation registered to that silo or one of its predecessors. // For new silos, remove any activation registered to one of its predecessors. if (activationAddress.SiloAddress.IsPredecessorOf(silo) || (activationAddress.SiloAddress.Equals(silo) && dead)) { DirectoryCache.Remove(activationAddress.GrainId); } } }