protected override void Run() { while (router.Running) { // Run through all cache entries and do the following: // 1. If the entry is not expired, skip it // 2. If the entry is expired and was not accessed in the last time interval -- throw it away // 3. If the entry is expired and was accessed in the last time interval, put into "fetch-batch-requests" list // At the end of the process, fetch batch requests for entries that need to be refreshed // Upon receiving refreshing answers, if the entry was not changed, double its expiration timer. // If it was changed, update the cache and reset the expiration timer. // this dictionary holds a map between a silo address and the list of grains that need to be refreshed var fetchInBatchList = new Dictionary <SiloAddress, List <GrainId> >(); // get the list of cached grains // for debug only int cnt1 = 0, cnt2 = 0, cnt3 = 0, cnt4 = 0; // run through all cache entries var enumerator = cache.GetStoredEntries(); while (enumerator.MoveNext()) { var pair = enumerator.Current; GrainId grain = pair.Key; var entry = pair.Value; SiloAddress owner = router.CalculateTargetSilo(grain); if (owner == null) // Null means there's no other silo and we're shutting down, so skip this entry { continue; } if (owner.Equals(router.MyAddress)) { // we found our owned entry in the cache -- it is not supposed to happen unless there were // changes in the membership Log.Warn(ErrorCode.Runtime_Error_100185, "Grain {0} owned by {1} was found in the cache of {1}", grain, owner, owner); cache.Remove(grain); cnt1++; // for debug } else { if (entry == null) { // 0. If the entry was deleted in parallel, presumably due to cleanup after silo death cache.Remove(grain); // for debug cnt3++; } else if (!entry.IsExpired()) { // 1. If the entry is not expired, skip it cnt2++; // for debug } else if (entry.NumAccesses == 0) { // 2. If the entry is expired and was not acccessed in the last time interval -- throw it away cache.Remove(grain); // for debug cnt3++; } else { // 3. If the entry is expired and was accessed in the last time interval, put into "fetch-batch-requests" list if (!fetchInBatchList.ContainsKey(owner)) { fetchInBatchList[owner] = new List <GrainId>(); } fetchInBatchList[owner].Add(grain); // And reset the entry's access count for next time entry.NumAccesses = 0; cnt4++; // for debug } } } if (Log.IsVerbose2) { Log.Verbose2("Silo {0} self-owned (and removed) {1}, kept {2}, removed {3} and tries to refresh {4} grains", router.MyAddress, cnt1, cnt2, cnt3, cnt4); } // send batch requests SendBatchCacheRefreshRequests(fetchInBatchList); ProduceStats(); // recheck every X seconds (Consider making it a configurable parameter) Thread.Sleep(SLEEP_TIME_BETWEEN_REFRESHES); } }
protected override async Task Run() { while (router.Running) { // Run through all cache entries and do the following: // 1. If the entry is not expired, skip it // 2. If the entry is expired and was not accessed in the last time interval -- throw it away // 3. If the entry is expired and was accessed in the last time interval, put into "fetch-batch-requests" list // At the end of the process, fetch batch requests for entries that need to be refreshed // Upon receiving refreshing answers, if the entry was not changed, double its expiration timer. // If it was changed, update the cache and reset the expiration timer. // this dictionary holds a map between a silo address and the list of grains that need to be refreshed var fetchInBatchList = new Dictionary <SiloAddress, List <GrainId> >(); // get the list of cached grains // for debug only int cnt1 = 0, cnt2 = 0, cnt3 = 0, cnt4 = 0; // run through all cache entries var enumerator = cache.GetStoredEntries(); while (enumerator.MoveNext()) { var pair = enumerator.Current; GrainId grain = pair.Key; var entry = pair.Value; SiloAddress owner = router.CalculateGrainDirectoryPartition(grain); if (owner == null) // Null means there's no other silo and we're shutting down, so skip this entry { continue; } if (entry == null) { // 0. If the entry was deleted in parallel, presumably due to cleanup after silo death cache.Remove(grain); // for debug cnt3++; } else if (!entry.IsExpired()) { // 1. If the entry is not expired, skip it cnt2++; // for debug } else if (entry.NumAccesses == 0) { // 2. If the entry is expired and was not accessed in the last time interval -- throw it away cache.Remove(grain); // for debug cnt3++; } else { // 3. If the entry is expired and was accessed in the last time interval, put into "fetch-batch-requests" list if (!fetchInBatchList.TryGetValue(owner, out var list)) { fetchInBatchList[owner] = list = new List <GrainId>(); } list.Add(grain); // And reset the entry's access count for next time entry.NumAccesses = 0; cnt4++; // for debug } } if (Log.IsEnabled(LogLevel.Trace)) { Log.LogTrace( "Silo {SiloAddress} self-owned (and removed) {OwnedAndRemovedCount}, kept {KeptCount}, removed {RemovedCount} and tried to refresh {RefreshedCount} grains", router.MyAddress, cnt1, cnt2, cnt3, cnt4); } // send batch requests SendBatchCacheRefreshRequests(fetchInBatchList); ProduceStats(); // recheck every X seconds (Consider making it a configurable parameter) await Task.Delay(SLEEP_TIME_BETWEEN_REFRESHES); } }