LevelDB: ошибка ввода-вывода: XXX.sst: слишком много открытых файлов

Я использую LevelDB в своем приложении с 5 базами данных. Каждая база данных открывается с параметром max_open_files = 64.

ulimit -Sn показывает, что операционная система имеет ограничение в 1024 файла. Установка ограничения на 2048 решает проблему. Поскольку я распространяю это приложение среди людей, оно должно иметь настройки по умолчанию, которые работают «из коробки», не требуя от людей настройки своей операционной системы.

leveldb::Status status = db_spends_->Get(
    leveldb::ReadOptions(), spent_slice, &raw_spend);
if (!status.ok())
{
    std::cerr << "fetch_spend: " << status.ToString() << std::endl;
    return false;
}

Я получаю много этих ошибок и не могу читать вообще.

"fetch_spend: IO error: XXXX.sst: Too many open files"

В одном подкаталоге с именем database есть 5 баз данных:

$ ls
addr  block  block_hash  spend  tx
$ du -sh .
16G .
$ du -sh *
2.6G    addr
653M    block
7.2M    block_hash
2.6G    spend
9.4G    tx
$ for i in `ls`; do echo $i; ls $i | wc -l; done
addr
1279
block
333
block_hash
10
spend
1433
tx
5252

Я хотел бы изменить ограничение в 2 МБ внутри LevelDB для каждого файла .sst, но это не кажется регулируемым, и я видел этот патч только в Google: https://github.com/basho/leveldb/pull/7

Я использую Ubuntu 13.04 64bit.

Вот код, который я использую для открытия баз данных. Если я покажу open_options.max_open_files перед вызовом leveldb::DB::Open(), он отобразит 64 (как и ожидалось).

bool open_db(const std::string& prefix, const std::string& db_name,
    std::unique_ptr<leveldb::DB>& db, leveldb::Options open_options)
{
    using boost::filesystem::path;
    path db_path = path(prefix) / db_name;
    leveldb::DB* db_base_ptr = nullptr;
    leveldb::Status status =
        leveldb::DB::Open(open_options, db_path.native(), &db_base_ptr);
    if (!status.ok())
    {
        log_fatal(LOG_BLOCKCHAIN) << "Internal error opening '"
            << db_name << "' database: " << status.ToString();
        return false;
    }
    // The cointainer ensures db_base_ptr is now managed.
    db.reset(db_base_ptr);
    return true;
}

...

// Create comparator for blocks database.
depth_comparator_.reset(new depth_comparator);
// Open LevelDB databases
const size_t cache_size = 1 << 20;
// block_cache, filter_policy and comparator must be deleted after use!
open_options_.block_cache = leveldb::NewLRUCache(cache_size / 2);
open_options_.write_buffer_size = cache_size / 4;
open_options_.filter_policy = leveldb::NewBloomFilterPolicy(10);
open_options_.compression = leveldb::kNoCompression;
open_options_.max_open_files = 64;
open_options_.create_if_missing = true;
// The blocks database options needs its depth comparator too.
leveldb::Options blocks_open_options = open_options_;
blocks_open_options.comparator = depth_comparator_.get();
if (!open_db(prefix, "block", db_blocks_, blocks_open_options))
    return false;
if (!open_db(prefix, "block_hash", db_blocks_hash_, open_options_))
    return false;
if (!open_db(prefix, "tx", db_txs_, open_options_))
    return false;
if (!open_db(prefix, "spend", db_spends_, open_options_))
    return false;
if (!open_db(prefix, "addr", db_address_, open_options_))
    return false;

Даже если я поставлю max_open_files = 20, у меня все равно будет та же проблема.


person genjix    schedule 10.06.2013    source источник


Ответы (1)


До недавнего времени могло быть какое-то патологическое поведение, когда max_option_files был установлен на ‹ 74, где использовались сотни файловых дескрипторов вместо того, что было указано в параметре. (Последняя версия зажимов leveldb дает ограничение на минимальное значение 74.) Имеет ли какой-либо эффект установка его на ~ 80? Если нет, и вы все еще сталкиваетесь с проблемой, можете ли вы запустить соответствующее заклинание lsof, когда увидите плохое поведение? Это скажет нам, куда идут файловые дескрипторы.

person dgrogan    schedule 19.06.2013