aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Scripting/ScriptReloadMgr.cpp
diff options
context:
space:
mode:
authorNaios <naios-dev@live.de>2016-04-17 21:31:04 +0200
committerNaios <naios-dev@live.de>2016-04-18 22:11:23 +0200
commit2809f11839ff0fd4eec45b2e116811b0698dd05b (patch)
tree1710d1d2e36285cefbd99b82b0b49edf503ad4ad /src/server/game/Scripting/ScriptReloadMgr.cpp
parenta679829050087e6c98aba624a2d6903af5f1728b (diff)
Core/Scripting: Use the systems temporary path for caching shared libs
* Disables the shared library caching on platforms completely which never block files on usage (like linux). (cherry picked from commit 081720b5dd5a80aa77181712d85d309d64d3ec03)
Diffstat (limited to 'src/server/game/Scripting/ScriptReloadMgr.cpp')
-rw-r--r--src/server/game/Scripting/ScriptReloadMgr.cpp170
1 files changed, 119 insertions, 51 deletions
diff --git a/src/server/game/Scripting/ScriptReloadMgr.cpp b/src/server/game/Scripting/ScriptReloadMgr.cpp
index 5b492306cd8..6862125369b 100644
--- a/src/server/game/Scripting/ScriptReloadMgr.cpp
+++ b/src/server/game/Scripting/ScriptReloadMgr.cpp
@@ -56,6 +56,7 @@ ScriptReloadMgr* ScriptReloadMgr::instance()
#include "Config.h"
#include "BuiltInConfig.h"
#include "ScriptMgr.h"
+#include "SHA1.h"
#include "StartProcess.h"
#include "MPSCQueue.h"
#include "GitRevision.h"
@@ -64,8 +65,10 @@ namespace fs = boost::filesystem;
#ifdef _WIN32
#include <windows.h>
+ #define HOTSWAP_PLATFORM_REQUIRES_CACHING
#else // Posix
#include <dlfcn.h>
+ // #define HOTSWAP_PLATFORM_REQUIRES_CACHING
#endif
// Promote the sScriptReloadMgr to a HotSwapScriptReloadMgr
@@ -102,10 +105,10 @@ typedef void* HandleType;
class SharedLibraryUnloader
{
public:
- SharedLibraryUnloader()
- : _path() { }
- explicit SharedLibraryUnloader(fs::path const& path)
- : _path(path) { }
+ explicit SharedLibraryUnloader(fs::path path)
+ : path_(std::move(path)) { }
+ SharedLibraryUnloader(fs::path path, Optional<fs::path> cache_path)
+ : path_(std::move(path)), cache_path_(std::move(cache_path)) { }
void operator() (HandleType handle) const
{
@@ -119,26 +122,37 @@ public:
if (!success)
{
TC_LOG_ERROR("scripts.hotswap", "Failed to unload (syscall) the shared library \"%s\".",
- _path.generic_string().c_str());
+ path_.generic_string().c_str());
return;
}
- boost::system::error_code error;
- if (fs::remove(_path, error))
+ /// When the shared library was cached delete it's shared version
+ if (cache_path_)
{
- TC_LOG_TRACE("scripts.hotswap", "Lazy unloaded and deleted the shared library \"%s\".",
- _path.generic_string().c_str());
+ boost::system::error_code error;
+ if (!fs::remove(*cache_path_, error))
+ {
+ TC_LOG_ERROR("scripts.hotswap", "Failed to delete the cached shared library \"%s\" (%s).",
+ cache_path_->generic_string().c_str(), error.message().c_str());
+
+ return;
+ }
+
+ TC_LOG_TRACE("scripts.hotswap", "Lazy unloaded the shared library \"%s\" "
+ "and deleted it's cached version at \"%s\"",
+ path_.generic_string().c_str(), cache_path_->generic_string().c_str());
}
else
{
- TC_LOG_ERROR("scripts.hotswap", "Failed to delete the shared library \"%s\" (%s).",
- _path.generic_string().c_str(), error.message().c_str());
+ TC_LOG_TRACE("scripts.hotswap", "Lazy unloaded the shared library \"%s\".",
+ path_.generic_string().c_str());
}
}
private:
- fs::path _path;
+ fs::path const path_;
+ Optional<fs::path> const cache_path_;
};
typedef std::unique_ptr<typename std::remove_pointer<HandleType>::type, SharedLibraryUnloader> HandleHolder;
@@ -165,7 +179,8 @@ public:
ScriptModule& operator= (ScriptModule const&) = delete;
ScriptModule& operator= (ScriptModule&& right) = delete;
- static Optional<std::shared_ptr<ScriptModule>> CreateFromPath(fs::path const& path);
+ static Optional<std::shared_ptr<ScriptModule>>
+ CreateFromPath(fs::path const& path, Optional<fs::path> cache_path);
char const* GetScriptModuleRevisionHash() const override
{
@@ -215,23 +230,41 @@ static bool GetFunctionFromSharedLibrary(HandleType handle, std::string const& n
}
// Load a shared library from the given path.
-Optional<std::shared_ptr<ScriptModule>> ScriptModule::CreateFromPath(fs::path const& path)
+Optional<std::shared_ptr<ScriptModule>>
+ ScriptModule::CreateFromPath(fs::path const& path, Optional<fs::path> cache_path)
{
+ auto const load_path = [&] () -> fs::path {
+ if (cache_path)
+ return *cache_path;
+ else
+ return path;
+ }();
+
#ifdef _WIN32
- HandleType handle = LoadLibrary(path.generic_string().c_str());
+ HandleType handle = LoadLibrary(load_path.generic_string().c_str());
#else // Posix
- HandleType handle = dlopen(path.c_str(), RTLD_LAZY);
+ HandleType handle = dlopen(load_path.generic_string().c_str(), RTLD_LAZY);
#endif
if (!handle)
{
- TC_LOG_ERROR("scripts.hotswap", "Could not load the shared library \"%s\" for reading.",
- path.generic_string().c_str());
+ if (cache_path)
+ {
+ TC_LOG_ERROR("scripts.hotswap", "Could not dynamic load the shared library \"%s\" "
+ "(the library is cached at %s)",
+ path.generic_string().c_str(), cache_path->generic_string().c_str());
+ }
+ else
+ {
+ TC_LOG_ERROR("scripts.hotswap", "Could not dynamic load the shared library \"%s\".",
+ path.generic_string().c_str());
+ }
+
return boost::none;
}
// Use RAII to release the library on failure.
- HandleHolder holder(handle, SharedLibraryUnloader(path));
+ HandleHolder holder(handle, SharedLibraryUnloader(path, std::move(cache_path)));
GetScriptModuleRevisionHashType getScriptModuleRevisionHash;
AddScriptsType addScripts;
@@ -357,7 +390,7 @@ static bool IsDebuggerBlockingRebuild()
///
/// This class manages shared library loading/unloading through watching
/// the script module directory. Loaded shared libraries are mirrored
-/// into a .cache subdirectory to allow lazy unloading as long as
+/// into a cache subdirectory to allow lazy unloading as long as
/// the shared library is still used which is useful for scripts
/// which can't be instantly replaced like spells or instances.
/// Several modules which reference different versions can be kept loaded
@@ -545,28 +578,28 @@ public:
}
}
- // Get the cache directory path
- fs::path const cache_path = []
- {
- auto path = fs::absolute(sScriptReloadMgr->GetLibraryDirectory());
- path /= ".cache";
- return path;
- }();
+ #ifdef HOTSWAP_PLATFORM_REQUIRES_CACHING
+
+ temporary_cache_path_ = CalculateTemporaryCachePath();
// We use the boost filesystem function versions which accept
// an error code to prevent it from throwing exceptions.
boost::system::error_code code;
- if ((!fs::exists(cache_path, code) || (fs::remove_all(cache_path, code) > 0)) &&
- !fs::create_directory(cache_path, code))
+ if ((!fs::exists(temporary_cache_path_, code)
+ || (fs::remove_all(temporary_cache_path_, code) > 0)) &&
+ !fs::create_directory(temporary_cache_path_, code))
{
- TC_LOG_ERROR("scripts.hotswap", "Couldn't create the cache directory \"%s\".",
- cache_path.generic_string().c_str());
+ TC_LOG_ERROR("scripts.hotswap", "Couldn't create the cache directory at \"%s\".",
+ temporary_cache_path_.generic_string().c_str());
+
return;
}
// Used to silent compiler warnings
(void)code;
+ #endif // #ifdef HOTSWAP_PLATFORM_REQUIRES_CACHING
+
// Correct the CMake prefix when needed
if (sWorld->getBoolConfig(CONFIG_HOTSWAP_PREFIX_CORRECTION_ENABLED))
DoCMakePrefixCorrectionIfNeeded();
@@ -698,6 +731,32 @@ private:
_fileWatcher.watch();
}
+ static fs::path CalculateTemporaryCachePath()
+ {
+ auto path = fs::temp_directory_path();
+
+ path /= Trinity::StringFormat("tc_script_cache_%s_%s",
+ GitRevision::GetBranch(),
+ CalculateSHA1Hash(sConfigMgr->GetFilename()).c_str());
+
+ return path;
+ }
+
+ fs::path GenerateUniquePathForLibraryInCache(fs::path path)
+ {
+ ASSERT(!temporary_cache_path_.empty(),
+ "The temporary cache path wasn't set!");
+
+ // Create the cache path and increment the library counter to use an unique name for each library
+ auto cache_path = temporary_cache_path_;
+ cache_path /= Trinity::StringFormat("%s.%u%s",
+ path.stem().generic_string().c_str(),
+ _unique_library_name_counter++,
+ path.extension().generic_string().c_str());
+
+ return cache_path;
+ }
+
/// Updates the current state of the given source path
void UpdateSourceChangeRequest(std::string const& module_name,
fs::path const& path,
@@ -778,31 +837,37 @@ private:
ASSERT(_running_script_module_names.find(path) == _running_script_module_names.end(),
"Can't load a module which is running already!");
- // Create the cache path and increment the library counter to use an unique name for each library
- fs::path cache_path = fs::absolute(sScriptReloadMgr->GetLibraryDirectory());
- cache_path /= ".cache";
- cache_path /= Trinity::StringFormat("%s.%u%s",
- path.stem().generic_string().c_str(),
- _unique_library_name_counter++,
- path.extension().generic_string().c_str());
+ Optional<fs::path> cache_path;
+
+ #ifdef HOTSWAP_PLATFORM_REQUIRES_CACHING
+
+ // Copy the shared library into a cache on platforms which lock files on use (windows).
+ cache_path = GenerateUniquePathForLibraryInCache(path);
- boost::system::error_code code;
- fs::copy_file(path, cache_path, fs::copy_option::fail_if_exists, code);
- if (code)
{
- TC_LOG_FATAL("scripts.hotswap", ">> Failed to create cache entry for module "
- "\"%s\" at \"%s\" with reason (\"%s\")!",
- path.filename().generic_string().c_str(), cache_path.generic_string().c_str(),
- code.message().c_str());
+ boost::system::error_code code;
+ fs::copy_file(path, *cache_path, fs::copy_option::fail_if_exists, code);
+ if (code)
+ {
+ TC_LOG_FATAL("scripts.hotswap", ">> Failed to create cache entry for module "
+ "\"%s\" at \"%s\" with reason (\"%s\")!",
+ path.filename().generic_string().c_str(), cache_path->generic_string().c_str(),
+ code.message().c_str());
+
+ // Find a better solution for this but it's much better
+ // to start the core without scripts
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+ ABORT();
+ return;
+ }
- // Find a better solution for this but it's much better
- // to start the core without scripts
- std::this_thread::sleep_for(std::chrono::seconds(5));
- ABORT();
- return;
+ TC_LOG_TRACE("scripts.hotswap", ">> Copied the shared library \"%s\" to \"%s\" for caching.",
+ path.filename().generic_string().c_str(), cache_path->generic_string().c_str());
}
- auto module = ScriptModule::CreateFromPath(cache_path);
+ #endif // #ifdef HOTSWAP_PLATFORM_REQUIRES_CACHING
+
+ auto module = ScriptModule::CreateFromPath(path, cache_path);
if (!module)
{
TC_LOG_FATAL("scripts.hotswap", ">> Failed to load script module \"%s\"!",
@@ -1348,6 +1413,9 @@ private:
// Is true when the build job dispatcher should stop after
// the current job has finished
bool terminate_early;
+
+ // The path to the tc_scripts temporary cache
+ fs::path temporary_cache_path_;
};
/// Maps efsw actions to strings