internal SiloAddress CalculateGrainDirectoryPartition(GrainId grainId) { // give a special treatment for special grains if (grainId.IsSystemTarget) { if (log.IsEnabled(LogLevel.Trace)) { log.LogTrace( "Silo {LocalSilo} looked for a system target {SystemTarget}, returned {ResultSilo}", this.siloAddress, grainId, this.siloAddress); } // every silo owns its system targets return(this.siloAddress); } if (this.ring.Count == 0) { return(null); } SiloAddress siloAddress = null; int hash = unchecked ((int)grainId.GetUniformHashCode()); // need to implement a binary search, but for now simply traverse the list of silos sorted by their hashes for (var index = this.ring.Count - 1; index >= 0; --index) { var item = this.ring[index]; if (item.GetConsistentHashCode() <= hash) { 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 = this.ring[this.ring.Count - 1]; } if (log.IsEnabled(LogLevel.Trace)) { log.LogTrace( "Silo {LocalSilo} calculated directory partition owner silo {Silo} for grain {Grain}: {GrainHash} --> {SiloHash}", this.siloAddress, siloAddress, grainId, hash, siloAddress?.GetConsistentHashCode()); } return(siloAddress); }
/// <summary> /// Get a reference to the <see cref="GrainService"/> responsible for actioning the request based on the <paramref name="callingGrainId"/>. /// </summary> protected TGrainService GetGrainService(GrainId callingGrainId) { var hashCode = callingGrainId.GetUniformHashCode(); var destination = ringProvider.GetPrimaryTargetSilo(hashCode); var grainId = SystemTargetGrainId.CreateGrainServiceGrainId(grainType, destination); var grainService = grainFactory.GetSystemTarget <TGrainService>(grainId); return(grainService); }
/// <summary> /// Precedence function to resolve races among clusters that are trying to create an activation for a particular grain. /// </summary> /// <param name="grain">The GrainID under consideration.</param> /// <param name="clusterLeft"></param> /// <param name="clusterRight"></param> /// <returns> /// The function returns "true" if clusterLeft has precedence over clusterRight. /// </returns> internal static bool ActivationPrecedenceFunc(GrainId grain, string clusterLeft, string clusterRight) { // Make sure that we're not calling this function with default cluster identifiers. if (clusterLeft == null || clusterRight == null) { throw new OrleansException("ActivationPrecedenceFunction must be called with valid cluster identifiers."); } // use string comparison for cluster precedence, with polarity based on uniform grain hash if (grain.GetUniformHashCode() % 2 == 0) return string.Compare(clusterLeft, clusterRight, StringComparison.Ordinal) < 0; else return string.Compare(clusterRight, clusterLeft, StringComparison.Ordinal) < 0; }
/// <summary> /// Precedence function to resolve races among clusters that are trying to create an activation for a particular grain. /// </summary> /// <param name="grain">The GrainID under consideration.</param> /// <param name="clusterLeft"></param> /// <param name="clusterRight"></param> /// <returns> /// The function returns "true" if clusterLeft has precedence over clusterRight. /// </returns> internal static bool ActivationPrecedenceFunc(GrainId grain, string clusterLeft, string clusterRight) { // Make sure that we're not calling this function with default cluster identifiers. if (clusterLeft == null || clusterRight == null) { throw new OrleansException("ActivationPrecedenceFunction must be called with valid cluster identifiers."); } // use string comparison for cluster precedence, with polarity based on uniform grain hash if (grain.GetUniformHashCode() % 2 == 0) { return(string.Compare(clusterLeft, clusterRight, StringComparison.Ordinal) < 0); } else { return(string.Compare(clusterRight, clusterLeft, StringComparison.Ordinal) < 0); } }
public Task DeleteGrain(GrainId grain) { SiloAddress silo = CalculateTargetSilo(grain); if (silo == null) { // We don't know about any other silos, and we're stopping, so throw throw new InvalidOperationException("Grain directory is stopping"); } if (log.IsVerbose) { log.Verbose("Silo {0} tries to lookup for {1}-->{2} ({3}-->{4})", MyAddress, grain, silo, grain.GetUniformHashCode(), silo.GetConsistentHashCode()); } if (silo.Equals(MyAddress)) { // remove from our partition DirectoryPartition.RemoveGrain(grain); return(TaskDone.Done); } // remove from the cache DirectoryCache.Remove(grain); // send request to the owner return(GetDirectoryReference(silo).DeleteGrain(grain, NUM_RETRIES)); }
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); }
public bool LocalLookup(GrainId grain, out List <ActivationAddress> addresses) { localLookups.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} tries to lookup for {1}-->{2} ({3}-->{4})", MyAddress, grain, silo, grain.GetUniformHashCode(), silo.GetConsistentHashCode()); } // check if we own the grain if (silo.Equals(MyAddress)) { LocalDirectoryLookups.Increment(); addresses = GetLocalDirectoryData(grain); if (addresses == 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("LocalLookup mine {0}=null", grain); } return(false); } if (log.IsVerbose2) { log.Verbose2("LocalLookup mine {0}={1}", grain, addresses.ToStrings()); } LocalDirectorySuccesses.Increment(); localSuccesses.Increment(); return(true); } // handle cache cacheLookups.Increment(); addresses = GetLocalCacheData(grain); if (addresses == null) { if (log.IsVerbose2) { log.Verbose2("TryFullLookup else {0}=null", grain); } return(false); } if (log.IsVerbose2) { log.Verbose2("LocalLookup cache {0}={1}", grain, addresses.ToStrings()); } cacheSuccesses.Increment(); localSuccesses.Increment(); return(true); }
/// <summary> /// Finds the silo that owns the directory information for the given grain ID. /// This routine will always return a non-null silo address unless the excludeThisSiloIfStopping parameter is true, /// this is the only silo known, and this silo is stopping. /// </summary> /// <param name="grain"></param> /// <param name="excludeThisSiloIfStopping"></param> /// <returns></returns> public SiloAddress CalculateTargetSilo(GrainId grain, bool excludeThisSiloIfStopping = true) { // give a special treatment for special grains if (grain.IsSystemTarget) { if (log.IsVerbose2) { log.Verbose2("Silo {0} looked for a system target {1}, returned {2}", MyAddress, grain, MyAddress); } // every silo owns its system targets return(MyAddress); } if (Constants.SystemMembershipTableId.Equals(grain)) { if (Seed == null) { string grainName; if (!Constants.TryGetSystemGrainName(grain, out grainName)) { grainName = "MembershipTableGrain"; } var errorMsg = grainName + " cannot run without Seed node - please check your silo configuration file and make sure it specifies a SeedNode element. " + " Alternatively, you may want to use AzureTable for LivenessType."; throw new ArgumentException(errorMsg, "grain = " + grain); } // Directory info for the membership table grain has to be located on the primary (seed) node, for bootstrapping if (log.IsVerbose2) { log.Verbose2("Silo {0} looked for a special grain {1}, returned {2}", MyAddress, grain, Seed); } return(Seed); } SiloAddress siloAddress; int hash = unchecked ((int)grain.GetUniformHashCode()); lock (membershipCache) { if (membershipRingList.Count == 0) { // If the membership ring is empty, then we're the owner by default unless we're stopping. return(excludeThisSiloIfStopping && !Running ? null : MyAddress); } // excludeMySelf from being a TargetSilo if we're not running and the excludeThisSIloIfStopping flag is true. see the comment in the Stop method. bool excludeMySelf = !Running && excludeThisSiloIfStopping; // need to implement a binary search, but for now simply traverse the list of silos sorted by their hashes siloAddress = membershipRingList.FindLast(siloAddr => (siloAddr.GetConsistentHashCode() <= hash) && (!siloAddr.Equals(MyAddress) || !excludeMySelf)); 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 = membershipRingList[membershipRingList.Count - 1]; // Make sure it's not us... if (siloAddress.Equals(MyAddress) && excludeMySelf) { siloAddress = membershipRingList.Count > 1 ? membershipRingList[membershipRingList.Count - 2] : null; } } } if (log.IsVerbose2) { log.Verbose2("Silo {0} calculated directory partition owner silo {1} for grain {2}: {3} --> {4}", MyAddress, siloAddress, grain, hash, siloAddress.GetConsistentHashCode()); } return(siloAddress); }
public Task DeleteGrain(GrainId grain) { SiloAddress silo = CalculateTargetSilo(grain); if (silo == null) { // We don't know about any other silos, and we're stopping, so throw throw new InvalidOperationException("Grain directory is stopping"); } if (log.IsVerbose) log.Verbose("Silo {0} tries to lookup for {1}-->{2} ({3}-->{4})", MyAddress, grain, silo, grain.GetUniformHashCode(), silo.GetConsistentHashCode()); if (silo.Equals(MyAddress)) { // remove from our partition DirectoryPartition.RemoveGrain(grain); return TaskDone.Done; } // remove from the cache DirectoryCache.Remove(grain); // send request to the owner return GetDirectoryReference(silo).DeleteGrain(grain, NUM_RETRIES); }
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; }
/// <summary> /// Finds the silo that owns the directory information for the given grain ID. /// This routine will always return a non-null silo address unless the excludeThisSiloIfStopping parameter is true, /// this is the only silo known, and this silo is stopping. /// </summary> /// <param name="grain"></param> /// <param name="excludeThisSiloIfStopping"></param> /// <returns></returns> public SiloAddress CalculateTargetSilo(GrainId grain, bool excludeThisSiloIfStopping = true) { // give a special treatment for special grains if (grain.IsSystemTarget) { if (log.IsVerbose2) log.Verbose2("Silo {0} looked for a system target {1}, returned {2}", MyAddress, grain, MyAddress); // every silo owns its system targets return MyAddress; } if (Constants.SystemMembershipTableId.Equals(grain)) { if (Seed == null) { string grainName; if (!Constants.TryGetSystemGrainName(grain, out grainName)) grainName = "MembershipTableGrain"; var errorMsg = grainName + " cannot run without Seed node - please check your silo configuration file and make sure it specifies a SeedNode element. " + " Alternatively, you may want to use AzureTable for LivenessType."; throw new ArgumentException(errorMsg, "grain = " + grain); } // Directory info for the membership table grain has to be located on the primary (seed) node, for bootstrapping if (log.IsVerbose2) log.Verbose2("Silo {0} looked for a special grain {1}, returned {2}", MyAddress, grain, Seed); return Seed; } SiloAddress siloAddress; int hash = unchecked((int)grain.GetUniformHashCode()); lock (membershipCache) { if (membershipRingList.Count == 0) { // If the membership ring is empty, then we're the owner by default unless we're stopping. return excludeThisSiloIfStopping && !Running ? null : MyAddress; } // excludeMySelf from being a TargetSilo if we're not running and the excludeThisSIloIfStopping flag is true. see the comment in the Stop method. bool excludeMySelf = !Running && excludeThisSiloIfStopping; // need to implement a binary search, but for now simply traverse the list of silos sorted by their hashes siloAddress = membershipRingList.FindLast(siloAddr => (siloAddr.GetConsistentHashCode() <= hash) && (!siloAddr.Equals(MyAddress) || !excludeMySelf)); 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 = membershipRingList[membershipRingList.Count - 1]; // Make sure it's not us... if (siloAddress.Equals(MyAddress) && excludeMySelf) { siloAddress = membershipRingList.Count > 1 ? membershipRingList[membershipRingList.Count - 2] : null; } } } if (log.IsVerbose2) log.Verbose2("Silo {0} calculated directory partition owner silo {1} for grain {2}: {3} --> {4}", MyAddress, siloAddress, grain, hash, siloAddress.GetConsistentHashCode()); return siloAddress; }
public async Task <AddressAndTag> LookupAsync(GrainId grainId, int hopCount = 0) { (hopCount > 0 ? RemoteLookupsReceived : fullLookups).Increment(); // see if the owner is somewhere else (returns null if we are owner) var forwardAddress = this.CheckIfShouldForward(grainId, hopCount, "LookUpAsync"); // on all silos other than first, we insert a retry delay and recheck owner before forwarding if (hopCount > 0 && forwardAddress != null) { await Task.Delay(RETRY_DELAY); forwardAddress = this.CheckIfShouldForward(grainId, hopCount, "LookUpAsync"); if (forwardAddress is object) { int hash = unchecked ((int)grainId.GetUniformHashCode()); this.log.LogWarning($"LookupAsync - It seems we are not the owner of grain {grainId} (hash: {hash:X}), trying to forward it to {forwardAddress} (hopCount={hopCount})"); } } if (forwardAddress == null) { // we are the owner LocalDirectoryLookups.Increment(); var localResult = DirectoryPartition.LookUpActivation(grainId); if (localResult.Address == null) { // it can happen that we cannot find the grain in our partition if there were // some recent changes in the membership if (log.IsEnabled(LogLevel.Trace)) { log.Trace("FullLookup mine {0}=none", grainId); } localResult.Address = default; localResult.VersionTag = GrainInfo.NO_ETAG; return(localResult); } if (log.IsEnabled(LogLevel.Trace)) { log.Trace("FullLookup mine {0}={1}", grainId, localResult.Address); } LocalDirectorySuccesses.Increment(); return(localResult); } else { // Just a optimization. Why sending a message to someone we know is not valid. if (!IsValidSilo(forwardAddress)) { throw new OrleansException($"Current directory at {MyAddress} is not stable to perform the lookup for grainId {grainId} (it maps to {forwardAddress}, which is not a valid silo). Retry later."); } RemoteLookupsSent.Increment(); var result = await GetDirectoryReference(forwardAddress).LookupAsync(grainId, hopCount + 1); // update the cache if (result.Address is { } address&& IsValidSilo(address.SiloAddress)) { DirectoryCache.AddOrUpdate(address, result.VersionTag); } if (log.IsEnabled(LogLevel.Trace)) { log.Trace("FullLookup remote {0}={1}", grainId, result.Address); } return(result); } }
public bool LocalLookup(GrainId grain, out AddressAndTag result) { localLookups.Increment(); SiloAddress silo = CalculateGrainDirectoryPartition(grain); if (log.IsEnabled(LogLevel.Debug)) { log.Debug("Silo {0} tries to lookup for {1}-->{2} ({3}-->{4})", MyAddress, grain, silo, grain.GetUniformHashCode(), silo?.GetConsistentHashCode()); } //this will only happen if I'm the only silo in the cluster and I'm shutting down if (silo == null) { if (log.IsEnabled(LogLevel.Trace)) { log.Trace("LocalLookup mine {0}=null", grain); } result = new AddressAndTag(); return(false); } // handle cache cacheLookups.Increment(); var address = GetLocalCacheData(grain); if (address != default) { result = new AddressAndTag { Address = address, }; if (log.IsEnabled(LogLevel.Trace)) { log.Trace("LocalLookup cache {0}={1}", grain, result.Address); } cacheSuccesses.Increment(); localSuccesses.Increment(); return(true); } // check if we own the grain if (silo.Equals(MyAddress)) { LocalDirectoryLookups.Increment(); result = GetLocalDirectoryData(grain); if (result.Address == null) { // it can happen that we cannot find the grain in our partition if there were // some recent changes in the membership if (log.IsEnabled(LogLevel.Trace)) { log.Trace("LocalLookup mine {0}=null", grain); } return(false); } if (log.IsEnabled(LogLevel.Trace)) { log.Trace("LocalLookup mine {0}={1}", grain, result.Address); } LocalDirectorySuccesses.Increment(); localSuccesses.Increment(); return(true); } if (log.IsEnabled(LogLevel.Trace)) { log.Trace("TryFullLookup else {0}=null", grain); } result = default; return(false); }
/// <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); }
private void CreateGR(int n, int type) { Guid guid; if (type == 1) { guid = Guid.Parse(string.Format("00000000-0000-0000-0000-{0:X12}", n)); } else { guid = Guid.Parse(string.Format("{0:X8}-0000-0000-0000-000000000000", n)); } IEchoGrain grain = GrainClient.GrainFactory.GetGrain <IEchoGrain>(guid); GrainId grainId = ((GrainReference)grain.AsReference <IEchoGrain>()).GrainId; output.WriteLine("Guid = {0}, Guid.HashCode = x{1:X8}, GrainId.HashCode = x{2:X8}, GrainId.UniformHashCode = x{3:X8}", guid, guid.GetHashCode(), grainId.GetHashCode(), grainId.GetUniformHashCode()); }
/// <summary>Get a uniform hash code for this grain reference.</summary> public uint GetUniformHashCode() { // GrainId already includes the hashed type code for generic arguments. return(GrainId.GetUniformHashCode()); }
public bool LocalLookup(GrainId grain, out List<ActivationAddress> addresses) { localLookups.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} tries to lookup for {1}-->{2} ({3}-->{4})", MyAddress, grain, silo, grain.GetUniformHashCode(), silo.GetConsistentHashCode()); // check if we own the grain if (silo.Equals(MyAddress)) { LocalDirectoryLookups.Increment(); addresses = GetLocalDirectoryData(grain); if (addresses == 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("LocalLookup mine {0}=null", grain); return false; } if (log.IsVerbose2) log.Verbose2("LocalLookup mine {0}={1}", grain, addresses.ToStrings()); LocalDirectorySuccesses.Increment(); localSuccesses.Increment(); return true; } // handle cache cacheLookups.Increment(); addresses = GetLocalCacheData(grain); if (addresses == null) { if (log.IsVerbose2) log.Verbose2("TryFullLookup else {0}=null", grain); return false; } if (log.IsVerbose2) log.Verbose2("LocalLookup cache {0}={1}", grain, addresses.ToStrings()); cacheSuccesses.Increment(); localSuccesses.Increment(); return true; }