Re: using cdb for 'update' without race condition?
ari edelkind <[email protected]> Fri, 11 Apr 2008 17:00:15 -0400
| Newsgroups | gmane.comp.djb.cdb |
|---|---|
| Message-ID | <[email protected]> |
[email protected] wrote: > ari edelkind <[email protected]> wrote: > > set -o noclobber > > > > while ! (exec >"$REMASTER_FILE") 2>&- > > do > > sleep 1 > > done > > Ah, so you're talking about O_EXCL, not locking. Yes, that will work, > but again, you're busy-waiting instead of letting the kernel wake you > up when it's your turn. Yes, it's a form of lock, and it's what i used for illustration in this example. This method combines a clarification of what you presumed "won't work" with a method that you conceded _would_ work, so it's a fitting demonstration. You can, frankly, use whatever form of locking you desire; you still approach it in the same manner. Rewriting cdb files isn't a procedure that would be appropriate for a high-traffic update environment anyway, so "busy-waiting" isn't necessarily a poor tactic. I should add that there aren't many options for shell scripts that can _avoid_ "busy-waiting", but perhaps it would have been clearer if i'd written: ------------------------------ REMASTER_FILE=$REMASTER_FILE perl -e 'use Fcntl ":flock"; open (LOCK, ">>$ENV{REMASTER_FILE}") or die; die unless flock(LOCK, LOCK_EX); print "Y\n"; close(STDOUT); <STDIN>; # block until co-process input (or close) ' 2>/dev/null |& read -p islocked; [[ "$islocked" = "Y" ]] || exit 1 ... ------------------------------ You can make your own judgments. To recap, when i say, "you still approach it in the same manner," the "manner" to which i've been referring since my response to the original post is: lock -> do whatever -> commit -> unlock Depending on what you want to do, you can translate this into: set -o noclobber && (exec >target) && do_stuff_to_target \ && commit; rm -f target or set -o noclobber && (echo $$ >target.lock) && do_stuff_to_target \ && commit; rm -f target.lock or ln -s target.$myhost.$$ target.lock && do_stuff_to_target \ && commit; rm -f target.lock # better over nfs, thanks to symlink(2) or lockfile target.lock && do_stuff_to_target \ && commit; rm -f target.lock # also better over nfs, thanks to link(2) # lets `lockfile` "busy-wait" for you # not all systems come with `lockfile` or pseudocode: fd=open(target) && lock(fd) && do_stuff_to_target \ && commit; unlock(fd) Once again, i've intentionally left logic for handling errors and stale lock files out of my examples. As i've also stated, the "manner" can be mildly adjusted to: lock -> do whatever -> commit_and_unlock If the lock file is the file to be committed itself, you can still commit the file by renaming it into place (e.g. `mv file.tmp file.cdb`), which will effectively unlock 'file.tmp' directly after it is committed. That is, even if you still hold a kernel-level lock on the committed open file descriptor, new processes attempting to create and acquire a lock on a new 'file.tmp' can. And this is what you want, because the file has already been committed. > Also, if the script gets killed in the middle > of making an update, you'll have a stale remaster file blocking all > further updates until you intervene manually. With a permanent, > separate file used just for locking, you have no busy-waiting and (if > you're not on NFS) no chance of stale locks. If you _are_ using nfs, stale locks will not be the greatest of your locking problems using kernel-supported file locks (nor is a simple open(...,O_CREAT|O_EXCL) sufficient in such a case, as i noted in a prior e-mail). Stale remaster files needn't require manual intervention, either, if one takes appropriate measures in one's code. I've taken a neutral stance on locking tactics from the start; i couldn't care less which method you use. You've made it clear that you, personally, wouldn't use open(...,O_CREAT|O_EXCL) locking, and that's fine. Indeed, depending on your environment, perhaps only the prjsuperduperlockprocessfilesystemnetworkthegoogleandtheinternets method would be suitable. Feel free to use it and be happy. ari