libfoedus-core
FOEDUS Core Library
Filesystem wrapper

Filesystem wrapper, an analogue of boost::filesystem. More...

Detailed Description

Filesystem wrapper, an analogue of boost::filesystem.

These methods abstract accesses to filesystems like boost::filesystem and std::filesystem in C++1z(?). We should not directly call POSIX or Windows filesystem APIs in other modules. Instead, all of them should go through this package.

Why this package exists
The best case scenario for us is the standard C++ library provides filesystem abstraction. However, the spec (based on Boost filesystem ver2) didn't get into even C++14, let alone its implmentations. Thus, we can't rely on it at all. Boost filesystem has a few issues, too. First, it is changing and has some issue when C++11 is enabled. Furthermore, the filesystem package is NOT a header-only module in boost. We do not want to introduce additional dependencies to the gigantic boost shared library, which might not be available or has versioning issues in some environment. Rather, we just need only a small subset of functionalities in those libraries because our usage of filesystem is quite minimal and simplistic. Hence, we do it ourselves.
Direct File I/O
Another goal to have this package is to abstract Direct I/O (O_DIRECT in linux and FILE_FLAG_NO_BUFFERING in Windows). We need them to bypass filesystem-level caching, but these are not in C++ standards at all and won't be (if it happens, Linus would get a heart attack: https://lkml.org/lkml/2007/1/10/233 ).
Class/method designs
Basically, we clone Boost filesystem's class/method into this package when we find a need for some filesystem API access in our code. Due to our specialized needs, we might simplify the API. Our goal is not to duplicate all Boost filesystem classes. Just add what we need.
Collaboration diagram for Filesystem wrapper:

Files

file  fwd.hpp
 Forward declarations of classes in filesystem package.
 

Classes

struct  foedus::fs::DeviceEmulationOptions
 Set of configurations to emulate slower devices for some experiments. More...
 
class  foedus::fs::DirectIoFile
 Represents an I/O stream on one file without filesystem caching. More...
 
struct  foedus::fs::FileStatus
 Analogue of boost::filesystem::file_status. More...
 
struct  foedus::fs::SpaceInfo
 Analogue of boost::filesystem::space_info. More...
 
class  foedus::fs::Path
 Analogue of boost::filesystem::path. More...
 

Typedefs

typedef assorted::FixedString< 508 > foedus::fs::FixedPath
 Represents a fixed (thus can be placed in shared memory) path string. More...
 

Enumerations

enum  foedus::fs::FileType {
  foedus::fs::kStatusError = 0, foedus::fs::kFileNotFound, foedus::fs::kRegularFile, foedus::fs::kDirectoryFile,
  foedus::fs::kTypeUnknown
}
 Analogue of boost::filesystem::file_type. More...
 
enum  foedus::fs::FilePermission {
  foedus::fs::kNoPerms = 0, foedus::fs::kOwnerRead = 0400, foedus::fs::kOwnerWrite = 0200, foedus::fs::kOwnerExe = 0100,
  foedus::fs::kOwnerAll = 0700, foedus::fs::kGroupRead = 040, foedus::fs::kGroupWrite = 020, foedus::fs::kGroupExe = 010,
  foedus::fs::kGroupAll = 070, foedus::fs::kOthersRead = 04, foedus::fs::kOthersWrite = 02, foedus::fs::kOthersExe = 01,
  foedus::fs::kOthersAll = 07, foedus::fs::kAllAll = kOwnerAll|kGroupAll|kOthersAll, foedus::fs::kPermsNotKnown = 0xFFFF
}
 Analogue of boost::filesystem::perm. More...
 

Functions

FileStatus foedus::fs::status (const Path &p)
 Returns the status of the file. More...
 
bool foedus::fs::exists (const Path &p)
 Returns if the file exists. More...
 
bool foedus::fs::is_directory (const Path &p)
 Returns if the file is a directory. More...
 
bool foedus::fs::is_regular_file (const Path &p)
 Returns if the file is a regular file. More...
 
Path foedus::fs::current_path ()
 Returns the current working directory. More...
 
Path foedus::fs::home_path ()
 Returns the absolute path of the home directory of the user running this process. More...
 
Path foedus::fs::absolute (const std::string &p)
 Returns the absolue path of the specified path. More...
 
bool foedus::fs::create_directories (const Path &p, bool sync=false)
 Recursive mkdir (mkdirs). More...
 
