What is the best way to create a lock from a web application?

徘徊边缘 提交于 2019-12-05 04:10:50

Did you consider using middleware for that, such as MSMQ or ActiveMQ? Once the image resize request to web server is submitted, it goes to the queue. A separate application would check the queue, resize the image and save it to cache.

I would avoid locks if you can - especially since you don't need to lock here. You also want to avoid one machine locking based on another machines processing. If two machines create the same resized image, I assume they would be the same. So, if two machines happen to resize the same issue because they both missed the cache then its only slightly less efficient (wasted time) but very likely better than locking (and possibly deadlocking) and trying to optimize the edge case.

One option would be to create the resized image locally and enqueue the cached item into a central queue (database? in memory on central service?) either with the data or with a reference how to pull it from the front end machine. The centralized cache queue is processed serially. If two duplicates get put in the queue between the time it's resized by more than one machine and the queue item can get processed, it doesn't matter since processing the duplicate would simply condition pulling it since it's already on disk.

Firstly, generate the filename with a GUID so that you know you aren't going to have duplicate filenames.

Guid.NewGuid()

Then prevent locking on the images by using the code below :-

    public static Image GetImageWithoutLocking(string workingPathFileName)
    {
        Image returnImage = null;
        try
        {
            using (FileStream fileStream = new FileStream(Path.Combine(LivePaths.WorkingFolder, workingPathFileName), FileMode.Open, FileAccess.Read))
            {
                byte[] img;
                img = new byte[fileStream.Length];
                fileStream.Read(img, 0, img.Length);
                fileStream.Close();
                returnImage = Image.FromStream(new MemoryStream(img));
                img = null;
            }
        }
        catch 
        {
            throw;
        }
        return returnImage;
    } 

I have this code running very effectively and it was the only way I could find to be sure that the file is never locked.

Using a database to list file hashes would be the quickest way to do it. Then this can be shared between all tiers it also allows you to offload any locking in to the Transactional SQL (T-SQL).

Other large scale applications that have to store TB like Symantec Enterprise Vault do the same thing.

It should be no different from web apps that need to control the editing/updating of data in a database.

As far as I have tried, successfully, was storing the image as a blob field in the database. I had the blob editing controlled just as any other data field would.

Which means you have to be familiar with how web services work with the database to deal with collisions and concurrency control.

As an alternative If you cannot afford a highly scalable rdbms ... Instead of storing as blob in the database, you could store the file name/path, where the actual image is stored in the file system. The database provides the unique key to an image. All accesses to any image has to be done thro its database record. Every time a new image is generated, the following takes place under an atomic transaction in the order prescribed

  1. it is stored under a new name/path
  2. if success, the database record is updated
  3. if success, the old image is deleted

This is the contingencies you have to treat: if the last step is not successful (system/power failure may be), the db record would be rolled back and you would have an orphan image. Or if the db update fails, the newly stored image would end up as an orphan.

Therefore, to keep your file system sane and clear away orphans, you will probably delete images that are older than 24 hours.

For a more robust solution, refer to a description of my web app caching technique:

http://h2g2java.blessedgeek.com/2010/04/page-caching-using-request-parametric.html

I would suggest 2 solutions which are similar in the nature. one of them is to use a WCF service layer. Within this service, you can use a concurrent dictionary. You should develop a hash code in such a way that, same image would create the same hash. Therefore you will have a single instance of the image in your concurrent dictionary. You can as well add time stamp to your class which will represent the image. It might have a use. Once you generate the image you can update this class in your class with the location of generated image. and you can have a big flag which will indicate that this image is being processed if you have another request comes in asking for a resize. then you ignore that request. Not only that you are using a concurrent dictionary, you can also lock single key within the dictionary again. but if you use a bit flag as CurrentlyProcessing, you wont need a lock. This would be a very fast and efficient solution, IMO.

Another solution would be a distibuted hash table such as appfabric cache. Same logic as above.

what do u think?

I am not sure if you really need to solve this point - consider the following points:

  • what if one server starts resizing a specific and the resiszing process gets somehow "stuck" ? IF you implement what you describe then all other servers would wait for that server to finish... not sure this makes for a good user experience
  • OTOH if you don't implement that you only loose a bit of time but are not confronted with solved the above issue...

I would definitely implement some sort of either DB- or (central) in-memory-cache of the contents (image IDs) of the 2nd-tier-cache to avoud machines from getting into conflicts when copying the resized image into the cache...

If you want to make a client be able to process one random image at a time first you store a flag in the viewstate when you the request is sumbitted. The flag is raised when the data is submitted and flag is resetted when you finish processing the image. When you get a request just check if the flag is raised or not. if raised reject to process the image.

In second case, namely, if you want to pretend user to submit the pretty same image you can store the name and size(bytewise) of the image in viewstate and when user selects an image you compare the name and size of the image before you process the image. if the size and name of the image are the same that you stored in viewstate you reject to process the image. otherwise you process it.

Hope it can help you.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!