/// <summary>
        /// Перебирает события в логах
        /// </summary>
        /// <param name="iteratorParams">Параметры итератора</param>
        /// <returns>Итератор для перебора событий</returns>
        private IEnumerable <EventRecord> GetEventsRundown(EventIteratorParams iteratorParams)
        {
            var logsIterator = new LogsIterator(_storageNamePredicate);
            var totalRead    = 0;

            // перебираем логи в порядке убывания даты
            foreach (var helper in logsIterator.StreamedLogsRundown(
                         iteratorParams.FromDate, iteratorParams.ToDate))
            {
                // читаем лог с конца, для позиционирования в логе используем индекс
                // чтение выполняем блоками по _reverseBlockSize событий

                // определяем количество итераций по текущему логу
                var iterationsCount = helper.Index.RecordCount / _reverseBlockSize;
                if (helper.Index.RecordCount % _reverseBlockSize > 0)
                {
                    iterationsCount++;
                }

                if (iterationsCount == 0)
                {
                    // пустой лог
                    continue;
                }

                for (var i = 0L; i < iterationsCount; i++)
                {
                    // флаг принудительной остановки чтения лога, если он не дописан
                    var stopReadThisLog = false;

                    // определяем индекс первой записи в блоке (начинается с нуля)
                    var firstRecordOfBlock = helper.Index.RecordCount -
                                             (i + 1) * _reverseBlockSize;
                    // и число событий, которые нужно считать
                    var eventsToRead = _reverseBlockSize;

                    if (firstRecordOfBlock < 0)
                    {
                        // если попали сюда, это означает, что число записей в логе
                        // не кратно _reverseBlockSize и нужно уточнить eventsToRead:
                        eventsToRead = _reverseBlockSize + firstRecordOfBlock;

                        // номер первой записи в этом случае равен нулю:
                        firstRecordOfBlock = 0;
                    }

                    // переходим к нужному куску индексированных данных
                    helper.Index.Seek(firstRecordOfBlock);

                    // читаем очередной блок записей
                    var bufferedEvents = new EventRecord[eventsToRead];

                    try
                    {
                        // флаг принудительного поиска по логу
                        var seekInLog = true;

                        for (var j = 0L; j < eventsToRead; j++)
                        {
                            // определяем индексированные данные очередной записи
                            var currentIndex = helper.Index.GetNext();

                            if (seekInLog)
                            {
                                // устанавливаем смещение в логе на начало очередной записи
                                helper.Reader.Seek(currentIndex.Offset, SeekOrigin.Begin);
                                seekInLog = false;
                            }

                            // читаем очередное сообщение
                            for (var k = 0; k < currentIndex.LinesCount; k++)
                            {
                                var storageEntry = EventRecordHelper.GetRawEntry(
                                    helper.Reader.ReadLine());

                                if (!iteratorParams.SourceFilter.Contains(storageEntry[3].TrimEnd()) ||
                                    !iteratorParams.EventTypeFilter.Contains(storageEntry[4].TrimEnd()))
                                {
                                    // прерываем чтение этого сообщения и взводим флаг принудительного
                                    // поиска по логу
                                    seekInLog = true;
                                    break;
                                }

                                if (bufferedEvents[j] == null)
                                {
                                    bufferedEvents[j] = EventRecordHelper.CreateFromStorageEntry(
                                        storageEntry);
                                }
                                else
                                {
                                    bufferedEvents[j].Text.Add(storageEntry[5]);
                                }
                            }
                        }
                    }
                    catch (IndexOutOfRangeException)
                    {
                        // попали в недописанный кусок лога
                        stopReadThisLog = true;
                    }

                    // разворачиваем блок записей
                    Array.Reverse(bufferedEvents);

                    // возвращаем записи как результат работы итератора
                    foreach (var eventRecord in bufferedEvents)
                    {
                        if (eventRecord == null)
                        {
                            // пропускаем события, не попавшие под фильтр
                            continue;
                        }

                        // возвращаем событие
                        yield return(eventRecord);

                        // увеличиваем счетчик событий
                        totalRead++;
                        // достигли максимального количества событий
                        if (totalRead == iteratorParams.MaxEvents)
                        {
                            yield break;
                        }
                    }

                    if (stopReadThisLog)
                    {
                        break;
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// Переиндексация
        /// </summary>
        /// <param name="validationResult">Результат валидации индекса</param>
        /// <param name="logFile">Имя лог-файла</param>
        /// <param name="indexName">Имя индекса</param>
        private void ReIndex(IndexValidationResult validationResult, string logFile,
                             string indexName)
        {
            if (validationResult.State == IndexState.Corrupted && File.Exists(indexName))
            {
                // удаляем существующий индекс
                File.Delete(indexName);
            }

            using (var source = OpenForReading(logFile))
                using (var index = OpenForWriting(indexName))
                {
                    var recordId     = string.Empty;
                    var recordOffset = 0L;
                    var recordLines  = 0;

                    var reader = new LineReader(source);

                    using (var writer = new BinaryWriter(index, Encoding.Default))
                    {
                        // записываем размер исходного лога
                        writer.Seek(0, SeekOrigin.Begin);
                        writer.Write(source.Length);

                        switch (validationResult.State)
                        {
                        case IndexState.Corrupted:
                            // оставляем место для количества записей в исходном логе
                            writer.Write(validationResult.RecordsCount);
                            break;

                        case IndexState.Obsolete:
                            // подсчет числа записей начнем с последней известной
                            // записи в логе
                            validationResult.RecordsCount--;
                            // перемещаемся к началу последней записи в логе
                            source.Seek(validationResult.LastRecordOffset, SeekOrigin.Begin);
                            // перемещаемся к концу индексного файла минус один элемент индекса
                            // (начинаем переиндексацию с последней известной записи!)
                            writer.Seek(-(int)IndexElementSize, SeekOrigin.End);
                            break;
                        }

                        // читаем исходный лог до конца
                        while (!reader.Eof)
                        {
                            // запоминаем текущую позицию в логе
                            var currentOffset = source.Position;

                            // читаем очередную строку лога
                            var rawEntry = EventRecordHelper.GetRawEntry(reader.ReadLine());
                            // проверяем ее на валидность по числу полей
                            if (!EventRecordHelper.IsValidEntry(rawEntry))
                            {
                                // вероятнее всего, это - недозаписанное событие
                                // в текущем логе, прерываем чтение
                                break;
                            }

                            // если сохраненный идентификатор записи не совпадает с
                            // идентификатором считанной строки, эта строка является
                            // первой в записи
                            if (string.Compare(recordId, rawEntry[0]) != 0)
                            {
                                if (!string.IsNullOrEmpty(recordId))
                                {
                                    // сведения о предыдущей записи нужно сохранить
                                    // в индексном файле
                                    writer.Write(recordOffset);
                                    writer.Write(recordLines);

                                    // обнуляем счетчик строк в записи
                                    recordLines = 0;
                                }

                                // увеличиваем счетчик записей в логе
                                validationResult.RecordsCount++;
                                recordId     = rawEntry[0];
                                recordOffset = currentOffset;
                            }

                            // увеличиваем число строк в записи
                            recordLines++;

                            // последняя запись
                            if (reader.Eof)
                            {
                                // сохраняем сведения о последней записи
                                writer.Write(recordOffset);
                                writer.Write(recordLines);
                            }
                        }

                        // сохраняем итоговое количество записей в индексе
                        writer.Seek(sizeof(Int64), SeekOrigin.Begin);
                        writer.Write(validationResult.RecordsCount);
                    }
                }
        }