1
0

refactored chunk Queue to seperate class

This commit is contained in:
Tycho Bickerstaff 2013-12-31 15:48:57 +00:00
parent d0cd9a2b36
commit f3736b1eb7
7 changed files with 161 additions and 123 deletions

View File

@ -14,7 +14,6 @@
/** This is really only a placeholder to be used in places where we need to "make up" a chunk's Y coord. /** This is really only a placeholder to be used in places where we need to "make up" a chunk's Y coord.
It will help us when the new chunk format comes out and we need to patch everything up for compatibility. It will help us when the new chunk format comes out and we need to patch everything up for compatibility.
*/ */

View File

@ -20,10 +20,10 @@ class cEvent
{ {
public: public:
cEvent(void); cEvent(void);
~cEvent(); virtual ~cEvent();
void Wait(void); virtual void Wait(void);
void Set (void); virtual void Set (void);
private: private:

View File

@ -22,7 +22,6 @@ In the descending class' constructor call the Start() method to start the thread
class cIsThread class cIsThread
{ {
protected: protected:

View File

@ -1,30 +1,104 @@
#pragma once #pragma once
#include <list>
#include "../OSSupport/Promise.h"
//this empty struct allows function inlining
template<class T> template<class T>
class cDeleter struct cQueueFuncs
{ {
public: public:
static void Delete(T) {}; static void Delete(T) {};
} static void Combine(T&, const T) {};
};
template<class T, class D = cDelete> template<class ItemType, class Funcs = cQueueFuncs<ItemType> >
class cQueue class cQueue
{ {
typedef typename std::list<ItemType> ListType;
//magic typedef to persuade clang that the iterator is a type
typedef typename ListType::iterator iterator;
public: public:
cQueue(int warnsize); cQueue() {}
cQueue(cQueue<T>& queue); ~cQueue() {}
~cQueue();
void EnqueueItem(ItemType a_item)
{
cCSLock Lock(m_CS);
m_contents.push_back(a_item);
m_evtAdded.Set();
}
void EnqueueItemIfNotPresent(ItemType a_item)
{
cCSLock Lock(m_CS);
for (iterator itr = m_contents.begin(); itr != m_contents.end(); ++itr)
{
if((*itr) == a_item) {
Funcs funcTable;
funcTable.Combine(*itr,a_item);
return;
}
}
m_contents.push_back(a_item);
m_evtAdded.Set();
}
bool TryDequeueItem(ItemType& item)
{
cCSLock Lock(m_CS);
if (m_contents.size() == 0) return false;
item = m_contents.front();
m_contents.pop_front();
return true;
}
ItemType DequeueItem()
{
cCSLock Lock(m_CS);
while (m_contents.size() == 0)
{
cCSUnlock Unlock(m_CS);
m_evtAdded.Wait();
}
return m_contents.pop_front();
}
cPromise* BlockTillEmpty() {
return new cEmptyQueuePromise(this);
}
//can all be inlined when delete is a noop
void Clear()
{
cCSLock Lock(m_CS);
Funcs funcTable;
while (!m_contents.empty())
{
funcTable.Delete(m_contents.front());
m_contents.pop_front();
}
}
size_t Size()
{
cCSLock Lock(m_CS);
return m_contents.size();
}
bool Remove(ItemType item)
{
cCSLock Lock(m_CS);
m_contents.remove(item);
}
void EnqueueItem(T item);
bool TryDequeueItem(T& item);
T DequeueItem();
void BlockTillEmpty(cEvent CancelationEvent);
void Clear();
int Size();
private: private:
int warnsize; ListType m_contents;
} cCriticalSection m_CS;
cEvent m_evtAdded;
//template classes must be implemented in the header class cEmptyQueuePromise : public cPromise {
#include "Queue.inc" public:
cEmptyQueuePromise(cQueue* a_Queue) : cPromise(), m_Queue(a_Queue) {}
virtual bool IsCompleted() {return m_Queue->Size() != 0;}
private:
cQueue* m_Queue;
};
};

View File

@ -1,4 +0,0 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules

View File

@ -13,7 +13,7 @@
#include "../Generating/ChunkGenerator.h" #include "../Generating/ChunkGenerator.h"
#include "../Entities/Entity.h" #include "../Entities/Entity.h"
#include "../BlockEntities/BlockEntity.h" #include "../BlockEntities/BlockEntity.h"
#include "../OSSupport/Promise.h"
@ -63,8 +63,6 @@ cWorldStorage::~cWorldStorage()
{ {
delete *itr; delete *itr;
} // for itr - m_Schemas[] } // for itr - m_Schemas[]
m_LoadQueue.clear();
m_SaveQueue.clear();
} }
@ -98,9 +96,7 @@ void cWorldStorage::WaitForFinish(void)
LOG("Waiting for the world storage to finish saving"); LOG("Waiting for the world storage to finish saving");
{ {
// Cancel all loading requests: m_LoadQueue.Clear();
cCSLock Lock(m_CSQueues);
m_LoadQueue.clear();
} }
// Wait for the saving to finish: // Wait for the saving to finish:
@ -120,32 +116,36 @@ void cWorldStorage::WaitForFinish(void)
void cWorldStorage::WaitForQueuesEmpty(void) void cWorldStorage::WaitForQueuesEmpty(void)
{ {
cCSLock Lock(m_CSQueues);
while (!m_ShouldTerminate && (!m_LoadQueue.empty() || !m_SaveQueue.empty())) cPromise * LoadPromise = m_LoadQueue.BlockTillEmpty();
{ cPromise * SavePromise = m_SaveQueue.BlockTillEmpty();
cCSUnlock Unlock(Lock); cPromise * QueuePromise = LoadPromise->WaitFor(SavePromise);
m_evtRemoved.Wait(); cPromise * CancelPromise = QueuePromise->CancelOn(m_ShouldTerminate);
} CancelPromise->Wait();
delete CancelPromise;
delete QueuePromise;
delete SavePromise;
delete LoadPromise;
} }
int cWorldStorage::GetLoadQueueLength(void) size_t cWorldStorage::GetLoadQueueLength(void)
{ {
cCSLock Lock(m_CSQueues); cCSLock Lock(m_CSQueues);
return (int)m_LoadQueue.size(); return m_LoadQueue.Size();
} }
int cWorldStorage::GetSaveQueueLength(void) size_t cWorldStorage::GetSaveQueueLength(void)
{ {
cCSLock Lock(m_CSQueues); cCSLock Lock(m_CSQueues);
return (int)m_SaveQueue.size(); return m_SaveQueue.Size();
} }
@ -154,22 +154,7 @@ int cWorldStorage::GetSaveQueueLength(void)
void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate)
{ {
// Queues the chunk for loading; if not loaded, the chunk will be generated m_LoadQueue.EnqueueItemIfNotPresent(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate));
{
cCSLock Lock(m_CSQueues);
// Check if already in the queue:
for (sChunkLoadQueue::iterator itr = m_LoadQueue.begin(); itr != m_LoadQueue.end(); ++itr)
{
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ) && (itr->m_Generate == a_Generate))
{
return;
}
}
m_LoadQueue.push_back(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate));
}
m_Event.Set();
} }
@ -178,12 +163,7 @@ void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, boo
void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
{ {
{ m_SaveQueue.EnqueueItemIfNotPresent(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
cCSLock Lock(m_CSQueues);
m_SaveQueue.remove (cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); // Don't add twice
m_SaveQueue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
}
m_Event.Set();
} }
@ -192,12 +172,8 @@ void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
void cWorldStorage::QueueSavedMessage(void) void cWorldStorage::QueueSavedMessage(void)
{ {
// Pushes a special coord pair into the queue, signalizing a message instead: // Pushes a special coord pair into the queue, signalizing a message instead
{ m_SaveQueue.EnqueueItem(cChunkCoords(0, CHUNK_Y_MESSAGE, 0));
cCSLock Lock(m_CSQueues);
m_SaveQueue.push_back(cChunkCoords(0, CHUNK_Y_MESSAGE, 0));
}
m_Event.Set();
} }
@ -206,7 +182,7 @@ void cWorldStorage::QueueSavedMessage(void)
void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ) void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
{ {
cCSLock Lock(m_CSQueues); /*cCSLock Lock(m_CSQueues);
for (sChunkLoadQueue::iterator itr = m_LoadQueue.begin(); itr != m_LoadQueue.end(); ++itr) for (sChunkLoadQueue::iterator itr = m_LoadQueue.begin(); itr != m_LoadQueue.end(); ++itr)
{ {
if ((itr->m_ChunkX != a_ChunkX) || (itr->m_ChunkY != a_ChunkY) || (itr->m_ChunkZ != a_ChunkZ)) if ((itr->m_ChunkX != a_ChunkX) || (itr->m_ChunkY != a_ChunkY) || (itr->m_ChunkZ != a_ChunkZ))
@ -217,7 +193,8 @@ void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
Lock.Unlock(); Lock.Unlock();
m_evtRemoved.Set(); m_evtRemoved.Set();
return; return;
} // for itr - m_LoadQueue[] } // for itr - m_LoadQueue[]*/
m_LoadQueue.Remove(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ,true));
} }
@ -226,11 +203,7 @@ void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk) void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk)
{ {
{ m_SaveQueue.Remove(a_Chunk);
cCSLock Lock(m_CSQueues);
m_SaveQueue.remove(a_Chunk);
}
m_evtRemoved.Set();
} }
@ -281,19 +254,19 @@ void cWorldStorage::Execute(void)
m_Event.Wait(); m_Event.Wait();
// Process both queues until they are empty again: // Process both queues until they are empty again:
bool HasMore; bool Success;
do do
{ {
HasMore = false; Success = false;
if (m_ShouldTerminate) if (m_ShouldTerminate)
{ {
return; return;
} }
HasMore = LoadOneChunk(); Success = LoadOneChunk();
HasMore = HasMore | SaveOneChunk(); Success |= SaveOneChunk();
m_evtRemoved.Set(); m_evtRemoved.Set();
} while (HasMore); } while (Success);
} }
} }
@ -304,19 +277,7 @@ void cWorldStorage::Execute(void)
bool cWorldStorage::LoadOneChunk(void) bool cWorldStorage::LoadOneChunk(void)
{ {
sChunkLoad ToLoad(0, 0, 0, false); sChunkLoad ToLoad(0, 0, 0, false);
bool HasMore; bool ShouldLoad = m_LoadQueue.TryDequeueItem(ToLoad);
bool ShouldLoad = false;
{
cCSLock Lock(m_CSQueues);
if (!m_LoadQueue.empty())
{
ToLoad = m_LoadQueue.front();
m_LoadQueue.pop_front();
ShouldLoad = true;
}
HasMore = !m_LoadQueue.empty();
}
if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ)) if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ))
{ {
if (ToLoad.m_Generate) if (ToLoad.m_Generate)
@ -330,7 +291,7 @@ bool cWorldStorage::LoadOneChunk(void)
// m_World->ChunkLoadFailed(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ); // m_World->ChunkLoadFailed(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ);
} }
} }
return HasMore; return ShouldLoad;
} }
@ -339,33 +300,24 @@ bool cWorldStorage::LoadOneChunk(void)
bool cWorldStorage::SaveOneChunk(void) bool cWorldStorage::SaveOneChunk(void)
{ {
cChunkCoords Save(0, 0, 0); cChunkCoords ToSave(0, 0, 0);
bool HasMore; bool ShouldSave = m_SaveQueue.TryDequeueItem(ToSave);
bool ShouldSave = false; if(ShouldSave) {
{ if (ToSave.m_ChunkY == CHUNK_Y_MESSAGE)
cCSLock Lock(m_CSQueues);
if (!m_SaveQueue.empty())
{ {
Save = m_SaveQueue.front(); LOGINFO("Saved all chunks in world %s", m_World->GetName().c_str());
m_SaveQueue.pop_front(); return ShouldSave;
ShouldSave = true;
} }
HasMore = !m_SaveQueue.empty(); if (ShouldSave && m_World->IsChunkValid(ToSave.m_ChunkX, ToSave.m_ChunkZ))
}
if (Save.m_ChunkY == CHUNK_Y_MESSAGE)
{
LOGINFO("Saved all chunks in world %s", m_World->GetName().c_str());
return HasMore;
}
if (ShouldSave && m_World->IsChunkValid(Save.m_ChunkX, Save.m_ChunkZ))
{
m_World->MarkChunkSaving(Save.m_ChunkX, Save.m_ChunkZ);
if (m_SaveSchema->SaveChunk(Save))
{ {
m_World->MarkChunkSaved(Save.m_ChunkX, Save.m_ChunkZ); m_World->MarkChunkSaving(ToSave.m_ChunkX, ToSave.m_ChunkZ);
if (m_SaveSchema->SaveChunk(ToSave))
{
m_World->MarkChunkSaved(ToSave.m_ChunkX, ToSave.m_ChunkZ);
}
} }
} }
return HasMore; return ShouldSave;
} }