bool foedus::fs::create_directory (const Path &p, bool sync=false)
 mkdir. More...
 
uint64_t foedus::fs::file_size (const Path &p)
 Returns size of the file. More...
 
bool foedus::fs::remove (const Path &p)
 Deletes a regular file or an empty directory. More...
 
uint64_t foedus::fs::remove_all (const Path &p)
 Recursively deletes a directory. More...
 
SpaceInfo foedus::fs::space (const Path &p)
 Returns free space information for the device the file is on. More...
 
std::string foedus::fs::unique_name (uint64_t differentiator=0)
 Equivalent to unique_path("%%%%-%%%%-%%%%-%%%%"). More...
 
std::string foedus::fs::unique_name (const std::string &model, uint64_t differentiator=0)
 Returns a randomly generated file name with the given template. More...
 
bool foedus::fs::fsync (const Path &path, bool sync_parent_directory=false)
 Makes the content and metadata of the file durable all the way up to devices. More...
 
bool foedus::fs::atomic_rename (const Path &old_path, const Path &new_path)
 Renames the old file to the new file with the POSIX atomic-rename semantics. More...
 
bool foedus::fs::durable_atomic_rename (const Path &old_path, const Path &new_path)
 fsync() on source file before rename, then fsync() on the parent folder after rename. More...
 
bool foedus::fs::rename (const Path &old_path, const Path &new_path)
 Just a synonym of atomic_rename() to avoid confusion. More...
 

Typedef Documentation

typedef assorted::FixedString<508> foedus::fs::FixedPath

Represents a fixed (thus can be placed in shared memory) path string.

Definition at line 83 of file filesystem.hpp.

Enumeration Type Documentation

Analogue of boost::filesystem::perm.

Enumerator
kNoPerms 
kOwnerRead 
kOwnerWrite 
kOwnerExe 
kOwnerAll 
kGroupRead 
kGroupWrite 
kGroupExe 
kGroupAll 
kOthersRead 
kOthersWrite 
kOthersExe 
kOthersAll 
kAllAll 
kPermsNotKnown 

Definition at line 51 of file filesystem.hpp.

51  {
52  kNoPerms = 0, // kFileNotFound is kNoPerms rather than kPermsNotKnown
53 
54  // POSIX equivalent macros given in comments.
55  // Values are from POSIX and are given in octal per the POSIX standard.
56 
57  // permission bits
58 
59  kOwnerRead = 0400, // S_IRUSR, Read permission, owner
60  kOwnerWrite = 0200, // S_IWUSR, Write permission, owner
61  kOwnerExe = 0100, // S_IXUSR, Execute/search permission, owner
62  kOwnerAll = 0700, // S_IRWXU, Read, write, execute/search by owner
63 
64  kGroupRead = 040, // S_IRGRP, Read permission, group
65  kGroupWrite = 020, // S_IWGRP, Write permission, group
66  kGroupExe = 010, // S_IXGRP, Execute/search permission, group
67  kGroupAll = 070, // S_IRWXG, Read, write, execute/search by group
68 
69  kOthersRead = 04, // S_IROTH, Read permission, others
70  kOthersWrite = 02, // S_IWOTH, Write permission, others
71  kOthersExe = 01, // S_IXOTH, Execute/search permission, others
72  kOthersAll = 07, // S_IRWXO, Read, write, execute/search by others
73 
75 
76  kPermsNotKnown = 0xFFFF, // present when directory_entry cache not loaded
77 };

Analogue of boost::filesystem::file_type.

Enumerator
kStatusError 
kFileNotFound 
kRegularFile 
kDirectoryFile 
kTypeUnknown 

Definition at line 38 of file filesystem.hpp.

Function Documentation

Path foedus::fs::absolute ( const std::string &  p)

Returns the absolue path of the specified path.

Definition at line 62 of file filesystem.cpp.

62  {
63  return Path(p);
64 }
bool foedus::fs::atomic_rename ( const Path old_path,
const Path new_path 
)

Renames the old file to the new file with the POSIX atomic-rename semantics.

Parameters
[in]old_pathpath of the file to rename
[in]new_pathpath after rename
Returns
whether the rename succeeded
Precondition
exists(old_path)
!exists(new_path) is NOT a pre-condition. See below.

This is analogus to boost::filesystem::rename(), but we named this atomic_rename to clarify that this implementation guarantees the POSIX atomic-rename semantics. When new_path already exists, this method atomically swaps the file on filesystem with the old_path file, appropriately deleting the old file. This is an essential semantics to achieve safe and fault-tolerant file writes. And, for that usecase, do NOT forget to also call fsync before/after rename, too. Use durable_atomic_rename() to make sure.

