mirror of
https://github.com/DarkflameUniverse/DarkflameServer
synced 2024-08-30 18:43:58 +00:00
Merge pull request #499 from EmosewaMC/master-server-shutdown
Dramatically speed up server shutdown and specify database destruction source in logging message
This commit is contained in:
commit
f45cb380e0
@ -57,7 +57,7 @@ int main(int argc, char** argv) {
|
|||||||
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||||
} catch (sql::SQLException& ex) {
|
} catch (sql::SQLException& ex) {
|
||||||
Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s\n", ex.what());
|
Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s\n", ex.what());
|
||||||
Database::Destroy();
|
Database::Destroy("AuthServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
delete Game::logger;
|
delete Game::logger;
|
||||||
return 0;
|
return 0;
|
||||||
@ -143,11 +143,12 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Delete our objects here:
|
//Delete our objects here:
|
||||||
Database::Destroy();
|
Database::Destroy("AuthServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
delete Game::logger;
|
delete Game::logger;
|
||||||
|
|
||||||
return 0;
|
exit(EXIT_SUCCESS);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
dLogger * SetupLogger() {
|
dLogger * SetupLogger() {
|
||||||
|
@ -61,7 +61,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
catch (sql::SQLException& ex) {
|
catch (sql::SQLException& ex) {
|
||||||
Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s\n", ex.what());
|
Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s\n", ex.what());
|
||||||
Database::Destroy();
|
Database::Destroy("ChatServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
delete Game::logger;
|
delete Game::logger;
|
||||||
return 0;
|
return 0;
|
||||||
@ -150,11 +150,12 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Delete our objects here:
|
//Delete our objects here:
|
||||||
Database::Destroy();
|
Database::Destroy("ChatServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
delete Game::logger;
|
delete Game::logger;
|
||||||
|
|
||||||
return 0;
|
exit(EXIT_SUCCESS);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
dLogger * SetupLogger() {
|
dLogger * SetupLogger() {
|
||||||
|
@ -26,9 +26,10 @@ void Database::Connect(const string& host, const string& database, const string&
|
|||||||
con->setClientOption("MYSQL_OPT_RECONNECT", &myTrue);
|
con->setClientOption("MYSQL_OPT_RECONNECT", &myTrue);
|
||||||
} //Connect
|
} //Connect
|
||||||
|
|
||||||
void Database::Destroy() {
|
void Database::Destroy(std::string source) {
|
||||||
if (!con) return;
|
if (!con) return;
|
||||||
Game::logger->Log("Database", "Destroying MySQL connection!\n");
|
if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!\n", source.c_str());
|
||||||
|
else Game::logger->Log("Database", "Destroying MySQL connection!\n");
|
||||||
con->close();
|
con->close();
|
||||||
delete con;
|
delete con;
|
||||||
} //Destroy
|
} //Destroy
|
||||||
|
@ -22,7 +22,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static void Connect(const std::string& host, const std::string& database, const std::string& username, const std::string& password);
|
static void Connect(const std::string& host, const std::string& database, const std::string& username, const std::string& password);
|
||||||
static void Destroy();
|
static void Destroy(std::string source="");
|
||||||
static sql::Statement* CreateStmt();
|
static sql::Statement* CreateStmt();
|
||||||
static sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
|
static sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
|
||||||
};
|
};
|
||||||
|
@ -161,6 +161,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
const std::map<LWOOBJID, LWOOBJID>& GetModels() const;
|
const std::map<LWOOBJID, LWOOBJID>& GetModels() const;
|
||||||
|
|
||||||
|
LWOCLONEID GetCloneId() { return clone_Id; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* This
|
* This
|
||||||
|
@ -47,6 +47,7 @@ namespace Game {
|
|||||||
|
|
||||||
bool shutdownSequenceStarted = false;
|
bool shutdownSequenceStarted = false;
|
||||||
void ShutdownSequence();
|
void ShutdownSequence();
|
||||||
|
int FinalizeShutdown();
|
||||||
dLogger* SetupLogger();
|
dLogger* SetupLogger();
|
||||||
void StartAuthServer();
|
void StartAuthServer();
|
||||||
void StartChatServer();
|
void StartChatServer();
|
||||||
@ -168,7 +169,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
std::cout << "Account created successfully!\n";
|
std::cout << "Account created successfully!\n";
|
||||||
|
|
||||||
Database::Destroy();
|
Database::Destroy("MasterServer");
|
||||||
delete Game::logger;
|
delete Game::logger;
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
@ -318,13 +319,8 @@ int main(int argc, char** argv) {
|
|||||||
t += std::chrono::milliseconds(highFrameRate);
|
t += std::chrono::milliseconds(highFrameRate);
|
||||||
std::this_thread::sleep_until(t);
|
std::this_thread::sleep_until(t);
|
||||||
}
|
}
|
||||||
|
FinalizeShutdown();
|
||||||
//Delete our objects here:
|
exit(EXIT_SUCCESS);
|
||||||
Database::Destroy();
|
|
||||||
delete Game::im;
|
|
||||||
delete Game::server;
|
|
||||||
delete Game::logger;
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -664,7 +660,7 @@ void HandlePacket(Packet* packet) {
|
|||||||
RakNet::BitStream inStream(packet->data, packet->length, false);
|
RakNet::BitStream inStream(packet->data, packet->length, false);
|
||||||
uint64_t header = inStream.Read(header);
|
uint64_t header = inStream.Read(header);
|
||||||
|
|
||||||
auto* instance =Game::im->GetInstanceBySysAddr(packet->systemAddress);
|
auto* instance = Game::im->GetInstanceBySysAddr(packet->systemAddress);
|
||||||
|
|
||||||
if (instance == nullptr) {
|
if (instance == nullptr) {
|
||||||
return;
|
return;
|
||||||
@ -745,12 +741,20 @@ void ShutdownSequence() {
|
|||||||
auto ticks = 0;
|
auto ticks = 0;
|
||||||
|
|
||||||
if (!Game::im) {
|
if (!Game::im) {
|
||||||
exit(0);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds...\n");
|
Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds...\n");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
|
auto packet = Game::server->Receive();
|
||||||
|
if (packet) {
|
||||||
|
HandlePacket(packet);
|
||||||
|
Game::server->DeallocatePacket(packet);
|
||||||
|
packet = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto done = true;
|
auto done = true;
|
||||||
|
|
||||||
for (auto* instance : Game::im->GetInstances()) {
|
for (auto* instance : Game::im->GetInstances()) {
|
||||||
@ -764,6 +768,7 @@ void ShutdownSequence() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
|
Game::logger->Log("MasterServer", "Finished shutting down MasterServer!\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -773,9 +778,21 @@ void ShutdownSequence() {
|
|||||||
ticks++;
|
ticks++;
|
||||||
|
|
||||||
if (ticks == 600 * 6) {
|
if (ticks == 600 * 6) {
|
||||||
|
Game::logger->Log("MasterServer", "Finished shutting down by timeout!\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(0);
|
FinalizeShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int FinalizeShutdown() {
|
||||||
|
//Delete our objects here:
|
||||||
|
Database::Destroy("MasterServer");
|
||||||
|
delete Game::im;
|
||||||
|
delete Game::server;
|
||||||
|
delete Game::logger;
|
||||||
|
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -77,6 +77,9 @@ bool chatConnected = false;
|
|||||||
bool worldShutdownSequenceStarted = false;
|
bool worldShutdownSequenceStarted = false;
|
||||||
bool worldShutdownSequenceComplete = false;
|
bool worldShutdownSequenceComplete = false;
|
||||||
void WorldShutdownSequence();
|
void WorldShutdownSequence();
|
||||||
|
void WorldShutdownProcess(uint32_t zoneId);
|
||||||
|
void FinalizeShutdown();
|
||||||
|
void SendShutdownMessageToMaster();
|
||||||
|
|
||||||
dLogger* SetupLogger(int zoneID, int instanceID);
|
dLogger* SetupLogger(int zoneID, int instanceID);
|
||||||
void HandlePacketChat(Packet* packet);
|
void HandlePacketChat(Packet* packet);
|
||||||
@ -475,80 +478,16 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (worldShutdownSequenceStarted && !worldShutdownSequenceComplete)
|
if (worldShutdownSequenceStarted && !worldShutdownSequenceComplete) {
|
||||||
{
|
WorldShutdownProcess(zoneID);
|
||||||
if (framesSinceShutdownSequence == 0) {
|
break;
|
||||||
|
|
||||||
ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, u"Server shutting down...", true);
|
|
||||||
|
|
||||||
for (auto i = 0; i < Game::server->GetReplicaManager()->GetParticipantCount(); ++i)
|
|
||||||
{
|
|
||||||
const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(i);
|
|
||||||
|
|
||||||
auto* entity = Player::GetPlayer(player);
|
|
||||||
|
|
||||||
if (entity != nullptr && entity->GetCharacter() != nullptr)
|
|
||||||
{
|
|
||||||
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
|
||||||
|
|
||||||
if (skillComponent != nullptr)
|
|
||||||
{
|
|
||||||
skillComponent->Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
entity->GetCharacter()->SaveXMLToDatabase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PropertyManagementComponent::Instance() != nullptr) {
|
|
||||||
ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, u"Property data saved...", true);
|
|
||||||
PropertyManagementComponent::Instance()->Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, u"Character data saved...", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
framesSinceShutdownSequence++;
|
|
||||||
|
|
||||||
if (framesSinceShutdownSequence == 100)
|
|
||||||
{
|
|
||||||
while (Game::server->GetReplicaManager()->GetParticipantCount() > 0)
|
|
||||||
{
|
|
||||||
const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(0);
|
|
||||||
|
|
||||||
Game::server->Disconnect(player, SERVER_DISCON_KICK);
|
|
||||||
}
|
|
||||||
|
|
||||||
CBITSTREAM;
|
|
||||||
PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN_RESPONSE);
|
|
||||||
Game::server->SendToMaster(&bitStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (framesSinceShutdownSequence == 300)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Metrics::AddMeasurement(MetricVariable::CPUTime, (1e6 * (1000.0 * (std::clock() - metricCPUTimeStart))) / CLOCKS_PER_SEC);
|
Metrics::AddMeasurement(MetricVariable::CPUTime, (1e6 * (1000.0 * (std::clock() - metricCPUTimeStart))) / CLOCKS_PER_SEC);
|
||||||
Metrics::EndMeasurement(MetricVariable::Frame);
|
Metrics::EndMeasurement(MetricVariable::Frame);
|
||||||
}
|
}
|
||||||
|
FinalizeShutdown();
|
||||||
//Delete our objects here:
|
return EXIT_SUCCESS;
|
||||||
if (Game::physicsWorld) Game::physicsWorld = nullptr;
|
|
||||||
if (Game::zoneManager) delete Game::zoneManager;
|
|
||||||
|
|
||||||
Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)\n", Game::server->GetZoneID(), instanceID);
|
|
||||||
|
|
||||||
Metrics::Clear();
|
|
||||||
Database::Destroy();
|
|
||||||
delete Game::chatFilter;
|
|
||||||
delete Game::server;
|
|
||||||
delete Game::logger;
|
|
||||||
|
|
||||||
worldShutdownSequenceComplete = true;
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dLogger * SetupLogger(int zoneID, int instanceID) {
|
dLogger * SetupLogger(int zoneID, int instanceID) {
|
||||||
@ -1279,35 +1218,75 @@ void HandlePacket(Packet* packet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldShutdownSequence()
|
void WorldShutdownProcess(uint32_t zoneId) {
|
||||||
{
|
Game::logger->Log("WorldServer", "Saving map %i instance %i\n", zoneId, instanceID);
|
||||||
if (worldShutdownSequenceStarted || worldShutdownSequenceComplete)
|
for (auto i = 0; i < Game::server->GetReplicaManager()->GetParticipantCount(); ++i) {
|
||||||
{
|
const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(i);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
worldShutdownSequenceStarted = true;
|
auto* entity = Player::GetPlayer(player);
|
||||||
|
Game::logger->Log("WorldServer", "Saving data!\n");
|
||||||
|
if (entity != nullptr && entity->GetCharacter() != nullptr) {
|
||||||
|
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
||||||
|
|
||||||
auto t = std::chrono::high_resolution_clock::now();
|
if (skillComponent != nullptr) {
|
||||||
auto ticks = 0;
|
skillComponent->Reset();
|
||||||
|
}
|
||||||
|
std::string message = "Saving character " + entity->GetCharacter()->GetName() + "...\n";
|
||||||
|
Game::logger->Log("WorldServer", message);
|
||||||
|
entity->GetCharacter()->SaveXMLToDatabase();
|
||||||
|
message = "Character data for " + entity->GetCharacter()->GetName() + " was saved!\n";
|
||||||
|
Game::logger->Log("WorldServer", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Game::logger->Log("WorldServer", "Attempting to shutdown world, zone (%i), instance (%i), max 10 seconds...\n", Game::server->GetZoneID(), instanceID);
|
if (PropertyManagementComponent::Instance() != nullptr) {
|
||||||
|
Game::logger->Log("WorldServer", "Saving ALL property data for zone %i clone %i!\n", zoneId, PropertyManagementComponent::Instance()->GetCloneId());
|
||||||
|
PropertyManagementComponent::Instance()->Save();
|
||||||
|
Game::logger->Log("WorldServer", "ALL property data saved for zone %i clone %i!\n", zoneId, PropertyManagementComponent::Instance()->GetCloneId());
|
||||||
|
}
|
||||||
|
|
||||||
while (true)
|
Game::logger->Log("WorldServer", "ALL DATA HAS BEEN SAVED FOR ZONE %i INSTANCE %i!\n", zoneId, instanceID);
|
||||||
{
|
|
||||||
if (worldShutdownSequenceStarted)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
t += std::chrono::milliseconds(highFrameRate);
|
while (Game::server->GetReplicaManager()->GetParticipantCount() > 0) {
|
||||||
std::this_thread::sleep_until(t);
|
const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(0);
|
||||||
|
|
||||||
ticks++;
|
Game::server->Disconnect(player, SERVER_DISCON_KICK);
|
||||||
|
}
|
||||||
if (ticks == 600)
|
SendShutdownMessageToMaster();
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldShutdownSequence() {
|
||||||
|
if (worldShutdownSequenceStarted || worldShutdownSequenceComplete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
worldShutdownSequenceStarted = true;
|
||||||
|
|
||||||
|
Game::logger->Log("WorldServer", "Zone (%i) instance (%i) shutting down outside of main loop!\n", Game::server->GetZoneID(), instanceID);
|
||||||
|
WorldShutdownProcess(Game::server->GetZoneID());
|
||||||
|
FinalizeShutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FinalizeShutdown() {
|
||||||
|
//Delete our objects here:
|
||||||
|
if (Game::physicsWorld) Game::physicsWorld = nullptr;
|
||||||
|
if (Game::zoneManager) delete Game::zoneManager;
|
||||||
|
|
||||||
|
Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)\n", Game::server->GetZoneID(), instanceID);
|
||||||
|
|
||||||
|
Metrics::Clear();
|
||||||
|
Database::Destroy("WorldServer");
|
||||||
|
delete Game::chatFilter;
|
||||||
|
delete Game::server;
|
||||||
|
delete Game::logger;
|
||||||
|
|
||||||
|
worldShutdownSequenceComplete = true;
|
||||||
|
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendShutdownMessageToMaster() {
|
||||||
|
CBITSTREAM;
|
||||||
|
PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN_RESPONSE);
|
||||||
|
Game::server->SendToMaster(&bitStream);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user