[mapguide-commits] r7056 - in trunk/Tools/Maestro: OSGeo.MapGuide.MaestroAPI.Local OSGeo.MapGuide.MaestroAPI.Native

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Mon Oct 1 06:12:09 PDT 2012


Author: jng
Date: 2012-10-01 06:12:08 -0700 (Mon, 01 Oct 2012)
New Revision: 7056

Modified:
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Local/LocalConnection.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Native/LocalNativeConnection.cs
Log:
Improve Local and LocalNative implementation of SetResourceData. Since MgByteSource cannot take a System.IO.Stream we do a simple test. If the input System.IO.Stream is seekable and is under 30MB, we read the entire stream into a byte[] and use the MgByteSource(byte[], int) overload, otherwise we dump the input stream to a temp file and use the MgByteSource(string) overload. This way, if the input stream turns out to be really huge (eg. several GBs of data), we won't be reading the entire stream into memory (and most likely triggering a System.OutOfMemoryException in the process).

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Local/LocalConnection.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Local/LocalConnection.cs	2012-10-01 12:15:14 UTC (rev 7055)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Local/LocalConnection.cs	2012-10-01 13:12:08 UTC (rev 7056)
@@ -353,26 +353,50 @@
             return new MgReadOnlyStream(fetch);
         }
 
+        const int MAX_INPUT_STREAM_SIZE_MB = 30;
+
         public override void SetResourceData(string resourceid, string dataname, ResourceDataType datatype, System.IO.Stream stream, Utility.StreamCopyProgressDelegate callback)
         {
-            //FIXME/BOGUS: We should be streaming this in! What if the resource data
-            //was several hundred MBs or 1-2 GBs in size? Hello System.OutOfMemoryException
-            //Other connection implementations are probably doing this too!
-            //
-            //BOGUS: Well we can't exactly plug in a System.IO.Stream to a MgByteSource
-            //either, and we can't extend SWIG proxy classes (not in the way it's currently set up anyways!). 
-            //So the only feasible solution is offload the input stream to a temp file and then create 
-            //an MgByteSource with the fileName ctor overload.
-            byte[] data = Utility.StreamAsArray(stream);
-            if (callback != null)
-                callback(0, data.Length, data.Length);
             var res = GetResourceService();
-            MgByteSource source = new MgByteSource(data, data.Length);
-            MgByteReader reader = source.GetReader();
-            res.SetResourceData(new MgResourceIdentifier(resourceid), dataname, datatype.ToString(), reader);
-            LogMethodCall("MgResourceService::SetResourceData", true, resourceid, dataname, datatype.ToString(), "MgByteReader");
-            if (callback != null)
-                callback(data.Length, 0, data.Length);
+            MgByteReader reader = null;
+            string tmpPath = null;
+            //If stream is under our hard-coded limit (and it's seekable, which is how we're able to get that number), use the
+            //overload of MgByteSource that accepts a byte[]. Otherwise dump the stream to a temp file and use the
+            //file name overload (otherwise if our input stream happens to be several GBs, we run risk of
+            //System.OutOfMemoryExceptions being thrown back at us)
+            if (stream.CanSeek && stream.Length < (MAX_INPUT_STREAM_SIZE_MB * 1024 * 1024))
+            {
+                byte[] data = Utility.StreamAsArray(stream);
+                MgByteSource source = new MgByteSource(data, data.Length);
+                reader = source.GetReader();
+            }
+            else
+            {
+                tmpPath = Path.GetTempFileName();
+                using (FileStream fs = File.OpenWrite(tmpPath))
+                {
+                    stream.CopyTo(fs);
+                }
+                MgByteSource source = new MgByteSource(tmpPath);
+                reader = source.GetReader();
+            }
+            try
+            {
+                res.SetResourceData(new MgResourceIdentifier(resourceid), dataname, datatype.ToString(), reader);
+                LogMethodCall("MgResourceService::SetResourceData", true, resourceid, dataname, datatype.ToString(), "MgByteReader");
+            }
+            finally
+            {
+                if (!string.IsNullOrEmpty(tmpPath) && File.Exists(tmpPath))
+                {
+                    //Be a responsible citizen and clean up our temp files when done
+                    try
+                    {
+                        File.Delete(tmpPath);
+                    }
+                    catch { }
+                }
+            }
         }
 
         public override void UploadPackage(string filename, Utility.StreamCopyProgressDelegate callback)

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Native/LocalNativeConnection.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Native/LocalNativeConnection.cs	2012-10-01 12:15:14 UTC (rev 7055)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Native/LocalNativeConnection.cs	2012-10-01 13:12:08 UTC (rev 7056)
@@ -1040,17 +1040,50 @@
             return this;
         }
 
+        const int MAX_INPUT_STREAM_SIZE_MB = 30;
+
         public override void SetResourceData(string resourceid, string dataname, ResourceDataType datatype, Stream stream, OSGeo.MapGuide.MaestroAPI.Utility.StreamCopyProgressDelegate callback)
         {
-            byte[] data = Utility.StreamAsArray(stream);
-            if (callback != null)
-                callback(0, data.Length, data.Length);
             MgResourceService res = this.Connection.CreateService(MgServiceType.ResourceService) as MgResourceService;
-            MgByteReader reader = new MgByteReader(data, data.Length, "binary/octet-stream");
-            res.SetResourceData(new MgResourceIdentifier(resourceid), dataname, datatype.ToString(), reader);
-            LogMethodCall("MgResourceService::SetResourceData", true, resourceid, dataname, datatype.ToString(), "MgByteReader");
-            if (callback != null)
-                callback(data.Length, 0, data.Length);
+            MgByteReader reader = null;
+            string tmpPath = null;
+            //If stream is under our hard-coded limit (and it's seekable, which is how we're able to get that number), use the
+            //overload of MgByteSource that accepts a byte[]. Otherwise dump the stream to a temp file and use the
+            //file name overload (otherwise if our input stream happens to be several GBs, we run risk of
+            //System.OutOfMemoryExceptions being thrown back at us)
+            if (stream.CanSeek && stream.Length < (MAX_INPUT_STREAM_SIZE_MB * 1024 * 1024))
+            {
+                byte[] data = Utility.StreamAsArray(stream);
+                MgByteSource source = new MgByteSource(data, data.Length);
+                reader = source.GetReader();
+            }
+            else
+            {
+                tmpPath = Path.GetTempFileName();
+                using (FileStream fs = File.OpenWrite(tmpPath))
+                {
+                    stream.CopyTo(fs);
+                }
+                MgByteSource source = new MgByteSource(tmpPath);
+                reader = source.GetReader();
+            }
+            try
+            {
+                res.SetResourceData(new MgResourceIdentifier(resourceid), dataname, datatype.ToString(), reader);
+                LogMethodCall("MgResourceService::SetResourceData", true, resourceid, dataname, datatype.ToString(), "MgByteReader");
+            }
+            finally
+            {
+                if (!string.IsNullOrEmpty(tmpPath) && File.Exists(tmpPath))
+                {
+                    //Be a responsible citizen and clean up our temp files when done
+                    try
+                    {
+                        File.Delete(tmpPath);
+                    }
+                    catch { }
+                }
+            }
         }
 
         public override void UploadPackage(string filename, OSGeo.MapGuide.MaestroAPI.Utility.StreamCopyProgressDelegate callback)



More information about the mapguide-commits mailing list