See also
http://pubs.opengroup.org/onlinepubs/009695399/functions/rename.html
Eat My Data: How Everybody Gets File IO Wrong: https://www.flamingspork.com/talks/2007/06/eat_my_data.odp

Definition at line 199 of file filesystem.cpp.

References foedus::fs::Path::c_str(), and foedus::fs::rename().

Referenced by foedus::fs::durable_atomic_rename(), and foedus::fs::rename().

199  {
200  return ::rename(old_path.c_str(), new_path.c_str()) == 0;
201 }
bool rename(const Path &old_path, const Path &new_path)
Just a synonym of atomic_rename() to avoid confusion.
Definition: filesystem.hpp:286

Here is the call graph for this function:

Here is the caller graph for this function:

bool foedus::fs::create_directories ( const Path p,
bool  sync = false 
)

Recursive mkdir (mkdirs).

Parameters
[in]ppath of the directory to create
[in]sync(optional, default false) wheter to call fsync() on the created directories and their parents. This is required to make sure the new directory entries become durable.
Returns
whether the directory already exists or creation succeeded

Definition at line 89 of file filesystem.cpp.

References foedus::fs::create_directory(), foedus::fs::Path::empty(), foedus::fs::exists(), and foedus::fs::Path::parent_path().

Referenced by foedus::log::MetaLogger::initialize_once(), foedus::log::LogManagerPimpl::initialize_once(), foedus::fs::DirectIoFile::open(), foedus::externalize::Externalizable::save_to_file(), and foedus::snapshot::SnapshotManagerPimpl::snapshot_metadata().

89  {
90  if (exists(p)) {
91  return true;
92  }
93  if (create_directory(p, sync)) {
94  return true;
95  }
96  // if failed, create parent then try again
97  Path parent = p.parent_path();
98  if (parent.empty()) {
99  return false;
100  }
101  if (!create_directories(parent, sync) && !exists(parent)) {
102  return false;
103  }
104  // now ancestors exist.
105  return create_directory(p, sync);
106 }
bool create_directory(const Path &p, bool sync=false)
mkdir.
Definition: filesystem.cpp:108
bool create_directories(const Path &p, bool sync=false)
Recursive mkdir (mkdirs).
Definition: filesystem.cpp:89
bool exists(const Path &p)
Returns if the file exists.
Definition: filesystem.hpp:128

Here is the call graph for this function:

Here is the caller graph for this function:

bool foedus::fs::create_directory ( const Path p,
bool  sync = false 
)

mkdir.

Parameters
[in]ppath of the directory to create
[in]sync(optional, default false) wheter to call fsync() on the created directory and its parent. This is required to make sure the new directory entry becomes durable.
Returns
whether the directory already exists or creation whether succeeded

Definition at line 108 of file filesystem.cpp.

References foedus::fs::Path::c_str(), and foedus::fs::fsync().

Referenced by foedus::fs::create_directories().

108  {
109  int ret = ::mkdir(p.c_str(), S_IRWXU);
110  if (ret != 0) {
111  return false;
112  }
113  if (sync) {
114  return fsync(p, true);
115  } else {
116  return true;
117  }
118 }
bool fsync(const Path &path, bool sync_parent_directory=false)
Makes the content and metadata of the file durable all the way up to devices.
Definition: filesystem.cpp:203

Here is the call graph for this function:

Here is the caller graph for this function:

Path foedus::fs::current_path ( )

Returns the current working directory.

Definition at line 66 of file filesystem.cpp.

References ASSERT_ND.

Referenced by foedus::fs::Path::Path().

66  {
67  Path cur;
68  for (size_t path_max = 128;; path_max *=2) { // loop 'til buffer large enough
69  std::vector<char> buf(path_max);
70  if (::getcwd(&buf[0], path_max) == 0) {
71  ASSERT_ND(errno == ERANGE);
72  } else {
73  cur = std::string(&buf[0]);
74  break;
75  }
76  }
77  return cur;
78 }
#define ASSERT_ND(x)
A warning-free wrapper macro of assert() that has no performance effect in release mode even when 'x'...
Definition: assert_nd.hpp:72

Here is the caller graph for this function:

bool foedus::fs::durable_atomic_rename ( const Path old_path,
const Path new_path 
)

