1
0
forked from 0ad/0ad

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:
elexis 2016-02-19 11:22:32 +00:00
parent 4cda0b7040
commit a32ed75bff
5 changed files with 19 additions and 8 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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";

View File

@ -201,6 +201,10 @@ OsPath getDateIndexSubdirectory(const OsPath& parentDir)
const std::time_t timestamp = std::time(nullptr);
const struct std::tm* now = std::localtime(&timestamp);
// 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;
}

View File

@ -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;