diff --git a/src/database/database.cpp b/src/database/database.cpp index 2e32f0b22..a971d5759 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -73,13 +73,13 @@ v3s16 MapDatabase::getIntegerAsBlock(s64 i) return pos; } -std::string MapDatabase::getBlockAsString(const v3bpos_t &pos) const { +std::string MapDatabase::getBlockAsString(const v3bpos_t &pos) { std::ostringstream os; os << "a" << pos.X << "," << pos.Y << "," << pos.Z; return os.str().c_str(); } -v3bpos_t MapDatabase::getStringAsBlock(const std::string &i) const { +v3bpos_t MapDatabase::getStringAsBlock(const std::string &i) { std::istringstream is(i); v3bpos_t pos; char c; diff --git a/src/database/database.h b/src/database/database.h index d0b07582a..c7fe664d9 100644 --- a/src/database/database.h +++ b/src/database/database.h @@ -47,8 +47,8 @@ class MapDatabase : public Database static s64 getBlockAsInteger(const v3s16 &pos); static v3s16 getIntegerAsBlock(s64 i); - std::string getBlockAsString(const v3pos_t &pos) const; - v3pos_t getStringAsBlock(const std::string &i) const; + static std::string getBlockAsString(const v3pos_t &pos); + static v3pos_t getStringAsBlock(const std::string &i); virtual void listAllLoadableBlocks(std::vector &dst) = 0; }; diff --git a/src/fm_abm.cpp b/src/fm_abm.cpp index 98ac0d17d..5b9c686c7 100644 --- a/src/fm_abm.cpp +++ b/src/fm_abm.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include "irr_v3d.h" #include "map.h" #include "profiler.h" @@ -185,7 +188,8 @@ void ABMHandler::apply(MapBlock *block, bool activate) std::lock_guard lock(block->abm_triggers_mutex); if (!block->abm_triggers) - block->abm_triggers = std::make_unique(); + block->abm_triggers = + std::make_unique(); block->abm_triggers->emplace_back( abm_trigger_one{i, p, c, active_object_count, @@ -334,6 +338,13 @@ size_t MapBlock::abmTriggersRun(ServerEnvironment *m_env, u32 time, bool activat } if (abm_triggers->empty()) abm_triggers.reset(); + + if (triggers_count) { + std::stringstream key; + key << "a" << getPos().X << "," << getPos().Y << "," << getPos().Z; + m_env->blocks_with_abm.put(key.str(), std::to_string(time)); + } + return triggers_count; } diff --git a/src/fm_server.cpp b/src/fm_server.cpp index c67a8e79a..b5b3d1035 100644 --- a/src/fm_server.cpp +++ b/src/fm_server.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include "database/database.h" #include "emerge.h" #include "irrTypes.h" #include "irr_v3d.h" @@ -327,6 +329,8 @@ class AbmWorldThread : public thread_pool return nullptr; } + int16_t abm_world_load_all = -1; // -1 : auto; 0 : disable; 1 : force + g_settings->getS16NoEx("abm_world_load_all", abm_world_load_all); u64 abm_world_throttle = m_server->isSingleplayer() ? 10 : 0; g_settings->getU64NoEx("abm_world_throttle", abm_world_throttle); u64 abm_world_max_clients = m_server->isSingleplayer() ? 1 : 0; @@ -345,24 +349,44 @@ class AbmWorldThread : public thread_pool if (!can_work()) { tracestream << "Abm world wait" << '\n'; - - std::this_thread::sleep_for(std::chrono::seconds(10)); + sleep(10); continue; } - std::vector loadable_blocks; + std::vector loadable_blocks; + + auto time_start = porting::getTimeMs(); + + if (abm_world_load_all <= 0) { +#if USE_LEVELDB + if (const auto it = m_server->getEnv() + .blocks_with_abm.database.new_iterator(); + it) { + for (it->SeekToFirst(); it->Valid(); it->Next()) { + const auto key = it->key().ToString(); + if (key.starts_with("a")) { + const v3bpos_t pos = MapDatabase::getStringAsBlock(key); + loadable_blocks.emplace_back(pos); + } + } + } +#endif + } - TimeTaker bll("Block list load", nullptr); + // Load whole world firts time, fill blocks_with_abm + if (abm_world_load_all && loadable_blocks.empty()) { + actionstream << "Abm world full load" << '\n'; + m_server->getEnv().getServerMap().listAllLoadableBlocks(loadable_blocks); + } - m_server->getEnv().getServerMap().listAllLoadableBlocks(loadable_blocks); const auto loadable_blocks_size = loadable_blocks.size(); infostream << "Abm world blocks " << loadable_blocks_size << " per " - << bll.getTimerTime() << " from " << abm_world_last - << " max_clients " << abm_world_max_clients << " throttle " - << abm_world_throttle << '\n'; + << (porting::getTimeMs() - time_start) / 1000 << " from " + << abm_world_last << " max_clients " << abm_world_max_clients + << " throttle " << abm_world_throttle << '\n'; size_t cur_n = 0, processed = 0, triggers_total = 0; - auto time_start = porting::getTimeMs(); + time_start = porting::getTimeMs(); const auto printstat = [&]() { auto time = porting::getTimeMs(); @@ -442,7 +466,7 @@ class AbmWorldThread : public thread_pool printstat(); abm_world_last = 0; - std::this_thread::sleep_for(std::chrono::seconds(60)); + sleep(60); } END_DEBUG_EXCEPTION_HANDLER return nullptr; @@ -554,6 +578,7 @@ void Server::maintenance_start() m_env->getServerMap().m_map_loading_enabled = false; // fmtodo: m_env->getServerMap().dbase->close(); m_env->m_key_value_storage.clear(); + m_env->blocks_with_abm.close(); stat.close(); actionstream << "Server: Starting maintenance: bases closed now." << std::endl; }; @@ -562,6 +587,7 @@ void Server::maintenance_end() { // fmtodo:m_env->getServerMap().dbase->open(); stat.open(); + m_env->blocks_with_abm.open(); m_env->getServerMap().m_map_saving_enabled = true; m_env->getServerMap().m_map_loading_enabled = true; m_emerge->startThreads(); diff --git a/src/server.cpp b/src/server.cpp index f8df36092..81d9f8b78 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1339,6 +1339,8 @@ int Server::save(float dtime, float dedicated_server_step, bool breakable) { m_env->saveMeta(); stat.save(); + m_env->blocks_with_abm.save(); + } save_break:; diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 0a5a8f3a7..99af6a2f5 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -1,4 +1,7 @@ set(server_SRCS + + ${CMAKE_CURRENT_SOURCE_DIR}/fm_key_value_cached.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/activeobjectmgr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/luaentity_sao.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mods.cpp diff --git a/src/server/fm_key_value_cached.cpp b/src/server/fm_key_value_cached.cpp new file mode 100644 index 000000000..10e71167b --- /dev/null +++ b/src/server/fm_key_value_cached.cpp @@ -0,0 +1,79 @@ +/* + This file is part of Freeminer. + + Freeminer is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Freeminer is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Freeminer. If not, see . +*/ + +//#include + +//#include "stat.h" +//#include "gettime.h" +//#include "log.h" + +#include "fm_key_value_cached.h" + +KeyValueCached::KeyValueCached(const std::string &savedir, const std::string &name) : + database(savedir, name){}; + +KeyValueCached::~KeyValueCached() +{ + save(); +}; + +void KeyValueCached::save() +{ + std::lock_guard lock(mutex); + for (const auto &ir : stats) { + //errorstream<<"stat saving: "< stats; + + KeyValueCached(const std::string &savedir, const std::string &name); + ~KeyValueCached(); + + void save(); + void unload(); + void open(); + void close(); + + const std::string &get(const std::string &key); + const std::string &put(const std::string &key, const std::string &value); + +private: + std::mutex mutex; +}; diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 5d71eef00..52ffb6f03 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -455,6 +455,7 @@ ServerEnvironment::ServerEnvironment(ServerMap *map, m_abmhandler(this), m_circuit(script_iface, map, server->ndef(), path_world), + blocks_with_abm(path_world, "abm_world"), m_map(map), m_script(script_iface), diff --git a/src/serverenvironment.h b/src/serverenvironment.h index cc32fb209..688216f69 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "irr_v3d.h" #include "map.h" +#include "server/fm_key_value_cached.h" #include "settings.h" #include "server/activeobjectmgr.h" #include "threading/concurrent_set.h" @@ -493,6 +494,7 @@ class ServerEnvironment final : public Environment u32 m_active_block_analyzed_last = 0; std::mutex m_max_lag_estimate_mutex; public: + KeyValueCached blocks_with_abm; size_t abm_world_last = 0; //end of freeminer diff --git a/src/stat.cpp b/src/stat.cpp index e2e4871c5..45810b904 100644 --- a/src/stat.cpp +++ b/src/stat.cpp @@ -19,21 +19,21 @@ #include "stat.h" #include "gettime.h" -//#include "log.h" - -Stat::Stat(std::string savedir) : - database(savedir, "stat") { +Stat::Stat(const std::string &savedir) : database(savedir, "stat") +{ update_time(); }; -Stat::~Stat() { +Stat::~Stat() +{ save(); }; -void Stat::save() { +void Stat::save() +{ std::lock_guard lock(mutex); - for(const auto & ir : stats) { + for (const auto &ir : stats) { //errorstream<<"stat saving: "<. */ -#ifndef STAT_H -#define STAT_H +#pragma once #include #include #include "key_value_storage.h" -#include "log.h" -typedef float stat_value; - -class Stat { +class Stat +{ public: + using stat_value = float; + KeyValueStorage database; std::unordered_map stats; // todo: make shared std::string day, week, month; - Stat(std::string savedir); + Stat(const std::string &savedir); ~Stat(); void save(); @@ -41,13 +40,13 @@ class Stat { void open(); void close(); - stat_value get(const std::string & key); - stat_value write_one(const std::string & key, const stat_value & value); - stat_value add(const std::string & key, const std::string & player = "", stat_value value = 1); + const stat_value &get(const std::string &key); + const stat_value &write_one(const std::string &key, const stat_value &value); + const stat_value &add( + const std::string &key, const std::string &player = "", stat_value value = 1); void update_time(); + private: std::mutex mutex; }; - -#endif diff --git a/src/threading/thread_pool.cpp b/src/threading/thread_pool.cpp index ba1a44a2b..75fb89ae9 100644 --- a/src/threading/thread_pool.cpp +++ b/src/threading/thread_pool.cpp @@ -4,21 +4,24 @@ #include "porting.h" thread_pool::thread_pool(const std::string &name, int priority) : - m_name(name), - m_priority(priority) { - requeststop = false; + m_name(name), m_priority(priority) +{ + request_stop = false; }; -thread_pool::~thread_pool() { +thread_pool::~thread_pool() +{ join(); }; -void thread_pool::func() { +void thread_pool::func() +{ reg(); run(); }; -void thread_pool::reg(const std::string &name, int priority) { +void thread_pool::reg(const std::string &name, int priority) +{ if (!name.empty()) m_name = name; @@ -31,60 +34,84 @@ void thread_pool::reg(const std::string &name, int priority) { porting::setThreadPriority(m_priority); }; -void thread_pool::start (int n) { +void thread_pool::start(const size_t n) +{ #if !NDEBUG - infostream << "start thread "<< m_name << " n="<