fsync() on source file before rename, then fsync() on the parent folder after rename.

This method makes 2 fsync calls, one on old file before rename and another on the parent directory after rename.

Note that we don't need fsync on parent directory before rename assuming old_path and new_path is in the same folder (if not, you have to call fsync yourself before calling this method). Even if a crash happens right after rename, we still see the old content of new_path.

Also, we don't need fsync on new_path after rename because POSIX rename doesn't change the inode of renamed file. It's already there as soon as parent folder's fsync is done.

Quite complex and expensive, but this is required to make it durable regardless of filesystems. Fortunately, we have to call this method only once per epoch-advance.

Definition at line 236 of file filesystem.cpp.

References foedus::fs::atomic_rename(), foedus::fs::fsync(), and foedus::fs::Path::parent_path().

Referenced by foedus::externalize::Externalizable::save_to_file().

236  {
237  if (!fsync(old_path, false)) {
238  return false;
239  }
240  if (!atomic_rename(old_path, new_path)) {
241  return false;
242  }
243  return fsync(new_path.parent_path(), false);
244 }
bool atomic_rename(const Path &old_path, const Path &new_path)
Renames the old file to the new file with the POSIX atomic-rename semantics.
Definition: filesystem.cpp:199
bool fsync(const Path &path, bool sync_parent_directory=false)
Makes the content and metadata of the file durable all the way up to devices.
Definition: filesystem.cpp:203

Here is the call graph for this function:

Here is the caller graph for this function:

uint64_t foedus::fs::file_size ( const Path p)

Returns size of the file.

Definition at line 120 of file filesystem.cpp.

References foedus::fs::Path::c_str().

Referenced by foedus::snapshot::LogMapper::handle_process(), foedus::snapshot::SnapshotWriter::open(), foedus::fs::DirectIoFile::open(), foedus::snapshot::SnapshotManagerPimpl::read_snapshot_metadata(), foedus::restart::RestartManagerPimpl::redo_meta_logs(), and foedus::snapshot::SnapshotManagerPimpl::snapshot_metadata().

120  {
121  struct stat path_stat;
122  int ret = ::stat(p.c_str(), &path_stat);
123  if (ret != 0) {
124  return static_cast<uint64_t>(-1);
125  }
126  if (!S_ISREG(path_stat.st_mode)) {
127  return static_cast<uint64_t>(-1);
128  }
129  return static_cast<uint64_t>(path_stat.st_size);
130 }

Here is the call graph for this function:

Here is the caller graph for this function:

bool foedus::fs::fsync ( const Path path,
bool  sync_parent_directory = false 
)

Makes the content and metadata of the file durable all the way up to devices.

Parameters
[in]pathpath of the file to make durable
[in]sync_parent_directory(optional, default false) whether to also call fsync on the parent directory to make sure the directory entry is written to device. This is required when you create a new file, rename, etc.
Returns
whether the sync succeeded or not. If failed, check the errno global variable (set by lower-level library).

Surprisingly, there is no analogus method in boost::filesystem. This method provides the fundamental building block of fault-tolerant systems; fsync. We so far don't provide fdatasync (no metadata sync), but this should suffice.

Definition at line 203 of file filesystem.cpp.

References foedus::fs::Path::c_str(), foedus::fs::is_directory(), and foedus::fs::Path::parent_path().

Referenced by foedus::snapshot::SnapshotWriter::close(), foedus::fs::create_directory(), foedus::fs::durable_atomic_rename(), foedus::externalize::Externalizable::save_to_file(), foedus::snapshot::SnapshotManagerPimpl::snapshot_metadata(), foedus::fs::DirectIoFile::sync(), and foedus::fs::DirectIoFile::truncate().

203  {
204  int sync_ret;
205  if (!is_directory(path)) {
206  int descriptor = ::open(path.c_str(), O_RDONLY);
207  if (descriptor < 0) {
208  return false;
209  }
210  sync_ret = ::fsync(descriptor);
211  ::close(descriptor);
212  } else {
213  DIR *dir = ::opendir(path.c_str());
214  if (!dir) {
215  return false;
216  }
217  int descriptor = ::dirfd(dir);
218  if (descriptor < 0) {
219  return false;
220  }
221 
222  sync_ret = ::fsync(descriptor);
223  ::closedir(dir);
224  }
225 
226  if (sync_ret != 0) {
227  return false;
228  }
229 
230  if (sync_parent_directory) {
231  return fsync(path.parent_path(), false);
232  } else {
233  return true;
234  }
235 }
bool is_directory(const Path &p)
Returns if the file is a directory.
Definition: filesystem.hpp:133
bool fsync(const Path &path, bool sync_parent_directory=false)
Makes the content and metadata of the file durable all the way up to devices.
Definition: filesystem.cpp:203

