blob: 94b45904eb994479834bf26aacf4ad188ed94e7b [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "kudu/fs/block_manager.h"
#include <algorithm>
#include <mutex>
#include <ostream>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include "kudu/gutil/integral_types.h"
#include "kudu/gutil/macros.h"
#include "kudu/gutil/strings/numbers.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/util/env.h"
#include "kudu/util/faststring.h"
#include "kudu/util/flag_tags.h"
// The default value is optimized for throughput in the case that
// there are multiple drives backing the tablet. By asynchronously
// flushing each block before issuing any fsyncs, the IO across
// disks is done in parallel.
//
// This increases throughput but can harm latency in the case that
// there are few disks and the WAL is on the same disk as the
// data blocks. The default is chosen based on the assumptions that:
// - latency is leveled across machines by Raft
// - latency-sensitive applications can devote a disk to the WAL
// - super-sensitive applications can devote an SSD to the WAL.
// - users could always change this to "never", which slows down
// throughput but may improve write latency.
DEFINE_string(block_manager_preflush_control, "finalize",
"Controls when to pre-flush a block. Valid values are 'finalize', "
"'close', or 'never'. If 'finalize', blocks will be pre-flushed "
"when writing is finished. If 'close', blocks will be pre-flushed "
"when their transaction is committed. If 'never', blocks will "
"never be pre-flushed but still be flushed when closed.");
TAG_FLAG(block_manager_preflush_control, experimental);
DEFINE_int64(block_manager_max_open_files, -1,
"Maximum number of open file descriptors to be used for data "
"blocks. If -1, Kudu will automatically calculate this value. "
"This is a soft limit. It is an error to use a value of 0.");
TAG_FLAG(block_manager_max_open_files, advanced);
TAG_FLAG(block_manager_max_open_files, evolving);
static bool ValidateMaxOpenFiles(const char* /*flagname*/, int64_t value) {
if (value == 0 || value < -1) {
LOG(ERROR) << "Invalid max open files: cannot be " << value;
return false;
}
return true;
}
DEFINE_validator(block_manager_max_open_files, &ValidateMaxOpenFiles);
using strings::Substitute;
namespace kudu {
namespace fs {
BlockManagerOptions::BlockManagerOptions()
: read_only(false) {}
int64_t GetFileCacheCapacityForBlockManager(Env* env) {
// Maximize this process' open file limit first, if possible.
static std::once_flag once;
std::call_once(once, [&]() {
env->IncreaseResourceLimit(Env::ResourceLimitType::OPEN_FILES_PER_PROCESS);
});
uint64_t rlimit =
env->GetResourceLimit(Env::ResourceLimitType::OPEN_FILES_PER_PROCESS);
// See block_manager_max_open_files.
if (FLAGS_block_manager_max_open_files == -1) {
// Use file-max as a possible upper bound.
faststring buf;
uint64_t buf_val;
if (ReadFileToString(env, "/proc/sys/fs/file-max", &buf).ok() &&
safe_strtou64(buf.ToString(), &buf_val)) {
rlimit = std::min(rlimit, buf_val);
}
// Callers of this function expect a signed 64-bit integer, so we need to
// cap rlimit just in case it's too large.
return std::min((2 * rlimit) / 5, static_cast<uint64_t>(kint64max));
}
LOG_IF(FATAL, FLAGS_block_manager_max_open_files > rlimit) <<
Substitute(
"Configured open file limit (block_manager_max_open_files) $0 "
"exceeds process open file limit (ulimit) $1",
FLAGS_block_manager_max_open_files, rlimit);
return FLAGS_block_manager_max_open_files;
}
} // namespace fs
} // namespace kudu