0

I have seen several similar issues on Stack before but nothing that seems to fit my needs.

I have a simple scenario. A webpage that streams a pdf file but a separate service that updates that same pdf file every so often. I have written both the web site and the serive so I can do whatever needs to be done.

The service actually does everything it needs to to do to a temp file and then at the very end it replaces or moves the temp file to the final pdf location.

My thought was to use a named mutex but the service generates a lot of pdf files so I don't want all pdf files locked from reading because I am writing a specific pdf at the moment. I didn't think it was practical to have a named mutex for every single pdf file either.

This seems like it should be simple. What am I missing? Suggestions on how to control access to each pdf file so the webpage does not try to stream it at the same moment the service tries to overwrite it? Logs show this happens several times every day.

mdutra
  • 393
  • 5
  • 18
  • `I didn't think it was practical to have a named mutex for every single pdf file either.` Why? – SLaks Aug 08 '13 at 19:13
  • The number of pdf file to manage continues to grow over time so I could have hundreds of pdf files. I also thought I would name the mutex the name of the pdf but I won't know when I can safely dispose of the mutex. – mdutra Aug 08 '13 at 19:28
  • 1
    Open the file in Exclusive mode http://stackoverflow.com/questions/685135/open-file-in-exclusive-mode-in-c-sharp – Mike Aug 08 '13 at 19:32
  • Won't that cause one application to throw an exception? I just want the "other" app to wait till the first one is done and then complete the task. I already get an exception when the file is in use and usually results in the pdf not getting updated as it needs to be. – mdutra Aug 08 '13 at 19:38
  • You can loop until you don't get the exception put the open in a localized try/catch block within a do while loop. If there's an exception, wait and try again, or fail and try again later. All depends on how you want to handle the exception. – Mike Aug 08 '13 at 19:42

2 Answers2

0

I'd version the PDFs.

Assume you have a file, FOO.PDF, that you want to stream. Its actual name would be FOO.1.PDF. When a user requests FOO.PDF, the Web server gets a list of all the files in the directory that match "FOO.*.PDF", and selects the one with the highest number.

When uploading a file, you upload to a temp file and then do a directory for "FOO.*.PDF", get the highest version number, increment it by 1, and then rename the temp file. So the next time a client wants FOO.PDF, he'll find FOO.2.PDF.

This completely eliminates any sharing or locking problems. You will, however, have to clean the directory from time to time to remove stale versions.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
0

Here is what I tried and it does seem to work pretty well so far:

string mutexName = String.Format(@"Global\{0}", caseId.ToString());
Mutex mutex;
if (!Mutex.TryOpenExisting(mutexName, out mutex))
{
     bool isNew;
     MutexSecurity mSec = new MutexSecurity();
     SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
     MutexAccessRule rule = new MutexAccessRule(sid, MutexRights.FullControl, AccessControlType.Allow);

      mSec.AddAccessRule(rule);
      mutex = new Mutex(false, mutexName, out isNew, mSec);
}
if (mutex.WaitOne(5000))
{
     try
     {
          // read/write/modify the file
     }
     finally 
     {
          mutex.ReleaseMutex();
     }
}
else
{
     Common.LogInfoMessage(String.Format("Timed out waiting for pdf mutex. CaseId: {0}", caseId));
}

Since the 2 processes were running under different user accounts I had to pass in a MutexSecurity object. In this case I just gave everyone access to it but I could give just the 2 accounts access to it if I wanted to restrict it further. Also, make sure you make the name global...didn't do that at first.

Going to run this for a few days and see what the logs say. I have a good feeling though.

mdutra
  • 393
  • 5
  • 18
  • What happens when you want to add a new file? Do you automatically create a new Mutex with that file name? Or is this a single global mutex that will block if any other file is being accessed? – Jim Mischel Aug 08 '13 at 21:52
  • A new mutex is created for each pdf file. I am assuming that garbage collection will clean up mutexes that have no references to them after a period of time. This was my main concern though. – mdutra Aug 09 '13 at 14:45