поиск сотен шаблонов в огромных лог-файлах - PullRequest
1 голос
/ 29 апреля 2011

Мне нужно получить множество имен файлов из каталога htdocs веб-сервера, а затем использовать этот список имен файлов для поиска в огромном количестве архивных файлов журналов для последнего доступа к этим файлам.

Я планирую сделать это в C ++ с Boost. Сначала я взял бы новейший журнал и прочитал его в обратном порядке, проверяя каждую строку на наличие всех имен файлов, которые я получил.

Если имя файла совпадает, я читаю Time from Logstring и сохраняю его последний доступ. Теперь мне больше не нужно искать этот файл, так как я хочу знать только последний доступ.

Вектор имен файлов для поиска должен быстро уменьшаться.

Интересно, как я могу решить эту проблему с несколькими потоками наиболее эффективно.

Разбить ли я файлы журналов и позволить каждому потоку искать часть журналов из памяти, и если у потока есть совпадение, он удаляет это имя файла из вектора имен файлов или есть более эффективный способ сделать это?

Ответы [ 3 ]

1 голос
/ 29 апреля 2011

Попробуйте использовать mmap, это избавит вас от значительного выпадения волос. Я чувствовал себя быстрым и в каком-то странном настроении вспомнить свои знания по mmap, поэтому написал простую вещь, чтобы вы начали. Надеюсь, это поможет!

Прелесть mmap в том, что его можно легко распараллелить с OpenMP. Это также действительно хороший способ предотвратить узкие места ввода / вывода. Позвольте мне сначала определить класс Logfile, а затем я перейду к реализации.

Вот файл заголовка (logfile.h)

#ifndef _LOGFILE_H_
#define _LOGFILE_H_

#include <iostream>
#include <fcntl.h>
#include <stdio.h>
#include <string>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

using std::string;

class Logfile {

public:

    Logfile(string title);

    char* open();
    unsigned int get_size() const;
    string get_name() const;
    bool close();

private:

    string name;
    char* start;
    unsigned int size;
    int file_descriptor;

};

#endif

А вот и файл .cpp.

#include <iostream>
#include "logfile.h"

using namespace std;

Logfile::Logfile(string name){
    this->name = name;
    start = NULL;
    size = 0;
    file_descriptor = -1;

}

char* Logfile::open(){

    // get file size
    struct stat st;
    stat(title.c_str(), &st);

    size = st.st_size;

    // get file descriptor
    file_descriptor = open(title.c_str(), O_RDONLY);
    if(file_descriptor < 0){
        cerr << "Error obtaining file descriptor for: " << title.c_str() << endl;
        return NULL;
    }

    // memory map part
    start = (char*) mmap(NULL, size, PROT_READ, MAP_SHARED, file_descriptor, 0);
    if(start == NULL){
        cerr << "Error memory-mapping the file\n";
        close(file_descriptor);
        return NULL;
    }

    return start;
}

unsigned int Logfile::get_size() const {
    return size;
}

string Logfile::get_title() const {
    return title;
}

bool Logfile::close(){

    if( start == NULL){
        cerr << "Error closing file. Was closetext() called without a matching opentext() ?\n";
        return false;
    }

    // unmap memory and close file
    bool ret = munmap(start, size) != -1 && close(file_descriptor) != -1;
    start = NULL;
    return ret;

}

Теперь, используя этот код, вы можете использовать OpenMP для совместного использования этих файлов журналов, т. Е.

Logfile lf ("yourfile");
char * log = lf.open();
int size = (int) lf.get_size();

#pragma omp parallel shared(log, size) private(i)
{
  #pragma omp for
  for (i = 0 ; i < size ; i++) {
     // do your routine
  }
  #pragma omp critical
     // some methods that combine the thread results
}
1 голос
/ 29 апреля 2011

Анализ файла журнала в таблице базы данных (SQLite ftw).Одним из полей будет путь.

В другой таблице добавьте искомые файлы.

Теперь это простое соединение с производной таблицей.Примерно так.

SELECT l.file, l.last_access FROM toFind f
LEFT JOIN ( 
    SELECT file, max(last_access) as last_access from logs group by file
) as l ON f.file = l.file

Все файлы в toFind будут там и будут иметь last_access NULL для тех, которые не найдены в журналах.

0 голосов
/ 21 ноября 2011

Хорошо, это уже несколько дней назад, но я потратил некоторое время на написание кода и работу с SQLite в других проектах.

Я все еще хотел сравнить DB-подход с MMAP-решением только с точки зрения производительности.

Конечно, это сэкономит вам много работы, если вы сможете использовать SQL-запросы для обработки всех проанализированных данных. Но я действительно не заботился о количестве работы, потому что я все еще многому учусь, и вот что я узнал:

Этот MMAP-подход - если вы правильно его реализуете - абсолютно превосходен по производительности. Это невероятно быстро, что вы заметите, если внедрите пример «подсчета слов», который можно рассматривать как «привет мир» для MapReduce Algo.

Теперь, если вы хотите еще больше воспользоваться SQL-языком, правильным подходом будет реализация вашего собственного SQL-Wrapper, который тоже использует вид Map-Reduce посредством совместного использования запросов между потоками.

Возможно, вы можете поделиться объектами по идентификатору между потоками, где каждый поток обрабатывает свое собственное соединение с БД. Затем он запрашивает объекты в своей части набора данных.

Это было бы намного быстрее, чем просто записывать вещи в БД SQLite обычным способом.

После всего, что вы можете сказать:

MMAP - самый быстрый способ обработки строк SQL обеспечивает отличную функциональность для приложений-анализаторов, но замедляет работу, если вы не реализуете оболочку для обработки SQL-запросов

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...