예제 #1
0
 private Task <ContentHashListWithDeterminism> GetContentHashListAsync(StrongFingerprint strongFingerprint)
 {
     return(_getContentHashListCommandPool.RunAsync(
                new SQLiteParameter("@weakFingerprint", SerializeWithHashType(strongFingerprint.WeakFingerprint)),
                new SQLiteParameter("@selectorContentHash", strongFingerprint.Selector.ContentHash.SerializeReverse()),
                new SQLiteParameter("@selectorOutput", strongFingerprint.Selector.Output)));
 }
예제 #2
0
        /// <summary>
        ///     Enumerate known selectors for a given weak fingerprint.
        /// </summary>
        internal async Task <Result <Selector[]> > GetSelectorsCoreAsync(
            Context context,
            Fingerprint weakFingerprint)
        {
            var stopwatch = new Stopwatch();

            try
            {
                Tracer.GetSelectorsStart(context, weakFingerprint);
                stopwatch.Start();

                var fingerprint        = SerializeWithHashType(weakFingerprint);
                var getSelectorsResult = (await _getSelectorsCommandPool.RunAsync(new SQLiteParameter("@weakFingerprint", fingerprint))).ToArray();

                Tracer.GetSelectorsCount(context, weakFingerprint, getSelectorsResult.Length);
                return(getSelectorsResult);
            }
            catch (Exception exception)
            {
                Tracer.Debug(context, $"{Component}.GetSelectors() error=[{exception}]");
                return(Result.FromException <Selector[]>(exception));
            }
            finally
            {
                stopwatch.Stop();
                Tracer.GetSelectorsStop(context, stopwatch.Elapsed);
            }
        }
예제 #3
0
        /// <summary>
        ///     Force LRU.
        /// </summary>
        public async Task PurgeAsync(Context context, bool strict = true)
        {
            var margin = strict ? 0 : _touchBatchSize;

            if (!_lruEnabled || _currentRowCount <= _config.MaxRowCount + margin)
            {
                return;
            }

            await RunExclusiveAsync(async() =>
            {
                var stopwatch    = Stopwatch.StartNew();
                _currentRowCount = await GetRowCountAsync();
                var rowsToPurge  = _currentRowCount - _config.MaxRowCount;
                Tracer.PurgeStart(context, (int)rowsToPurge);

                if (rowsToPurge > 0)
                {
                    await _purgeCommandPool.RunAsync(new SQLiteParameter("@rowsToPurge", rowsToPurge));
                }

                _currentRowCount = await GetRowCountAsync();
                Tracer.PurgeStop(context, (int)_currentRowCount, stopwatch.Elapsed);
            }).ConfigureAwait(false);
        }
예제 #4
0
        private async Task TouchAsync(Context context, List <TouchMessage> list)
        {
            int originalCount = list.Count;
            var stopwatch     = Stopwatch.StartNew();

            Tracer.TouchStart(context, originalCount);

            while (list.Count > 0)
            {
                List <TouchMessage> messages = list.Take(TouchBatchPartitionSize).ToList();
                list.RemoveRange(0, messages.Count);

                if (messages.Count == TouchBatchPartitionSize)
                {
                    // We have a full partition and can use the partition prepared statement.
                    var parameters = new SQLiteParameter[TouchBatchPartitionSize * 4];
                    for (int i = 0, j = 0; i < TouchBatchPartitionSize; i++)
                    {
                        var message = messages[i];

                        parameters[j++] = new SQLiteParameter(
                            "@fileTimeUtc" + i, message.FileTimeUtc);
                        parameters[j++] = new SQLiteParameter(
                            "@weakFingerprint" + i, SerializeWithHashType(message.StrongFingerprint.WeakFingerprint));
                        parameters[j++] = new SQLiteParameter(
                            "@selectorContentHash" + i, message.StrongFingerprint.Selector.ContentHash.SerializeReverse());
                        parameters[j++] = new SQLiteParameter(
                            "@selectorOutput" + i, message.StrongFingerprint.Selector.Output);
                    }

                    await RunExclusiveAsync(async() => await _touchPartitionCommandPool.RunAsync(parameters)).ConfigureAwait(false);
                }
                else
                {
                    var parameters = new SQLiteParameter[4];
                    foreach (var message in messages)
                    {
                        parameters[0] = new SQLiteParameter(
                            "@fileTimeUtc", message.FileTimeUtc);
                        parameters[1] = new SQLiteParameter(
                            "@weakFingerprint", SerializeWithHashType(message.StrongFingerprint.WeakFingerprint));
                        parameters[2] = new SQLiteParameter(
                            "@selectorContentHash", message.StrongFingerprint.Selector.ContentHash.SerializeReverse());
                        parameters[3] = new SQLiteParameter(
                            "@selectorOutput", message.StrongFingerprint.Selector.Output);

                        await RunExclusiveAsync(async() => await _touchSingleCommandPool.RunAsync(parameters)).ConfigureAwait(false);
                    }
                }
            }

            Tracer.TouchStop(context, stopwatch.Elapsed, originalCount);
        }
