Пример #1
0
        private IndexMeta getIndexMeta()
        {
            // TODO: all this needs cleaning.
            var(index, aliased) = findOrCreateIndex(Name);

            if (!AppSettings.IsRebuild && !aliased)
            {
                updateAlias(Name, index);
            }

            // look for any existing resume data.
            var indexMeta = IndexMeta.GetByName(index) ?? new IndexMeta
            {
                Alias = Name,
                Name  = index,
            };

            indexMeta.LastId = ResumeFrom ?? indexMeta.LastId;

            if (AppSettings.IsRebuild)
            {
                // Save the position the score processing queue should be reset to if rebuilding an index.
                // If there is already an existing value, the processor is probabaly resuming from a previous run,
                // so we likely want to preserve that value.
                if (!indexMeta.ResetQueueTo.HasValue)
                {
                    var mode = HighScore.GetRulesetId <T>();
                    indexMeta.ResetQueueTo = ScoreProcessQueue.GetLastProcessedQueueId(mode);
                }
            }
            else
            {
                if (string.IsNullOrWhiteSpace(indexMeta.Schema))
                {
                    throw new Exception("FATAL ERROR: attempting to process queue without a known version.");
                }

                if (indexMeta.Schema != AppSettings.Schema)
                {
                    // A switchover is probably happening, so signal that this mode should be skipped.
                    throw new VersionMismatchException($"`{Name}` found version {indexMeta.Schema}, expecting {AppSettings.Schema}");
                }

                // process queue reset if any.
                if (indexMeta.ResetQueueTo.HasValue)
                {
                    Console.WriteLine($"Resetting queue_id > {indexMeta.ResetQueueTo}");
                    ScoreProcessQueue.UnCompleteQueued <T>(indexMeta.ResetQueueTo.Value);
                    indexMeta.ResetQueueTo = null;
                }
            }

            indexMeta.UpdatedAt = DateTimeOffset.UtcNow;
            IndexMeta.UpdateAsync(indexMeta);
            IndexMeta.Refresh();

            return(indexMeta);
        }
Пример #2
0
        public static void UnCompleteQueued <T>(ulong from) where T : HighScore
        {
            using (var dbConnection = new MySqlConnection(AppSettings.ConnectionString))
            {
                var mode = HighScore.GetRulesetId <T>();

                dbConnection.Open();
                dbConnection.Execute("UPDATE score_process_queue SET status = 1 WHERE queue_id > @from AND mode = @mode", new { from, mode });
            }
        }
Пример #3
0
        /// <summary>
        /// Self contained database reader task. Reads the database by cursoring through records
        /// and adding chunks into readBuffer.
        /// </summary>
        /// <param name="resumeFrom">The cursor value to resume from;
        /// use null to resume from the last known value.</param>
        /// <returns>The database reader task.</returns>
        private Task <long> databaseReaderTask(ulong resumeFrom) => Task.Factory.StartNew(() =>
        {
            long count = 0;
            var mode   = HighScore.GetRulesetId <T>();

            while (true)
            {
                try
                {
                    if (!AppSettings.IsRebuild)
                    {
                        Console.WriteLine("Reading from queue...");
                        var chunks = Model.Chunk <ScoreProcessQueue>($"status = 1 and mode = {mode}", AppSettings.ChunkSize);
                        foreach (var chunk in chunks)
                        {
                            var scoreIds      = chunk.Select(x => x.ScoreId).ToList();
                            var scores        = ScoreProcessQueue.FetchByScoreIds <T>(scoreIds).Where(x => x.ShouldIndex).ToList();
                            var removedScores = scoreIds
                                                .Except(scores.Select(x => x.ScoreId))
                                                .Select(scoreId => new T {
                                ScoreId = scoreId
                            })
                                                .ToList();
                            Console.WriteLine($"Got {chunk.Count} items from queue, found {scores.Count} matching scores, {removedScores.Count} missing scores");

                            DogStatsd.Increment("indexed", scores.Count, tags: new[] { $"mode:{mode}", "result:success" });
                            DogStatsd.Increment("indexed", removedScores.Count, tags: new[] { $"mode:{mode}", "result:missing" });

                            dispatcher.Enqueue(add: scores, remove: removedScores);
                            ScoreProcessQueue.CompleteQueued(chunk);
                            count += scores.Count;
                        }
                    }
                    else
                    {
                        Console.WriteLine($"Rebuild from {resumeFrom}...");
                        var chunks = Model.Chunk <T>(AppSettings.ChunkSize, resumeFrom);
                        foreach (var chunk in chunks)
                        {
                            var scores = chunk.Where(x => x.ShouldIndex).ToList();

                            dispatcher.Enqueue(scores);
                            DogStatsd.Increment("indexed", scores.Count, tags: new[] { $"mode:{mode}", "result:success" });
                            count += chunk.Count;
                            // update resumeFrom in this scope to allow resuming from connection errors.
                            resumeFrom = chunk.Last().CursorValue;
                        }
                    }

                    break;
                }
                catch (DbException ex)
                {
                    Console.Error.WriteLine(ex.Message);
                    Task.Delay(1000).Wait();
                }
            }

            dispatcher.EnqueueEnd();
            Console.WriteLine($"Finished reading database {count} records.");

            return(count);
        }, TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach);