/// <summary> /// Finds the silo that owns the directory information for the given grain ID. /// This method will only be null when I'm the only silo in the cluster and I'm shutting down /// </summary> /// <param name="grainId"></param> /// <returns></returns> public SiloAddress CalculateGrainDirectoryPartition(GrainId grainId) { // give a special treatment for special grains if (grainId.IsSystemTarget()) { if (Constants.SystemMembershipTableType.Equals(grainId)) { if (Seed == null) { var errorMsg = $"Development clustering cannot run without a primary silo. " + $"Please configure {nameof(DevelopmentClusterMembershipOptions)}.{nameof(DevelopmentClusterMembershipOptions.PrimarySiloEndpoint)} " + "or provide a primary silo address to the UseDevelopmentClustering extension. " + "Alternatively, you may want to use reliable membership, such as Azure Table."; throw new ArgumentException(errorMsg, "grainId = " + grainId); } } if (log.IsEnabled(LogLevel.Trace)) { log.Trace("Silo {0} looked for a system target {1}, returned {2}", MyAddress, grainId, MyAddress); } // every silo owns its system targets return(MyAddress); } SiloAddress siloAddress = null; int hash = unchecked ((int)grainId.GetUniformHashCode()); // excludeMySelf from being a TargetSilo if we're not running and the excludeThisSIloIfStopping flag is true. see the comment in the Stop method. // excludeThisSIloIfStopping flag was removed because we believe that flag complicates things unnecessarily. We can add it back if it turns out that flag // is doing something valuable. bool excludeMySelf = !Running; var existing = this.directoryMembership; if (existing.MembershipRingList.Count == 0) { // If the membership ring is empty, then we're the owner by default unless we're stopping. return(!Running ? null : MyAddress); } // need to implement a binary search, but for now simply traverse the list of silos sorted by their hashes for (var index = existing.MembershipRingList.Count - 1; index >= 0; --index) { var item = existing.MembershipRingList[index]; if (IsSiloNextInTheRing(item, hash, excludeMySelf)) { siloAddress = item; break; } } if (siloAddress == null) { // If not found in the traversal, last silo will do (we are on a ring). // We checked above to make sure that the list isn't empty, so this should always be safe. siloAddress = existing.MembershipRingList[existing.MembershipRingList.Count - 1]; // Make sure it's not us... if (siloAddress.Equals(MyAddress) && excludeMySelf) { siloAddress = existing.MembershipRingList.Count > 1 ? existing.MembershipRingList[existing.MembershipRingList.Count - 2] : null; } } if (log.IsEnabled(LogLevel.Trace)) { log.Trace("Silo {0} calculated directory partition owner silo {1} for grain {2}: {3} --> {4}", MyAddress, siloAddress, grainId, hash, siloAddress?.GetConsistentHashCode()); } return(siloAddress); }