Thrill  0.1
config.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * foxxll/mng/config.cpp
3  *
4  * Part of FOXXLL. See http://foxxll.org
5  *
6  * Copyright (C) 2002 Roman Dementiev <[email protected]>
7  * Copyright (C) 2007, 2009 Johannes Singler <[email protected]>
8  * Copyright (C) 2008, 2009 Andreas Beckmann <[email protected]>
9  * Copyright (C) 2013 Timo Bingmann <[email protected]>
10  *
11  * Distributed under the Boost Software License, Version 1.0.
12  * (See accompanying file LICENSE_1_0.txt or copy at
13  * http://www.boost.org/LICENSE_1_0.txt)
14  **************************************************************************/
15 
16 #include <cassert>
17 #include <fstream>
18 
19 #include <tlx/logger/core.hpp>
20 
22 #include <foxxll/common/utils.hpp>
23 #include <foxxll/config.hpp>
24 #include <foxxll/io/file.hpp>
25 #include <foxxll/mng/config.hpp>
26 #include <foxxll/version.hpp>
29 #include <tlx/string/split.hpp>
30 
31 #if FOXXLL_WINDOWS
32  #ifndef NOMINMAX
33  #define NOMINMAX
34  #endif
35  #include <windows.h>
36 #else
37  #include <unistd.h>
38 #endif
39 
40 namespace foxxll {
41 
42 static inline bool exist_file(const std::string& path)
43 {
44  TLX_LOG0 << "foxxll: Checking " << path << " for disk configuration.";
45  std::ifstream in(path.c_str());
46  return in.good();
47 }
48 
50  : is_initialized(false)
51 { }
52 
54 {
55  for (disk_list_type::const_iterator it = disks_list.begin();
56  it != disks_list.end(); it++)
57  {
58  if (it->delete_on_exit)
59  {
60  TLX_LOG1 << "foxxll: Removing disk file: " << it->path;
61  unlink(it->path.c_str());
62  }
63  }
64 }
65 
67 {
70 
71  first_flash = 0;
72 
73  // if disks_list is empty, then try to load disk configuration files
74  if (disks_list.size() == 0)
75  {
76  find_config();
77  }
78 
79  max_device_id_ = 0;
80 
81  is_initialized = true;
82 }
83 
85 {
86  // check several locations for disk configuration files
87 
88  // check STXXLCFG environment path
89  const char* cfg = getenv("STXXLCFG");
90  if (cfg && exist_file(cfg))
91  return load_config_file(cfg);
92 
93 #if !FOXXLL_WINDOWS
94  // read environment, unix style
95  const char* hostname = getenv("HOSTNAME");
96  const char* home = getenv("HOME");
97  const char* suffix = "";
98 #else
99  // read environment, windows style
100  const char* hostname = getenv("COMPUTERNAME");
101  const char* home = getenv("APPDATA");
102  const char* suffix = ".txt";
103 #endif
104 
105  // check current directory
106  {
107  std::string basepath = "./" + default_config_file_name();
108 
109  if (hostname && exist_file(basepath + "." + hostname + suffix))
110  return load_config_file(basepath + "." + hostname + suffix);
111 
112  if (exist_file(basepath + suffix))
113  return load_config_file(basepath + suffix);
114  }
115 
116  // check home directory
117  if (home)
118  {
119  std::string basepath =
120  std::string(home) + "/" + default_config_file_name();
121 
122  if (hostname && exist_file(basepath + "." + hostname + suffix))
123  return load_config_file(basepath + "." + hostname + suffix);
124 
125  if (exist_file(basepath + suffix))
126  return load_config_file(basepath + suffix);
127  }
128 
129  // load default configuration
131 }
132 
134 {
135  TLX_LOG1 << "foxxll: [Warning] no config file found.";
136  TLX_LOG1 << "foxxll: Using default disk configuration.";
137  disk_config entry1(default_disk_path(), 1000 * 1024 * 1024,
139  entry1.delete_on_exit = true;
140  entry1.autogrow = true;
141  add_disk(entry1);
142 }
143 
144 void config::load_config_file(const std::string& config_path)
145 {
146  std::vector<disk_config> flash_list;
147  std::ifstream cfg_file(config_path.c_str());
148 
149  if (!cfg_file)
150  return load_default_config();
151 
152  std::string line;
153 
154  while (std::getline(cfg_file, line))
155  {
156  // skip comments
157  if (line.size() == 0 || line[0] == '#') continue;
158 
159  disk_config entry;
160  entry.parse_line(line); // throws on errors
161 
162  if (!entry.flash)
163  disks_list.push_back(entry);
164  else
165  flash_list.push_back(entry);
166  }
167  cfg_file.close();
168 
169  // put flash devices after regular disks
170  first_flash = static_cast<unsigned int>(disks_list.size());
171  disks_list.insert(disks_list.end(), flash_list.begin(), flash_list.end());
172 
173  if (disks_list.empty()) {
174  FOXXLL_THROW(
175  std::runtime_error,
176  "No disks found in '" << config_path << "'."
177  );
178  }
179 }
180 
182 {
183  disks_list.push_back(cfg);
184  // no flash disks anymore
185  ++first_flash;
186  return *this;
187 }
188 
189 unsigned int config::max_device_id()
190 {
191  return max_device_id_;
192 }
193 
195 {
196  return max_device_id_++;
197 }
198 
199 void config::update_max_device_id(unsigned int devid)
200 {
201  if (max_device_id_ < devid + 1)
202  max_device_id_ = devid + 1;
203 }
204 
205 std::pair<unsigned, unsigned> config::regular_disk_range() const
206 {
207  assert(is_initialized);
208  return std::pair<unsigned, unsigned>(0, first_flash);
209 }
210 
211 std::pair<unsigned, unsigned> config::flash_range() const
212 {
213  assert(is_initialized);
214  return std::pair<unsigned, unsigned>(
215  first_flash, static_cast<unsigned>(disks_list.size())
216  );
217 }
218 
220 {
222  assert(disk < disks_list.size());
223  return disks_list[disk];
224 }
225 
226 const std::string& config::disk_path(size_t disk) const
227 {
228  assert(is_initialized);
229  return disks_list[disk].path;
230 }
231 
233 {
234 #if !FOXXLL_WINDOWS
235  return "/var/tmp/foxxll";
236 #else
237  char* tmpstr = new char[255];
238  if (GetTempPathA(255, tmpstr) == 0)
239  FOXXLL_THROW_WIN_LASTERROR(resource_error, "GetTempPathA()");
240  std::string result = tmpstr;
241  result += "foxxll.tmp";
242  delete[] tmpstr;
243  return result;
244 #endif
245 }
246 
248 {
249 #if !FOXXLL_WINDOWS
250  return "syscall";
251 #else
252  return "wincall";
253 #endif
254 }
255 
257 {
258  return ".stxxl";
259 }
260 
262 {
263  assert(is_initialized);
264  return disks_list[disk].size;
265 }
266 
268 {
269  assert(is_initialized);
270  return disks_list[disk].io_impl;
271 }
272 
274 {
275  assert(is_initialized);
276 
278 
279  for (disk_list_type::const_iterator it = disks_list.begin();
280  it != disks_list.end(); it++)
281  {
282  total_size += it->size;
283  }
284 
285  return total_size;
286 }
287 
288 ////////////////////////////////////////////////////////////////////////////////
289 
291  : size(0),
292  autogrow(true),
293  delete_on_exit(false),
294  direct(DIRECT_TRY),
295  flash(false),
296  queue(file::DEFAULT_QUEUE),
297  device_id(file::DEFAULT_DEVICE_ID),
298  raw_device(false),
299  unlink_on_open(false),
300  queue_length(0)
301 { }
302 
304  const std::string& _io_impl)
305  : path(_path),
306  size(_size),
307  io_impl(_io_impl),
308  autogrow(true),
309  delete_on_exit(false),
311  flash(false),
312  queue(file::DEFAULT_QUEUE),
313  device_id(file::DEFAULT_DEVICE_ID),
314  raw_device(false),
315  unlink_on_open(false),
316  queue_length(0)
317 {
318  parse_fileio();
319 }
320 
322  : size(0),
323  autogrow(true),
324  delete_on_exit(false),
326  flash(false),
327  queue(file::DEFAULT_QUEUE),
328  device_id(file::DEFAULT_DEVICE_ID),
329  raw_device(false),
330  unlink_on_open(false),
331  queue_length(0)
332 {
333  parse_line(line);
334 }
335 
337 {
338  // split off disk= or flash=
339  std::vector<std::string> eqfield = tlx::split('=', line, 2, 2);
340 
341  if (eqfield[0] == "disk") {
342  flash = false;
343  }
344  else if (eqfield[0] == "flash") {
345  flash = true;
346  }
347  else {
348  FOXXLL_THROW(
349  std::runtime_error,
350  "Unknown configuration token " << eqfield[0]
351  );
352  }
353 
354  // *** Set Default Extra Options ***
355 
356  autogrow = true; // was default for a long time, have to keep it this way
357  delete_on_exit = false;
358  direct = DIRECT_TRY;
359  // flash is already set
362  unlink_on_open = false;
363 
364  // *** Save Basic Options ***
365 
366  // split at commands, at least 3 fields
367  std::vector<std::string> cmfield = tlx::split(',', eqfield[1], 3, 3);
368 
369  // path:
371  // replace $$ -> pid in path
372  {
373  std::string::size_type pos;
374  if ((pos = path.find("$$")) != std::string::npos)
375  {
376 #if !FOXXLL_WINDOWS
377  int pid = getpid();
378 #else
379  DWORD pid = GetCurrentProcessId();
380 #endif
381  path.replace(pos, 3, to_str(pid));
382  }
383  }
384 
385  // size: (default unit MiB)
386  if (!tlx::parse_si_iec_units(cmfield[1], &size, 'M')) {
387  FOXXLL_THROW(
388  std::runtime_error,
389  "Invalid disk size '" << cmfield[1] << "' in disk configuration file."
390  );
391  }
392 
393  if (size == 0) {
394  autogrow = true;
395  delete_on_exit = true;
396  }
397 
398  // io_impl:
399  io_impl = cmfield[2];
400  parse_fileio();
401 }
402 
404 {
405  // skip over leading spaces
406  size_t leadspace = io_impl.find_first_not_of(' ');
407  if (leadspace > 0)
408  io_impl = io_impl.substr(leadspace);
409 
410  // split off extra fileio parameters
411  size_t spacepos = io_impl.find(' ');
412  if (spacepos == std::string::npos)
413  return; // no space in fileio
414 
415  // *** Parse Extra Fileio Parameters ***
416 
417  std::string paramstr = io_impl.substr(spacepos + 1);
418  io_impl = io_impl.substr(0, spacepos);
419 
420  std::vector<std::string> param = tlx::split(' ', paramstr);
421 
422  for (std::vector<std::string>::const_iterator p = param.begin();
423  p != param.end(); ++p)
424  {
425  // split at equal sign
426  std::vector<std::string> eq = tlx::split('=', *p, 2, 2);
427 
428  // *** PLEASE try to keep the elseifs sorted by parameter name!
429  if (*p == "") {
430  // skip blank options
431  }
432  else if (*p == "autogrow" || *p == "noautogrow" || eq[0] == "autogrow")
433  {
434  // TODO: which fileio implementation support autogrow?
435 
436  if (*p == "autogrow") autogrow = true;
437  else if (*p == "noautogrow") autogrow = false;
438  else if (eq[1] == "off") autogrow = false;
439  else if (eq[1] == "on") autogrow = true;
440  else if (eq[1] == "no") autogrow = false;
441  else if (eq[1] == "yes") autogrow = true;
442  else
443  {
444  FOXXLL_THROW(
445  std::runtime_error,
446  "Invalid parameter '" << *p << "' in disk configuration file."
447  );
448  }
449  }
450  else if (*p == "delete" || *p == "delete_on_exit")
451  {
452  delete_on_exit = true;
453  }
454  else if (*p == "direct" || *p == "nodirect" || eq[0] == "direct")
455  {
456  // io_impl is not checked here, but I guess that is okay for DIRECT
457  // since it depends highly platform _and_ build-time configuration.
458 
459  if (*p == "direct") direct = DIRECT_ON; // force ON
460  else if (*p == "nodirect") direct = DIRECT_OFF; // force OFF
461  else if (eq[1] == "off") direct = DIRECT_OFF;
462  else if (eq[1] == "try") direct = DIRECT_TRY;
463  else if (eq[1] == "on") direct = DIRECT_ON;
464  else if (eq[1] == "no") direct = DIRECT_OFF;
465  else if (eq[1] == "yes") direct = DIRECT_ON;
466  else
467  {
468  FOXXLL_THROW(
469  std::runtime_error,
470  "Invalid parameter '" << *p << "' in disk configuration file."
471  );
472  }
473  }
474  else if (eq[0] == "queue")
475  {
476  if (io_impl == "linuxaio") {
477  FOXXLL_THROW(std::runtime_error, "Parameter '" << *p << "' invalid for fileio '" << io_impl << "' in disk configuration file.");
478  }
479 
480  char* endp;
481  queue = static_cast<int>(strtoul(eq[1].c_str(), &endp, 10));
482  if (endp && *endp != 0) {
483  FOXXLL_THROW(
484  std::runtime_error,
485  "Invalid parameter '" << *p << "' in disk configuration file."
486  );
487  }
488  }
489  else if (eq[0] == "queue_length")
490  {
491  if (io_impl != "linuxaio") {
492  FOXXLL_THROW(
493  std::runtime_error, "Parameter '" << *p << "' "
494  "is only valid for fileio linuxaio "
495  "in disk configuration file."
496  );
497  }
498 
499  char* endp;
500  queue_length = static_cast<int>(strtoul(eq[1].c_str(), &endp, 10));
501  if (endp && *endp != 0) {
502  FOXXLL_THROW(
503  std::runtime_error,
504  "Invalid parameter '" << *p << "' in disk configuration file."
505  );
506  }
507  }
508  else if (eq[0] == "device_id" || eq[0] == "devid")
509  {
510  char* endp;
511  device_id = static_cast<int>(strtoul(eq[1].c_str(), &endp, 10));
512  if (endp && *endp != 0) {
513  FOXXLL_THROW(
514  std::runtime_error,
515  "Invalid parameter '" << *p << "' in disk configuration file."
516  );
517  }
518  }
519  else if (*p == "raw_device")
520  {
521  if (!(io_impl == "syscall")) {
522  FOXXLL_THROW(std::runtime_error, "Parameter '" << *p << "' invalid for fileio '" << io_impl << "' in disk configuration file.");
523  }
524 
525  raw_device = true;
526  }
527  else if (*p == "unlink" || *p == "unlink_on_open")
528  {
529  if (!(io_impl == "syscall" || io_impl == "linuxaio" ||
530  io_impl == "mmap"))
531  {
532  FOXXLL_THROW(std::runtime_error, "Parameter '" << *p << "' invalid for fileio '" << io_impl << "' in disk configuration file.");
533  }
534 
535  unlink_on_open = true;
536  }
537  else
538  {
539  FOXXLL_THROW(
540  std::runtime_error,
541  "Invalid optional parameter '" << *p << "' in disk configuration file."
542  );
543  }
544  }
545 }
546 
548 {
549  std::ostringstream oss;
550 
551  oss << io_impl;
552 
553  if (!autogrow)
554  oss << " autogrow=no";
555 
556  if (delete_on_exit)
557  oss << " delete_on_exit";
558 
559  // tristate direct variable: OFF, TRY, ON
560  if (direct == DIRECT_OFF)
561  {
562  oss << " direct=off";
563  }
564  else if (direct == DIRECT_TRY)
565  { } // silenced: oss << " direct=try";
566  else if (direct == DIRECT_ON)
567  {
568  oss << " direct=on";
569  }
570  else
571  FOXXLL_THROW(std::runtime_error, "Invalid setting for 'direct' option.");
572 
573  if (flash) {
574  oss << " flash";
575  }
576 
578  oss << " queue=" << queue;
579  }
580 
582  oss << " devid=" << device_id;
583  }
584 
585  if (raw_device) {
586  oss << " raw_device";
587  }
588 
589  if (unlink_on_open) {
590  oss << " unlink_on_open";
591  }
592 
593  if (queue_length != 0) {
594  oss << " queue_length=" << queue_length;
595  }
596 
597  return oss.str();
598 }
599 
600 } // namespace foxxll
601 
602 /**************************************************************************/
external_size_type size
file size to initially allocate
Definition: config.hpp:46
void update_max_device_id(unsigned int devid)
Update the automatic physical device id counter.
Definition: config.cpp:199
unsigned int next_device_id()
Returns next automatic physical device id counter.
Definition: config.cpp:194
std::string & expand_environment_variables(std::string *sp)
Expand substrings $ABC_123 and ${ABC_123} into the corresponding environment variables.
std::string path
the file path used by the io implementation
Definition: config.hpp:43
virtual void initialize()
Definition: config.cpp:66
void check_initialized()
Definition: config.hpp:151
void parse_fileio()
parse the "io_impl" parameter into the optional parameter fields.
Definition: config.cpp:403
static const unsigned int DEFAULT_DEVICE_ID
Definition: file.hpp:92
unsigned int max_device_id()
Returns automatic physical device id counter.
Definition: config.cpp:189
#define FOXXLL_THROW(exception_type, error_message)
Throws exception_type with "Error in [function] : [error_message]".
external_size_type disk_size(size_t disk) const
Definition: config.cpp:261
virtual void load_config_file(const std::string &config_path)
Load disk configuration file.
Definition: config.cpp:144
bool unlink_on_open
unlink file immediately after opening (available on most Unix)
Definition: config.hpp:103
virtual std::string default_disk_path()
Definition: config.cpp:232
std::string io_impl
io implementation to access file
Definition: config.hpp:49
disk_config()
default constructor
Definition: config.cpp:290
virtual std::string default_disk_io_impl()
Returns name of the default I/O implementation.
Definition: config.cpp:247
unsigned int max_device_id_
static counter for automatic physical device enumeration
Definition: config.hpp:175
std::string to_str(const Type &t)
Format any ostream-able type into a string.
Definition: utils.hpp:36
void parse_line(const std::string &line)
Definition: config.cpp:336
external_size_type total_size() const
Returns the total size over all disks.
Definition: config.cpp:273
std::vector< std::string > split(char sep, const std::string &str, std::string::size_type limit)
Split the given string at each separator character into distinct substrings.
Definition: split.cpp:20
virtual void find_config()
Search several places for a config file.
Definition: config.cpp:84
virtual ~config()
deletes autogrow files
Definition: config.cpp:53
disk_config & disk(size_t disk)
Returns mutable disk_config structure for additional disk parameters.
Definition: config.cpp:219
static bool exist_file(const std::string &path)
Definition: config.cpp:42
disk_list_type disks_list
list of configured disks
Definition: config.hpp:122
bool parse_si_iec_units(const char *str, uint64_t *out_size, char default_unit)
Parse a string like "343KB" or "44 GiB" into the corresponding size in bytes.
const std::string & disk_io_impl(size_t disk) const
Definition: config.cpp:267
bool flash
marks flash drives (configuration entries with flash= instead of disk=)
Definition: config.hpp:89
static const int DEFAULT_QUEUE
Definition: file.hpp:89
std::pair< unsigned, unsigned > regular_disk_range() const
Returns contiguous range of regular disks w/o flash devices in the array of all disks.
Definition: config.cpp:205
FOXXLL library namespace
std::basic_string< char, std::char_traits< char >, Allocator< char > > string
string with Manager tracking
Definition: allocator.hpp:220
virtual std::string default_config_file_name()
returns the name of the default config file prefix
Definition: config.cpp:256
#define TLX_LOG0
Override default output: never or always output log.
Definition: core.hpp:144
bool is_initialized
Finished initializing config.
Definition: config.hpp:128
std::string fileio_string() const
return formatted fileio name and optional configuration parameters
Definition: config.cpp:547
void print_library_version_mismatch()
Check and print mismatch between header and library versions.
Definition: version.hpp:84
bool raw_device
turned on by syscall fileio when the path points to a raw block device
Definition: config.hpp:100
int queue_length
desired queue length for linuxaio_file and linuxaio_queue
Definition: config.hpp:106
static const int DEFAULT_LINUXAIO_QUEUE
Definition: file.hpp:90
const std::string & disk_path(size_t disk) const
Definition: config.cpp:226
config & add_disk(const disk_config &cfg)
Definition: config.cpp:181
config()
Constructor: this must be inlined to print the header version string.
Definition: config.cpp:49
bool delete_on_exit
delete file on program exit (default for autoconfigurated files)
Definition: config.hpp:81
#define TLX_LOG1
Definition: core.hpp:145
virtual void load_default_config()
Load default configuration.
Definition: config.cpp:133
bool autogrow
autogrow file if more disk space is needed, automatically set if size == 0.
Definition: config.hpp:78
unsigned int device_id
Definition: config.hpp:97
unsigned first_flash
In disks_list, flash devices come after all regular disks.
Definition: config.hpp:125
uint64_t external_size_type
Definition: types.hpp:27
std::pair< unsigned, unsigned > flash_range() const
Definition: config.cpp:211
enum foxxll::disk_config::direct_type direct
std::string get_version_string_long()
Return longer "X.Y.Z (feature) (version)" version string (of headers)
Definition: version.hpp:40