Here is the call graph for this function:

Here is the caller graph for this function:

Path foedus::fs::home_path ( )

Returns the absolute path of the home directory of the user running this process.

So far this checks only HOME environment variable, which might not be set in some environment. In that case, this returns an empty path. A truly crossplatform home_path is not in standard C++, unfortunately.

See also
http://stackoverflow.com/questions/2552416/how-can-i-find-the-users-home-dir-in-a-cross-platform-manner-using-c

Definition at line 80 of file filesystem.cpp.

Referenced by foedus::fs::Path::Path().

80  {
81  const char *home = ::getenv("HOME");
82  if (home) {
83  return Path(home);
84  } else {
85  return Path();
86  }
87 }

Here is the caller graph for this function:

bool foedus::fs::is_directory ( const Path p)
inline

Returns if the file is a directory.

Definition at line 133 of file filesystem.hpp.

References foedus::fs::FileStatus::is_directory(), and foedus::fs::status().

Referenced by foedus::fs::Path::child_paths(), and foedus::fs::fsync().

133 {return status(p).is_directory(); }
bool is_directory() const
Definition: filesystem.hpp:99
FileStatus status(const Path &p)
Returns the status of the file.
Definition: filesystem.cpp:45

Here is the call graph for this function:

Here is the caller graph for this function:

bool foedus::fs::is_regular_file ( const Path p)
inline

Returns if the file is a regular file.

Definition at line 138 of file filesystem.hpp.

References foedus::fs::FileStatus::is_regular_file(), and foedus::fs::status().

138 {return status(p).is_regular_file(); }
FileStatus status(const Path &p)
Returns the status of the file.
Definition: filesystem.cpp:45
bool is_regular_file() const
Definition: filesystem.hpp:98

Here is the call graph for this function:

bool foedus::fs::remove ( const Path p)

Deletes a regular file or an empty directory.

Returns
whether succeeded

Definition at line 132 of file filesystem.cpp.

References foedus::fs::FileStatus::exists(), foedus::fs::FileStatus::is_regular_file(), and foedus::fs::status().

Referenced by foedus::memory::SharedMemory::release_block().

132  {
133  FileStatus s = status(p);
134  if (!s.exists()) {
135  return 0;
136  } else if (s.is_regular_file()) {
137  return std::remove(p.c_str()) == 0;
138  } else {
139  int ret = ::rmdir(p.c_str());
140  if (ret == 0) {
141  return true;
142  } else {
143  return false;
144  }
145  }
146 }
bool remove(const Path &p)
Deletes a regular file or an empty directory.
Definition: filesystem.cpp:132
FileStatus status(const Path &p)
Returns the status of the file.
Definition: filesystem.cpp:45

Here is the call graph for this function:

Here is the caller graph for this function:

uint64_t foedus::fs::remove_all ( const Path p)

Recursively deletes a directory.

Returns
number of files/directories deleted.

Definition at line 148 of file filesystem.cpp.

References foedus::fs::Path::child_paths().

148  {
149  uint64_t count = 1;
150  std::vector< Path > child_paths = p.child_paths();
151  for (Path child : child_paths) {
152  count += remove_all(child);
153  }
154  remove(p);
155  return count;
156 }
uint64_t remove_all(const Path &p)
Recursively deletes a directory.
Definition: filesystem.cpp:148

Here is the call graph for this function:

bool foedus::fs::rename ( const Path old_path,
const Path new_path 
)
inline

Just a synonym of atomic_rename() to avoid confusion.

Definition at line 286 of file filesystem.hpp.

References foedus::fs::atomic_rename().

Referenced by foedus::fs::atomic_rename().

286  {
287  return atomic_rename(old_path, new_path);
288 }
bool atomic_rename(const Path &old_path, const Path &new_path)
Renames the old file to the new file with the POSIX atomic-rename semantics.
Definition: filesystem.cpp:199

Here is the call graph for this function:

Here is the caller graph for this function:

SpaceInfo foedus::fs::space ( const Path p)

Returns free space information for the device the file is on.

Definition at line 158 of file filesystem.cpp.

