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))); }
/// <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); } }
/// <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); }
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); }
/// <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"); })); }