Author: rgrabowski
Date: Mon May 25 17:46:43 2009
New Revision: 778461

URL: http://svn.apache.org/viewvc?rev=778461&view=rev
Log:
Fix for LOG4NET-164. Added MutexLock which allows for faster inter-process file 
locking compared to MinimalLock.

Modified:
    logging/log4net/trunk/src/Appender/FileAppender.cs

Modified: logging/log4net/trunk/src/Appender/FileAppender.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/Appender/FileAppender.cs?rev=778461&r1=778460&r2=778461&view=diff
==============================================================================
--- logging/log4net/trunk/src/Appender/FileAppender.cs (original)
+++ logging/log4net/trunk/src/Appender/FileAppender.cs Mon May 25 17:46:43 2009
@@ -20,7 +20,7 @@
 using System;
 using System.IO;
 using System.Text;
-
+using System.Threading;
 using log4net.Util;
 using log4net.Layout;
 using log4net.Core;
@@ -162,7 +162,7 @@
                        }
                        void IDisposable.Dispose() 
                        {
-                               this.Close();
+                               Close();
                        }
                        public override void Write(byte[] buffer, int offset, 
int count) 
                        {
@@ -356,6 +356,56 @@
                                get { return m_appender; }
                                set { m_appender = value; }
                        }
+
+            /// <summary>
+            /// Helper method that creates a FileStream under 
CurrentAppender's SecurityContext.
+            /// </summary>
+            /// <remarks>
+            /// <para>
+            /// Typically called during OpenFile or AcquireLock. 
+            /// </para>
+            /// <para>
+            /// If the directory portion of the <paramref name="filename"/> 
does not exist, it is created
+            /// via Directory.CreateDirecctory.
+            /// </para>
+            /// </remarks>
+            /// <param name="filename"></param>
+            /// <param name="append"></param>
+            /// <param name="fileShare"></param>
+            /// <returns></returns>
+            protected Stream CreateStream(string filename, bool append, 
FileShare fileShare)
+            {
+                using (CurrentAppender.SecurityContext.Impersonate(this))
+                {
+                    // Ensure that the directory structure exists
+                    string directoryFullName = Path.GetDirectoryName(filename);
+
+                    // Only create the directory if it does not exist
+                    // doing this check here resolves some permissions failures
+                    if (!Directory.Exists(directoryFullName))
+                    {
+                        Directory.CreateDirectory(directoryFullName);
+                    }
+
+                    FileMode fileOpenMode = append ? FileMode.Append : 
FileMode.Create;
+                    return new FileStream(filename, fileOpenMode, 
FileAccess.Write, FileShare.Read);
+                }
+            }
+
+            /// <summary>
+            /// Helper method to close <paramref name="stream"/> under 
CurrentAppender's SecurityContext.
+            /// </summary>
+            /// <remarks>
+            /// Does not set <paramref name="stream"/> to null.
+            /// </remarks>
+            /// <param name="stream"></param>
+            protected void CloseStream(Stream stream)
+            {
+                using (CurrentAppender.SecurityContext.Impersonate(this))
+                {
+                    stream.Close();
+                }
+           }
                }
 
                /// <summary>
@@ -389,21 +439,7 @@
                        {
                                try
                                {
-                                       
using(CurrentAppender.SecurityContext.Impersonate(this))
-                                       {
-                                               // Ensure that the directory 
structure exists
-                                               string directoryFullName = 
Path.GetDirectoryName(filename);
-
-                                               // Only create the directory if 
it does not exist
-                                               // doing this check here 
resolves some permissions failures
-                                               if 
(!Directory.Exists(directoryFullName))
-                                               {
-                                                       
Directory.CreateDirectory(directoryFullName);
-                                               }
-
-                                               FileMode fileOpenMode = append 
? FileMode.Append : FileMode.Create;
-                                               m_stream = new 
FileStream(filename, fileOpenMode, FileAccess.Write, FileShare.Read);
-                                       }
+                    m_stream = CreateStream(filename, append, FileShare.Read);
                                }
                                catch (Exception e1)
                                {
@@ -421,10 +457,8 @@
                        /// </remarks>
                        public override void CloseFile()
                        {
-                               
using(CurrentAppender.SecurityContext.Impersonate(this))
-                               {
-                                       m_stream.Close();
-                               }
+                CloseStream(m_stream);
+                m_stream = null;
                        }
 
                        /// <summary>
@@ -522,22 +556,7 @@
                                {
                                        try
                                        {
-                                               
using(CurrentAppender.SecurityContext.Impersonate(this))
-                                               {
-                                                       // Ensure that the 
directory structure exists
-                                                       string 
directoryFullName = Path.GetDirectoryName(m_filename);
-
-                                                       // Only create the 
directory if it does not exist
-                                                       // doing this check 
here resolves some permissions failures
-                                                       if 
(!Directory.Exists(directoryFullName))
-                                                       {
-                                                               
Directory.CreateDirectory(directoryFullName);
-                                                       }
-
-                                                       FileMode fileOpenMode = 
m_append ? FileMode.Append : FileMode.Create;
-                                                       m_stream = new 
FileStream(m_filename, fileOpenMode, FileAccess.Write, FileShare.Read);
-                                                       m_append=true;
-                                               }
+                        m_stream = CreateStream(m_filename, m_append, 
FileShare.Read);
                                        }
                                        catch (Exception e1)
                                        {
@@ -558,14 +577,108 @@
                        /// </remarks>
                        public override void ReleaseLock()
                        {
-                               
using(CurrentAppender.SecurityContext.Impersonate(this))
-                               {
-                                       m_stream.Close();
-                                       m_stream=null;
-                               }
+                CloseStream(m_stream);
+                m_stream = null;
                        }
                }
 
+        /// <summary>
+        /// Provides cross-process file locking.
+        /// </summary>
+        /// <author>Ron Grabowski</author>
+        /// <author>Steve Wranovsky</author>
+        public class MutexLock : LockingModelBase
+        {
+            private Mutex m_mutex = null;
+            private bool m_mutexClosed = false;
+            private Stream m_stream = null;
+
+            /// <summary>
+            /// Open the file specified and prepare for logging.
+            /// </summary>
+            /// <param name="filename">The filename to use</param>
+            /// <param name="append">Whether to append to the file, or 
overwrite</param>
+            /// <param name="encoding">The encoding to use</param>
+            /// <remarks>
+            /// <para>
+            /// Open the file specified and prepare for logging. 
+            /// No writes will be made until <see cref="AcquireLock"/> is 
called.
+            /// Must be called before any calls to <see cref="AcquireLock"/>,
+            /// -<see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
+            /// </para>
+            /// </remarks>
+            public override void OpenFile(string filename, bool append, 
Encoding encoding)
+            {
+                try
+                {
+                    m_stream = CreateStream(filename, append, 
FileShare.ReadWrite);
+
+                    string mutextFriendlyFilename = filename
+                            .Replace("\\", "_")
+                            .Replace(":", "_")
+                            .Replace("/", "_");
+
+                    m_mutex = new Mutex(false, mutextFriendlyFilename); 
+                }
+                catch (Exception e1)
+                {
+                    CurrentAppender.ErrorHandler.Error("Unable to acquire lock 
on file " + filename + ". " + e1.Message);
+                }
+            }
+
+            /// <summary>
+            /// Close the file
+            /// </summary>
+            /// <remarks>
+            /// <para>
+            /// Close the file. No further writes will be made.
+            /// </para>
+            /// </remarks>
+            public override void CloseFile()
+            {
+                CloseStream(m_stream);
+                m_stream = null;
+
+                m_mutex.ReleaseMutex();
+                m_mutex.Close();
+                m_mutexClosed = true;
+            }
+
+            /// <summary>
+            /// Acquire the lock on the file
+            /// </summary>
+            /// <returns>A stream that is ready to be written to.</returns>
+            /// <remarks>
+            /// <para>
+            /// Does nothing. The lock is already taken
+            /// </para>
+            /// </remarks>
+            public override Stream AcquireLock()
+            {
+                // TODO: add timeout?
+                m_mutex.WaitOne();
+
+                // should always be true (and fast) for FileStream
+                if (m_stream.CanSeek)
+                {
+                    m_stream.Seek(0, SeekOrigin.End);
+                }
+
+                return m_stream;
+            }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            public override void ReleaseLock()
+            {
+                if (m_mutexClosed == false)
+                {
+                    m_mutex.ReleaseMutex();
+                }
+            }
+        }
+
                #endregion Locking Models
 
                #region Public Instance Constructors


Reply via email to