diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp index acc043e5f..c408146b8 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp @@ -119,9 +119,27 @@ bool WinsockNetLayer::Initialize() return true; } -void WinsockNetLayer::Shutdown() +void WinsockNetLayer::StopListening() { StopAdvertising(); + + s_active = false; + if (s_listenSocket != INVALID_SOCKET) + { + closesocket(s_listenSocket); + s_listenSocket = INVALID_SOCKET; + } + if (s_acceptThread != nullptr) + { + WaitForSingleObject(s_acceptThread, 2000); + CloseHandle(s_acceptThread); + s_acceptThread = nullptr; + } +} + +void WinsockNetLayer::Shutdown() +{ + StopListening(); StopDiscovery(); s_joinCancel = true; @@ -133,29 +151,14 @@ void WinsockNetLayer::Shutdown() } s_joinState = eJoinState_Idle; - s_active = false; s_connected = false; - if (s_listenSocket != INVALID_SOCKET) - { - closesocket(s_listenSocket); - s_listenSocket = INVALID_SOCKET; - } - if (s_hostConnectionSocket != INVALID_SOCKET) { closesocket(s_hostConnectionSocket); s_hostConnectionSocket = INVALID_SOCKET; } - // Stop accept loop first so no new RecvThread can be created while shutting down. - if (s_acceptThread != nullptr) - { - WaitForSingleObject(s_acceptThread, 2000); - CloseHandle(s_acceptThread); - s_acceptThread = nullptr; - } - std::vector recvThreads; EnterCriticalSection(&s_connectionsLock); for (size_t i = 0; i < s_connections.size(); i++) diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h index 8a11e391d..ac049d9da 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h @@ -67,6 +67,7 @@ class WinsockNetLayer public: static bool Initialize(); static void Shutdown(); + static void StopListening(); static bool HostGame(int port, const char* bindIp = nullptr); static bool JoinGame(const char* ip, int port); diff --git a/Minecraft.Server/Windows64/ServerMain.cpp b/Minecraft.Server/Windows64/ServerMain.cpp index 4ab288f51..d56d31da5 100644 --- a/Minecraft.Server/Windows64/ServerMain.cpp +++ b/Minecraft.Server/Windows64/ServerMain.cpp @@ -705,6 +705,7 @@ int main(int argc, char **argv) LogWorldIO("Waiting for autosave to complete..."); } + WinsockNetLayer::StopListening(); MinecraftServer::HaltServer(); if (g_NetworkManager.ServerStoppedValid()) @@ -719,9 +720,22 @@ int main(int argc, char **argv) waitThread.WaitForCompletion(INFINITE); } + DWORD bgWaitStart = GetTickCount(); + DWORD lastHeartbeat = bgWaitStart; + if (ConsoleSaveFileOriginal::hasPendingBackgroundSave()) + { + LogInfof("shutdown", "Waiting for background save to complete..."); + } + while (ConsoleSaveFileOriginal::hasPendingBackgroundSave()) { TickCoreSystems(); + DWORD now = GetTickCount(); + if ((LONG)(now - lastHeartbeat) >= 5000) + { + LogInfof("shutdown", "waiting for background save to complete... (%u sec elapsed)", (now - bgWaitStart) / 1000); + lastHeartbeat = now; + } Sleep(10); } diff --git a/Minecraft.World/ConsoleSaveFileOriginal.cpp b/Minecraft.World/ConsoleSaveFileOriginal.cpp index 4d03c955d..f2ccc44f6 100644 --- a/Minecraft.World/ConsoleSaveFileOriginal.cpp +++ b/Minecraft.World/ConsoleSaveFileOriginal.cpp @@ -731,20 +731,37 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail ) s_bgSaveActive.store(true, std::memory_order_release); std::thread([snap, fileSize, thumb, thumbSz, meta, metaLen, this]() { + app.DebugPrintf("bg-save: thread started, fileSize=%u (%.1f MB)\n", fileSize, fileSize / (1024.0f * 1024.0f)); + unsigned int compLen = fileSize + 8; + app.DebugPrintf("bg-save: AllocateSaveData(%u) attempt 1\n", compLen); byte *buf = static_cast(StorageManager.AllocateSaveData(compLen)); if (!buf) { - // FAIL!! attempt precalc + app.DebugPrintf("bg-save: first alloc failed, computing compressed size...\n"); compLen = 0; + LARGE_INTEGER pcFreq, pcStart, pcEnd; + QueryPerformanceFrequency(&pcFreq); + QueryPerformanceCounter(&pcStart); Compression::getCompression()->Compress(nullptr, &compLen, snap, fileSize); + QueryPerformanceCounter(&pcEnd); + float precalcSec = (float)(pcEnd.QuadPart - pcStart.QuadPart) / (float)pcFreq.QuadPart; compLen += 8; + app.DebugPrintf("bg-save: precalc done in %.3f sec, compressed size=%u (%.1f MB)\n", precalcSec, compLen, compLen / (1024.0f * 1024.0f)); + app.DebugPrintf("bg-save: AllocateSaveData(%u) attempt 2\n", compLen); buf = static_cast(StorageManager.AllocateSaveData(compLen)); } if (buf) { - // COM,PRESS + app.DebugPrintf("bg-save: compressing %u bytes...\n", fileSize); + LARGE_INTEGER pcFreq, pcStart, pcEnd; + QueryPerformanceFrequency(&pcFreq); + QueryPerformanceCounter(&pcStart); Compression::getCompression()->Compress(buf + 8, &compLen, snap, fileSize); + QueryPerformanceCounter(&pcEnd); + float compSec = (float)(pcEnd.QuadPart - pcStart.QuadPart) / (float)pcFreq.QuadPart; + app.DebugPrintf("bg-save: compressed %u -> %u bytes (%.1f MB -> %.1f MB) in %.3f sec\n", + fileSize, compLen, fileSize / (1024.0f * 1024.0f), compLen / (1024.0f * 1024.0f), compSec); ZeroMemory(buf, 8); memcpy(buf + 4, &fileSize, sizeof(fileSize)); @@ -757,13 +774,15 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail ) memcpy(s_bgResult.textMeta, meta, sizeof(meta)); s_bgResult.textMetaBytes = metaLen; s_bgResult.pending = true; + app.DebugPrintf("bg-save: result stored, pending flush on main thread\n"); } else { - app.DebugPrintf("save buf alloc failed\n"); + app.DebugPrintf("bg-save: ALLOC FAILED - both attempts failed for %u byte world\n", fileSize); s_bgSaveActive.store(false, std::memory_order_release); } delete[] snap; + app.DebugPrintf("bg-save: snapshot freed, thread exiting\n"); }).detach(); return; } @@ -936,6 +955,7 @@ int ConsoleSaveFileOriginal::SaveSaveDataCallback(LPVOID lpParam,bool bRes) ConsoleSaveFile *pClass=static_cast(lpParam); #ifdef MINECRAFT_SERVER_BUILD + app.DebugPrintf("bg-save: SaveSaveDataCallback fired, success=%d\n", bRes ? 1 : 0); s_bgSaveActive.store(false, std::memory_order_release); #endif @@ -1194,13 +1214,14 @@ void ConsoleSaveFileOriginal::flushPendingBackgroundSave() if (!s_bgResult.pending) return; + app.DebugPrintf("bg-save: flushing to StorageManager (thumbSize=%u, metaBytes=%d)\n", s_bgResult.thumbSize, s_bgResult.textMetaBytes); StorageManager.SetSaveImages( s_bgResult.thumbData, s_bgResult.thumbSize, nullptr, 0, s_bgResult.textMeta, s_bgResult.textMetaBytes); StorageManager.SaveSaveData(&ConsoleSaveFileOriginal::SaveSaveDataCallback, s_bgResult.owner); s_bgResult.pending = false; - // the actual write isnt done until SaveSaveDataCallback fires + app.DebugPrintf("bg-save: StorageManager.SaveSaveData dispatched, awaiting callback\n"); } bool ConsoleSaveFileOriginal::hasPendingBackgroundSave()