View File

@ -16,6 +16,7 @@
#include "../ChunkDef.h" #include "../ChunkDef.h"
#include "../OSSupport/IsThread.h" #include "../OSSupport/IsThread.h"
#include "../OSSupport/Queue.h"
@ -24,6 +25,8 @@
// fwd: // fwd:
class cWorld; class cWorld;
typedef cQueue<cChunkCoords> cChunkCoordsQueue;
@ -78,8 +81,8 @@ public:
void WaitForFinish(void); void WaitForFinish(void);
void WaitForQueuesEmpty(void); void WaitForQueuesEmpty(void);
int GetLoadQueueLength(void); size_t GetLoadQueueLength(void);
int GetSaveQueueLength(void); size_t GetSaveQueueLength(void);
protected: protected:
@ -91,9 +94,24 @@ protected:
bool m_Generate; // If true, the chunk will be generated if it cannot be loaded bool m_Generate; // If true, the chunk will be generated if it cannot be loaded
sChunkLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ), m_Generate(a_Generate) {} sChunkLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ), m_Generate(a_Generate) {}
bool operator==(const sChunkLoad other) const
{
return this->m_ChunkX == other.m_ChunkX &&
this->m_ChunkY == other.m_ChunkY &&
this->m_ChunkZ == other.m_ChunkZ;
}
} ; } ;
typedef std::list<sChunkLoad> sChunkLoadQueue; struct FuncTable {
static void Delete(sChunkLoad) {};
static void Combine(sChunkLoad& a_orig, const sChunkLoad a_new)
{
a_orig.m_Generate |= a_new.m_Generate;
};
};
typedef cQueue<sChunkLoad,FuncTable> sChunkLoadQueue;
cWorld * m_World; cWorld * m_World;
AString m_StorageSchemaName; AString m_StorageSchemaName;
@ -101,7 +119,7 @@ protected:
// Both queues are locked by the same CS // Both queues are locked by the same CS
cCriticalSection m_CSQueues; cCriticalSection m_CSQueues;
sChunkLoadQueue m_LoadQueue; sChunkLoadQueue m_LoadQueue;
cChunkCoordsList m_SaveQueue; cChunkCoordsQueue m_SaveQueue;
cEvent m_Event; // Set when there's any addition to the queues cEvent m_Event; // Set when there's any addition to the queues
cEvent m_evtRemoved; // Set when an item has been removed from the queue, either by the worker thread or the Unqueue methods cEvent m_evtRemoved; // Set when an item has been removed from the queue, either by the worker thread or the Unqueue methods