Fix a race-condition when two games have been started simultaneously and attempt to create the same replay directory, refs #3255.
Instead of triggering a debug-breakpoint, print a warning to stdout and succeed in the N'th retry when having started N processes simultaneously. Previously the problem had been addressed by using the processID in the directory name. This was SVN commit r17776.
This commit is contained in:
parent
4cda0b7040
commit
a32ed75bff
@ -130,7 +130,7 @@ Status GetDirectoryEntries(const OsPath& path, CFileInfos* files, DirectoryNames
|
||||
}
|
||||
|
||||
|
||||
Status CreateDirectories(const OsPath& path, mode_t mode)
|
||||
Status CreateDirectories(const OsPath& path, mode_t mode, bool breakpoint)
|
||||
{
|
||||
if(path.empty())
|
||||
return INFO::OK;
|
||||
@ -146,7 +146,7 @@ Status CreateDirectories(const OsPath& path, mode_t mode)
|
||||
// If we were passed a path ending with '/', strip the '/' now so that
|
||||
// we can consistently use Parent to find parent directory names
|
||||
if(path.IsDirectory())
|
||||
return CreateDirectories(path.Parent(), mode);
|
||||
return CreateDirectories(path.Parent(), mode, breakpoint);
|
||||
|
||||
RETURN_STATUS_IF_ERR(CreateDirectories(path.Parent(), mode));
|
||||
|
||||
@ -154,7 +154,10 @@ Status CreateDirectories(const OsPath& path, mode_t mode)
|
||||
if(wmkdir(path, mode) != 0)
|
||||
{
|
||||
debug_printf("CreateDirectories: failed to mkdir %s (mode %d)\n", path.string8().c_str(), mode);
|
||||
WARN_RETURN(StatusFromErrno());
|
||||
if (breakpoint)
|
||||
WARN_RETURN(StatusFromErrno());
|
||||
else
|
||||
return StatusFromErrno();
|
||||
}
|
||||
|
||||
return INFO::OK;
|
||||
|
@ -80,7 +80,7 @@ LIB_API Status GetDirectoryEntries(const OsPath& path, CFileInfos* files, Direct
|
||||
|
||||
// same as boost::filesystem::create_directories, except that mkdir is invoked with
|
||||
// <mode> instead of 0755.
|
||||
LIB_API Status CreateDirectories(const OsPath& path, mode_t mode);
|
||||
LIB_API Status CreateDirectories(const OsPath& path, mode_t mode, bool breakpoint = true);
|
||||
|
||||
LIB_API Status DeleteDirectory(const OsPath& dirPath);
|
||||
|
||||
|
@ -72,7 +72,6 @@ void CReplayLogger::StartGame(JS::MutableHandleValue attribs)
|
||||
|
||||
m_Directory = getDateIndexSubdirectory(VisualReplay::GetDirectoryName());
|
||||
debug_printf("Writing replay to %s\n", m_Directory.string8().c_str());
|
||||
CreateDirectories(m_Directory, 0700);
|
||||
|
||||
m_Stream = new std::ofstream(OsString(m_Directory / L"commands.txt").c_str(), std::ofstream::out | std::ofstream::trunc);
|
||||
*m_Stream << "start " << m_ScriptInterface.StringifyJSON(attribs, false) << "\n";
|
||||
|
@ -201,6 +201,10 @@ OsPath getDateIndexSubdirectory(const OsPath& parentDir)
|
||||
const std::time_t timestamp = std::time(nullptr);
|
||||
const struct std::tm* now = std::localtime(×tamp);
|
||||
|
||||
// Two processes executing this simultaneously might attempt to create the same directory.
|
||||
int tries = 0;
|
||||
const int maxTries = 10;
|
||||
|
||||
int i = 0;
|
||||
OsPath path;
|
||||
char directory[256];
|
||||
@ -209,7 +213,14 @@ OsPath getDateIndexSubdirectory(const OsPath& parentDir)
|
||||
{
|
||||
sprintf(directory, "%04d-%02d-%02d_%04d", now->tm_year+1900, now->tm_mon+1, now->tm_mday, ++i);
|
||||
path = parentDir / CStr(directory);
|
||||
} while (DirectoryExists(path) || FileExists(path));
|
||||
|
||||
if (DirectoryExists(path) || FileExists(path))
|
||||
continue;
|
||||
|
||||
if (CreateDirectories(path, 0700, ++tries > maxTries) == INFO::OK)
|
||||
break;
|
||||
|
||||
} while(tries <= maxTries);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
@ -298,7 +298,6 @@ void CSimulation2Impl::ReportSerializationFailure(
|
||||
{
|
||||
const OsPath path = getDateIndexSubdirectory(psLogDir() / "serializationtest");
|
||||
debug_printf("Writing serializationtest-data to %s\n", path.string8().c_str());
|
||||
CreateDirectories(path, 0700);
|
||||
|
||||
// Clean up obsolete files from previous runs
|
||||
wunlink(path / "hash.before.a");
|
||||
@ -554,7 +553,6 @@ void CSimulation2Impl::DumpState()
|
||||
std::stringstream name;\
|
||||
name << std::setw(5) << std::setfill('0') << m_TurnNumber << ".txt";
|
||||
const OsPath path = m_OOSLogPath / name.str();
|
||||
CreateDirectories(path.Parent(), 0700);
|
||||
std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc);
|
||||
|
||||
file << "State hash: " << std::hex;
|
||||
|
Loading…
Reference in New Issue
Block a user