References foedus::fs::Path::c_str(), and foedus::fs::SpaceInfo::capacity_.

158  {
159  struct statfs vfs;
160  SpaceInfo info;
161  int ret = ::statfs(p.c_str(), &vfs);
162  if (ret == 0) {
163  info.capacity_ = static_cast<uint64_t>(vfs.f_blocks) * vfs.f_bsize;
164  info.free_ = static_cast<uint64_t>(vfs.f_bfree) * vfs.f_bsize;
165  info.available_ = static_cast<uint64_t>(vfs.f_bavail) * vfs.f_bsize;
166  } else {
167  info.available_ = 0;
168  info.capacity_ = 0;
169  info.free_ = 0;
170  }
171  return info;
172 }

Here is the call graph for this function:

FileStatus foedus::fs::status ( const Path p)

Returns the status of the file.

Definition at line 45 of file filesystem.cpp.

References foedus::fs::Path::c_str(), foedus::fs::kDirectoryFile, foedus::fs::kFileNotFound, foedus::fs::kRegularFile, foedus::fs::kStatusError, and foedus::fs::kTypeUnknown.

Referenced by foedus::storage::sequential::SequentialComposer::compose(), foedus::assorted::demangle_type_name(), foedus::fs::exists(), foedus::snapshot::LogMapper::handle_process(), foedus::soc::SocManagerPimpl::initialize_master(), foedus::EnginePimpl::initialize_once(), foedus::snapshot::MergeSort::initialize_once(), foedus::fs::is_directory(), foedus::fs::is_regular_file(), foedus::fs::remove(), foedus::soc::SocManagerPimpl::report_engine_fatal_error(), foedus::soc::SocManagerPimpl::wait_for_child_attach(), foedus::soc::SocManagerPimpl::wait_for_child_terminate(), foedus::soc::SocManagerPimpl::wait_for_children_module(), and foedus::soc::SocManagerPimpl::wait_for_master_module().

45  {
46  struct stat path_stat;
47  int ret = ::stat(p.c_str(), &path_stat);
48  if (ret != 0) {
49  // This is quite normal as we use this to check if a file exists. No message for it.
50  if (errno == ENOENT || errno == ENOTDIR) {
51  return FileStatus(kFileNotFound);
52  }
53  return FileStatus(kStatusError);
54  } else if (S_ISDIR(path_stat.st_mode)) {
55  return FileStatus(kDirectoryFile);
56  } else if (S_ISREG(path_stat.st_mode)) {
57  return FileStatus(kRegularFile);
58  }
59  return FileStatus(kTypeUnknown);
60 }

Here is the call graph for this function:

Here is the caller graph for this function:

std::string foedus::fs::unique_name ( uint64_t  differentiator = 0)

Equivalent to unique_path("%%%%-%%%%-%%%%-%%%%").

Definition at line 174 of file filesystem.cpp.

Referenced by foedus::externalize::Externalizable::save_to_file().

174  {
175  return unique_name("%%%%-%%%%-%%%%-%%%%", differentiator);
176 }
std::string unique_name(uint64_t differentiator=0)
Equivalent to unique_path("%%%%-%%%%-%%%%-%%%%").
Definition: filesystem.cpp:174

Here is the caller graph for this function:

std::string foedus::fs::unique_name ( const std::string &  model,
uint64_t  differentiator = 0 
)

Returns a randomly generated file name with the given template.

Parameters
[in]modelfile name template where % will be replaced with random hex numbers.
[in]differentiatoroptional parameter to further randomize this method.

We use std::chrono::high_resolution_clock::now() to get a random seed. However, even high_resolution_clock sometimes has low precision depending on environment. When you are concerned with a conflict (eg running many concurrent testcases), also give a differentiator.

Definition at line 177 of file filesystem.cpp.

177  {
178  const char* kHexChars = "0123456789abcdef";
179  uint64_t seed64 = std::chrono::high_resolution_clock::now().time_since_epoch().count();
180  seed64 += ::getpid(); // further use process ID to randomize. may help.
181  seed64 ^= differentiator;
182  uint32_t seed32 = (seed64 >> 32) ^ seed64;
183  std::string s(model);
184  for (size_t i = 0; i < s.size(); ++i) {
185  if (s[i] == '%') { // digit request
186  seed32 = ::rand_r(&seed32);
187  s[i] = kHexChars[seed32 & 0xf]; // convert to hex digit and replace
188  }
189  }
190  return s;
191 }