public static TimeSpan GetEffectiveLastAccessTime(LocalLocationStoreConfiguration configuration, TimeSpan age, int replicaCount, long size, bool isImportantReplica, double logInverseMachineRisk)
        {
            if (configuration.UseTieredDistributedEviction)
            {
                var ageBucketIndex = FindAgeBucketIndex(configuration, age);
                if (isImportantReplica)
                {
                    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);
            }
        }
 public EffectiveLastAccessTimeProvider(
     LocalLocationStoreConfiguration configuration,
     IClock clock,
     IContentResolver contentResolver)
 {
     _clock           = clock;
     _configuration   = configuration;
     _contentResolver = contentResolver;
 }
Exemplo n.º 3
0
 public ClusterStateManager(
     LocalLocationStoreConfiguration configuration,
     IClusterStateStorage storage,
     IClock?clock = null)
 {
     _configuration = configuration;
     _storage       = storage;
     _clock         = clock ?? SystemClock.Instance;
 }
        private static int FindAgeBucketIndex(LocalLocationStoreConfiguration configuration, TimeSpan age)
        {
            Contract.Requires(configuration.AgeBuckets.Count > 0);

            for (int i = 0; i < configuration.AgeBuckets.Count; i++)
            {
                var bucket = configuration.AgeBuckets[i];
                if (age < bucket)
                {
                    return(i);
                }
            }

            return(configuration.AgeBuckets.Count - 1);
        }
Exemplo n.º 5
0
        public void ZeroLocationsShouldNotCauseRuntimeError()
        {
            var hash  = ContentHash.Random();
            var clock = new MemoryClock();
            var entry = ContentLocationEntry.Create(
                locations: new ArrayMachineIdSet(new ushort[0]),
                contentSize: 42,
                lastAccessTimeUtc: clock.UtcNow,
                creationTimeUtc: clock.UtcNow);
            var configuration = new LocalLocationStoreConfiguration()
            {
                ThrottledEvictionInterval = TimeSpan.FromSeconds(1)
            };

            var rank = EffectiveLastAccessTimeProvider.GetReplicaRank(hash, entry, new MachineId(1), configuration, clock.UtcNow);

            rank.Should().Be(ReplicaRank.None);
        }
        public static ReplicaRank GetReplicaRank(
            ContentHash hash,
            ContentLocationEntry entry,
            MachineId localMachineId,
            LocalLocationStoreConfiguration configuration,
            DateTime now)
        {
            var locationsCount = entry.Locations.Count;

            var desiredReplicaCount = configuration.DesiredReplicaRetention;

            if (desiredReplicaCount == 0 ||
                locationsCount == 0) // It is possible for the entry to have 0 locations.
                                     // For instance, the database has 1 location but the machine is in the bad state
            {
                return(ReplicaRank.None);
            }

            if (locationsCount <= desiredReplicaCount
                // If using throttled eviction, we might need to upgrade the rank to Protected
                // so don't return here
                && configuration.ThrottledEvictionInterval == TimeSpan.Zero)
            {
                return(ReplicaRank.Important);
            }

            // Making sure that probabilistically, some locations are considered important for the current machine.
            long contentHashCode = unchecked ((uint)HashCodeHelper.Combine(hash[0] | hash[1] << 8, hash[1]));

            var importantRangeStart = contentHashCode % locationsCount;

            // Getting an index of a current location in the location list
            int currentMachineLocationIndex = entry.Locations.GetMachineIdIndex(localMachineId);

            if (currentMachineLocationIndex == -1)
            {
                // This is used for testing only. The machine Id should be part of the machines.
                // But in tests it is useful to control the behavior of this method and in some cases to guarantee that some replica won't be important.
                return(ReplicaRank.None);
            }

            // In case of important range wrapping around end of location list to start of location list
            // we need to compute a positive offset from the range start to see if the replica exists in the range
            // i.e. range start = 5, location count = 7, and desired location count = 3
            // important range contains [5, 6 and 0] since it overflows the end of the list
            var offset = currentMachineLocationIndex - importantRangeStart;

            if (offset < 0)
            {
                offset += locationsCount;
            }

            var lastImportantReplicaOffset = Math.Min(desiredReplicaCount, locationsCount) - 1;

            if (offset >= desiredReplicaCount)
            {
                return(ReplicaRank.None);
            }

            if (offset != lastImportantReplicaOffset)
            {
                // All but last important replica are always Protected
                return(ReplicaRank.Protected);
            }

            if (configuration.ThrottledEvictionInterval == TimeSpan.Zero)
            {
                // Throttled eviction is disabled. Just mark the replica as important
                // since its in the important range
                return(ReplicaRank.Important);
            }

            // How throttled eviction works:
            // 1. Compute which machines consider the content important
            // This is done by computing a hash code from the content hash modulo location count to
            // generate a start index into the list replicas.
            // For instance,
            // given locations: [4, 11, 22, 35, 73, 89]
            // locationCount = 6,
            // if contentHashCode % locationCount = 2 and DesiredReplicaCount = 3
            // then the machines considering content important are [22, 35, 73]
            // 2. All but last important replica must be consider Protected (i.e. 22, 35 have rank Protected)
            // 3. Compute if last replica is protected.
            // This is based of to time ranges or buckets of duration ThrottledEvictionInterval
            // For instance,
            // if ThrottleInterval = 20 minutes
            // 10:00AM-10:20AM -> (timeBucketIndex = 23045230) % DesiredReplicaCount = 2 = evictableOffset
            // 10:20AM-10:40AM -> (timeBucketIndex = 23045231) % DesiredReplicaCount = 0 = evictableOffset
            // 10:40AM-11:00AM -> (timeBucketIndex = 23045232) % DesiredReplicaCount = 1 = evictableOffset
            // 11:00AM-11:20AM -> (timeBucketIndex = 23045233) % DesiredReplicaCount = 2 = evictableOffset
            // So for times 10:00AM-10:20AM and 11:00AM-11:20AM the last important replica is evictable
            var timeBucketIndex = now.Ticks / configuration.ThrottledEvictionInterval.Ticks;

            // NOTE: We add contentHashCode to timeBucketIndex so that not all Protected content is considered evictable
            // at the same time
            var evictableOffset = (contentHashCode + timeBucketIndex) % desiredReplicaCount;

            if (evictableOffset == offset)
            {
                return(ReplicaRank.Important);
            }
            else
            {
                // The replica is not currently evictable. Mark it as protected which will give it the minimum effective age
                // so that it is only evicted as a last resort
                return(ReplicaRank.Protected);
            }
        }