public Result <IReadOnlyList <ContentEvictionInfo> > GetEffectiveLastAccessTimes( OperationContext context, IReadOnlyList <ContentHashWithLastAccessTime> contentHashes) { Contract.RequiresNotNull(contentHashes); Contract.Requires(contentHashes.Count > 0); // This is required because the code inside could throw. var effectiveLastAccessTimes = new List <ContentEvictionInfo>(); double logInverseMachineRisk = -Math.Log(_configuration.MachineRisk); foreach (var contentHash in contentHashes) { DateTime lastAccessTime = contentHash.LastAccessTime; int replicaCount = 1; ReplicaRank rank = ReplicaRank.None; var(localInfo, distributedEntry, isDesignatedLocation) = _contentResolver.GetContentInfo(context, contentHash.Hash); // Getting a size from content directory information first. long size = localInfo.Size; if (distributedEntry != null) { // Use the latest last access time between LLS and local last access time DateTime distributedLastAccessTime = distributedEntry.LastAccessTimeUtc.ToDateTime(); lastAccessTime = distributedLastAccessTime > lastAccessTime ? distributedLastAccessTime : lastAccessTime; rank = GetReplicaRank(contentHash.Hash, distributedEntry, _contentResolver.LocalMachineId, _configuration, _now); if (isDesignatedLocation) { rank = Combine(ReplicaRank.Designated, rank); } replicaCount = distributedEntry.Locations.Count; if (size == 0) { size = distributedEntry.ContentSize; } } var localAge = _now - contentHash.LastAccessTime; var age = _now - lastAccessTime; var effectiveAge = GetEffectiveLastAccessTime(_configuration, age, replicaCount, size, rank, logInverseMachineRisk); var info = new ContentEvictionInfo( contentHash.Hash, age: age, localAge: localAge, effectiveAge: effectiveAge, replicaCount: replicaCount, size: size, rank: rank); effectiveLastAccessTimes.Add(info); } return(Result.Success <IReadOnlyList <ContentEvictionInfo> >(effectiveLastAccessTimes)); }
/// <nodoc /> public ContentEvictionInfo( ContentHash contentHash, TimeSpan age, TimeSpan localAge, TimeSpan effectiveAge, int replicaCount, long size, ReplicaRank rank) { ContentHash = contentHash; Age = age; LocalAge = localAge; EffectiveAge = effectiveAge; ReplicaCount = replicaCount; Size = size; Rank = rank; }
public static TimeSpan GetEffectiveLastAccessTime(LocalLocationStoreConfiguration configuration, TimeSpan age, int replicaCount, long size, ReplicaRank rank, double logInverseMachineRisk) { if (configuration.UseTieredDistributedEviction) { if (rank == ReplicaRank.Protected) { // Protected replicas should be evicted only as a last resort. return(TimeSpan.Zero); } var ageBucketIndex = FindAgeBucketIndex(configuration, age); if (rank != ReplicaRank.None) { ageBucketIndex = Math.Max(0, ageBucketIndex - configuration.ImportantReplicaBucketOffset); } return(configuration.AgeBuckets[ageBucketIndex]); } else { // Incorporate both replica count and size into an evictability metric. // It's better to eliminate big content (more bytes freed per eviction) and it's better to eliminate content with more replicas (less chance // of all replicas being inaccessible). // A simple model with exponential decay of likelihood-to-use and a fixed probability of each replica being inaccessible shows that the metric // evictability = age + (time decay parameter) * (-log(risk of content unavailability) * (number of replicas) + log(size of content)) // minimizes the increase in the probability of (content wanted && all replicas inaccessible) / per bytes freed. // Since this metric is just the age plus a computed quantity, it can be interpreted as an "effective age". TimeSpan totalReplicaPenalty = TimeSpan.FromMinutes(configuration.ContentLifetime.TotalMinutes * (Math.Max(1, replicaCount) * logInverseMachineRisk + Math.Log(Math.Max(1, size)))); return(age + totalReplicaPenalty); } }
private static ReplicaRank Combine(ReplicaRank rank1, ReplicaRank rank2) { return((ReplicaRank)Math.Max((byte)rank1, (byte)rank2)); }