tags:

views:

2307

answers:

4

I have two ASP.NET web application. One is responsible for processing some info and writing to a log file, and the other application is reponsible for reading the log file and displays the information based on user request.

Here's my code for the Writer

public static void WriteLog(String PathToLogFile, String Message)
{
    Mutex FileLock = new Mutex(false, "LogFileMutex");
    try
    {
        FileLock.WaitOne();
        using (StreamWriter sw = File.AppendText(FilePath))
        {
            sw.WriteLine(Message);
            sw.Close();
        }    
    }
    catch (Exception ex)
    {
        LogUtil.WriteToSystemLog(ex);
    }
    finally
    {
        FileLock.ReleaseMutex();
    }
}

And here's my code for the Reader :

private String ReadLog(String PathToLogFile)
{
    FileStream fs = new FileStream(
          PathToLogFile, FileMode.Open, 
          FileAccess.Read, FileShare.ReadWrite);
    StreamReader Reader = new StreamReader(fs);
    return Reader.ReadToEnd();
}

My question, is the above code enough to prevent locking in a web garden environemnt?

EDIT 1 : Dirty read is okay. EDIT 2 : Creating Mutex with new Mutex(false, "LogFileMutex"), closing StreamWriter

A: 

Doing this in a web based environment, you are going to have a lot of issues with file locks, can you change this up to use a database instead?

Most hosting solutions are allowing up to 250mb SQL databases.

Not only will a database help with the locking issues, it will also allow you to purge older data more easily, after a wile, that log read is going to get really slow.

Tom Anderson
The log file is seperated on daily basis, and after the data has been read and parsed,it get's stored in database. Subsequent request for that day data is retrieved from database, not from log file. The average log file for one day is 350k.
Salamander2007
so why not just use a database to begin with?
Tom Anderson
The database connection is not really reliable, and I need the writer code to still be able to perform even without database support.
Salamander2007
A: 

No it won't. First, you're creating a brand new mutex with every call so multiple threads are going to access the writing critical section. Second, you don't even use the mutex in the reading critical section so one thread could be attempting to read the file while another is attempting to write. Also, you're not closing the stream in the ReadLog method so once the first read request comes through your app won't be able to write any log entries anyway until garbage collection comes along and closes the stream for you... which could take awhile.

Spencer Ruport
I don't use mutex while reading the critical section because I open the stream non exclusively using FileAccess.Read, FileShare.ReadWrite. And I guess I forget to mention that dirty read is okay. I'll edit the question.
Salamander2007
On the Mutex note, it's my understanding that named mutex is unique per operating system. I could be wrong,. I'll look it up.
Salamander2007
+5  A: 

Sounds like your trying to implement a basic queue. Why not use a queue that gives you guarenteed availability. You could drop the messages into an MSMQ, then implement a windows service which will read from the queue and push the messages to the DB. If the writting to the DB fails you simply leave the message on the queue (Although you will want to handle posion messages so if it fails cause the data is bad you don't end up in an infinite loop)

This will get rid of all locking concerns and give you guarenteed delivery to your reader...

JoshBerke
+1. A queue would probably give better throughput than file locking...
Mitch Wheat
More importantly a queue will give better scalability in a web garden since you have no need for locking.
JoshBerke
Message Queue seems like a good idea. I'll try it next. Right now I'm trying to minimize dependency to other services
Salamander2007
@Sal: If your concerned with design depedancy hide the queue behind a facade, if your concerned with runtime depdendancy well...MSMQ is part of the OS but not installed by default so I understand but it is easy to add.
JoshBerke
+1  A: 

You should also be disposing of your mutex, as it derives from WaitHandle, and WaitHandle implements IDisposable:

using (Mutex FileLock = new Mutex(true, "LogFileMutex"))
{
    // ...
}

Also, perhaps consider a more unique name (a GUID perhaps) than "LogFileMutex", since another unrelated process could possibly use the same name inadvertantly.

Mitch Wheat