[mapguide-internals] Exception Handling for Memory limitations +
Patch for #480 & #520
UV
uvwild at gmail.com
Thu Apr 2 23:17:19 EDT 2009
Hi there,
I am trying to make the mgserver behave in the case of limited memory..
We are using a massive map for our client and the server keeps on
falling over. (did not reproduce in 2.0.2)
I followed the trace from StylizeLayerinto the SimpleSDFReader which
fails with a (ret != SQLiteDB_OK)
This interface to the underlying SQLiteTable::get call does not do
exception handling so we have lost the underlying reason.....
I assume its a failed malloc somewhere as I am investigating out of
memory behaviour.
Furthermore the MappingUtil::StylizeLayers method simply eats up the
exception.
I am not sure if this is really the desired behaviour. Maybe this should
be examinated in more detail.
I am just slowly getting fed up reading a lot of code that has clearly
not been written to be understood by other people.
So other approaches are needed.
== Smart Handling of Out of Memory Exceptions ==
I suggest to wrap all memory allocation deeper in the code into retry
loops with a time delay doubling at each repetition (like CSMA/CD).
Another option used in my ByteSink patch simply decreases the allocated
buffer as it can in this particular case.
This should increase server stability massively as memory is used and
returned a lot in this multi-threaded server.
This should provide a way for the halted threads to get the memory they
need at a later point in time.
I think waiting is a realistic engeering approach to solve the OoM
problem. (I learned this style while coding on a realtime audio engine :)
== Patch for #480 #520 ==
The patch cleans up the file handle and removes empty files. Furthermore
an intelligent exception handler uses a buffer of an available size if
1MB is not available anymore.
(1MB looks like a quite a hefty estimation of the needed size in the
first place.....)
-------------- next part --------------
Index: ByteSink.cpp
===================================================================
--- ByteSink.cpp (revision 3778)
+++ ByteSink.cpp (working copy)
@@ -188,7 +188,7 @@
void MgByteSink::ToFile(CREFSTRING filename)
{
unsigned char* bytes = 0;
-
+ FILE* f = 0; // needs to be in top scope to be able to clean it up in exception handler
MG_TRY()
// See if we are sourced from a temporary file byte source. If we are, just
@@ -202,7 +202,7 @@
else
{ // Do it the hard way. Create a new file and write it a block at a time
///Use ACE_OS::fopen() for Linux compatibility
- FILE* f = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(filename), ACE_TEXT("wb"));
+ f = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(filename), ACE_TEXT("wb"));
if (f == NULL)
{
@@ -221,11 +221,23 @@
}
}
- bytes = new unsigned char[BSINK_BUFFER_SIZE];
+ // allocate a huge buffer (usually 1MB) at first
+ int bSinkBufferSize = BSINK_BUFFER_SIZE;
+ do
+ { // retry allocation with half the size until we give up at 16kB
+ try {
+ bytes = new unsigned char[bSinkBufferSize];
+ } catch (exception& e) {
+ if (typeid(e) == typeid(bad_alloc) && bSinkBufferSize >= 1024*16)
+ bSinkBufferSize >>= 1;
+ else
+ throw e;
+ }
+ } while (bytes == 0);
size_t bytesReceived, bytesWritten;
- while ((bytesReceived = (size_t)m_reader->Read(bytes, BSINK_BUFFER_SIZE)) > 0)
+ while ((bytesReceived = (size_t)m_reader->Read(bytes, bSinkBufferSize)) > 0)
{
if((bytesWritten = ACE_OS::fwrite(bytes, 1, bytesReceived, f)) != bytesReceived)
{
@@ -245,6 +257,14 @@
MG_CATCH(L"MgByteSink::ToFile")
delete [] bytes;
+ if (NULL != f) ACE_OS::fclose(f); // close the file if not done yet
- MG_THROW()
+ if (NULL != mgException && ) {
+ struct _stat statInfo;
+ MgFileUtil::GetFileStatus(MG_WCHAR_TO_TCHAR(filename), statInfo);
+ // delete only if empty... we dont want to destroy files with useful content ....
+ if (statInfo.st_size == 0)
+ MgFileUtil::DeleteFile(MG_WCHAR_TO_TCHAR(filename));
+ }
+ MG_THROW( )
}
More information about the mapguide-internals
mailing list