http://stxxl.sourceforge.net
<dementiev@mpi-sb.mpg.de>
<singler@ira.uka.de>
<beckmann@cs.uni-frankfurt.de>
<tb@panthema.net>
http://www.boost.org/LICENSE_1_0.txt
#include <fstream>
#include <stxxl/bits/common/error_handling.h>
#include <stxxl/bits/config.h>
#include <stxxl/bits/io/file.h>
#include <stxxl/bits/mng/config.h>
#include <stxxl/bits/common/utils.h>
#include <stxxl/version.h>
#if STXXL_WINDOWS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#else
#include <unistd.h>
#endif
STXXL_BEGIN_NAMESPACE
static inline bool exist_file(const std::string& path)
{
std::ifstream in(path.c_str());
return in.good();
}
config::~config()
{
for (disk_list_type::const_iterator it = disks_list.begin();
it != disks_list.end(); it++)
{
if (it->delete_on_exit)
{
STXXL_ERRMSG("Removing disk file: " << it->path);
unlink(it->path.c_str());
}
}
}
void config::initialize()
{
if (disks_list.size() == 0)
{
find_config();
}
is_initialized = true;
}
void config::find_config()
{
const char* stxxlcfg = getenv("STXXLCFG");
if (stxxlcfg && exist_file(stxxlcfg))
return load_config_file(stxxlcfg);
#if !STXXL_WINDOWS
const char* hostname = getenv("HOSTNAME");
const char* home = getenv("HOME");
const char* suffix = "";
#else
const char* hostname = getenv("COMPUTERNAME");
const char* home = getenv("APPDATA");
const char* suffix = ".txt";
#endif
{
std::string basepath = "./.stxxl";
if (hostname && exist_file(basepath + "." + hostname + suffix))
return load_config_file(basepath + "." + hostname + suffix);
if (exist_file(basepath + suffix))
return load_config_file(basepath + suffix);
}
if (home)
{
std::string basepath = std::string(home) + "/.stxxl";
if (hostname && exist_file(basepath + "." + hostname + suffix))
return load_config_file(basepath + "." + hostname + suffix);
if (exist_file(basepath + suffix))
return load_config_file(basepath + suffix);
}
load_default_config();
}
void config::load_default_config()
{
STXXL_ERRMSG("Warning: no config file found.");
STXXL_ERRMSG("Using default disk configuration.");
#if !STXXL_WINDOWS
disk_config entry1("/var/tmp/stxxl", 1000 * 1024 * 1024, "syscall");
entry1.delete_on_exit = true;
entry1.autogrow = true;
#else
disk_config entry1("", 1000 * 1024 * 1024, "wincall");
entry1.delete_on_exit = true;
entry1.autogrow = true;
char* tmpstr = new char[255];
if (GetTempPath(255, tmpstr) == 0)
STXXL_THROW_WIN_LASTERROR(resource_error, "GetTempPath()");
entry1.path = tmpstr;
entry1.path += "stxxl.tmp";
delete[] tmpstr;
#endif
disks_list.push_back(entry1);
first_flash = (unsigned int)disks_list.size();
}
void config::load_config_file(const std::string& config_path)
{
std::vector<disk_config> flash_list;
std::ifstream cfg_file(config_path.c_str());
if (!cfg_file)
return load_default_config();
std::string line;
while (std::getline(cfg_file, line))
{
if (line.size() == 0 || line[0] == '#') continue;
disk_config entry;
entry.parse_line(line);
if (!entry.flash)
disks_list.push_back(entry);
else
flash_list.push_back(entry);
}
cfg_file.close();
first_flash = (unsigned int)disks_list.size();
disks_list.insert(disks_list.end(), flash_list.begin(), flash_list.end());
if (disks_list.empty()) {
STXXL_THROW(std::runtime_error,
"No disks found in '" << config_path << "'.");
}
}
uint64 config::total_size() const
{
assert(is_initialized);
uint64 total_size = 0;
for (disk_list_type::const_iterator it = disks_list.begin();
it != disks_list.end(); it++)
{
total_size += it->size;
}
return total_size;
}
disk_config::disk_config()
: size(0),
autogrow(false),
delete_on_exit(false),
direct(DIRECT_TRY),
flash(false),
queue(file::DEFAULT_QUEUE),
raw_device(false),
unlink_on_open(false)
{ }
disk_config::disk_config(const std::string& _path, uint64 _size,
const std::string& _io_impl)
: path(_path),
size(_size),
io_impl(_io_impl),
autogrow(false),
delete_on_exit(false),
direct(DIRECT_TRY),
flash(false),
queue(file::DEFAULT_QUEUE),
raw_device(false),
unlink_on_open(false)
{
parse_fileio();
}
disk_config::disk_config(const std::string& line)
: size(0),
autogrow(false),
delete_on_exit(false),
direct(DIRECT_TRY),
flash(false),
queue(file::DEFAULT_QUEUE),
raw_device(false),
unlink_on_open(false)
{
parse_line(line);
}
void disk_config::parse_line(const std::string& line)
{
std::vector<std::string> eqfield = split(line, "=", 2, 2);
if (eqfield[0] == "disk") {
flash = false;
}
else if (eqfield[0] == "flash") {
flash = true;
}
else {
STXXL_THROW(std::runtime_error,
"Unknown configuration token " << eqfield[0]);
}
autogrow = false;
delete_on_exit = false;
direct = DIRECT_TRY;
queue = file::DEFAULT_QUEUE;
unlink_on_open = false;
std::vector<std::string> cmfield = split(eqfield[1], ",", 3, 3);
path = cmfield[0];
{
std::string::size_type pos;
if ((pos = path.find("###")) != std::string::npos)
{
#if !STXXL_WINDOWS
int pid = getpid();
#else
DWORD pid = GetCurrentProcessId();
#endif
path.replace(pos, 3, to_str(pid));
}
}
if (!parse_SI_IEC_size(cmfield[1], size, 'M')) {
STXXL_THROW(std::runtime_error,
"Invalid disk size '" << cmfield[1] << "' in disk configuration file.");
}
if (size == 0) {
autogrow = true;
delete_on_exit = true;
}
io_impl = cmfield[2];
parse_fileio();
}
void disk_config::parse_fileio()
{
size_t leadspace = io_impl.find_first_not_of(' ');
if (leadspace > 0)
io_impl = io_impl.substr(leadspace);
size_t spacepos = io_impl.find(' ');
if (spacepos == std::string::npos)
return;
std::string paramstr = io_impl.substr(spacepos + 1);
io_impl = io_impl.substr(0, spacepos);
std::vector<std::string> param = split(paramstr, " ");
for (std::vector<std::string>::const_iterator p = param.begin();
p != param.end(); ++p)
{
std::vector<std::string> eq = split(*p, "=", 2, 2);
if (*p == "") {
}
else if (*p == "autogrow")
{
autogrow = true;
}
else if (*p == "delete" || *p == "delete_on_exit")
{
delete_on_exit = true;
}
else if (*p == "direct" || *p == "nodirect" || eq[0] == "direct")
{
if (*p == "direct") direct = DIRECT_ON;
else if (*p == "nodirect") direct = DIRECT_OFF;
else if (eq[1] == "off") direct = DIRECT_OFF;
else if (eq[1] == "try") direct = DIRECT_TRY;
else if (eq[1] == "on") direct = DIRECT_ON;
else if (eq[1] == "no") direct = DIRECT_OFF;
else if (eq[1] == "yes") direct = DIRECT_ON;
else
{
STXXL_THROW(std::runtime_error,
"Invalid parameter '" << *p << "' in disk configuration file.");
}
}
else if (eq[0] == "queue")
{
char* endp;
queue = strtoul(eq[1].c_str(), &endp, 10);
if (endp && *endp != 0) {
STXXL_THROW(std::runtime_error,
"Invalid parameter '" << *p << "' in disk configuration file.");
}
}
else if (*p == "raw_device")
{
if (!(io_impl == "syscall")) {
STXXL_THROW(std::runtime_error, "Parameter '" << *p << "' invalid for fileio '" << io_impl << "' in disk configuration file.");
}
raw_device = true;
}
else if (*p == "unlink" || *p == "unlink_on_open")
{
if (!(io_impl == "syscall" || io_impl == "mmap") || io_impl == "wbtl") {
STXXL_THROW(std::runtime_error, "Parameter '" << *p << "' invalid for fileio '" << io_impl << "' in disk configuration file.");
}
unlink_on_open = true;
}
else
{
STXXL_THROW(std::runtime_error,
"Invalid optional parameter '" << *p << "' in disk configuration file.");
}
}
}
std::string disk_config::fileio_string() const
{
std::ostringstream oss;
oss << io_impl;
if (autogrow)
oss << " autogrow";
if (delete_on_exit)
oss << " delete_on_exit";
if (direct == DIRECT_OFF)
oss << " direct=off";
else if (direct == DIRECT_TRY)
;
else if (direct == DIRECT_ON)
oss << " direct=on";
else
assert(!"Invalid setting for 'direct' option.");
if (flash)
oss << " flash";
if (queue != file::DEFAULT_QUEUE)
oss << " queue=" << queue;
if (raw_device)
oss << " raw_device";
if (unlink_on_open)
oss << " unlink_on_open";
return oss.str();
}
STXXL_END_NAMESPACE