예제 #5
0
        /// <summary>
        ///     Store a ContentHashList
        /// </summary>
        internal Task <AddOrGetContentHashListResult> AddOrGetContentHashListAsync(
            Context context,
            StrongFingerprint strongFingerprint,
            ContentHashListWithDeterminism contentHashListWithDeterminism,
            IContentSession contentSession,
            CancellationToken cts)
        {
            return(AddOrGetContentHashListCall.RunAsync(Tracer, new OperationContext(context, cts), strongFingerprint, async() =>
            {
                const int maxAttempts = 5;
                int attemptCount = 0;
                while (attemptCount++ <= maxAttempts)
                {
                    var contentHashList = contentHashListWithDeterminism.ContentHashList;
                    var determinism = contentHashListWithDeterminism.Determinism;

                    // Load old value
                    var oldContentHashListWithDeterminism = await GetContentHashListAsync(strongFingerprint);
                    var oldContentHashList = oldContentHashListWithDeterminism.ContentHashList;
                    var oldDeterminism = oldContentHashListWithDeterminism.Determinism;

                    // Make sure we're not mixing SinglePhaseNonDeterminism records
                    if (oldContentHashList != null &&
                        (oldDeterminism.IsSinglePhaseNonDeterministic != determinism.IsSinglePhaseNonDeterministic))
                    {
                        return AddOrGetContentHashListResult.SinglePhaseMixingError;
                    }

                    // Match found.
                    // Replace if incoming has better determinism or some content for the existing entry is missing.
                    if (oldContentHashList == null || oldDeterminism.ShouldBeReplacedWith(determinism) ||
                        !(await contentSession.EnsureContentIsAvailableAsync(context, oldContentHashList, cts).ConfigureAwait(false)))
                    {
                        AddOrGetContentHashListResult contentHashListResult = await RunExclusiveAsync(
                            async() =>
                        {
                            // double check again.
                            var contentHashListInStore = await GetContentHashListAsync(strongFingerprint);

                            if (contentHashListInStore != oldContentHashListWithDeterminism)
                            {
                                return new AddOrGetContentHashListResult(contentHashListInStore);
                            }

                            var fileTimeUtc = _clock.UtcNow.ToFileTimeUtc();

                            await _replaceCommandPool.RunAsync(
                                new SQLiteParameter("@weakFingerprint", SerializeWithHashType(strongFingerprint.WeakFingerprint)),
                                new SQLiteParameter("@selectorContentHash", strongFingerprint.Selector.ContentHash.SerializeReverse()),
                                new SQLiteParameter("@selectorOutput", strongFingerprint.Selector.Output),
                                new SQLiteParameter("@fileTimeUtc", fileTimeUtc),
                                new SQLiteParameter("@payload", contentHashList.Payload?.ToArray()),
                                new SQLiteParameter("@determinism", determinism.EffectiveGuid.ToByteArray()),
                                new SQLiteParameter("@serializedDeterminism", determinism.Serialize()),
                                new SQLiteParameter("@contentHashList", contentHashList.Serialize()));

                            // Bump count if this is a new entry.
                            if (oldContentHashList == null)
                            {
                                IncrementCountOnAdd();
                            }

                            // Accept the value
                            return new AddOrGetContentHashListResult(
                                new ContentHashListWithDeterminism(null, determinism));
                        });

                        // our add lost - need to retry.
                        if (contentHashListResult.ContentHashListWithDeterminism.ContentHashList != null)
                        {
                            continue;
                        }

                        if (contentHashListResult.ContentHashListWithDeterminism.ContentHashList == null)
                        {
                            return contentHashListResult;
                        }
                    }

                    if (oldContentHashList != null && oldContentHashList.Equals(contentHashList))
                    {
                        return new AddOrGetContentHashListResult(
                            new ContentHashListWithDeterminism(null, oldDeterminism));
                    }

                    // If we didn't accept a deterministic tool's data, then we're in an inconsistent state
                    if (determinism.IsDeterministicTool)
                    {
                        return new AddOrGetContentHashListResult(
                            AddOrGetContentHashListResult.ResultCode.InvalidToolDeterminismError,
                            oldContentHashListWithDeterminism);
                    }

                    // If we did not accept the given value, return the value in the cache
                    return new AddOrGetContentHashListResult(oldContentHashListWithDeterminism);
                }

                return new AddOrGetContentHashListResult("Hit too many races attempting to add content hash list into the cache");
            }));
        }