[Mono-devel-list] proposed patch for System.Configuration.ConfigurationSetting

eric lindvall eric at 5stops.com
Wed Nov 19 01:07:34 EST 2003


I noticed that with the last fixes for ConfigurationSetting (adding
caching) ends up not being very multi-threaded-friendly.

This patch includes general cleanup with the biggest changes being
removing a lot of the redundant locks, making use of using() statements
(to make sure we don't leak any fd's), and generaly tried to clarify the
code.

thanks.

e.


-------------- next part --------------
Index: System.Configuration/ConfigurationSettings.cs
===================================================================
RCS file: /mono/mcs/class/System/System.Configuration/ConfigurationSettings.cs,v
retrieving revision 1.28
diff -u -p -u -r1.28 ConfigurationSettings.cs
--- System.Configuration/ConfigurationSettings.cs	6 Nov 2003 07:40:27 -0000	1.28
+++ System.Configuration/ConfigurationSettings.cs	19 Nov 2003 06:01:45 -0000
@@ -17,21 +17,19 @@ using System.IO;
 using System.Runtime.CompilerServices;
 using System.Xml;
 using System.Xml.XPath;
+using System.Threading;
 
 namespace System.Configuration
 {
 	public sealed class ConfigurationSettings
 	{
-		static IConfigurationSystem config;
-			
 		private ConfigurationSettings ()
 		{
 		}
 
 		public static object GetConfig (string sectionName)
 		{
-			if (config == null)
-				config = DefaultConfig.GetInstance ();
+                        IConfigurationSystem config = DefaultConfig.GetInstance ();
 
 			return config.GetConfig (sectionName);
 		}
@@ -39,14 +37,15 @@ namespace System.Configuration
 		public static NameValueCollection AppSettings
 		{
 			get {
-				object appSettings = GetConfig ("appSettings");
+				NameValueCollection appSettings = 
+                                        (NameValueCollection) GetConfig ("appSettings");
+
 				if (appSettings == null)
 					appSettings = new NameValueCollection ();
 
-				return (NameValueCollection) appSettings;
+				return appSettings;
 			}
 		}
-
 	}
 
 	//
@@ -55,58 +54,55 @@ namespace System.Configuration
 	//
 	class DefaultConfig : IConfigurationSystem
 	{
-		static object creatingInstance = new object ();
-		static object buildingData = new object ();
-		static DefaultConfig instance;
+		static object instance = null;
 		ConfigurationData config;
 
 		private DefaultConfig ()
 		{
+                        this.Init();
 		}
 
 		public static DefaultConfig GetInstance ()
 		{
 			if (instance == null) {
-				lock (creatingInstance) {
+				lock (typeof (DefaultConfig)) {
 					if (instance == null) {
-						instance = new DefaultConfig ();
-						instance.Init ();
+                                                Interlocked.Exchange (
+                                                                ref instance, new DefaultConfig());
 					}
-					
 				}
 			}
 
-			return instance;
+			return ((DefaultConfig) instance);
 		}
 
 		public object GetConfig (string sectionName)
 		{
-			if (config == null) 
-				return null;
+                        if (config == null)
+                        {
+                                throw (new InvalidOperationException ("ConfigurationSettings not initialized."));
+                        }
 
 			return config.GetConfig (sectionName);
 		}
 
 		public void Init ()
 		{
-			if (config == null){
-				lock (buildingData) {
-					if (config != null)
-						return;
-
-					ConfigurationData data = new ConfigurationData ();
-					if (data.Load (GetMachineConfigPath ())) {
-						ConfigurationData appData = new ConfigurationData (data);
-						appData.Load (GetAppConfigPath ());
-						config = appData;
-					} else {
-						Console.WriteLine ("** Warning **: cannot find " + GetMachineConfigPath ());
-						Console.WriteLine ("Trying to load app config file...");
-						data.Load (GetAppConfigPath ());
-						config = data;
-					}
-				}
-			}
+                        try
+                        {
+                                ConfigurationData data = new ConfigurationData (GetMachineConfigPath ());
+                                ConfigurationData appData = new ConfigurationData (GetAppConfigPath (), data);
+                                config = appData;
+                        }
+                        catch (Exception e)
+                        {
+                                Console.WriteLine ("** Warning **: cannot find " + 
+                                                GetMachineConfigPath () + ": " + e.Message);
+                                Console.WriteLine ("Trying to load app config file...");
+
+                                ConfigurationData data = new ConfigurationData (GetAppConfigPath ());
+                                config = data;
+                        }
 		}
 
 		[MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -126,7 +122,6 @@ namespace System.Configuration
 				return null;
 
 			return configFile;
-
 		}
 	}
 
@@ -188,56 +183,31 @@ namespace System.Configuration
 		object removedMark = new object ();
 		object groupMark = new object ();
                 object emptyMark = new object ();
-                FileWatcherCache fileCache = null;
+                FileWatcherCache fileCache;
 
-                private FileWatcherCache FileCache {
-                        get {
-                                if (fileCache == null) {
-                                        if (fileName != null) {
-                                                fileCache = new FileWatcherCache (fileName);
-                                        } else {
-                                                fileCache = parent.FileCache;
-                                        }
-                                }
-
-                                return fileCache;
-                        }
-                }
-
-		public ConfigurationData () : this (null)
-		{
-		}
-
-		public ConfigurationData (ConfigurationData parent)
+		public ConfigurationData (string fileName) : this (fileName, null)
 		{
-			this.parent = (parent == this) ? null : parent;
-			factories = new Hashtable ();
 		}
 
-		public bool Load (string fileName)
+		public ConfigurationData (string fileName, ConfigurationData parent)
 		{
-			if (fileName == null || !File.Exists (fileName))
-				return false;
+                        if (fileName == null)
+                        {
+                                throw (new ArgumentNullException ("fileName"));
+                        }
 
 			this.fileName = fileName;
-			XmlTextReader reader = null;
+                        this.fileCache = new FileWatcherCache (fileName);
+			this.parent = (parent == this) ? null : parent;
+			factories = new Hashtable ();
 
-			try {
-				try {
-					FileStream fs = new FileStream (fileName, FileMode.Open, FileAccess.Read);
-					reader = new XmlTextReader (fs);
-				} catch (Exception) {
-					return false;
-				}
+                        using (FileStream fs = new FileStream (fileName, FileMode.Open, FileAccess.Read))
+                        {
+                                XmlTextReader reader = new XmlTextReader (fs);
 
 				InitRead (reader);
 				ReadConfigFile (reader);
-			} finally {
-				if (reader != null)
-					reader.Close();
-			}
-
-			return true;
+                        }
 		}
 
 		object GetHandler (string sectionName)
@@ -246,8 +216,8 @@ namespace System.Configuration
 			if (o == null || o == removedMark) {
 				if (parent != null)
 					return parent.GetHandler (sectionName);
-
-				return null;
+                                else
+                                        return null;
 			}
 
 			if (o is IConfigurationSectionHandler)
@@ -271,50 +241,44 @@ namespace System.Configuration
 		}
 
 		//TODO: Should use XPath when it works properly for this.
-		XmlDocument GetDocumentForSection (string sectionName)
+		private XmlDocument GetDocumentForSection (string sectionName)
 		{
-			if (fileName == null || !File.Exists (fileName))
-				return null;
-
-			XmlTextReader reader = null;
-			try {
-				FileStream fs = new FileStream (fileName, FileMode.Open, FileAccess.Read);
-				reader = new XmlTextReader (fs);
-			} catch {
-				return null;
-			}
-
-			ConfigXmlDocument doc = new ConfigXmlDocument ();
-			InitRead (reader);
-			string [] sectionPath = sectionName.Split ('/');
-			int i = 0;
-			if (!reader.EOF) {
-				if (reader.Name == "configSections")
-					reader.Skip ();
-
-				while (!reader.EOF) {
-					if (reader.NodeType == XmlNodeType.Element &&
-					    reader.Name == sectionPath [i]) {
-						if (++i == sectionPath.Length) {
-							doc.LoadSingleElement (fileName, reader);
-							break;
-						}
-						MoveToNextElement (reader);
-						continue;
-					}
-					reader.Skip ();
-					if (reader.NodeType != XmlNodeType.Element)
-						MoveToNextElement (reader);
-				}
-			}
+                        using (FileStream fs = new FileStream (fileName, FileMode.Open, FileAccess.Read))
+                        {
+                                XmlTextReader reader = new XmlTextReader (fs);
+
+                                ConfigXmlDocument doc = new ConfigXmlDocument ();
+                                InitRead (reader);
+                                string [] sectionPath = sectionName.Split ('/');
+                                int i = 0;
+                                if (!reader.EOF) {
+                                        if (reader.Name == "configSections")
+                                                reader.Skip ();
+
+                                        while (!reader.EOF) {
+                                                if (reader.NodeType == XmlNodeType.Element &&
+                                                                reader.Name == sectionPath [i]) {
+                                                        if (++i == sectionPath.Length) {
+                                                                doc.LoadSingleElement (fileName, reader);
+                                                                break;
+                                                        }
+                                                        MoveToNextElement (reader);
+                                                        continue;
+                                                }
+                                                reader.Skip ();
+                                                if (reader.NodeType != XmlNodeType.Element)
+                                                        MoveToNextElement (reader);
+                                        }
+                                }
 
-			reader.Close ();
-			return doc;
+                                return doc;
+                        }
 		}
 		
-		object GetConfigInternal (string sectionName)
+		private object GetConfigInternal (string sectionName)
 		{
 			object handler = GetHandler (sectionName);
+
 			if (handler == null)
 				return null;
 
@@ -322,6 +286,7 @@ namespace System.Configuration
 				return handler;
 
 			object parentConfig = null;
+
 			if (parent != null)
 				parentConfig = parent.GetConfig (sectionName);
 
@@ -329,8 +294,8 @@ namespace System.Configuration
 			if (doc == null || doc.DocumentElement == null) {
 				if (parentConfig == null)
 					return null;
-
-				return parentConfig;
+                                else
+                                        return parentConfig;
 			}
 			
 			return ((IConfigurationSectionHandler) handler).Create (parentConfig, fileName, doc.DocumentElement);
@@ -338,17 +303,20 @@ namespace System.Configuration
 
 		public object GetConfig (string sectionName)
 		{
-                        object config = this.FileCache [sectionName];
+                        lock (this)
+                        {
+                                object config = this.fileCache [sectionName];
 
-                        if (config == emptyMark)
-                                return null;
+                                if (config == emptyMark)
+                                        return null;
 
-                        if (config != null)
-                                return config;
+                                if (config != null)
+                                        return config;
 
-			config = GetConfigInternal (sectionName);
-			this.FileCache [sectionName] = (config == null) ? emptyMark : config;
-			return config;
+                                config = GetConfigInternal (sectionName);
+                                this.fileCache [sectionName] = (config == null) ? emptyMark : config;
+                                return config;
+                        }
                 }
 
 		private object LookForFactory (string key)


More information about the Mono-devel-list mailing list