Slashdot Mirror


Data Locking In a Web Application?

An anonymous reader writes "We recently developed a multi-user application and deployed it to our users. This is a web-based application that used to be a Windows application which was written in Delphi using Paradox databases for the client database. In the Windows application, we used the ability in Paradox to lock records which would prevent users from editing the same data. However, in the web application we did not add in a locking facility for the data due to its disconnected nature (at least that's how I was shot down). Now our users are asking to have the locking back, as they are stepping on each others' edits from time to time. I have been assigned to look at best practices for web application locking of data, and figured I would post the question here to see what others have done or to get some pointers to locations for best practices on doing locking with in a web application. I have an idea of how to do this, but don't want to taint the responses so I'll leave it off for the time being."

283 comments

  1. Duct Tape by Anonymous Coward · · Score: 5, Funny

    Lots and lots of Duct Tape.

    1. Re:Duct Tape by Mikkeles · · Score: 1

      More seriously, you may wish to investigate 'Software Transactional Memory' (STM).

      --
      Great minds think alike; fools seldom differ.
  2. Same as bugzilla? by Derek+Pomery · · Score: 5, Informative

    Same as bugzilla does. Just use a timestamp or counter on the records so you can tell when an edit occurred while you were editing
    Then you can review the edit.
    If you want, you can use XHR (maybe with a slow load response for performance depending on the number of users) to notify that an edit happened.

    --
    -- perl -e'print pack"H*","6e656d6f406d38792e6f7267"' /. ate my old sig. Bastards.
    1. Re:Same as bugzilla? by Anonymous Coward · · Score: 4, Informative

      Exactly, this is how I have done it in every web application I have developed. If someone updates the data while someone else is editing then they will get a message saying someone did an edit. They then get a chance to review the new data and modify their edit if needed.

      NOTE: It is critical that the user not lose their edit. Save that data even if you don't actually do the update. There is nothing more annoying than spending 15 minutes carefully putting in a bunch of data just to have it lost due to someone else editing the same record. Let the user review what happened and then modify (or not) their own data they were putting in.

    2. Re:Same as bugzilla? by dindi · · Score: 2, Informative

      On top of this you could actually send AJAX requests while editing to see if someone is requesting the data. Carefully, considering performance.

      An other option is to check-out, check-in with a session. In this case of course you need to make sure if a checked-out file's session is still alive.

    3. Re:Same as bugzilla? by Anonymous Coward · · Score: 0

      What's amazing to me is that this idea isn't blindingly obvious until you've had it explained to you clearly. I remember when I was a new developer and someone showed me this the first time. I couldn't believe I had been so dumb. I couldn't believe I had never thought of it myself.

      That's why I believe getting out and talking to and learning from other developers is absolutely critical.

    4. Re:Same as bugzilla? by Zarf · · Score: 4, Informative

      For the record this is called: http://en.wikipedia.org/wiki/Optimistic_locking

      --
      [signature]
    5. Re:Same as bugzilla? by Dexx · · Score: 5, Insightful

      To ensure the edit isn't lost, we handle this by kicking the user back to the form with a message. You could go one step further and get the modified record from the DB, then highlight the field in question and give the user the option to keep/override. You could make it more intelligent by detecting the collision, analysing the difference, then committing if no fields conflict. Depends on the business logic, I guess.

      --
      Feel the fear and do it anyway.
    6. Re:Same as bugzilla? by gmrath · · Score: 1

      I deal with a browser-based CMMS system at work that has this fault. One would hope for the cost of the purchase of software, hardware and the annual maintenance (not cheap) that the developers would make sure the system has something as basic as record locking, notification that the record is in use, or both. After all, it's a front end of a relatively sophisticated database. And databases have been around a while and for the most part are thoroughly understood. The first package we had: V2.0; the current package V4.0. Guess what? No record locking. And no luck with the vendor. They are very nice and seem to be attentive to bug reports, but still no record locking. The CMMS system is better than most for our application and is easy to learn and use. It's this one thing that's the pisser. We've learned to save work very, very frequently. And you're right, there's nothing quite as annoying as losing 15 minutes or more of work. Just gone. Just a information box saying, in effect, "So Sorry, record in use, entries not saved". Really wish you were on that dev team.

    7. Re:Same as bugzilla? by Casandro · · Score: 1

      True, the way to go is simply to store every change and usually display the newest version of a record. This also allows you to make an "undo" function which your users will appreciate very much.

    8. Re:Same as bugzilla? by dgatwood · · Score: 1

      The trivial solution is to set a time stamp and user ID every time somebody goes in to modify it. If the time stamp is within the last thirty minutes, display a warning that "John Doe is editing this file. You should check with him/her before making changes to make sure you don't collide." That's good enough for 99% of these sorts of things.

      But yeah, rolling back and showing both versions in a side-by-side view when collisions occur is a nicer user experience if you're dealing with a lot of users. Using diff and patch to generate a suggested merging of the two new revisions with changes highlighted in yellow and conflicts shown in red is nicer still.

      --

      Check out my sci-fi/humor trilogy at PatriotsBooks.

    9. Re:Same as bugzilla? by Anonymous Coward · · Score: 1, Insightful

      I absolutely HATE this method, because 90% of the time you are given: "Their edited field" and "Your edited field" - both of which are completely useless for comparing changes. Please, if you do this, make sure to show changes, not end results. (This can be as simple as including the "original" alongside

    10. Re:Same as bugzilla? by Anonymous Coward · · Score: 0

      Finally, can't believe I had to read this far down before somebody actually used the terminology.

    11. Re:Same as bugzilla? by nahdude812 · · Score: 5, Informative

      When a client wanted to know while they were working on a record that someone else had it open (they truly wanted the record locked while one user had it up on the screen), we used a LOCKED_BY and LOCKED_UNTIL field on each relevant record. While editing, records are read-only if LOCKED_UNTIL is in the future and LOCKED_BY is not the current user.

      On the edit page, an AJAX call is made on a 10 second interval which updates LOCKED_UNTIL to be +30 seconds (this way even if there are network issues of some sort, three consecutive status updates need to fail in a row). If the browser is closed or the computer blue screens, etc, after 30 seconds the record unlocks itself. When you save the record, LOCKED_BY is nulled, and LOCKED_UNTIL is set to the epoch.

      We also employed a version ID so that if all else fails and your client for some reason stops keeping the record locked (eg you suspend your laptop and come back to it later), when you submit your edits; if anyone else had made edits while your client was unable to keep the record locked, you're still given an indication that another user updated the record. The interval update checks the version ID too (a single SQL statement with PostgreSQL's excellent UPDATE RETURNING syntax) and warns the client if somehow someone else updated the version without this client having been able to maintain the lock - as soon as the next update interval succeeds the user gets notice.

      The ajax call was basically something like:
      UPDATE tbl_something
      SET locked_by = (current_user), locked_until = (time+30)
      WHERE record_id = (record_id)
      AND locked_by = (current_user)
      RETURNING
      locked_by, version_id

      Double check that locked_by is still the current user and version_id is still the known version of this record.

    12. Re:Same as bugzilla? by Ash+Vince · · Score: 1

      The problem with record locking on web apps is that unless they are written with it in mind then it can be very hard to implement. This is particularly an issue if the application uses the edit page as a way of viewing data as well. In this case the system may have no way of knowing if a user is actually editing a record or just seeing what is currently there.

      The problem with your little "Record in Use" box is that the system has no way of knowing if the person who locked the record actually closed their browser and so the record would be locked indefinitely. Now you might say that you could use JavaScript and the onUnload event to trap this, but you would be wrong as most of these toolbars (Google, Yahoo, etc) that people have installed trap the onUnload event silently and do not provide a list of allowed sites. This then leaves the only way do to record locking well in a web app as to have the edit page constantly sending status reports to the server.

      While this is not very difficult to implement it does require a developer with some fairly advanced knowledge of Javascript. You would be amazed how easy it is to write a web application with almost no javascript knowledge. I do not find it hard to believe that a small company who only have one product would have very little knowledge of AJAX.

      It took me about 1 month of being a professional web developer before I needed to use Javascript to validate a form. After 5 years I have still not come across a situation where I needed to use AJAX. I have worked it into a few projects to keep my skillset up but the reality is that I could have completed those projects with other, possibly inferior but still acceptable to the client solutions. Were they happier with my fancy method? Yes. Was the extra time spent always worth the good will of the customer or the extra time charged? Maybe.

      This sounds like your problem. It sounds like you need to suggest to your vendor that the lack of decent record locking may be a deal breaker that is forcing you to look elsewhere. If you have a good relationship with them this may help, but do you think the money you give them as a client will cover the cost of implementing this or are there enough other clients asking for it as well?

      --
      I dont read /. to RTFA, I read /. to offend people in ignorance.
    13. Re:Same as bugzilla? by KillerBob · · Score: 2, Insightful

      Mod parent up.

      That's basically what I was going to suggest, and I think it's more in line with what the clients of the OP are asking for... in Paradox, when a record was locked it was tagged read-only until it was unlocked (or the lock expired). This way, when you're using a multi-user database access program, one user can open/edit a record, and other users can access the information within, but nobody else can modify it. So if you implement it the way parent is saying, you'll end up with a system that's much more in line with the behaviour that the client had with their Paradox database, and will likely give better functionality.

      The way that other people are suggesting, honestly, would just annoy me. I'd be *really* pissed if I opened a document, spent half an hour working on it, then committed my changes only to find out that somebody else had been spending time working on it as well. That adds up to a lot of wasted time. If, however, I were given an indication that somebody else was editing it, I could work on a different record without wasting my time.

      --
      If you believe everything you read, you'd better not read. - Japanese proverb
    14. Re:Same as bugzilla? by Raffaello · · Score: 1

      Or you could just use a timeout on the lock. You could even include a countdown timer on the edit page so the user knows how much time they have before the record is unlocked again and any unsaved changes will be lost. A lot of ticketing web sites use this method. You select a set of tickets to review and a timer starts running. If you don't approve them (seat location, price, etc.) and enter your payment information before the timer expires, then they go back into the general pool - essentially record locking where the records are theater tickets.

      This way if the user locking a record closes his browser, goes to lunch, starts watching hulu, has a browser or system crash, etc., when the timer runs out the record is unlocked and others can edit it.

    15. Re:Same as bugzilla? by hoggoth · · Score: 1

      > Finally, can't believe I had to read this far down before somebody actually used the terminology.

      I can't believe you read this far down, thinking all the while that somebody should use the right terminology, terminology which you clearly knew and you didn't bother to post it yourself, but THEN after seeing it you DID bother to post a content-free message.

      --
      - For the complete works of Shakespeare: cat /dev/random (may take some time)
    16. Re:Same as bugzilla? by TheUnknownCoder · · Score: 2, Insightful

      Beautifully simple! If I may add: try to keep all this functionality inside your Data Access Layer. That will really make things simpler in the presentation layer (your web pages).

      --
      Uncopyrightable: The longest word you can write without repeating a letter.
    17. Re:Same as bugzilla? by mini+me · · Score: 1

      Given that posts are ordered chronologically, the only way he could have posted it before would be to go back in time. Last time I checked, nobody had found a solution to that problem yet.

    18. Re:Same as bugzilla? by TooMuchToDo · · Score: 2, Interesting

      The way that other people are suggesting, honestly, would just annoy me. I'd be *really* pissed if I opened a document, spent half an hour working on it, then committed my changes only to find out that somebody else had been spending time working on it as well. That adds up to a lot of wasted time. If, however, I were given an indication that somebody else was editing it, I could work on a different record without wasting my time.

      I think Google Docs shows an excellent way of handling this. It uses AJAX to tell everyone on that page, spreadsheet, etc. who else is viewing/collaborating on it, and changes are reflected in real time. You don't have to go so far as to reflect changes in real-time, but just seeing who else is working on the doc would be helpful so you could IM them to collaborate and prevent collisions.

    19. Re:Same as bugzilla? by MightyMartian · · Score: 1

      This is pretty much how I implemented it. I had a table that tracked records being edited, and as part of the garbage keeping, whenever a web app page was loaded, it would just run through the table and any lock that was deemed stale was was cleared.

      The only issue with that would be something that required a lot of data entry. If someone is going to be sitting on the same page for 20 minutes entering data, this might not be so successful. In that case I'd probably just consider tracking each load of such a page as a separate record. You would have the master record table, which would be nothing more than an id, and then another table that stored all the edits of the record (an edit history, really). When a user posted, you would just use the timestamp and then it would flag "Hey, someone else has an entry". How you deal with it at that point is up to you; allow the last user to redact or whatever.

      --
      The world's burning. Moped Jesus spotted on I50. Details at 11.
    20. Re:Same as bugzilla? by ormico · · Score: 0

      I have always heard this refered to as Optomistic Concurancy and it how I usually develop web apps or even non-web apps. Locks tend to be bad for lots of reasons.

    21. Re:Same as bugzilla? by Anonymous Coward · · Score: 0

      What I can believe is that there are thousands of people who actually studied distributed computing as part of a CS degree, who can't get a job, but people who are clearly and dangerously unqualified seem to have no trouble at all, and don't even fear for their safety.

    22. Re:Same as bugzilla? by BoxRec · · Score: 1

      I like it and I'm going to use it, thanks :-)

    23. Re:Same as bugzilla? by Anonymous Coward · · Score: 0

      "AJAX" was what was meant by "XHR"
      aka XMLHttpRequest

      Only without using a stupid buzzword.

    24. Re:Same as bugzilla? by SoopahMan · · Score: 2, Informative

      This is a very good solution but it can still paralyze you if someone:
      * Opens an important record
      * Gets distracted
      * Leaves for vacation for 2 weeks

      Now their PC is locked with the page open and constantly polling, the record is locked forever, and people are angry. This can be solved with a message like
      "This record is locked. _Take Control of this record_" - Clicking it would up-end the equasion - in order to keep control the other user has to click a "I'm still editing" link within a minute. This would solve not only the vacation disaster, but the lunch annoyance.

      Depending on your resources and how large a "Record" is, you may consider getting more granular as well. You could lock by field, or form section, to capture use cases where for example "I'll type up the client notes, you update their contact info to fix any errors you find, and we'll call them about this as soon as possible."

    25. Re:Same as bugzilla? by RareButSeriousSideEf · · Score: 1

      Good points.

      I've finally come to the opinion that locking is unnecessarily expensive, and doesn't tend to enhance collision handling capabilities beyond a simple concurrency timestamp check.

      The poster really only needs to answer one question: What should happen when a user attempts to save a record that another user has modified? There are only so many options: (1) Reject the change and warn, or accept the change silently, or accept the change with a warning, then (2) refresh the data silently, or warn about losing changes and optionally refresh the data, or refresh to a shadow copy and offer merge possibilities.

      The pattern I use in my own ORM tools is to simply reject and warn when a user attempts to save a stale object (as determined by the concurrency timestamp which is part of every object's state). Then it's up to the implementer to warn about losing changes, optionally refresh the data, and finally offer merge possibilities when the amount of potentially lost work is significant. It's easy, it scales, and it doesn't leave orphan locks.

      The unspoken question is, why not design a user workflow that avoids synchronization issues instead of contriving Rube Goldbergesque concurrency schemes to handle them?

    26. Re:Same as bugzilla? by Anonymous Coward · · Score: 0

      You're working from the assumption that CS degrees teach concurrent programming skills. They must teach that in the masters programs or something.

    27. Re:Same as bugzilla? by psyclone · · Score: 1

      Why not design a user workflow that avoids synchronization issues?

      Agreed. With many clients, dealing with hundreds of open locks at a time, as well as those same hundreds of rows being updated by ajax every 10s seems like a nightmare to manage. If you have single-master, multi-slave database replication, it seems like ajax polling for an updated timestamp on the record should be sufficient, and/or handling the cases you described in (1) and (2) above.

    28. Re:Same as bugzilla? by kelnos · · Score: 2

      I've finally come to the opinion that locking is unnecessarily expensive, and doesn't tend to enhance collision handling capabilities beyond a simple concurrency timestamp check.

      I guess that's fine, depending on the users' needs. If "typical" edits require spending 20 minutes fiddling around with a web form before the user clicks the save button, I bet they're gonna be pretty pissed when they get a rejection message and their 20 minutes of work gets thrown away.

      With this in mind, if you're going to use your optimistic locking approach, you'd need to add more code that, instead of rejecting conflicting changes outright, presents the user with options, possibly listing the conflicting changes.

      Personally I'd find the auto-expiring lock option to be the best (the user will know going into it that someone else is editing), though hitting the DB to update the timestamp every 10 seconds doesn't scale to a large number of users. But there are other options, like ones some wiki software uses, where you get a longer locking period (on the order of several minutes), and you have to manually refresh the lock before it expires. Or you can possibly refresh the lock automatically, by checking to see if the user isn't idle.

      The unspoken question is, why not design a user workflow that avoids synchronization issues...?

      Yeah, that would be ideal, but may not be practical. The article poster says they're migrating a native app to a web app, so changing the users' workflow may not be an option.

      --
      Xfce: Lighter than some, heavier than others. Just right.
    29. Re:Same as bugzilla? by Anonymous Coward · · Score: 0

      YOU LIE!

    30. Re:Same as bugzilla? by complete+loony · · Score: 1

      A multiuser application I've worked on locked the entire client when you opened it. While a user had any client screen open, nobody else could modify any of the data on any of the 30 or so client related tables / screens. But then the application also had a kind of workflow system, so the client was assigned to one person to review anyway.

      --
      09F91102 no, 455FE104 nope, F190A1E8 uh-uh, 7A5F8A09 that's not it, C87294CE no. Ah! 452F6E403CDF10714E41DFAA257D313F.
    31. Re:Same as bugzilla? by nahdude812 · · Score: 1

      Depending of course on the culture present where the application is deployed, allowing someone to seize control of a record you have locked can be extremely frustrating. At some companies, people would just make a habit of clicking that option whenever it was presented to them, essentially defeating the purpose.

      Much better would be an application session timeout (which we used on the above described app as well). If you haven't moved the mouse or pressed a key within a configured interval (or changed screens since it's a web app), your session expires and any open records are closed (more precisely you're returned to the application login screen). That does of course lead to times when edits are lost (which is the primary reason for all this locking to begin with), so this is really mostly just a stop-gap to protect against a user just keeping the record locked indefinitely. Idle timeout in our case was I think 60 minutes.

      Since you're really mostly addressing a corner case at this point (someone goes on an extended leave while leaving the edit screen open, especially as in our case on an app where most edits are under 5 to 10 minutes), there are probably a couple of other better solutions to this (though which we hadn't implemented).

      For one, you could have an administrator screen which enables forcibly unlocking records which are locked by a certain user (simply nulling the LOCKED_BY column accomplishes this since the lock maintenance poller only maintains the lock if LOCKED_BY is still the current user, so the client will stop refreshing the lock).

      If the "take control of this record" option really is the right solution (eg, this happens frequently for whatever reason and it's too high of an administrative overhead to have only a handful of users capable of seizing control of records), then a LOCKED_AT timestamp seems to be in order, where you can only take control of the record if LOCKED_AT is a certain amount of time in the past.

    32. Re:Same as bugzilla? by xelah · · Score: 1

      Agreed. With many clients, dealing with hundreds of open locks at a time, as well as those same hundreds of rows being updated by ajax every 10s seems like a nightmare to manage.

      You don't actually need ACID semantics for the 10s heartbeats....what you need is a repository somewhere that tells you whether user/session/lock [x] is still alive. The database is a convenient but expensive one. If you really have a load problem and need locks then you can put all of this in a server/some servers somewhere, accessed by, say, CORBA or RMI. You quite possibly have an application server or somesuch handy already anyway. If a server crashes just restart it; it'll be up to date again in ten seconds. Such a thing can be useful elsewhere, too - such as for caching login cookies or rarely changed data.

    33. Re:Same as bugzilla? by psyclone · · Score: 1

      The examples given by others in the thread so far have been relational database driven.

      But you raise a good point to use an application's cache instead of hitting the DB. The bummer is that you need a shared/global cache (or separate app) for all of your app-servers to hit against.

      The gain is when you need to restart the entire application (say major code deployment), you only need to _not_ persist the cache to disk, which is a lot easier than cleaning all the locks out of the DB.

      Still, having no locks and gracefully failing or merging near-concurrent updates seems simpler and scalable.

  3. Re:The euphemism treadmill by Anonymous Coward · · Score: 1, Informative

    I think you have that backwards.

    http://www.merriam-webster.com/dictionary/taint

  4. This book: by walmass · · Score: 2, Informative

    on Google Books. You are welcome

    1. Re:This book: by Firehed · · Score: 1

      A handy resource (Google has full O'reilly books? When did that happen?), but I don't think it's quite what the OP had in mind. It sounds like the issue is more of the checkin/checkout/merge nature, rather than table-level locking. In which case keep it simple (at least to start) - when the first user starts editing, some sort of "in use by $userId" flag is set, and everyone else gets read-only access. When that user saves the document (or closes/cancels), remove the flag. Some sort of live editing (a la Google Docs) or diff/merge functionality might be good for v2 for a nicer experience.

      Adjust as needed to fit your actual requirements, but don't overcomplicate it.

      --
      How are sites slashdotted when nobody reads TFAs?
    2. Re:This book: by geminidomino · · Score: 1

      when the first user starts editing, some sort of "in use by $userId" flag is set, and everyone else gets read-only access.

      I've been looking at a way to do something just like this myself on a LAMP app. The problem I have is that I am aware that Users Are Idiots(TM) and do fun things like stop halfway through an edit to piss off for two hours, and I haven't found anyway to have the app force an "unlock" when the session expires...

      So far the only obvious solution (cronjob checking) is a non-starter, for various implementation reasons.

    3. Re:This book: by plastbox · · Score: 1

      One really simple way of doing it is (as a previous poster suggested) having the client send an AJAX call signifying that the document is still open. So, when I click "Edit" on "shopping_list.txt" it's database entry gets it's "edit_by" set to my userID and "ts_editing" field set to unix_timestamp() (for mysql or time() for php). The edit-page sends an AJAX request every.. say.. 30 seconds to a file that updates the timestamp.

      Now, when you list the available files, you will see that I am editing "shopping_list.txt" because it's current "ts_editing" is larger than (unix_timestamp() - 60). At most 1 minute after I leave the editing page, either by saving or by closing the window, the document will become available for editing again.

      If you are uncomfortable with JavaScript, check out jquery. In fact, check it out, even if you consider your js skills to be badass. The code for updating the editing-timestamp can be as simple as follows:

      function updatelock()
      {
      $.get("updatelock.php");
      }

      $(document).ready(function() {
      setInterval("updatelock()", 30000);
      });

      Assuming you set the flags mentioned earlier upon opening the file for edit, updatelock.php really only needs to do a
      UPDATE `files` SET ts_editing = UNIX_TIMESTAMP() WHERE edit_by = $_SESSION['userid'] AND ts_editing > UNIX_TIMESTAMP() - 60
      (updating the timestamp on anything you temporarily own that hasn't timed out) or something like that. =P

    4. Re:This book: by jadavis · · Score: 1

      At most 1 minute after I leave the editing page, either by saving or by closing the window

      I don't think this is a good approach. Lots of people leave browser tabs open for indeterminate amounts of time as they move on to other tasks.

      --
      Social scientists are inspired by theories; scientists are humbled by facts.
    5. Re:This book: by icebraining · · Score: 1

      Yes, but how could you know if it's the case?

      You could, as a response to those AJAX call, inform the user that someone is requesting access and ask him to click a button if he's still editing. If he doesn't, save the current state and close.

    6. Re:This book: by Anonymous Coward · · Score: 0

      file lock? on a shared list? in a txt file? used on the web? from multiple users?

      WTF???

    7. Re:This book: by plastbox · · Score: 1

      Sorry if I failed to make myself clear, the post was written pretty early in the morning. =P

      If the user leaves the browser tab open, the JavaScript running in the background keeps the document locked. While this prevents any loss of data it also prevents other users from editing the file should the user decide to leave work early and not close the tab (which, on second thought, is probably what you meant).

      This, of course, could (and should) be mitigated by having an inactivity timeout for the user's login session. Just make sure the users know that if they leave their computers for 20 (or whatever works for your application) minutes they will be logged out. Add a bit of JavaScript (jQuery, oh sweet cross-browser compatibility) to the updatelock() function that adds "?active=1" to the AJAX query if the document has been changed, and code in updatelock.php that updates the user's activity timestamp if !empty($_GET['active']).

      The result is document locking that allows only one user editing any given document, inactivity timeout (sensitive to typing in the document) and making the document available soon after the user is done, even should (s)he simply close the tab/window. And, since only one user is allowed to edit the document at any given time, one could even implement autosave.

      For the sake of not losing information, I'd definitely not be adverse to creating a temporary copy of a document when a user opens it for editing, auto-saving to this temp document and leaving any older versions of the document read-only when the user clicks "Save". Still, I'd stick with my one-user lock scheme to avoid two users editing a document and having only the version saved last appear as the most current version.

    8. Re:This book: by plastbox · · Score: 1

      Very elegant solution, but it doesn't solve the problem of users leaving their computers for short periods of time without saving documents and such. Let's say we're talking about someone who has a receptionist type role. The user who has the document open would have to get a grace period of at least, say, 10 minutes to click yes or no, and that would severely try the patience of whoever was trying to open the document.

      As I said below, I think a better solution would be to detect keypresses in the forms or the entire document and add "?active=1" to the update query. If the open document hasn't been changed in 10 minutes, it becomes unlocked. Perhaps the user's temporary incarnation of the file (with auto-save and all that) stays in the system as a read-only document only available to the creator, so that he/she doesn't completely lose their work even if they forget to save and suffer a timeout.

    9. Re:This book: by tweek · · Score: 1

      For the sake of not losing information, I'd definitely not be adverse to creating a temporary copy of a document when a user opens it for editing, auto-saving to this temp document and leaving any older versions of the document read-only when the user clicks "Save". Still, I'd stick with my one-user lock scheme to avoid two users editing a document and having only the version saved last appear as the most current version.

      I agree. This should really be the norm. This shouldn't operate ANY differently than a database does depending on isolation level. I like the idea of a collab-style "this use is also editing" but in the end, why the hell are two people editing the same thing at the same time other than for non-technical reasons. You can't solve ALL soft skill problems with technology.

      So really there are a few options:

      • collaborative style notifications/shared workspace messaging (the whole "this user is editing" thing)
      • exclusive access at edit with an acceptable timeout (the process for determining the timeout is irrelevant)
      • dirty reads where similar to READ-UNCOMMITTED isolation level

      I like a hybrid approach using exclusive access + collab along with some sort of versioning in place. I.E.

      • Suzie opens doc 1. Begins to edit.
      • Bobby opens doc 1. Notified that Suzie has exclusive access. Bobby is given the option of seeing the current saved version and allowed an option to edit a temporary copy.
      • In the event that Suzie is still editing when Bobby saves, Bobby's copy is stored as a Draft. At the point that Suzie finally commits her edit (after taking a 20 minute smoke break, hitting the head and getting lunch), Bobby is given the option to compare his changes to Suzie's changes.
      • At this point Bobby has exclusive access in case Frank decides to ALSO update the fucking record.
      • If Charles comes along to ALSO edit this obviously popular entry, he's prevented because these people obviously aren't talking to each other and need to get in the same fucking room and work some shit out.
      --
      "Fighting the underpants gnomes since 1998!" "Bruce Schneier knows the state of schroedinger's cat"
    10. Re:This book: by molecular · · Score: 1

      on Google Books.

      You are welcome

      The chapter you're pointing to describes mysql table-locking as far as I can tell at a glance.

      Table-locking is pretty much out of the question for the purpose here, since you would effectively prevent any editing to take place on any row within that table while some user would edit some (other) row in the table.

      You're welcome.

    11. Re:This book: by lena_10326 · · Score: 1

      A full table lock bound to unpredictable http sessions? Really now. And.. pray tell what's going to clear out the lock when the unlock request never comes? Garbage collection? How would a hacky garbage collector process distinguish a long session vs an abandoned session?

      In this case, going with an optimistic lock and handling conflicts after they've occurred is clearly a better solution. Your solution punctuated with smugness was totally inappropriate because web sessions are driven by unpredictable, unreliable, and untrustworthy humans. A full table lock would only work inside trusted network consisting of automated clients adhering to programmatic access patterns.

      Hand over your developer card now.

      --
      Camping on quad since 1996.
  5. More detail please by MichaelSmith · · Score: 1

    I the web version uses a database then your locking should work the same way. If it uses flat files or something you can create lock files along with the data. But IMHO lock files are a PITA.I suppose its locks which are a pain....

  6. Re:The euphemism treadmill by Anonymous Coward · · Score: 4, Funny

    So that's what the song "Tainted Love" is really about! Who knew.

  7. The way this is generally handled... by Omnifarious · · Score: 4, Informative

    You make sure that edits are handled in a form on a web page with a submit button. The user gets to fiddle all the bits they want on the web page, then they hit the submit button. At that point the web app goes and locks the stuff it needs to do to update the database to reflect the user's changes. It then applies those changes, then commits them, thereby releasing all the locks.

    If two users might potentially be editing the same records, keep an SHA-256 hash of the original data around as a hidden form field. Then when the update proceeds, check the data to make sure the SHA-256 hash matches the data you fetched when you generated the form page (helpfully put into a hidden form field). If the hash doesn't match, tell the person who did the submit that some fields may have changed and somehow present them with what those changes might be.

    1. Re:The way this is generally handled... by palegray.net · · Score: 5, Interesting

      My company has an internal app that approaches locking in a different manner. When you start updating a record, it uses an AJAX routine to set a lock on the record being updated. As long as you're still on that page, you "have the lock" and other users are notified of this if they attempt to edit the record. Once your changes are submitted, the lock is released automatically. It's possible to "steal" a lock in our model; this may not work for everyone. If you didn't want to allow this, you could incorporate a timeout for locks, whereby the original user would be notified that the lock had expired due to inactivity.

    2. Re:The way this is generally handled... by omkhar · · Score: 2, Informative

      Storing the hash of the original data client side is bad from a security perspective. A malicious user could manipulate the hash as they sought fit. I'd keep the hash in a server side session specific variable. I realize the damage that could be done seems small, but I wouldn't trust *anything* - especially a critical part of your locking mechanism - to a variable that could be manipulated client side.

    3. Re:The way this is generally handled... by Omnifarious · · Score: 1

      Can you explain to me how a malicious person's manipulation of the hash value could damage anything? How would they know what to change it to? I suppose they could just hash the form fields and hope, but that's easily defeated by adding in a server side session variable as salt.

      Also, while this isn't exactly the best practice, the question made it clear that it was a fairly small internal web app. So worrying about malicious users on that scale is likely not an issue.

    4. Re:The way this is generally handled... by palegray.net · · Score: 1

      Agreed. The GP might be right in theory, but it probably doesn't matter in practice. Some people feel a compulsion to pick nits, I suppose.

    5. Re:The way this is generally handled... by Omnifarious · · Score: 1

      I think that would likely be a lot nicer from a user's perspective. :-)

      But it would also take more work and have the locking mechanism rely on Javascript. You could still use my method as a backup for when Javascript didn't work for whatever reason.

    6. Re:The way this is generally handled... by Anonymous Coward · · Score: 0

      This is the method I would suggest too. The first part doesn't seem to really matter, it is really the hash comparing that prevents double editing. You could do the check with XHR as well.
      The OP makes it sound as if edit overwrites are fairly infrequent ("time to time") so exclusive locking may be a little overboard.

      Might be nice if you offered the user an option to merge their changes with the existing ones in the event of a collision.

    7. Re:The way this is generally handled... by nanospook · · Score: 2, Insightful

      Some interesting ideas here.. Especially the AJAX idea.. However, consider this. Any scheme that involves telling the user "after the fact" that the record has changed is "wasting" the user's/companies time and money, resulting in rework. If your scheme tells you ahead of time that so and so has the lock and you can't, then you save the user's efforts. Of course, I'm speaking generically in that some data entry systems might be ok with multiple edits of the same records.

      --
      Have you fscked your local propeller head today?
    8. Re:The way this is generally handled... by omkhar · · Score: 1

      Can you explain to me how a malicious person's manipulation of the hash value could damage anything? How would they know what to change it to?

      Any input taken should be scrutinized for injection, overflows etc. Another input from "out there" another set of variable to scrub. A sloppily coded hash/verification could be a vector for SQL injection for example.

      I suppose they could just hash the form fields and hope, but that's easily defeated by adding in a server side session variable as salt.

      If you have a session to begin with... just store it server side

      Also, while this isn't exactly the best practice, the question made it clear that it was a fairly small internal web app. So worrying about malicious users on that scale is likely not an issue

      assumptions regarding the scope, confidentiality, integrity or availability requirements weren't part of my answer. Only that from a security perspective, anytime you have another piece of information that's user submitted, requires a thorough check/scrub/sanitization prior to being processed.

    9. Re:The way this is generally handled... by Anonymous Coward · · Score: 0

      Use properly parametrized stored procedures/prepared statements and you don't need to worry about SQL injection.

    10. Re:The way this is generally handled... by Omnifarious · · Score: 1

      A hash value is 43 bytes of base64 encoded stuff. It's trivial to validate that it's still 64 bytes of base64 encoded stuff when you get it back. And verifying that it's the right set of base64 encoded stuff is fairly easy too. If it matches the result of computing the hash of what's in the database, the database hasn't changed since the form was generated. If it has, the database hash changed. The only possible attack is fiddling the hash value to be the hash of the data that now is in the database, which would require a willing accomplice who could tell you what the new values are because that's how they set them. And the result of that would be that their values are stomped on.

      Also, no SQL injection is possible because the hash value itself isn't stored in the database so there's no reason to include it in a database query in any way.

      So, I don't think there is an attack that could work by fiddling the hash value sent back in a hidden form field.

      And, doing so gives you extra security against X-site scripting attacks involving someone having a POST that goes against the web app URL from a completely different page. They are certain to not be able to get the hash value correct and the user isn't going to be tossed back from their attempt to post with a confusing message about the database having been updated since they filled out the form.

      For extra security against X-site scripting attacks you can make the hash be a MAC instead and have the key be some secret server side data from the server side session data structure. But that then starts requiring you to actually have sessions, which it doesn't sound like the original poster has.

      Just because someone is using data in hidden form fields for something important does not automatically mean that they are doing something insecure. This analysis I just posted was actually done in my head before I made the original post.

    11. Re:The way this is generally handled... by Omnifarious · · Score: 1

      Oh, I just thought of a reason why the AJAX idea would be even harder than I originally thought. I bet the web app doesn't even use cookies or sessions at all. That makes that kind of thing a lot harder to implement.

    12. Re:The way this is generally handled... by rta · · Score: 1

      I like this solution better than the optimistic locking usually seen in web apps, but it's a matter of the specific use-case, of course. This is a good method when there is a) significant chance of collision and/or b) editing takes a lot of effort or is high cost.

      pessimistic locking (even with js automation, timeouts and overrides as you describe) has the downside of of high complexity/cost of implementation, and as the guy above says you still need versioning or other system as backup if this is at all an "important" system since you can't (shouldn't) trust that the web browser will do the right thing.

      bugzilla's done ok w/ just collision detection for a good 10 or 15 years :-)

    13. Re:The way this is generally handled... by Mathinker · · Score: 1

      For extra security against X-site scripting attacks you can make the hash be a MAC instead and have the key be some secret server side data from the server side session data structure. But that then starts requiring you to actually have sessions, which it doesn't sound like the original poster has.

      Am I missing something here, or didn't you skip a step in the security hierarchy? A MAC with a fixed secret server side key would still be more secure than a vanilla hash (it would limit the attacker to replay attacks), yet not need sessions, no?

      Or was everyone saying "hash" when they meant "fixed-key MAC" (since there really is no reason I can see not to implement a fixed key MAC, here, instead)?

    14. Re:The way this is generally handled... by palegray.net · · Score: 1

      I largely agree, although for an internal application I think JavaScript can be an assumed capability. It's actually not a lot of work; it could probably be implemented in a couple of days with some investigation into jquery and some minor DB changes ;).

    15. Re:The way this is generally handled... by omkhar · · Score: 1

      Last post on this topic - clearly you and I have a different understanding of security. No HTTP POST/GET variable are typed - you can throw whatever you want in them. Lazy assumptions about length won't help you either. Point is, there is an extra set of data to parse. Whenever there is data to parse, there is the potential for an exploit. See my solution above, and lets move on.

    16. Re:The way this is generally handled... by palegray.net · · Score: 1

      Well, bolt on some session handling :). That piece should be separate from primary application logic anyhow, so it shouldn't be too difficult to put in place.

    17. Re:The way this is generally handled... by palegray.net · · Score: 1

      Honestly, it shouldn't be difficult to add this to any existing web application. I think it's a prerequisite for any situation where there is a chance of collisions (as you pointed out), unless the users are technically savvy enough to be presented with a diff of the values and allowed to make a decision based on the available data. In my view, versions should still be maintained as part of a comprehensive logging system (regardless of which approach is taken). This isn't difficult either; it's a simple matter of tracking the version data in a separate write-only table.

    18. Re:The way this is generally handled... by Omnifarious · · Score: 1

      Oh, you're right. I didn't think of that. It would be more secure, and that's a good idea. And you're right, given that idea there is no good reason not to implement it using a MAC instead of a hash.

      I still don't think the plain old hash is all that insecure though.

    19. Re:The way this is generally handled... by spiffmastercow · · Score: 2, Interesting

      How do you make sure the lock gets released when the page closes? I once investigated this, but determined that I would have to either a.) set a timeout on the lock and have the page update the lock every x seconds, or b.) use the page close event and hope that the user's browser doesn't close unexpectedly.

    20. Re:The way this is generally handled... by Anonymous Coward · · Score: 0

      I don't know how the parent does it, but you couldn't rely on the page close event if you want any kind of robustness. There would definitely be cases where you never receive the page close event notification (for a variety reasons).

      You would need a server side thread to handle the lock renewal in some way (such as you suggest with limited time locks unless they are renewed).

    21. Re:The way this is generally handled... by plastbox · · Score: 1

      Seconded! jQuery is pure genius! It takes the tedious work of making JavaScript work reliably across different browsers and turns it into something fun, easy and efficient (and of course, automatically cross-browser compatible).

    22. Re:The way this is generally handled... by buchner.johannes · · Score: 1

      Obviously the first has to be used (as GP said, AJAX is used). But you don't have to look into proprietary web apps, dokuwiki does that too.

      --
      NB: The message above might reflect my opinion right now, but not necessarily tomorrow or next year.
    23. Re:The way this is generally handled... by plastbox · · Score: 1

      See my post further up. Setting a timeout and having it updated as long as the page is open is nothing short of trivial and should work very well. There might be better ways of doing this, but I fail to see any.

    24. Re:The way this is generally handled... by Anonymous Coward · · Score: 0

      Well, the alternative that is proposed is to send the user away, which might waste his time just as much.
      The perfect approach is of course to not use any of these but instead implement a fully automatic, always correct merging of changes.
      Unfortunately that is unlikely to be possible in most cases, so you _will_ end up wasting someone's time, the question is just whose, how, and how much of it.

    25. Re:The way this is generally handled... by omuls+are+tasty · · Score: 1

      I fail to see how it matters for this particular locking purpose. Please explain what are the gains of scenario 1 gain over scenario 2 from a malicious user perspective:

      1. Mallory makes some changes; another user makes other changes to the same document and saves it before Mallory does. Priory to posting her changes back, Mallory retrieves the new hash, and changes the form value accordingly, thus cleverly escaping your locking mechanism
      2. Mallory makes some changes; another user makes other changes to the same document and saves it before Mallory does. Mallory posts the form normally, gets notified that the document has been changed in the meantime and clicks "save anyway"
    26. Re:The way this is generally handled... by CharlyFoxtrot · · Score: 1

      This is an old problem too, it's not like desktop apps have never unexpectedly quit after locking a DB record. The method you describe has been tried & tested for many years.

      --
      If all else fails, immortality can always be assured by spectacular error.
    27. Re:The way this is generally handled... by plastbox · · Score: 1

      Yeah, I know *cough* MS Office *cough* but as far as I know most desktop applications don't feature a lock timeout. At least MS Office doesn't. The solution I am suggesting solves this elegantly and as a whole presents exactly one of each file to the users, and that file is locked for the duration of the edit (plus, say 10 minutes for the timeout).

      I see no flaws in this approach but please inform me if you do!

    28. Re:The way this is generally handled... by nanospook · · Score: 1

      Sure it depends on the situation. But most cases, they can work on something else so its not wasted time. Often you can design your "process" so that they never work on the same record at the same time because their tasks lists are "on purpose" not overlapping.

      --
      Have you fscked your local propeller head today?
    29. Re:The way this is generally handled... by Anonymous Coward · · Score: 0

      Well, the alternative that is proposed is to send the user away, which might waste his time just as much.

      The other alternative is to inform the user and let them decide whether they would rather be sent away or continue and possibly step on someone else's changes.

    30. Re:The way this is generally handled... by TooMuchToDo · · Score: 1

      Have a "lock last refreshed" field in the database, and a process that scans records for locks that haven't been refreshed in X seconds (whatever you think is sane) and release the lock.

    31. Re:The way this is generally handled... by Lord+Jester · · Score: 1

      You could also do this, I would think, using stored procedures for data reads as well as writes.

      The first step in a read of unlocked data would be to lock the row/dataset. You can accomplish this with a "lock column" which is just an id column. This id can be a user id or more appropriately a session id.

      Then on the submit, the record is unlocked by removing the entry in the "lock column".

      Only a matching user/session id can write to that data.

      Upon reading, if the "lock column" is not null, read in the data but notify the user that it is read only.

      *** Disclaimer ***

      It is early and I just came up with this off the top of my head, so there may well be flaws with, or at least a better method to acomplish, this task.

    32. Re:The way this is generally handled... by Lord+Jester · · Score: 1

      Indeed. jQuery rocks. I have started introducing it to existing apps here. I just wish the other developers would see the beauty and not remain tied to archaic methods.

    33. Re:The way this is generally handled... by mhelander · · Score: 1

      All this malicious user would accomplish would be to bypass the locking mechanism - that is, save his changes even though someone else has updated the same document with changes unseen to the "malicious user".

      "Damn, apparently there's a conflict in my commit....but not to worry, I won't have to resort to inspecting the changes and merge - I'll just rerun the hash-algo on the other user's changes and use that hash, allowing me to save _without actually looking at the other user's changes_!!"

      You could, of course, achieve the same malicious results by refreshing but _not look_ at the other user's changes and just commit your version as the good one, not caring about any merge...

    34. Re:The way this is generally handled... by Baki · · Score: 1

      Would suggest the have a timeout on the lock. i.e. the page has to renew the lock every x seconds as long as you are on the page.
      If the browser crashes, the lock will be released soon.

  8. Hibernate In Action (even if not using Java) by Zarf · · Score: 2, Interesting

    is a great book about this. Even if you don't use Hibernate or Java. If you hate Java just take the parts of the book dealing with Java and burn them. The rest of the book has awesome discussion of database design for the web... and those parts are worth the purchase price by themselves.

    "Hibernate in Action" covers "Optimistic Locking" which is a simple technique. Just put a versionNumber column in every table and never let anyone insert any version number less than the one in the database... http://en.wikipedia.org/wiki/Optimistic_locking ... if you have another scheme... even if it is smarter and better than this in every conceivable way DO NOT DO IT without FIRST getting Optimistic Locking working.

    --
    [signature]
    1. Re:Hibernate In Action (even if not using Java) by Anonymous Coward · · Score: 0

      I agree wholeheartedly. Optimistic Locking is the way to go (here's another wikipedia article: http://en.wikipedia.org/wiki/Optimistic_concurrency_control). Reliance on pessimistic locking techniques, will only get you into trouble in a stateless, web browser world.

    2. Re:Hibernate In Action (even if not using Java) by xelah · · Score: 1

      It's a simple, effective and elegant technique which fails to solve the problem. Yes, it stops a second user throwing away a first user's changes....by throwing away the second user's changes. You can write and the user can negotiate some sort of conflict resolution, but in terms of your software's behaviour as presented to your users that's really a whole other option (there are four: 1. first user wins; 2. second user wins; 3. locks; 4. tell the user and let him merge or choose, eg like Subversion).

      HTTP may be stateless, but the world and people's view of it is not. Locking is a readily understood concept and it prevents users doing work which needs to be thrown away or repaired, or which is duplicating what someone else is doing. It may not be appropriate to the (real-world) situation, but if your customer does demand it don't try to explain that his world-view is wrong. Optimistic locking might be an acceptable flaw in some cases, especially if the granularity is done carefully (one user changes a customer's address, another gives him some loyalty points - there need not be a conflict), but good luck convincing your users it's anything other than a flaw.

      If you don't want to do full locking or it's not acceptable then it may be better to use most-recent-wins. Only save changes (don't save stored information which the user didn't change, treating logical blocks of data like address fields as a unit) and try to make your fields inherently concurrent first, though. This is probably more intuitive behaviour than first-user-wins (why should an older edit take precedence over a newer one?).

  9. Answer is optimistic locking by Anonymous Coward · · Score: 0

    optimistic locking: http://en.wikipedia.org/wiki/Optimistic_concurrency_control

    1. Re:Answer is optimistic locking by Anonymous Coward · · Score: 0

      Exactly. That and versioning AKA Wikipedia where conflicts have to be resolved.

  10. Its doable, ajax helps by Anonymous Coward · · Score: 0

    The standard technique I've use before:

    onChange handlers on each input field.
    On first change, send an AJAX request to the server to lock the data
    If lock succeeds, do nothing
    If lock fails, alert the user to that fact and disable all inputs on that record.
    On submit, release lock.
    On navigate away (next transaction by that user) release the lock
    Auto expire the lock after some reasonable period of time in case the user A) went to lunch or B) navigated to www.cnn.com

    1. Re:Its doable, ajax helps by Anonymous Coward · · Score: 0

      I love the smell of Slashdot in the morning.

    2. Re:Its doable, ajax helps by plastbox · · Score: 1, Informative

      I agree, there is no reason to go with an inferior solution just because it's perceived as simpler. Lock the document when it is opened for editing, refresh the lock timestamp periodically (as long as the user is actually changing the document), release the lock when the user saves the document or when it times out (from user closing the window/tab, browser crashing, inactivity).

      Of course version control is a great feature but from my experience users want, and need, simplicity. They want to relate to one version of a file, not an ever growing tree of different versions. Thus, the best implementation of this in my mind is exclusive locking coupled with saving the document as a new entry in the database with an increased version number.

    3. Re:Its doable, ajax helps by Anonymous Coward · · Score: 0

      You really oughta learn how to read, chief. And not assume so much.

      Too bad you went coward - it would be useful to know which moron you are.

  11. Re:The euphemism treadmill by Kaboom13 · · Score: 1, Offtopic

    http://en.wiktionary.org/wiki/taint
    Seems to think the "to soil" meaning came first, independent of the slang meaning referring to your perineum.

  12. Lock the same as any other app... by Anonymous Coward · · Score: 0

    The only thing is that it is much harder to determine if the client is still there & active, so you should release the lock.

    With ajax widgets & cookie state it's not that difficult to determine if the client is still there.

  13. use a hash/timestamp by psy · · Score: 1

    Create a timestamp/random hash and store it against each record, then include it in your update query.

    UPDATE table SET
          data1 = @Data,
          hash = NewHash()
    WHERE ID = @ID
    AND Hash = @Hash

    Every save, change the hash to a new value.

    If someone has changed the record and another person goes to save it, the hash wont match and 0 records will be updated. This can then be captured in your web application.

    If 0 records updated - display error saying "user has already changed record, please reload page"
    If 1 records updated - display success.

    1. Re:use a hash/timestamp by Anonymous Coward · · Score: 0

      I must admit that hash idea is rather surprising to me. I can confidently say I would use an incrementing version number myself and would never think to do a hash. The probability of hash collision is probably infinitesimal. The probability of collision between two copies of an incrementing version number is zero. There is a probability two timestamps conflicting if your users update sub-second from each other. If we worked together I would probably argue that the incrementing version number is the simplest solution so it is correct.

      If you were my boss and anyway senior to me I would let you use your hashes but I wouldn't worry too much about it since it's likely we work in a tiny shop on tiny apps that have tiny numbers of users and we have tiny salaries. And I would start quietly looking for a new job.

    2. Re:use a hash/timestamp by larry+bagina · · Score: 2, Funny

      You could use an incrementing hash. Then you'd both be happy.

      --
      Do you even lift?

      These aren't the 'roids you're looking for.

    3. Re:use a hash/timestamp by Anonymous Coward · · Score: 0

      Just...

      UPDATE table
      SET
          data = @data,
          version = version + 1
      WHERE
          id = @id
          AND version = @version

    4. Re:use a hash/timestamp by overbaud · · Score: 1

      Actually use GUIDs. You will run out of numbers (finite) long before you run out of GUIDs (infinite). So no, incrementing numbers is not correct. Also if you are using SQL replication and the likes incrementing numbers will clash and you will need to have a GUID column anyway. If you were the enterprise developer you think you are you would know this. If I was your boss I'd suggest you start looking for a new job based on both your talent and your attitude.

      --
      Users... the only thing keeping 1st level support from being the bottom feeders.
    5. Re:use a hash/timestamp by molecular · · Score: 1

      GUIDs (infinite)

      infinite? Definitely not! Maybe not less infinite than space and time, but not infine. Damn, they're even enumerable.

    6. Re:use a hash/timestamp by psy · · Score: 1

      Thanks to overbaud's reply below. By hash i was meaning a solution such as guid value. I was speaking generically and not taking the literal meaning of hash for the purpose of being database agnostic.

    7. Re:use a hash/timestamp by overbaud · · Score: 1

      Infinite has various contexts. One being intersection and in theory all things being equal GUIDS should never technically intersect. Just as two parallel lines run parallel for infinity, although the two lines clearly have a start and end. http://en.wikipedia.org/wiki/Infinity Still for the problem in the thred GUIDs are the solution. Nitpicking of english aside.

      --
      Users... the only thing keeping 1st level support from being the bottom feeders.
  14. Re:The euphemism treadmill by grub · · Score: 1

    Bahahaha, almost had brandy on my keyboard.
    Good one, thanks.

    --
    Trolling is a art,
  15. Optimistic concurrency by Shimmer · · Score: 5, Informative

    Slashdot is hardly the right venue to get a good answer to this question (how the hell did it end up in the Hardware category?), but I've dealt with this a zillion times, so I'll give a pointer to what is very likely the correct answer: optimistic locking.

    Hard locks are probably not what you want in a stateless web app. (E.g. What happens if someone locks a record and then is hit by a bus?) Instead, here's how it works:

    1. User X fetches version 1 of Record A.
    2. User Y fetches version 1 of Record A.
    3. User X modifies her copy of Record A and attempts to save the change.
    4. System checks whether incoming version (1) matches database version (1). It does, so the save proceeds and the version number on the record is updated to 2.
    5. User Y modifies his copy of Record A and attempts to save the change.
    6. System checks whether incoming version (1) matches database version (2). It does not, so User Y is notified that he cannot save his changes.
    7. User Y fetches version 2 of Record A and tries again.

    This is also known in the vernacular as "second save loses". It may sound too harsh, but it is much better than "first save loses and user isn't notified", which is what you get if you have no currency checking at all. And it's also much more web friendly that your old desktop app (which uses an approach that is technically called "pessimistic locking").

    --
    The most rabid believers in American Exceptionalism are the exact same people whose policies are destroying it.
    1. Re:Optimistic concurrency by gr7 · · Score: 4, Informative

      What shimmer says is exactly what you should do with 2 possible additions. Often people leave themselves in a web page for an hour and then start to make edits. So when the user makes the first edit, use ajax to see if there was already an edit done in the meantime so they know before they make lots of changes.

      Also you should consider using sequences instead of checking if the data changed. Both are good ideas in certain situations. For example with a table that is only edited once every few months, I use a sequence on the whole table. For a table that is changed 100 times per day by 3 different users, either do row based sequences or check to see if the 'from' part of the changes match the database.

    2. Re:Optimistic concurrency by Anonymous Coward · · Score: 3, Insightful

      Slashdot is hardly the right venue to get a good answer to this question

      Actually slashdot is really good at this kind of stuff, there was a few dozen relevant, on-topic, well-written replies soon after the question was posted.

      On the other hand, political discussions ... embarrassing.

    3. Re:Optimistic concurrency by hibiki_r · · Score: 4, Insightful

      +5 Is not enough for the value of the parent post. Optimistic Locking is the right answer in 99% of the cases. The issue then becomes how you want to deal with re-submitted of changes. If the entities to be saved are small and very atomic, asking the user to retype, making sure their changes are still sensible on the modified record makes sense. If your records are very large and/or very complex, then you might consider using some business knowledge to see if changes to the record can be grouped logically, and maybe even committed individually: If someone changed data for X shipment of a purchase order, while someone else changed Y, then the changes don't really have to conflict.

      But whatever you do, build it around optimistic locking: Don't try to lock a record because somebody just has it open somewhere on a remote location. That path leads to madness.

    4. Re:Optimistic concurrency by Tablizer · · Score: 1

      Hard locks are probably not what you want in a stateless web app.

      Hard locks can suck anyhow. I once worked in a place where every now and then somebody would forget to close a form screen and run off or swap to another app, leaving it locked. Unfortunately, the system didn't track who had it open, so a message was sent to the front desk, and EVERYONE in the building would hear something like this on the overhead paging speakers: "Whoever is locking customer 1234, please close your screen or call X." I heard about 3 of those a week.

      Even if the system did track who locked it, it would still require a fair amount of investigation to resolve. Not the best technology approach to shared data unless everyone's in the same room.

    5. Re:Optimistic concurrency by ArcadeNut · · Score: 3, Funny

      Slashdot is hardly the right venue to get a good answer to this question (how the hell did it end up in the Hardware category?)

      Ok, so if Slashdot isn't the right venue to get an answer, should he ignore your answer?

      --
      Visit the Arcade Restoration Workshop @ http://www.arcaderestoration.com
    6. Re:Optimistic concurrency by MagicM · · Score: 2, Informative

      There is one gap in this. If steps 3 and 5 happen at the same time, then steps 4 and 6 happen at the same time, and both User X and User Y could pass the "System checks whether incoming version matches database version" check. Some locking is still required, otherwise it will look to both Users as if they "won".

    7. Re:Optimistic concurrency by argodk · · Score: 4, Informative

      Absolutely correct, but that just means that there has to be server-side locks for the commitment phase (4-6), it doesn't impact the client-side. This has an implication for performance of the commitment phase, but luckily, database vendors have been struggling with efficient implementation of commit for years, so using the transaction features of whatever database is used for storage should resolve most of those problems (i.e. check and update the version number in the database in a single transaction).

    8. Re:Optimistic concurrency by gullevek · · Score: 1

      this can be solved with a timestamp at which the user loaded the data, first come, first servers. second one gets notice the data has been changed.

      --
      "Freiheit ist immer auch die Freiheit des Andersdenkenden" - Rosa Luxemburg, 1871 - 1919
    9. Re:Optimistic concurrency by Anonymous Coward · · Score: 0

      If it's a database, they're atomic changes. They can't happen 'at the same time', because the database will lock that row for write, and the other write will block waiting.

      NB I'm talking about sensible databases here. things that don't follow ACID don't count.

    10. Re:Optimistic concurrency by cerberusss · · Score: 5, Funny

      Hard locks are probably not what you want in a stateless web app. (E.g. What happens if someone locks a record and then is hit by a bus?)

      There's a Firefox extension for that.

      In our company, users' pulses are tethered to the USB bus. The Firefox extension can then use this information. People spend hours in our time accounting system, which has a pessimistic locking scheme. The Firefox extension sends an 'unlock' when the user's pulse stops for whatever reason. We've had buses driving users over, we've had rabid squirrels, a janitor going postal, exploding Sony laptops and a manager doing the 'Godfather-baseball-bat-routine' on an unsuspecting employee. Our time accounting system runs great, we've never had a stray lock.

      --
      8 of 13 people found this answer helpful. Did you?
    11. Re:Optimistic concurrency by dkf · · Score: 1

      We use the approach described in a Wiki implementation and it works pretty well. However, I suggest a refinement...

      6. System checks whether incoming version (1) matches database version (2). It does not, so User Y is notified that he cannot save his changes.
      7. User Y fetches version 2 of Record A and tries again.

      If this happens, you should consider trying to do a merge of the two sets of changes; if the merge succeeds (e.g., because the edits are of different parts of the page) then you can commit the merged version instead of throwing it back in User Y's face. The technology for such merges is pretty well known; it's been used in software version control systems like CVS, SVN and GIT for many years.

      --
      "Little does he know, but there is no 'I' in 'Idiot'!"
    12. Re:Optimistic concurrency by plastbox · · Score: 1

      Not the best technology approach to shared data unless everyone's in the same room.

      ..unless the locks time out after some set period of inactivity and the users know this well enough to not whine horribly when they screw up and have to retype their changes in the new document (or fetch what they wrote from the temporary, read-only, auto-saved document that was created when they clicked "edit").

      Or what about this! Using AJAX, you save every change the users do on the fly and also reload the contents of the document the user has open. It would be even more multiplayer notepad than IRC and there would never be any issues with anyone losing information due to system weirdness/bugs/shortcomings!

    13. Re:Optimistic concurrency by lord_sarpedon · · Score: 1

      You really have to wonder what's going on behind the scenes in some of the database-backed apps that we interact with daily. There are plenty of PHP monkeys that concat SQL to parameters. But there are plenty of others that have just never thought about locking. Or have it wrong. There are subtle concurrency bugs all over the place - the database usually handles it well enough that many developers just never catch on.

      --
      "Strangers have the best candy" -Me
    14. Re:Optimistic concurrency by CatoNine · · Score: 1

      Yes. End of topic. :-)

    15. Re:Optimistic concurrency by aj50 · · Score: 1

      If your users don't do edits on the same data (e.g. a forum) or your webapp isn't heavily used (e.g. internal app for a small company), you can have plenty of concurrency bugs all through your code which never get triggered.

      --
      I wish to remain anomalous
    16. Re:Optimistic concurrency by aj50 · · Score: 1

      At some level, where users can read and write data, locking is always required.

      In the most basic case, a user must never retrieve a half written record, therefore the database must ensure that a read either occurs before or after a write, never mid-way through.

      (Note that the database may make some optimizations here as serialization of operations only has to be maintained from the clients point of view. Internally, the database may be updating the record and indexes at the same time that data is being read but taking steps to ensure that a read either returns the old data or the new data.)

      This doesn't mean that the client has to lock things explicitly. The update in Step 4 could be done like this:

      UPDATE records SET key1 = value1, key2 = value2 WHERE id = ? AND timestamp = ?

      If the timestamp has changed (because another client committed a change) then the update won't modify any rows. The client must check to see how many rows were modified to see whether the update was successful.

      --
      I wish to remain anomalous
    17. Re:Optimistic concurrency by aj50 · · Score: 1

      All well and good until Firefox (or the whole OS) crashes.

      (Yes, I get the joke, I just take a sick pleasure in pulling it apart)

      --
      I wish to remain anomalous
    18. Re:Optimistic concurrency by JumpDrive · · Score: 1

      Slashdot is hardly the right venue to get a good answer to this question

      Yeah, but I'd rather see this type of question and attempts at an answer, than 14 reviews of games and interviews with game developers and CEO's of gaming companies.

      I think that there should be a fork of ./ for people who work on linux/unix and like linux/unix. :)

    19. Re:Optimistic concurrency by Anonymous Coward · · Score: 0

      Might be better, but still sounds wrong to me.

    20. Re:Optimistic concurrency by Anonymous Coward · · Score: 0

      This is still suboptimal, and requires another field, and updating it (the version or timestamp).

      The changes made by user X may have nothing to do with the fields changed by or relevant to user Y. And you have to make sure EVERY piece of code that might update that record ALSO respects/updates the versioning field. Same with every manual update by the DBA.

      I do one MD5 of all the fields queried by the user concatenated together when the form is loaded.

      I re-query the data, and MD5 the fields when the user tries to do the update. If the MD5 does not match, the user is informed that some other user changed the data in this record while they were wasting time, and the record is redisplayed with the updates from the other user.

      In some cases, I iterate over the fields to see which ones changed, and highlight them for the user.

    21. Re:Optimistic concurrency by Shimmer · · Score: 1

      Yes, this is a good way to do it.

      --
      The most rabid believers in American Exceptionalism are the exact same people whose policies are destroying it.
    22. Re:Optimistic concurrency by danger42 · · Score: 1

      (E.g. What happens if someone locks a record and then is hit by a bus?)

      Well, the first thing that happens is the company investigates why there was a bus in their call center.

      --
      -nd
    23. Re:Optimistic concurrency by Lord+Ender · · Score: 1

      I think your response is a damn good example of the fact that is the right venue to get a good answer to this question.

      --
      A slashdotter who didn't build his own computer is like a Jedi who didn't build his own lightsaber.
    24. Re:Optimistic concurrency by Shimmer · · Score: 1

      Thanks, but there are lots of important architectural considerations that are necessarily left out such a discussion. It's not much different from asking for legal advice - you might get a lawyer to answer, but don't take that answer as professional legal advice.

      --
      The most rabid believers in American Exceptionalism are the exact same people whose policies are destroying it.
    25. Re:Optimistic concurrency by Rary · · Score: 1

      Optimistic locking often makes sense if a user will only spend a short period of time on a record before saving.

      However, if I'm going to spend 20 minutes on a record, the last thing I want is to get to the end of that and finally be informed that someone else has been working on the same record this whole time, and now it's up to me to deal with merging the changes. If I'm going to commit that much time to a record, I want to be told beforehand that someone else is working on it. This is an opportunity for a process-based solution rather than a technical solution (ie. I can contact the other person working on the record so we can discuss and coordinate our changes).

      Obviously there are issues that arise, but they are easily dealt with. Locks can be designed to timeout if the user "is hit by a bus". There can also be the option to override a lock. Users are much happier when they're informed of what's going on and given options to deal with it before they commit considerable time to working on something.

      --

      "You cannot simultaneously prevent and prepare for war." -- Albert Einstein

    26. Re:Optimistic concurrency by fulldecent · · Score: 1

      >> In our company, users' pulses are tethered to the USB bus.

      Is this a read-only interface, or can you write a string of zeroes to it?

      --

      -- I was raised on the command line, bitch

    27. Re:Optimistic concurrency by Tablizer · · Score: 1

      Time-outs would anger people who have to take phone-calls or what-not. But it's certainly an option to consider. In that particular case, simply tracking who made the lock would've been the best route IMO (without overhauling the system to use more modern techniques).

    28. Re:Optimistic concurrency by MagicM · · Score: 1

      Even if they're atomic changes, and they both happen in sequence, the problem is that they both happen. The second user's data is stored, which means the first user's change was never seen by the second user and subsequently blindly overwritten.

    29. Re:Optimistic concurrency by MagicM · · Score: 1

      Good point. Instead of locking you can just do all the updates, and at the end update the version to 2 where version = 1. If this updates 0 rows, you need to roll back all of the updates and tell the user about the concurrent data change.

    30. Re:Optimistic concurrency by Anonymous Coward · · Score: 0

      If you are using a relational database, you can avoid the situation where steps 3 and 5 happen at the same time: instead of "check that I have the latest version and then update", do "update the latest version, which happens to be mine"; if you do not have the latest version, then you updated nothing.

      In pseudo-SQL:

      WRONG:
      SELECT version FROM table WHERE record = a;
      IF version = 1 THEN UPDATE table WHERE record = a ELSE notify_user:

      RIGHT:
      UPDATE table WHERE record = a AND version = 1;
      IF rows_updated = 0 THEN notify_user;

      Hope this helps...

    31. Re:Optimistic concurrency by molecular · · Score: 1

      +5 Is not enough for the value of the parent post. Optimistic Locking is the right answer in 99% of the cases

      I doubt that, see below.

      The issue then becomes how you want to deal with re-submitted of changes. If the entities to be saved are small and very atomic, asking the user to retype, making sure their changes are still sensible on the modified record makes sense.

      In many cases (>1%) the smallest cluster of changes that still has to be in one group to make sense is anywhere from small. Entering such changes might even involve making phone-calls, looking up data someplace else, making some calculations on a sheet of paper, etc.. and so it can be time-consuming and optimistic locking is a very bad choice in such cases.

      So q.e.d: Optimistic locking is not the right choice in many cases.

      If your records are very large and/or very complex, then you might consider using some business knowledge to see if changes to the record can be grouped logically, and maybe even committed individually: If someone changed data for X shipment of a purchase order, while someone else changed Y, then the changes don't really have to conflict.

      Sometimes the business-logic of a single object can be very complex and the data all intermangled. You can't just assume everything can be divided in small-enough independent pieces of data, just because you are too lazy to implement some sophisticated solution.

      But whatever you do, build it around optimistic locking: Don't try to lock a record because somebody just has it open somewhere on a remote location. That path leads to madness.

      Madness on the developer's side maybe, but optimistic locking can lead to madness on the user's side, even violence, trust me on this.

      I must agree with you on one thing, though: implementing optimistic locking first thing as a basis makes sense and can save you a lot of trouble.

    32. Re:Optimistic concurrency by Anonymous Coward · · Score: 0

      We've had buses driving users over, we've had rabid squirrels, a janitor going postal, exploding Sony laptops and a manager doing the 'Godfather-baseball-bat-routine' on an unsuspecting employee.

      No, the movie with the baseball bat scene was The Untouchables.

      Still, what a great way to motivate your employees!

  16. heh by shentino · · Score: 1

    Interesting.

    First management shoots you down on a technical point by a foot-stomping shove of fiat, and then turns around later when they get bit in the butt by the users and blames you for obeying them.

    1. Re:heh by IntlHarvester · · Score: 3, Insightful

      Actually, I don't blame them. The first instinct of people coming from a client-server background is to introduce to some form of record locking. Since this isn't "in the box" with web app frameworks, it makes sense to push back on the feature until you have user feedback or other analysis that it's actually required. Otherwise you are spending valuable time coding/debugging a feature that will rarely ever be used.

      --
      Business. Numbers. Money. People. Computer World.
    2. Re:heh by Anonymous Coward · · Score: 0

      Since this isn't "in the box" with web app frameworks

      Woah look what's in the box: Grails Guide: Pessimistic & Optimistic Locking ... that's a built in Hibernate feature common to all Java frameworks... for some reason I thought *all* frameworks had that baked in. Look Ruby on Rails has this too proving how AWESOME it is.

      What *lame* frameworks don't have this?

    3. Re:heh by IntlHarvester · · Score: 1

      Yeah, this is one of those posts I wish there was an edit button for :P Anyway, the UI isn't really in the box, just the more trivial database stuff.

      --
      Business. Numbers. Money. People. Computer World.
    4. Re:heh by Anonymous Coward · · Score: 0

      Judging from the amount of crazy schemes for doing locking that people have said they developed in these comments... I'd say the database stuff may be trivial but many developers don' t understand what it is, how it works, or why they should choose OCC most of the time. I agree. This stuff is pretty basic and the algorithms should be covered in any descent Operating Systems or Database class.

      I once interviewed a fella who said he had a Bachelor's of Science in Computer Science so I asked him if he took "Data Structures" I kept trying to lead him to the answer asking things like "how does a linked list work" and he repeatedly asked "what's that?" I tuned out after that... I figured either his college was a joke or he was lying. I didn't expect a right answer just a fumbling answer that told me this new college grad had some kind of exposure to the material... any exposure... I would have accepted "oh yeah that stuff about trees and oh-of-enne thingies..."

      So I honestly wonder: What do they teach these kids today?

    5. Re:heh by IntlHarvester · · Score: 1

      You have a point, but on the other hand Rails' lock_version & exception method isn't exactly all that "AWESOME" compared to what the Paradox people are expecting, and compared to some of the better schemes in these comments.

      My greater point was to convey my experience that 80% of the time someone asks for Record Locking, it's a low priority feature.

      --
      Business. Numbers. Money. People. Computer World.
  17. depends on the desried semantics by Anonymous Coward · · Score: 0

    Because http is stateless, it might be a bit of a challenge to take advantage of database locks since they only last inside a transaction, and you probably don't want a transaction to extend possibly indefinitely (ie, if the person shuts down their pc, goes home, dies in their sleep, and their pc is disappears for a week).

    Depending on the desired semantics, you may need to implement your own locking mechanism.
    When Person A requests a set of records with intent of modifying some of them, all the records in the set are marked as being modifiably only by Person A.
    When person B tries to pull down a set of records that overlap, any records that overlap with Person's set are marked as "being modified by Person A, you can't touch".
    That way, they at least know which records are not stable. Pretty trivial to do this in a database, you just need another table whose column are the rowids of the table in question and the id of the person currently editing the table. Compliance has to be enforced by your application rather than something lower level.

    1. Re:depends on the desried semantics by Anonymous Coward · · Score: 0

      "http is stateless" blah blah. So are ethernet frames. In fact other than for fragmentation, so is IP, but it doesn't stop anyone from implementing state on top. The problem is an application layer problem, not presentation or transport.

    2. Re:depends on the desried semantics by timmarhy · · Score: 1
      The above poster is the most level headed and sane on here so far, but i'm cringing at some of the suggestions on here. if you do ANYTHING, do this - get a decent fucking DBA who can guide you through these issues. solving this at the application layer is asking for disaster, this HAS to be done in the database.

      if this was me, my solution would be as follows

      1. on initiating your transaction, create a named sql object with the name being unquie based on the client's session (take your pick on how you do this, but this solves your state issues). in a decent sql server you can set a timeout on these query objects, so that if the session is closed it won't bog the system down (i don't know exactly what you plan on using so it's hard to say).

      2. take advantage of the databases build in locking - since your using your named object that persists within the database this is now easy and more importantly FAST. what i'm cringing about on here the most is the endless suggestions that require extra columns and requerying of the database from the webapp.

      like i said without knowing the database your using it's bit of a shot in the dark, but conceptually this is what you should be doing. one other thing i'd do also is create these queries from within an sql function, so that you don't need to give gobal create permissions or anything of that sort. it'll mean the function will have the permissions and not the clients, letting you lock things down nicely.

      --
      If you mod me down, I will become more powerful than you can imagine....
  18. LAN apps vs. Web apps by Anonymous Coward · · Score: 0

    You cannot lock a Web client the same way you used to do with LAN clients. Otherwise your entire application will grind to a stop with locks all over the place. The proper way to do it is let each client commit their work to a transaction history table. Either the sum or the last transaction is the current info. Think of it as an accounting ledger.

  19. google optimistic locking by Anonymous Coward · · Score: 0

    you probably want optimistic locking. have a quick read about this - and then decide if you are using timestamps, update id's or whatever suits your situation.

  20. 2 words by Anonymous Coward · · Score: 0

    Optimistic Locking.

  21. Check some frameworks... by Anonymous Coward · · Score: 0

    ...because It's been done in quite a few already. If you're using an ORM, chances are it already supports something.

    Otherswise, if you need to do it outside if a transaction in a single request, you basically have two options:
    1) Add locked_by (the user id) and locked_at (a timestamp) fields to the database, and populate them when someone gets a lock.
    2) Use a lock_version (just an integer) column and wrap your select in a transaction to also increment the column. Check the record you have against the record in the database (again, in a transaction) to make sure it hasn't changed since.

    The way Rails' ActiveRecord does lock_version is a good example to look at because it's relatively simple, so have a look.

  22. Re:The euphemism treadmill by Rophuine · · Score: 0, Offtopic

    "'tain't [it ain't] the pussy, 'tain't the asshole". This is a modern slang usage.

    Next time, check your references before you promulgate such tripe.

  23. Confluence by goofy183 · · Score: 4, Informative

    Look at Confluence by Atlassian. When you edit a page they track the edit action. When another user goes to edit the page they are warned that "John Doe is currently editing this page, last edit at date/time". They also do polling via AJAX so if you're working on a page and another user starts actually editing it you see a message on the page "Jane Doe started editing this page". They also save page drafts scoped to the user to help people resolve edit conflicts. It seems to balance things well with not explicitly forcing locks but actively letting users know when they are heading for a conflict.

    1. Re:Confluence by Anonymous Coward · · Score: 0

      I agree. I helped write a client/server application in Windows that doesn't use locking at all. The application simply informs a user that the 'data' is already open by another user.

      I would figure that this subject has more to do with the type of data, than an overall policy.

      My first rule for data integrity is: warn the users. Not my fault if they screw it up.

  24. File locking? by Ash-Fox · · Score: 0

    File locking with the contents of the user uid inside it in a /tmp type path?

    If you can write to it, it's not locked. Make sure the lock you use doesn't prevent reading.

    --
    Change is certain; progress is not obligatory.
  25. CouchDB by deweller · · Score: 4, Informative

    Check out CouchDB. It is built around the concepts of distributed (and even offline) databases and handles conflict resolution. It employs optimistic locking.

  26. Use Optimistic Locking by linuxhansl · · Score: 4, Informative
    Don't take out a database lock (also referred to as pessimistic lock sometimes). Web transactions tend to be long lived and there's typically no easy way to know when the user just abandoned the edit (and hence you would not really know when it save to release the lock, unless it is by timeout or explicit release by the user).

    Instead do optimistic locking... Assume there are no conflicting edits (or that they are at least rare). Then version each row (with a monotonically increasing number for example). At the beginning of the transaction also retrieve the version, and upon save verify that the version did not change - if it has changed there was a conflicting edit in the meanwhile and the current save should be prevented (you could then get fancy and retrieve the current version of the row from the database and show it to the user, etc).

    One can actually show that if the rate of collisions is low optimistic locking even performs better, whereas in scenarios where the contention is high (a significant fraction of transaction result in a conflict) pessimistic database locks performs better.

    1. Re:Use Optimistic Locking by Zarf · · Score: 1

      Awesome post. I like the description here: http://grails.org/doc/1.0.x/guide/single.html#5.3.5%20Pessimistic%20and%20Optimistic%20Locking but it is lacking the performance analysis commentary you have made.

      --
      [signature]
    2. Re:Use Optimistic Locking by Anonymous Coward · · Score: 0

      I've seen this happen on one of the major web apps in the market, I'm not going to mention which it is. But when we used that app and somebody just sat on a record, that record becomes locked for that person, now if he goes idle and the connection times out, it usually takes half a day for the system to know that the user abandoned the edit but it still is locked to that user, and it makes everybody who needs to edit that record very very happy for the better half part of the day knowing that it is still locked to another person.

  27. The full-fledge solution by Anonymous Coward · · Score: 0

    I did this once on a web application, and I was fairly happy with the results. Each time a user opened a record for editing, the user's username and a timestamp were written to two fields I appended to the table. The system also had a global record lock timeout (20 minutes in our case). If a 2nd user attempted to open the record for editing, the app would check to see if someone else had tried to open the record in the last 20 minutes, and if so, the 2nd user would be given a message that the record is locked, who locked it, and then present the user with a *clearly* read-only version of the record (just HTML text instead of HTML form elements). It quickly became clear that this worked for the users extremely well, but it was not easy to implement in our environment (ASP). It was also not an easy "drop in" scheme, and required extensive modification of the source code for each web page / database table that we wanted to add it to.

    1. Re:The full-fledge solution by Simon80 · · Score: 1

      There are many comments posted before yours that recommend optimistic locking, which is better than the pessimistic locking you just suggested. I also suggest that to be complete, an application should also attempt to merge the new version of the data with the change that the user is trying to make. For examples of merge algorithm implementations, the developer should look at a distributed version control system, like Git, Mercurial, or Bazaar.

      It was also not an easy "drop in" scheme, and required extensive modification of the source code for each web page / database table that we wanted to add it to.

      I don't envy the crazy amounts of code duplication that you clearly had to deal with on a regular basis.

  28. Re:The euphemism treadmill by Jurily · · Score: 0, Offtopic

    It cracks me up how "taint" originally was a noun referring to the perineum - the region between the ass and balls/muff, and now all of a sudden everyone just uses it to mean "to soil". It's so fascinating, how language evolves...

    BTW soil, guess where the earth chakra is.

  29. Three Options by Anonymous Coward · · Score: 0

    simple = time stamp. everyone understands it.
    elegant = ajax to show each user what the other user is doing in real time.
    complicated but feasible = distributed version control system - take a look at those algorithms (HG). the last user to save might have to do some merge operation.

  30. there are two parts to this by MagicM · · Score: 1

    The method I'm most familiar with consists of 2 parts:

    Each record[1] has a last_updated value associated with it.

    Part 1:
    When a user loads the record for editing, it also loads the last_updated value. Upon submitting, the last_updated value is compared against the stored value and if they don't match this is considered a concurrency error. Exactly what happens depends on the nature of the record, but usually a message is shown to the effect of "the record was changed by someone else, please reload it and retry your edit."
    This is necessary to avoid problems when user B updates data between the time user A loads the data and submits their updates.

    Part 2:
    At the exact moment when the submitted last_updated value is checked against the stored value, if the values do match then the stored value is locked for editing in the database.[2] For example via a "select for update" statement. Then the input is validated, the submitted data is stored, the last_updated value is updated, and all updates are committed, thereby releasing the lock.
    This is necessary to avoid problems when user A and user B submit their updates at almost the exact same time.

    [1] "record" could be a logical record that consists of multiple physical records in the database. You'd need one last_update value per logical record.
    [2] In some cases you need to lock multiple locks when multiple separate records affect each other. Exactly when and how this needs to happen is left as an exercise to the reader.

  31. ModifiedOn by the-matt-mobile · · Score: 1

    Put a datetime or timestamp field in each table called ModifiedOn. Every time the record is changed, update that date. Then, in your data access layer (you have one of those, right?), do not allow an update to a record if the ModfiedOn date has changed since you originally pulled the record. If the date was the same for all records being updated in the transaction, then no one touched them. It's called optimistic locking. Later, you can add more featureful locking on top of this with change resolution/merging, etc. But, this is a failsafe starting point to ensure data integrity.

  32. If you don't already know, get off the project. by kuzb · · Score: 1

    Anyone who doesn't understand the basics behind record locking/concurrency control and how to implement it shouldn't be involved in a multi-user concurrent application in the first place. This is really weak as far as slashdot articles go.

    --
    BeauHD. Worst editor since kdawson.
    1. Re:If you don't already know, get off the project. by timmarhy · · Score: 3, Insightful

      i don't argee. while he shouldn't be leading the project, he can still work on it. did you know everything about every application you've ever worked on operated??? this is how real world experience is gained, you don't start out the expert.

      --
      If you mod me down, I will become more powerful than you can imagine....
    2. Re:If you don't already know, get off the project. by Burnhard · · Score: 1

      Very well said. If he doesn't know already, he will by the time he completes the project. We all learned this way. Some theory, yes, but mostly by practice.

  33. Uh, lots of frameworks do this for free... by Anonymous Coward · · Score: 1, Informative

    Wow guys. Getting Optimistic locking for free is basically *why* you do stuff in frameworks like Spring+Hibernate, Ruby on Rails, or .Net you know.

  34. Timestamp and timer by Anonymous Coward · · Score: 0

    I personally use a timed lock, and use an ajax poll (on a timer) to update the timestamp for the duration of the edit session. I keep the timeout short, but not too short... that way if the user leaves, the edit is discarded and so is the lock (after a short time). Once the edit is done, the lock is removed of course.

  35. Re:The euphemism treadmill by obarthelemy · · Score: 0, Offtopic

    don't forget: "tain't the meat, it's the motion"

    http://www.geocities.com/merrystar3/allysongs/ItAintTheMeat.htm

    --
    The Cloud - because you don't care if your apps and data are up in the air.
  36. help the users by giving them info but not limits by roman_mir · · Score: 3, Funny

    I just made a console a month ago that handled this problem as follows:

    Records that need to be processed are in 'pending' (unconfirmed actually) status, once any user clicks to select the record, it is timestamped and the user is 'locking' it. Actually the user is assigned to it and all other users see that this record is 'locked' by the first user who selected it.

    However, now anyone can open the details of the record and do the following: they will see a button 'Take the lock away from $user$', so they can take the lock away! But there is history of who took whose lock, so the problem will be solved outside of the applicaction if they take each other locks away.

    If the user locked a record he has a choice of 'save', 'save and release lock', 'release lock' buttons on the record details.

    The users are allowed taking the lock away from each other so the lock resolution is pushed into the real world and out of the app.

  37. The way I do it by corychristison · · Score: 2, Informative

    Although I don't know what your implementation, or even what server-side language or database you use... I'll comment.

    - For the sake of simplicity, add 2 columns to the table you want to be able to lock. Call them `lk` (lock) and `lkts` (lock timestamp).
    - When a user is currently editing the row/document/whatever it is, have an icon of a lock or something to display in the list if someone is currently editing it.
    - When generating the list of 'documents'(/whatever it is), check `lkts` and compare it to the current time. If it is stale (5 mins old), clear it and allow people to edit it. Always allow users to view the data.
    - When a user clicks on the 'Edit' button, change the `lk` column to 1 and `lkts` to the current timestamp (UNIX_TIMESTAMP under sane DB's)
    - Use RPC or XML-RPC to save the document periodically (every 60 seconds or so). Every save, update the `lkts` with a fresh timestamp.
    - When the user clicks "Save and Exit" or "Save and Continue", have it submit the form the old fashioned way, save the data, and set `lk` and `lkts` to 0.
    - Use Javascript to detect how long of a period of time passes for of no-activity. If it goes on past, say, 10 minutes, submit the form (thereby clearing `lk` and `lkts` and allowing other users in to edit)

    This is bottom-of-the-barrel designed for simplicity. No security or anything in mind, but simply something that will work even after a browser crash or someone leaves the computer with a 'document' open and walks away.

    Disclaimer: Just worked 14 hours. Very tired, don't want to go into any more detail. If this makes absolutely no sense to anybody, please discard this message.

    1. Re:The way I do it by GreyWolf3000 · · Score: 1

      Not a bad recommendation.. one nitpick.. I would call the columns "lock" and "lock_timestamp."

      --
      Slashdot: Where people pretend to be twice as smart as they really are by behaving like children.
    2. Re:The way I do it by molecular · · Score: 1

      Not a bad recommendation.. one nitpick.. I would call the columns "lock" and "lock_timestamp."

      I would mod you up to heaven if I could. Thanks for the wise comment!

  38. The Only Choice is... by FlyingGuy · · Score: 4, Informative

    Optimistic Concurrency

    Both the curse and the blessing of web applications. Most of the work is offloaded to the browser, thus not bogging down the database servers with keeping a ton of row level locks in memory, or even worse, page level locks.

    For the programmers POV you use some back end language, php, java, ruby, python, it matters not, write a program, it launchs, connects to a database, ( no matter how much middle-ware you slap in ) sends it a query, gets the data, returns it for presentation, consideration and subsequent modification ( or not! ) by the user and then the program ends. You are no longer connected to the database, heck your browser is no longer connected to the server!

    Some have mentioned AJAX <sigh...> AJAX is nothing but bundling together a few different bits of tech to do ONE thing, make a call to the server without refreshing the page. No matter how you slice it and dice it, thats all it does, it makes a call through the web server, to launch a program written in one of the afore mentioned languages and it follows the same set of steps, through either the post method or the get method and nothing has changed!

    So you need a scheme to know if you can write to a record without overwriting someone else changes.

    The only real choice is to use a timestamp value, all databases support them, usually down to the millisecond of accuracy. It is a simple process which you can make more complicated as you desire. As many have mentioned, you read the record making sure you get the timestamp of the last update. That timestamp gets sent to the browser along with the data. When the user clicks save the stored procedure that does the actual update then compares the timestamp you are sending with the one on the current record as in "select for update ...." and if the one you are sending along does not match the one on the current record, then your update loses and the stored procedure reports that back and then you deal with the user feedback in any way you see fit. Typically this is done by sending back the record in is new state and telling the user, "sorry, but you have to star over.".

    Now having said that there is nothing to say that you cannot be imaginative with a bit of javascript or something like that, or even with the php array_diff() function or an equivalent in some other language then insert some fields above or below the the data that was previously changed to at least have the conflicting data shown in both forms eg: what it is NOW and what they wanted it to BE.

    --
    Hey KID! Yeah you, get the fuck off my lawn!
    1. Re:The Only Choice is... by Anonymous Coward · · Score: 0

      Very nice edit with the exception of the AJAX bit.
      The AJAX isn't to do anything fancy, it is to confirm that the web page is still active
      It is impossible to detect a hard close of a web page directly, but a closed page can't talk, so Bingo
      no talkie to web server, no lock.
      Rather superfluous with optimistic locking but there are times when pessimistic locking is needed

    2. Re:The Only Choice is... by discojohnson · · Score: 1

      A stored procedure to update the record using select for update is the only real way to do this, because in high concurrency environments, if upon issuing the update, the app selects the value of last modified and compares, then updates, someone else can update between the start of the select and the issued update. It happens a lot more than you think. Which is also why, as a DBA, it drives me nuts to see developers writing code that does a select count(*) to see how much work should be done, then does the work--just do the work on a cursor because your count can change.

    3. Re:The Only Choice is... by FlyingGuy · · Score: 1

      Attempting to do any sort of pessimistic locking in a web environ can be accomplished but doing so is fraught with peril. You are building in a set of conditions that will cripple your database very quickly and I really don't see a way out of it without going though an awful lot of shenanigans.

      Locks have been a problem since databases were invented. Row level locks, page level locks, byte range locks have all been implemented in some fashion but they all lead to the same problem, locked up records that are not available unless someone clears the lock, not viable in a huge multi-user database with massive concurrency requirements.

      AJAX can go part of the way in solving the problem, but it has to heartbeat. The main problem is still the web execution model of "start run and be done". A lot of repeated AJAX calls can really stall out the browser if something is delayed on the server. For pessimistic locking to really work well, we need a better model.

      --
      Hey KID! Yeah you, get the fuck off my lawn!
    4. Re:The Only Choice is... by Anonymous Coward · · Score: 0

      Some have mentioned AJAX

      Ajax is a valid and good way to query if the data has changed on the server. For example you can tell the user they're record has changed due they want to load the changes? (Comet works well also) In other words it is not the locking mechanism, but just a way to have more up to date info for the user.

      The only real choice is to use a timestamp value, all databases support them, usually down to the millisecond of accuracy.

      Timestamp is NOT unique! NEVER use a timestamp to validate revision. Timestamp is fine to see when it was last changed, but you could very will have it change twice in the same timestamp. And before you say anything about the odds of that, they are quite high on many systems I work with.

    5. Re:The Only Choice is... by FlyingGuy · · Score: 1

      timestamp being unique is not the issue, since we are not seeking uniqueness. What we are seeking to know is, "Has then record been modified since I read it." and for that a millisecond is pretty darn granular don't you think?

      Yes the httpRequest method is fine to do the occasional check to see if something has changed but I would caution you on the frequency of your checks since the httpRequest channel tends to freeze up the browser while waiting for the return.

      --
      Hey KID! Yeah you, get the fuck off my lawn!
    6. Re:The Only Choice is... by Anonymous Coward · · Score: 0

      How did that post get modded up? Dude... That was 6 full paragraphs of nothing

  39. Handled this on a web interface by JumpDrive · · Score: 2, Informative

    We ran into the same problem.
    What we finally did is lock the editing page, so that if someone else had it opened you were not allowed to update it until they removed the lock on that page.
    Or the user could over ride the page lock if they felt pretty sure that the other user was not using it for editing ( Maybe they just had it open on their desktop).
    In a table we put the page, user identification, and timestamp when the lock was created.
    So whenever the page was opened, it checked the table to see if it was locked. If it was locked, then it displayed header showing who had it locked and how long they have had it.
    We generally only have 3 to 4 users that may open a page for editing and they soon learn that if you are going to edit something after it has been sitting for some time to update the page.
    We should probably update this with ajax so that at least the header of the page tells the user someone else has taken the lock.
    But currently happens though is that the page won't update if it doesn't have a lock and the user has to go back if and start over if someone stole the lock. So far I haven't heard of it happening, because they usually open or update right before they start editing so they know they have the lock.
    But handling it in this manner has greatly reduced our problems.


    Yeah, it's amazing how if you think it could happen it will. And most of our problems, I think, were caused by users opening the same page on multiple computers and then instead of closing the page, they were updating the page with the old information.

  40. Re:The euphemism treadmill by chthonicdaemon · · Score: 0, Offtopic

    Taint (n) has its origins in Middle English (as a verb in the sense [convict, prove guilty] ): partly from Old French teint "tinged," based on Latin tingere "to dye, tinge"; partly a shortening of attaint, according to my Mac dictioary. Shows you how newer senses of words can be believed to be "original".

    --
    Languages aren't inherently fast -- implementations are efficient
  41. Way more informtion by mindstrm · · Score: 3, Insightful

    I think we'd need way more information to come up wiht a good solution - this is an overall application architecture problem, not just a locking problem.

    What are the use cases? what kind of app is it? what is it that you are trying to lock, exactly?

    1. Re:Way more informtion by Anonymous Coward · · Score: 1, Insightful

      If you have more than 10 minutes professional DB experience, you would know the poster has given ample information already. In fact, all he needed to say was "multi-user web app record locking, how?"

    2. Re:Way more informtion by raftpeople · · Score: 1

      Actually, all he had to say was "multi-user app record locking, how?".

      Whether it's for the web or not, these are the same issues and same methods used for multi-user apps since the 60's.

    3. Re:Way more informtion by xelah · · Score: 1

      The questioner didn't make clear if he meant 'my users are complaining about conflicting edits, what system behaviour can I introduce which will solve their problem?' or 'I want (pessimistic) locking, how can I do it?'. Either way he (and we) should start with the first question, not the second.

  42. Do your own damn job. by HomerJ · · Score: 0, Troll

    They aren't paying you money to ask a bunch of guys on Slashdot. Do it your damn self or find another job that you're actually qualified to do without submitting an "Ask Slashdot" anonymously to do it.

  43. Do as ticketmaster does... by Lord+Byron+II · · Score: 3, Interesting

    When you are ordering tickets through TicketMaster.com, they hold the seat assignment for you for 10 minutes. If you don't complete the transaction within that time frame, the tickets become public again.

    In your database setting, the user Alice wants to edit the customer Carol's record. The application gives Alice a lock on Carol's record for five minutes. If user Bob tries to edit Carol's record within the five minute window, he gets a message telling him to wait for 3:42 while Alice finishes her edit. When Alice is finished, the lock is released and if she doesn't finish in five minutes, the lock is released anyway and her edits are lost.

    You could also add the ability for the user to set the lock time, within a reasonable window, say 5-15 minutes. Also, consider adding the ability for the user to renew the lock.

    BTW - Paradox is still around? I haven't used it since 1993 or so. Wow.

    1. Re:Do as ticketmaster does... by Anonymous Coward · · Score: 0

      still use paradox daily.... it is the quickest way to do simple edits of dbase tables that most of our Mailing software uses.

    2. Re:Do as ticketmaster does... by Anonymous Coward · · Score: 0

      Paradox tables are still around, not so much Paradox itself.

      This topic hits a lot of of my hot buttons. First, there remains a need for server-less database systems for use in small environments/apps where a server is overkill. There needs to be a proper modern follow-on to dBASE/Paradox/Access. There are some good proprietary solutions but they are hidden away in niches.

      Second, Pessimistic locking is the best choice for small interactive apps. Don't let me type 10,000 words into a memo field and not let me save my changes. Keep everyone else out while I'm in there.

      Third, why, in this day and age, haven't we developed a lock-less database? If you are correcting the spelling of a customer's last name while I am changing their first name, who cares if you make your change right after mine, or I make my change right after yours? If these don't matter, why not allow the changes at the same time? DB Servers are generally single users where the actual database is concerned anyway. Yeah, we may but be creating transactions that will update a balance field. But we needn't be allowed to set the value of the balance, only adjust it up or down. That could be an attribute of the Balance field.

  44. heres a few pointers by weirdo557 · · Score: 0

    0x3A28213A 0x6339392C 0x736368xE

  45. This is user requirements, not implementation by viking80 · · Score: 4, Insightful

    This is more a question of requirements than implementation. If your users want wikipedia style optimistic locking, just do that. If your users want hard locking with a timeout, do that. Just like your online bank does.

    If users ask for hard locks without timeout, ask them what their real requirements are.

    --
    don't cut it off www.mgmbill.org
    1. Re:This is user requirements, not implementation by grey1 · · Score: 1

      just a small build on this point - it's about what the end-user community needs, not wants.

      Sometimes you'll have to work with them to explain why an alternative is better overall, when they are sure that their option is what they want (=need, as far as they are concerned! and they've designed the app for you! with diagrams...)

      --
      "we demand rigidly defined areas of doubt and uncertainty!"
    2. Re:This is user requirements, not implementation by JumpDrive · · Score: 1

      Amen

    3. Re:This is user requirements, not implementation by Anonymous Coward · · Score: 0

      Wow, I though I'd exhausted my pet peeves for this topic, but here's another. A technical decision was taken to use stateless, web-based technologies to replace an interactive GUI app. The stateless nature necessitated losing pessimistic locks. The users were unhappy with this.

      So your response is that the users caused the problem by not clearly stating their requirements. If they had any input at all, they probably wouldn't have thought that not losing a 15 minutes worth of data entry on a random basis would need to be something that wasn't blatantly obvious.

      For God's sake man, quit blaming your users, take responsibility (as the OP has) and own your applications.

  46. Carbon paper triplicate forms by Anonymous Coward · · Score: 0

    Changes have to be submitted in hard copy form.

    Carbon copies, real typewriter stuck copies, none of this pansy "3x copies" laser printer crap.

    The original for me, the 2nd copy for the 86 file and the 3rd barely legible copy as your receipt.

    We'll let you know in two weeks, maybe, if your changes are good.

  47. This sounds a lot like a RDBMS... by drfreak · · Score: 3, Informative

    Locking is a solved problem in most Database Management Systems. I think you are worried about the wrong layer of your application. Web and Application code is most often agnostic to how records are retrieved, updated, and locked for concurrency. For reference, look up the ACID properties of a typical RDBMS.

    1. Re:This sounds a lot like a RDBMS... by yolto · · Score: 1

      Problem is that you need to inform the user of locked records and give them options on how to handle them, requiring you to inject some awareness and handling of locking into your application layer.

  48. Replication conflict by mysidia · · Score: 1, Redundant

    Time to move your application to a Lotus Notes DB. At least that platform has handling for it.

    Either design your web app so two users won't step on each other, or design in a way of dealing with it... such as comparing a user's changes from the original form, and submitting those, instead of "overwriting all other changes"

    Or depending on the app... treat it like any version control system, keep both sets of conflicting changes, and let the users resolve them a bit later, after your app informs them of the conflict.

    1. Re:Replication conflict by Slashdot+Parent · · Score: 1

      Time to move your application to a Lotus Notes DB.

      OP specifically said it was a web app. Deploying Notes to each client machine is not in the spec.

      The keyword you are looking for is "Optimistic Locking". Google it and educate yourself.

      --
      They don't grade fathers, but if your daughter's a stripper, you fucked up. --Chris Rock
    2. Re:Replication conflict by mysidia · · Score: 1

      Who said anything about deploying Notes to client machines?

      Notes is a framework that can be used for many types of custom applications, many of them browser-based.

      Go Google it and educate yourself.

  49. 3 sided change detection by Anonymous Coward · · Score: 0

    We use knowledge from three sources for change detection:

    1. Data posted from the user
    2. Current state of data
    3. Initial state of form when initially loaded

    #3 is done by setting crc of field values and storing the CRC values in cookies but theres no shortage of available methods including just remembering initial values and sending them in the post form.

    The general goal is that when you save the form only fields that you have personally changed are updated in the database. Your program should not update all fields. You need a well behaved data management layer.

    If user A changes field 1 and user B changes field 2 there should be no conflict even if user B saves the form with stale data after user A made their change. Use diff between #3 and #1 to determine conflicts.

    If you are posting to an RDBMS recommend starting a transaction, updating the row in some nonsensical way that guarantees a write lock on the row. Read current state from the database (#2) and run through diffs of #1,2,3 to find any applicable conflicts. If there are no conflicts update the row and commit the transaction.

    If all system access follows the update before read semantic you get guaranteed behavior regardless of the read isolation semantics of the underlying RDBMS.

  50. AJAX is the way by Elixon · · Score: 1

    The XMLHttpRequest can be pretty fast when optimized for performance. There is plenty of time to request a lock and pull information about all current editors from the server between user clicking on "Edit" and focusing on the edited information and moving hands from the mouse back to keyboard... ;-) Lot of time to warn/notify/forbid the first edit before it really happens.

    Other approach is revisions. User might be informed that there is somebody else editing and the user might choose to request the lock/ignore warning. If ignored then the latest saved
    a) wins - overwrites earliest (but thanks the revisions nothing is permanently lost so all overwritten info can be recovered)
    b) the DIFF user interface is brought up and user may try to merge all changes that happened in the meantime into his/her revision before really saving (can be automated - depends on type of data and extent of changes, you can use open source diff tool that is provided as a library to many languages including PHP...)

    --
    Well, I've got to get back to work. When I stop rowing, the slave ship just goes in circles.
  51. Locking sucks; use versioning. by DamnStupidElf · · Score: 2, Insightful

    Wikipedia gets by without locking because it keeps multiple versions. If you really want to do locking, just throw a column in your database called "locked_by" and lock a record with "update foo set locked_by=CURRENT_USER where foo.id=WHATEVER and locked_by is null" and make all your updates conditional like "update foo set bar=baz, ..., locked_by=null where foo.id=WHATEVER and (locked_by is null or locked_by = CURRENT_USER)". Databases have atomic transactions for a reason...

  52. Locking scheme by PigIronBob · · Score: 1

    Use the primary key and an integer counter (date time stamps are to messy), apply the update with the primary key and counter as the 'where ' clause, if the update fails someone else has edited the record, and the user will need to refresh and try again. Pre-emptive locking is very messy , I would not recommend it. Often it is a kneejerk reaction to bad operational procedures within the production environment. You need to ask: what are multiple users doing trying to edit the same row at the same time? The counter based scheme sounds harsh but in reality it seldom leads to conflicts when the operations are run in a sensible manner.

    --
    You never catch me alive
  53. This is how I do it by frambris · · Score: 2, Interesting

    I have a separate locks-table with lock_id, id of the other record and timestamp. When a user brings up the record it is read only. He have to click Edit to begin editing and thus requiring a lock. This is where the lock table is checked. If there are no locks a lock entry is inserted and its lock_id is propagated to the edit form. Upon saving one checks that it is the same lock id, saves and removes lock. If a user tries to edit a locked record one can give him the option of either wait, or override if the users credentials allow it. He then get a new lock id. The other user either get an error message when saving stating that another one override his edit or some AJAX controller periodically checks the lock and takes action if it disappears. If the user just closes the edit form, forgets about it one can expire the lock by deleting old locks.

  54. AJAX? by GWBasic · · Score: 1

    An HTML text input has various Javascript events that you can use to trigger an AJAX call to the server, which you can then use to check if the record is locked. If you use the Prototype.js library to register events and make AJAX calls, it will handle the browser incompatibilities for you.

    If you need to push events to the client about when a record gets locked, then things become harder and you'll need to be creative. You can either poll, or use a combination of polling and blocking on the server. (When you block on the server, the server blocks an incoming HTTP request until an event occurs.)

  55. Is this too simplistic? by Anonymous Coward · · Score: 0

    Here is my solution:

    1 server emails everyone on internet that record (r) on table (t) on database (d) is about to be modified on host (h) by user (u) at time (hh:nn:ss +-GMT)
    2 in the email ask each user to reply with keyword (k1) in the body text if they also wish to edit this record otherwise respond with keyword (k2)
    3 wait until you have received a reply from every user

    no wait a minute, this isn't going to work - the mail might get tagged as spam and never be seen by the recipient. Step 3 would then wait forever and the original editor might get frustrated.

  56. Please please please.... by mcnazar · · Score: 1

    ... don't write a web app using Delphi.... and don't write a an app using Paradox.

    Having used both circa 1999 and vouch for the awesomeness of both products (at the time), the world has seriously moved on in regards to web development and database platforms.

    There are many viable (and cheaper and far more reliable and easier and....) solutions utilising PHP (and their frameworks), Ruby (and its Frameworks), Java and dare I say (wretch) ASP.

    Good luck!

  57. Who's in control? by Anonymous Coward · · Score: 0

    It would seem that the server wouldn't read an incoming message until he was ready to read it. If he was in the middle of an edit, he wouldn't be ready to read the next incoming message. That means you're single threading in the bottleneck where the message is read, but you can multi-thread in the edit process underneath it.

  58. Proper behavior by Anonymous Coward · · Score: 0

    Assuming that users want locking the old fashioned way, where only the first person who opens a record can edit it, you just have to be careful how you go about it.

    When a user opens a record, the client just has to ask the server every so often who has the lock. If nobody has the lock on that record, the server adds a row to a lock table indicating the username/IP/whatever of the client, and current time. That row is then returned whenever any client asks who has the lock for that record. If the lock belongs to the asking client, the client will recognize the user as himself and allow the edit; if not, the client can tell the user who currently has the lock.

    The key here is that the client will make this request every 10 seconds to keep the lock fresh. Every 30 seconds the server will go through the lock table and delete any locks that are over 30 seconds old. That way if a client ever abandons a record (the browser gets closed, crashes, or whatever), it will only be a minute before somebody else can edit the locked record.

    dom

  59. If you don't need a timestamp by littlebigman · · Score: 1

    In case you don't need to tell the original user when the record was changed by another user, you can just grab the old value in the SELECT, perform the UPDATE by including the old value in the WHERE clause, and check the result: If it didn't work or you don't get the new value when SELECTing the row, it means that someone else has updated this row while you were busy. Here's an example in SQLite: === CREATE TABLE IF NOT EXISTS mytable (id INTEGER PRIMARY KEY, label VARCHAR); INSERT INTO mytable (label) VALUES ("old"); //Some other user updates this row while you're busy UPDATE mytable SET label="concurrency" WHERE id=1; UPDATE mytable SET label="new" WHERE id=1 AND label="old"; //In case your DBMS doesn't return a value so you can tell if it went OK or not, //just reread the row: SELECT label FROM mytable; concurrency === HTH,

  60. Locking is easy, unlocking is the trick by salesgeek · · Score: 1

    Doing record locking isn't really that tough - there are a ton of ways to implement locking. The easiest is to add a lock and locked by column to your tables and set it whenever the user edits and unset it when they save. If you really want to get slick you can implement a lock table and log user edits (lock set for invoice 12231245 by joe.smoker on 01/01/2010 at 12:32:31 released by system_cleanup_process on 01/01/2010 at 15:33:00).

    The tough part is unlocking because web users have a strange way of walking away in the middle of edits. As a result, you'll have to have very strong session management so you can run a clean up process when a user times out that includes removing any locks the user may have active.

    About the time you get done with implementing locking, managers will want a way to manually override locks or will ask if you can do field level locking. At which point you are up against the, well, with enough time and money you can accomplish anything problem.

    Well... if you give a mouse popcorn...

    --
    -- $G
  61. Ajax "edit heartbeats" by BjarniSaevarsson · · Score: 1

    When a user starts to edit a page, send in "edit heartbeats" using ajax. The heartbeat msg changes f.e. by creating a hash of the edited text every 30 sec. If the "edit heartbeat" message does not change over time, f.e. 15min, you release the lock, if another user is asking for an edit.

  62. questions ? by Spaham · · Score: 1

    dude, do your business a favor : hire a professional.

    1. Re:questions ? by Shados · · Score: 1

      This.

      This question is just silly. Concurrency in applications is a solved problem, and douzens of thousands of pages have been written about concurrency mechanism (both at the user interface level and at the code level) in disconnected environments.

      I guess its what happens when people think the theory behind computers is the ONLY thing that matters. They miss out on the basics of software development. Whats next? "What are my options to do long running processes in a disconnected environment"? "How do I handle transactional processes in SOA"? Oh oh oh, my favorite!! "I do I make a process automatically retry if it fails at specific parts of it"?

    2. Re:questions ? by cratermoon · · Score: 1

      Seriously. Why does this scrub have a job when a developer who was solving this problem in 1994 is out of work? Might have something to do with outsourcing, pay rates, and idiot management who don't want to deal with a professional who would tell them up front that nixing multi-user concurrency in the design is stupid.

  63. give users an edit-lock by molecular · · Score: 2, Interesting

    This is how we did it in an in-house AJAX app for a big corporation.

    There would be a temp-table for every editable data-table in the db, that has the same structure plus a ID_User field. When a users starts editing a data-set, the data is copied into that temp-table. Other users trying to edit that data will get a view-only version of the page and info on who is editing the data. On "submit" the data is copied back to the "real" table, the lock thereby released.

    Should a user decide to abandon his session, crash his browser or anything like that, he will have his unsaved edits back on next login. He will even be redirected to the edit page automatically after login, if there are pending edits.

    A user can "steal" his own lock (actually session, that is) when he tries to log in with a fresh session (e.g. from another workstation at a colleague's). The old session will bail out automatically saying "session hijacked" (on any next ajax action) and the fresh session will get loaded with the old one's data.

    Other users can only steal locks after a timeout (to avoid problems with people going on vacation with locked data on them)

    ----

    This eactually worked pretty well from a user's perspective, because as opposed to with optimistic locking there would never be a situation where a user would have done some edits in vain or have extra work rechecking it.

    From a developer's perspective it was a pain in the ass (maintain 2 almost identical tables, maintain checkout/checkin-code everytime).

    From support's point of view, it wasn't too bad. Seldomly people would call and demand release of a lock because someone just went to have coffee and he had to edit the data real quick or managment would kill him on the spot because the data would be frozen in like 7 minutes to generate reports.

    1. Re:give users an edit-lock by geekoid · · Score: 1

      "There would be a temp-table for every editable data-table in the db, that has the same structure plus a ID_User field. When a users starts editing a data-set, the data is copied into that temp-table."

      dear lord that sucks.

      Between the question, and most of these answers I can see why software is in the state it's in.

      Nice solution you have there... for 1994.

      --
      The Kruger Dunning explains most post on /. http://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect
    2. Re:give users an edit-lock by molecular · · Score: 1

      "There would be a temp-table for every editable data-table in the db, that has the same structure plus a ID_User field. When a users starts editing a data-set, the data is copied into that temp-table."

      dear lord that sucks.

      Between the question, and most of these answers I can see why software is in the state it's in.

      Nice solution you have there... for 1994.

      I must agree with you, it's very "manual", old-school, error-prone and inefficient.

      To my defense: the app was started even before 1994, back then it was using an M$-Access frontend. The temp-table stuff was invented back then to get around the effects of the optimistic locking Access was doing and also to get around the horrible performance Access was showing with larger tables.

      When we migrated to the javascript frontend (still on IE6 TODAY!!!, it's horrible!) we just kept that system.

      I was not suggesting this would be the way to go.

      I find it interesting to be able show a solution for a web-app-related problem that was initially developed as a workaround for an unrelated problem that popped up even before webapps were in larger-scale use.

  64. Simple way to 'lock' by Anonymous Coward · · Score: 0

    The simplest way is to have some form of persistant storage to record when a user grabs a record for edit. Either a table, file or some shared memory like memcached to hold the record id. Then it's a simpler matter to check that before offering the requested record to the user. You could even implement a messaging / notification system to alert a secondary user when the record is checked back in.

  65. Been there, done that by Anonymous Coward · · Score: 0

    Keep a sessions table with logged in users and their last activity time. This gets updated by a common include file. The file also deletes all sessions > you session time out, so the table is self cleaning. When someone attempts to access a record for editing you look at the record and the sessions table. If the record is locked, and the person is still active, you give read only. If its locked and the person's session has expired (they would not have a session in the db as the first thing the page you are on did would have been to update your session and kill theirs if it was >20 minutes inactive) you claim the record for yourself. The edit page has a cancel button, save and save and exit. Cancel removes the lock then moves on to another page, save saves the data and keeps the lock, save and exit saves the data, removes the lock and moves on. No 2 users can edit the same data that way. This can be implemented with a single field in the table containing editable records, a 2 field sessions table and 50 lines of code over all.

  66. Here's what we did by Rysc · · Score: 1

    Our users wanted locking, so we did it this way:
      - Add a record in a lock table when a user accesses an item in edit mode.
      - Always delete any previous locks a user has when a new one is added (one lock per user).
      - Delete the user's lock records when the user explicitly logs out.
      - A job deletes all lock records for expired sessions (every five minutes).
      - Users accessing a locked record get a read only version and a notice that another user has it locked (complete with the other user's email and phone).

    The stored procedure for locking a record checks that there isn't one already before adding one and does so in a transaction. We rely on the database making a decision about who gets the lock record to make sure that simultaneous access doesn't cause problems, the theory being that the DB has better code for that kind of thing anyway.

    In the case where a user was editing something, timed out, got his lock deleted, another user edits it, and then the user comes back and hits submit... this doesn't have a significant chance of happening in our environment, so we didn't worry about it. Background polling from the browser is a possible but unreliable solution. You should never rely on a well behaved client when designing a web app (or any app). A suggestion I saw elsewhere in this story about using a hidden field with a checksum is a good idea which had not occurred to me. Another possible answer is to record each version separately and include the version being updated in a hidden field on the client, then check on the server that the version you're updating is the latest.

    --
    I want my Cowboyneal
  67. Forget locking by funehmon · · Score: 0

    Why not just log a timestamp of the last edit a user made to that individual record, and allow x minutes from that point to allow another user to edit the record. Same idea as a comment above but if you use a web farm, stay away from sessions as session state is not persisted between different servers in a web farm.

    1. Re:Forget locking by Anonymous Coward · · Score: 0

      if you use PHP or ASP's default sessions variables it is not, but if you set a cookie with a session id or pass it in the query string, and store the session id and information in a database on the server, then it is fine across servers. Broadvision did this. it works.

  68. This is a function of the webapp framework by Giant+Electronic+Bra · · Score: 1

    And if you aren't using a webapp framework which deals with this kind of thing transparently to application business logic, then you need a better framework.

    Seriously, look into things like JBoss SEAM. I'm not suggesting that any particular core technology is the preferred choice, but that happens to be one which provides a fairly nice implementation of the concept.

    Again in J2EE land, the concept is also more directly supported by EJB3 configurations using optimistic locking (the technical term for checking a counter/datestamp when a record to saved). Entity beans attached to an EntityManager which is configured for optlocking will handle the whole process transparently. If a stale record gets persisted, you'll get an appropriate exception at the SSB (application logic) layer and you can take whatever action you need to in the UI.

    These are the kinds of reasons everyone should be using well designed frameworks instead of hacking together any non-trivial webapps on their own. It looks easy, until you start to get into the details.

    --
    "Malo periculosam, libertatem quam quietam servitutem." -- Jefferson
    1. Re:This is a function of the webapp framework by Zarf · · Score: 1

      Heh. I'm going to post it again after all. http://grails.org/doc/1.0.x/guide/single.html#5.3.5%20Pessimistic%20and%20Optimistic%20Locking - leans on the underlying J2EE to accomplish this. A good framework should provide at least the underpinnings for this and I'm in total shock that people even *start* development today without knowing this stuff.

      --
      [signature]
  69. How about a "lockedby" field in the tables? by Spy+der+Mann · · Score: 1

    If a determinate record is being edited, you set the "lockedby" field in the record, and a "lockexpire" field (say, 30 mins). This is set when the user starts editing the page. This could be done in the same table, or in a specific table for locking purposes. This specific table would have the following fields:
    table, recordnumber,user,expires

    When the user finishes, the data is written and the locks are removed.

    If another user tries to edit a record, the software checks if that record is being "locked" by another user, and posts an error message.

    To solve the problem of users trying to access the same record at the same time, you simply insert the "locking" queries inside a transaction. Ta-da!

    1. Re:How about a "lockedby" field in the tables? by Omnifarious · · Score: 1

      Many wikis have advisory locks that work like this.

  70. Copy In Copy Out by Incognito+Milquetoas · · Score: 1

    We had a similar problem where we need locking across parent child records and across multiple web pages.

    We handled locking as follows:
    When a user goes to edit a record we make a copy of the record making the primary key of the parent record the negative value (e.g. key was 27 copy gets -27) and stamping a timestamp on it and the user who is editing. Then we copy all the child records as well with new keys but referencing the negative parent.

    This lets us use the database to hold changes between pages without having a large object model hold the data in the application server. We update the date stamp of the lock every intermediate save to the negative record.

    When the user finishes there multipage editing session and gracefully saves or cancels we copy back over the original record their changes and delete the negative copy.

    If a second user tries to edit they are told it is locked.

    If the first user exits ungracefully (e.g. reboots their PC mid session) we allow the same user to start a new edit session without a lock message but they lose their changes... (we could have given them a choice I guess to keep editing where they left off)

    If the lock was held for 2 hours without any updates any user can aquire the lock in case someone shut off their computer and left.

    A nightly job checks for abandoned records every night.

  71. Re:help the users by giving them info but not limi by Anonymous Coward · · Score: 0

    The users are allowed taking the lock away from each other so the lock resolution is pushed into the real world and out of the app.

    Hey, let's keep this civil. Give them some shooter game where they can resolve it.

  72. Re:help the users by giving them info but not limi by Anonymous Coward · · Score: 0

    That sounds great, but dealing with the real world is inconveniently expensive. Employee counseling and the restaffing costs due to unusually high employee homicide rates would probably outweigh the savings in programming cost and reliability.

    The new door locks and full-time armed guards in the data center would also be expensive.

  73. Can of worms revolving around mutexs by LSU_ADT_Geek · · Score: 1

    Computer science has addressed this issue with a variety of algorithms. It boils down to using mutexs (mutual exclusion). Wikipedia (http://en.wikipedia.org/wiki/Mutual_exclusion) has a number of algorithms that you should evaluate. The biggest problem is that once a lock is acquired, how long do you wait before you realize that the lock will never be released?

    1. Re:Can of worms revolving around mutexs by Slashdot+Parent · · Score: 1

      The biggest problem is that once a lock is acquired, how long do you wait before you realize that the lock will never be released?

      For 99% of web applications, Optimistic Locking is a better choice, because for 99% of applications, the normal usage pattern is for users not to be stepping on each other's toes. Two users editing the same data would be a relatively rare occurrence.

      If your app's usage pattern has a lot of contention to edit the same data, then you're forced to use pessimistic locking so you don't drive your users bonkers with "The record has changed since you started editing it--please resolve the conflicts" messages.

      --
      They don't grade fathers, but if your daughter's a stripper, you fucked up. --Chris Rock
  74. Warning the user + win goes to the swift by MasterOfGoingFaster · · Score: 1

    I use optimistic locking, but I warn the user when someone might be editing the record. We penalize slow users in favor of faster users.

    My app gives the user an 'edit' button. When they click it, they get a timestamp inserted in the record, and it is refreshed (thus they see if someone else is editing). If effect, this timestamp acts like a record lock, but if it is >5 minutes old, it is ignored. This means I don't have to have the server clearing old locks.

    Anytime I display the data, the clients looks at the timestamp, and if it is 5 minutes old, I color the field yellow. This warns the user that an edit may be in progress. If they choose to hit the edit button, they risk losing their edits.

    Downside: User 1 starts his edit, but takes 6 minutes. User 2 starts his edit @ 5.1 minutes (lock has 'expired') and completes before User 1. Thus User 1 loses his edit - and bitches to me.

    Upside: When User 1 bitches, I point out that it is his fault that he didn't complete the task in a reasonable time, and the quicker (busier?) user wins. Solution - quit screwing around when you edit, or you might have to do it twice.

    Yes, we have a lot of old timestamps sitting around, but the load on the server is light. We can flush those out easy enough at night.

    I'm sure someone will point out something I've overlooked, but it seems to work pretty good for us.

    Oh, if you hit the "cancel edit" button, we clear the timestamp, allowing others to edit. So in the case of a lock, user 2 can call user 1 and ask them to cancel the edit. I encourage users to communicate as a way to resolve these issues, rather than code a "my way or the highway" solution.

    --
    Place nail here >+
  75. joomla! by ddfire · · Score: 1

    the joomla! approuche is a smart one. when someone start editing an article the core block it and its keep blocked until the current editor save it, if the editor get disconected the article remains blocked until the editor reconect and save it or and admin unblock it. it use ajax to automatic save the article from time to time. maybe you can use something like that but you give every one the avility to unblock a register. cheers

  76. I wrote an article on something like this by syntap · · Score: 1

    I wrote an article for Delphi Developer magazine back in the late 90's on Paradox in client/server and shared network environments. To summarize, it can be done but you really need to move to a database server. Paradox was designed to be a desktop database, and use for anything else is difficult and unreliable, not to mention simply technically inappropriate for the tool.

    Database servers are meant to handle that kind of thing for you. I would suggest Firebird or Interbase if you want a more "Borland" (or whatever Borland is now) approach, or look into MySQL or even MS SQL Server Express.

  77. Message Queues by m0ntar3 · · Score: 1

    Write a message to a queue on "lock," clearing the message would be an "unlock." Zend_Queue has a good implementation for reference. Locks "timeout" when the message expires.

  78. Parent is absolutely right by Anonymous Coward · · Score: 0

    There's plenty of literature on this, but a quick read of Martin Fowler's Patterns of Enterprise Application Architecture [http://martinfowler.com/eaaCatalog/optimisticOfflineLock.html] should get you going.

    Basically, you keep a version_id for your record.
    You include this version_id in your form.
    When the user submits, you not only get the record by it's primary key, but also by the version_id (ie "... WHERE version_id = x")
    You modifiy the fields and then set version_id to x+1

    When the second user tries to commit his changed, version id will no longer match (x instead of x+1)
    and you can notify him.

    Cheers

  79. MachineChild by Anonymous Coward · · Score: 0

    http://en.wikipedia.org/wiki/Optimistic_concurrency_control

  80. Re:The euphemism treadmill by Anonymous Coward · · Score: 0

    It's offtopic, I know, but that is NOT the original meaning of "taint". Open a dictionary. There's more information in there than simply definitions. "Taint" is from Middle English (ca. 14-16th centuries) meaning "hue" or "dye". It's the same origin as "tint". Its meaning evolved from there to the idea of having a trace of contamination, infection or corruption.

    It wasn't until the late 20th or early 21st century that "taint" came to refer to the anatomical region you're referring to: the perineum.

    "It is better to keep your mouth closed and let people think you are a fool than to open it and remove all doubt."
    - Mark Twain

  81. Honestly...just write it yourself by The+Dancing+Panda · · Score: 1

    Put columns in the table in question called "lockedTime" and "lockedBy". Set them to null. When the user gets a record, set them. When they're done editing, set them to null again.

    Write a Stored Proc to run at some interval and unlock files that have been locked for whatever you think is "too long" (could be done once a day).

    A user can't edit a record that is locked by someone other than himself. You could get by with just a lockedTime, but lockedBy allows the user to get back to the record if they get disconnected for some reason.

    I don't know how your system works, but in every one I've seen, individual users don't have their own DB accounts; there is 1 DB account for the system. It's nice to know who has what record locked.

    Maybe I'm naive on how Phoenix DB works? I feel like anyone could have figured this out.

  82. A little more info on your app may help by Trails · · Score: 1

    What software, framework, persistence package, and db are you using?

    Hibernate, for example, has both optimistic and pessimistic locking. Optimistic is done with timestamps or version numbering.

    Pessimistic locking is backed by the db, so in some instances it does nothing. On mysql, using their innodb engine, as an example, all threads trying to access a locked record will actually block until the lock is released. The latter is often problematic in web apps, but is sometimes desireable.

    Hope that helps, and if you care to give more info, I might be able to give more specific answers.

    1. Re:A little more info on your app may help by Zarf · · Score: 1

      If we knew his framework we could point him to the right tutorials. Good point. I'd be in utter shock if every major framework in existence didn't have at least one free online tutorial on how to implement Optimistic Locking in their system.

      --
      [signature]
    2. Re:A little more info on your app may help by xelah · · Score: 1

      Pessimistic locking is backed by the db, so in some instances it does nothing. On mysql, using their innodb engine, as an example, all threads trying to access a locked record will actually block until the lock is released. The latter is often problematic in web apps, but is sometimes desireable.

      Holding a DB row/table lock for longer than a single server call is usually a bad idea. Consider:

      • The effect on your backup software. (It might work fine with the old data, it might block).
      • The effect on a DBA trying to, say, add a column.
      • The effect on other software updating columns unrelated to the edit (a last customer website login field for a customer locked by someone in a call centre, say).
      • The increased potential for deadlocks in the server.
      • The effect on the database engine itself (you may run in to performance problems with lots of locks, lots of open transactions or lots of waiting transactions).
      • How you would tell your second user that the record is locked by , rather than just letting his web browser time-out.
      • How the 'Save changes' web server request will resume the same DB transaction as the 'Start edit' web server request, which may have been sent to an entirely different computer.

      Don't use database-level row/table/index/whatever locks for this.

  83. Ajax by bigattichouse · · Score: 1

    Set up a GUID field in a table, with a timestamp and a username

    1. hash the md5(table+key)
    2. check for a lock
    3. insert a lock if it doesn't exist.
    4. have ajax check, and pop up a div with partial alpha to make the record readable, but an obvious visual cue that it is locked.

    OR, add the lock field to the table itself, and you can just do an Update where lock is null, and then check and see if you got the lock.

    --
    meh
  84. Wrong by Slashdot+Parent · · Score: 1

    This is a stateless web-based application, we we're talking long-running transactions. You're not going to hold a db transaction open while the user goes and eats lunch, has a few water-cooler discussions, and updates his fantasy football lineup (or simply abandons the transaction entirely!). Such a solution does not scale well, because you'll have to hold a db connection and a db transaction open for each user of your application who is modifying data until you can guarantee that he is no longer modifying data. Your database will grind to a screeching halt past a few thousand users.

    Since you can't scale an app under that model, ACID is not going to protect you. Consider the following scenario:
    1. User A reads record 1 and starts making modifications in his browser
    2. User B reads record 1 and starts making modifications in her browser
    3. User B finishes first and writes record 1 back to the database
    4. User A writes record 1 back to the database, obliterating User B's modifications

    Note: ACID was not violated here, and the database is still in a consistent state. Unfortunately, the record probably contains incorrect data, because user A didn't know about user B's modifications, and neither user even knows there was a ever a conflict!

    The correct answer in 99% of applications is to use some form of Optimistic Locking. In the remaining 1%, where usage patterns simply cause too much contention for the same data, a pessimistic locking approach would be required.

    --
    They don't grade fathers, but if your daughter's a stripper, you fucked up. --Chris Rock
    1. Re:Wrong by drfreak · · Score: 1

      Sorry, I just don't get why one would hold a transaction open while a web user goes to get a cup of coffee. The transaction shouldn't even start until the user clicks a "Save" button. Yes, HTML is stateless, but there are plenty of options for keeping some variable values for a predetermined amount of time.

    2. Re:Wrong by Slashdot+Parent · · Score: 1

      Did you read the example I posted?

      ACID only ensures that when multiple users hit "save" at the exact same time, that their updates are applied serially to the data and that reads don't pick up halfway-updated data. ACID does not guarantee anything beyond that.

      In particular, it does not guarantee that the application is preventing multiple users from inadvertently modifying the same data concurrently and clobbering each other's updates.

      If you rely only on ACID for data consistency, whomever is lucky enough to hit "save" last wins, and that person will never even know the damage he just caused.

      Your original point was that ACID will protect you. My continued contention is that you are simply wrong.

      --
      They don't grade fathers, but if your daughter's a stripper, you fucked up. --Chris Rock
    3. Re:Wrong by drfreak · · Score: 1

      I did read your example, and I don't think either of us are "wrong". How concurrency and transactions are utilized still is an exercise for the programmer in cases like this, I agree.

      If a certain amount of time needs to be guaranteed between changes to a record, a "Last Changed" timestamp could be used, checking if a certain interval of time has elapsed since the record was touched.

  85. in a word - Semi4s by MonsterMasher · · Score: 1
  86. Are you F'n kidding me? by geekoid · · Score: 1

    Locking the data? seriously? turn in your degree.

    --
    The Kruger Dunning explains most post on /. http://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect
    1. Re:Are you F'n kidding me? by cratermoon · · Score: 1

      Why does *this* guy have a job and a developer with 10+ years experience going back to the beginning of the web is on unemployment? Oh right, because I'm the guy who'd have looked management in the face when they first nixed proper concurrency design and said, "you can't do it that way, it'll break edits" and they'd have me out the door.

    2. Re:Are you F'n kidding me? by Zarf · · Score: 1

      Management does not see developers like a coach sees a basketball player. Management can't see the moves a developer has the same way a coach can see the moves a basketball player has. It's a hard thing to determine who the best writer of poetry is when you can't even read the language they write in and have never seen the things they write about. This is the fundamental problem with the management of developers... it is like an impedance mismatch.

      --
      [signature]
  87. You and me both... by Giant+Electronic+Bra · · Score: 1

    Yet it appears that about 90% of the people developing web apps are entirely sans-clue on the whole subject. Most of these apps I suspect never have ANY real design applied to them anyway, just ad-hoc stuff that starts from at best some templating system.

    Ah well, I shouldn't complain. I get to go in and clean up the mess (IE tell them what they have is probably worthless) and get paid for it.

    --
    "Malo periculosam, libertatem quam quietam servitutem." -- Jefferson
  88. Re:help the users by giving them info but not limi by snowwrestler · · Score: 1

    This works for a small set of users who know each other and can communicate offline easily and comfortably.

    In a big company though I might not know who $user$ is, and might not care. I just need to do my work and screw that guy, he can start over.

    --
    Build a man a fire, he's warm for one night. Set him on fire, and he's warm for the rest of his life.
  89. Here's what to do. by Animats · · Score: 2, Insightful

    OK. Here's what to do.

    1. Demonstrate how Wikipedia locks. Edit something in the Wikipedia sandbox from two adjacent computers, demonstrate what an "edit conflict" looks like, and show how you resolve it.
    2. Demonstrate how a hard-lock version control system, like Microsoft Visual SourceSafe, locks. Show what happens when you try to check out something on one machine that's already locked on another machine. Point out what happens if someone leaves something checked out.
    3. Get your management to decide which approach they want.
    4. Implement.
    1. Re:Here's what to do. by Zarf · · Score: 1

      I like this plan.

      --
      [signature]
  90. to sum it up by molecular · · Score: 1

    after reading most of the comments I can sum it up:

    Optimistic Locking: described here by many readers, easy to implement, also good idea to implement first even when using other scheme. It will piss off users from time to time, though, because they loose data. This is the choice of the (lazy) developer and/or the cheap customer.

    Real row-based or even finer locking: Hard to implement right with all the timeouts, user-infos, keeping unfinished edits over sessions,.... This is the choice of the demanding user that doesn't want to loose any work at all, and the wise customer.

    Realtime concurrent editing: not really sure about this.

    Ramble on, guys.

    1. Re:to sum it up by Anonymous Coward · · Score: 0

      after reading most of the comments I can sum it up:

      Optimistic Locking: described here by many readers, easy to implement, also good idea to implement first even when using other scheme. It will piss off users from time to time, though, because they loose data. This is the choice of the (lazy) developer and/or the cheap customer.

      Real row-based or even finer locking: Hard to implement right with all the timeouts, user-infos, keeping unfinished edits over sessions,.... This is the choice of the demanding user that doesn't want to loose any work at all, and the wise customer.

      Realtime concurrent editing: not really sure about this.

      Ramble on, guys.

      You'll be surprised how many use cases just doing Optimistic locking can solve. In a framework like the one I use Grails GORM there are even ways to implement custom UI handlers for the collisions so that users don't really lose data at all. The data is still "in flight" and you can direct it through many different workflows and business rules before it gets saved. You can do all this on a case-by-case basis as you need to.

      Discover TPS report collisions are easily merged? Do merge on TPS reports. Discover you need to do a fancy edit screen when looking at Foo records? Do complex versioned edit screens on Foo records. Discover you have to do special semaphore and locking on complicated workflow based processes? Do that in the controllers for those...

      This is a pragmatic approach that acknowledges much more sophisticated systems of locking are usually YAGNI (You Ain't Gonna Need It) and you spin up developer time when you find out you really do need it. Spend developer time solving *exactly* the problem you need solved and not doing complex general solutions that you will never need or only need for one event every decade.

      Your summary betrays your bias. I think you probably invented a very sophisticated system that is so much smarter and better than simple poor Optimistic Locking and you are in absolute love with your idea. You didn't want the slashdot crowd to help you... you wanted us to tell you how awesome you are and tell you what you were going to do was super and we all want to do what you did.

      Well. I'm not as arrogant as you. I invented a locking system involving a separate lock table, a lock time out, a flagging system for users, and all sorts of sophisticated things that let me do amazing stuff with locks. It was a huge development effort... Optimistic Locking with no UI resolution code beyond "oops" was ready for slip-stream to production in a week. Guess what... the pain of the edge cases where pessimistic locking is the "best" solution? They didn't care after the basic Optimistic Locking was in place. I was forced to concede that I was wrong... I learned something.

      Can you? From how you summarize this thread I don't think you really are learning.

  91. Re:help the users by giving them info but not limi by roman_mir · · Score: 1

    Except that the management will not like it if people take locks away from each other all the time and interfere with each others work. The only reason to take a lock away is if the work is not getting done by the other user for a period of time that is too long or if there is another meaningful reason that can be explained to the mgmt. I am sure that if someone is being a pita every day, he'll have difficult time explaining himself. The set of users in my case is about 30, they are even located between different buildings, so it's not like they see each other all the time.

  92. Last Saved Wins? by Anonymous Coward · · Score: 0

    Once worked on an app that was built upon a "last saved wins" rule. But the remarkable thing was that the rule was applied at the the column level, not the row level. So if User1 and User2 both cached local copies of the same row for editing before either saved and they updated mutually exclusive fields on that row, when User2 committed his/her edits (after User1 did), he/she didn't overwrite the updates made by User1. So basically we generated SQL update statements that only included the columns that were actually changed. If they happened to update some of the same fields ... you just got sort of what you'd expect anyway. Maybe we didn't have the same transaction volume you are dealing with and you could make arguments against that scheme on the basis of the fact that updates committed that way under those circumstances (example above) result in a row that is inconsistent with the expectations of both users since neither saw it on their screen as it is on the database after they are both done ... but it worked very well for us.

  93. for god's sake read grey by plopez · · Score: 1

    http://www.amazon.com/Transaction-Processing-Concepts-Techniques-Management/dp/1558601902/ref=sr_1_1?ie=UTF8&s=books&qid=1253900733&sr=8-1

    or any decent transaction processing book that uses him as a reference. Now with cloud computing this is more important than ever.

    And just because your DB has row level locking doesn't mean you have transactional integrity. Distributed transactions, ISAM databases, Hibernate, XML databases, race conditions, sloppy programming, poor DB design and outages can all conspire against you.

    There is no magic bullet.

    --
    putting the 'B' in LGBTQ+
  94. Hey, has anybody mentioned Optimistic Locking? by Anonymous Coward · · Score: 0

    Because you really should look into Optimistic Locking. I'll wait awhile to make sure nobody mentions it and then psuedo out an example.

  95. Verify Original Values Didn't Change by imnes · · Score: 1
    You can use a WHERE condition along with your UPDATE and DELETE statements to verify that the data hasn't been changed by another user before writing your changes, and if it does show some error message or otherwise handle it in some way that makes sense for your app. An interaction may look like this:

    1. User selects a row to edit. Application pulls all the columns for that row and stores them into the users session.
    2. User makes modifications to some fields and submits back to the server.
    3. Server issues an UPDATE statement and includes all the original column values in the WHERE clause to only update the record if nobody else has modified it since we started.

    SELECT id, color, name, description FROM vehicle WHERE id = '100'

    id = 100
    color = 'red'
    name = 'kia'
    description = 'cheap'

    User changes the color to 'blue' and saves changes, the app might do something like:

    UPDATE vehicle SET color='blue' WHERE id=100 AND color='red' AND name='kia' AND description='cheap'

    If anyone else modified a field in the row the update would fail and you can handle it however you like.

    1. Re:Verify Original Values Didn't Change by mhelander · · Score: 1

      +1

      Optimistic Concurrency is certainly the way to go, and if you can't put version columns in your database (perhaps you have a grumpy DBA) then the approach using original values lets you use Optimistic Concurrency without modifying the DB schema.

      Furthermore, it can help increase throughput: Sometimes an analysis of the domain shows that for some records, fields - or groups of fields - could be changed independently. In such a case, including only the values that had actually changed (or the values from a group where one or more values had changed) in the Optimistic Concurrency part of the Where clause (described in detail by the parent poster) could allow for two users to update the same record at the same time, as long as they only edit different fields, without getting a conflict. You can see which values have actually changed before inclusion in the SQL by comparing them to the original values.

      Finally, keeping the original values around in the client (web server) layer, which this approach requires, is useful for the times when conflicts do occur - at this time, you can present not just the new value that is currently in the database but also the original value that the user started with in the conflict resolution form.

  96. just a thought...they're still free, right? :) by Anonymous Coward · · Score: 0

    If it were me, I would attempt(emphasis on attempt) to avoid the locking problem altogether via DB and system design. Sure you will pay the price concerning the size of your data repository and concerning DB administration, but your transactions will be more data safe and user friendly. I know for some apps this would be impossible to eliminate altogether, but something might be gained from minimizing it. Now if you are in the situation where you are not so much concerned about end user experience, then ignore what I just said. :P

  97. Simple by Anonymous Coward · · Score: 0

    Do away with this darn infestation of WEB apps the web is for looking and reading ect not to use as a commercial data network , also by getting the net OFF most machines you get more work less games less botnets ect ect ect..

    We have just removed ALL games and internet of ALL computers in the workplace except for one that deals with emails and even that is restricted to heel and back and guess what output has gone thru the roof

  98. Take the word "web" out of your question... by GasparGMSwordsman · · Score: 1

    It sounds like you have a decent amount of experience writing software. My thought is, why are you treating this product any differently just because it is a "web" product?

    A "web" program is just the same as any distributed access program. The only difference from having a Mainframe with terminals, a web server with browser access and a client/server system is the UI (user interface).

    Personally I would say that the same locking system you were using before would probably work fine here. I would add either a time-out on the lock or a way of overriding that lock for when a user either walks away for the day or just hits close without saving.

  99. use postgresql, the best database by MagicMerlin · · Score: 1

    postgresql has short term transactional record locks as well as long term advisory locks. It has the ability to do paradox style locking if you are so inclined...

  100. Re:The euphemism treadmill by Anonymous Coward · · Score: 0

    So, according to the Oxford English Dictionary, the verb form of "taint", in the late 16th century, meant "To affect (esp. in a slight degree); to touch, tinge, imbue slightly (usually with some bad or undesirable quality)". You're comparing this verb to a noun that refers to the perineum. OED has no mention of the perineum in their entry for the noun form. The wikipedia article cited below has an etymology of unknown origin that describes your meaning. I would suggest that the word meant "to soil" long, long before people started using it to describe the perineum.

    It is fascinating how language evolves. It's also possible to see that evolution occur, if you're willing to do even the slightest amount of research.

  101. The most important advice about concurrency, ever by Anonymous Coward · · Score: 0

    Data concurrency is certainly one of the most difficult problems you can have in a web application - no, it's the most difficult. In fact, there's a 90 % of chances that... it's one more problem you don't need to solve. If you're just an 'enteprise programer' (ie, you don't work al Google, MS or IBM), chances all your approaches to locking are mistaken and wrong, and you are certainly intruducing locking bugs, which resort to classical programming theories... only per register or per table. And if you're a much better than average programmer, you should know: you almost certainly don't need it, at all.
    In the remaining 10 % of chances where you do need to acknowledge data concurrency, and you are certain that you can't avoid it because your carefully designed model would somewhat be invalidated by non-malevolant users, I can suggest you a few keywords: optimistic locking, optimistic concurrency, estate synchronization, transactionality.

    But the most important advice of all, one you should use as a golden rule with the heaviest weight, is that you should NEVER, I mean NEVER EVER, ask a DBA to help you: DBAs are alle a bunch of ignorant, incapable, malevolant and stupid bunch of overpaid bureaucrats, who will manipulate whatever you ask them as to create a false of need and rescue, but aren't even remotely interested in helping you - they despise programming to begin with.

  102. We don't lock by Eminor · · Score: 1

    The application that I'm working on does not lock the records. The business object remembers that initial values it was loaded with. If those have changed, when the user saves, it presents them with a message that someone else has already edited the record. Sure, that may be annoying to the user, but it really doesn't come up all that often.

    It's simple SQL:
    update client set unique_id = ?, first_name = ?, last_name = ? where unique_id = ? and first_name = ? and last_name = ?; (assuming no nulls allowed)

    In the set clause you use the new values, in the where clause you use the old values. If zero records are updated, you have a conflict.

  103. largely solved by doode · · Score: 1

    You may be interested in some software that addresses your problem directly and specializes in virtual locking - it's at www.arcs.us

  104. Check Beej's Guide by jawahar · · Score: 1

    I suggest OP to check Beej's Guide for mandatory and advisory locks.

  105. How about this by Anonymous Coward · · Score: 0

    The issue is time granularity. This would be a transaction based system with short granularity. Everyone sees the data nearly real-time and nearly simultaneous open multiple editing. No need to "own" or lock the page.

    For most people an interaction / update time could be 1/10 second. Computers can move data much faster. Much like a chat room. Each user's display screen would be updated several times a second- everyone would see the data as it currently is. So you would see typing / editing going on by everyone involved. It would be live, real-time (within 1/10 second, let's say) and constantly updated. When you're done, nothing to do- just close the page, walk away, stand-by, whatever. The record is kept closed by default- only opens for each edit character.

    I didn't say it would be efficient, but if optimized and write cached it would do what the requester wants.

  106. That path leads to madness by handy_vandal · · Score: 1

    That path leads to madness.

    Made me laugh!

    --
    -kgj
  107. Ruby on Rails - lock_version by Anonymous Coward · · Score: 0

    In Ruby on Rails, the column name 'lock_version' magically does optimistic locking for you.

    Set the default value to zero and always include a lock version value with each save.

    You can take it a step beyond by catching the StaleObjectError and returning a nicely worded error message instead of HTTP Error 500.

    Ruby on Rails has a big learning curve, but is wonderful organized. I am kinda a disorganized mess and forcing myself to do things the 'Ruby way' actually ends up saving a lot of time and frustration. It also makes me more employable.