在巨大的日志文件中搜索数百种模式

时间:2011-04-28 23:59:29

标签: c++ partitioning

我必须从网络服务器的htdocs目录中获取大量文件名,然后使用此文件名列表搜索大量存档日志文件,以便最后访问这些文件。

我打算用Boost在C ++中做这个。我会先获取最新的日志然后向后读它,检查我得到的所有文件名的每一行。

如果文件名匹配,我从Logstring读取Time并保存它的最后一次访问。现在我不再需要查找此文件,因为我只想知道上次访问。

要搜索的文件名向量应该快速减少。

我想知道如何处理这种多线程最有效的问题。

我是否对日志文件进行分区,让每个线程从内存中搜索一部分日志,如果一个线程匹配,它会从文件名向量中删除该文件名,还是有更有效的方法来执行此操作?

3 个答案:

答案 0 :(得分:1)

将日志文件解析为数据库表(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。

答案 1 :(得分:1)

尝试使用mmap,它会为您节省相当多的脱发。我感觉很快,并且有些奇怪的心情回忆起我的mmap知识,所以我写了一个简单的事情让你开始。希望这有帮助!

mmap的优点在于它可以轻松地与OpenMP并行化。这也是防止I / O瓶颈的一种非常好的方法。让我首先定义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
}

答案 2 :(得分:0)

好的,这已经是几天前了,但我花了一些时间编写代码并在其他项目中使用SQLite。

我仍然希望将DB-Approach与MMAP解决方案进行比较,仅仅是为了性能方面。

当然,如果您可以使用SQL-Queries来处理您解析的所有数据,它可以为您节省大量的工作。但我真的不关心工作量,因为我还在学习很多东西,我从中学到的是:

这种MMAP方法 - 如果你正确实施 - 在性能上绝对优越。令人难以置信的快速,你会注意到你实现了“字数统计”的例子,它可以被视为MapReduce算法的“你好世界”。

现在,如果您还想从SQL语言中受益,那么正确的方法就是实现您自己的SQL-Wrapper,它通过在线程之间共享查询来使用Map-Reduce。

您可以在线程之间按ID共享对象,其中每个线程都处理它自己的DB-Connection。然后它会查询对象中自己的数据集部分。

这比用通常的方式写SQLite DB要快得多。

毕竟你可以说:

MMAP是处理字符串处理的最快方法 SQL为解析器应用程序提供了很好的功能,但是如果你没有实现一个用于处理SQL-Queries的包装器,它就会减慢速度