Bug 5193 - sa-update is not atomic
Summary: sa-update is not atomic
Status: RESOLVED WORKSFORME
Alias: None
Product: Spamassassin
Classification: Unclassified
Component: sa-update (show other bugs)
Version: 3.1.7
Hardware: Other other
: P5 normal
Target Milestone: Undefined
Assignee: SpamAssassin Developer Mailing List
URL:
Whiteboard:
Keywords:
Depends on: 5446
Blocks:
  Show dependency tree
 
Reported: 2006-11-17 10:32 UTC by Tony Finch
Modified: 2019-08-01 12:02 UTC (History)
1 user (show)



Attachment Type Modified Status Actions Submitter/CLA Status
Atomic update wrapper for sa-update text/plain None Tony Finch [HasCLA]
atomic rules update with sa-compile support text/plain None Tony Finch [HasCLA]

Note You need to log in before you can comment on or make changes to this bug.
Description Tony Finch 2006-11-17 10:32:01 UTC
sa-update does not replace the rules directory atomically, which means that in
setups where spamassassin is restarted frequently there is a risk of it being
confused is sa-update is running when it starts. I have a wrapper script which
makes sa-update atomic which I can attach if you are interested, but it's
probably better to fix sa-update itself. Note that SpamAssassin itself should
also be fixed so that it doesn't get confused by the ruleset changing underneath
it as it opens the configuration files in turn.
Comment 1 Theo Van Dinter 2006-11-30 19:33:40 UTC
Patches welcome, but I don't think there's a way to make the update atomic.

As for SA being confused, it doesn't care if the rules are changed around while
it's running.  If you run sa-learn or spamassassin or restart spamd during an
update, there could be an issue.  Since that's a standard issue for every daemon
I can think of, I'm not sure there's much we should do about it.
Comment 2 Tony Finch 2006-12-01 03:37:07 UTC
A rough strategy for making updates atomic, at least per rules directory, is:

(1) When SA is starting it chdirs to each rules directory and reads the rules
files using just their basenames. This might not be necessary if it doesn't
matter that SA loads some rules from the old set and some from the new set.

(2) Updates populate a new directory with rules then atomically move it into
place. This might not be portable to non-Unix filesystems.

The problem with sa-update at the moment is that SA might see only a partial
ruleset when it starts, which is worse than no ruleset (in which case it falls
back to the original rules distributed with the code) or a changing ruleset.
Comment 3 Justin Mason 2006-12-01 04:07:05 UTC
Theo's right, btw -- there's really no way to make the updates *really* atomic.
 however we could certainly get it *nearer* to being atomic, I think, by
reducing the available race window duration. ;)




'(1) When SA is starting it chdirs to each rules directory and reads the rules
files using just their basenames. This might not be necessary if it doesn't
matter that SA loads some rules from the old set and some from the new set.'

I'd rather not do this; we try to avoid chdir()ing around since
Mail::SpamAssassin may be run from a third-party application, also it could
effect the environment seen by third-party plugins too with respect to paths. 

'(2) Updates populate a new directory with rules then atomically move it into
place. This might not be portable to non-Unix filesystems.'

This is preferred IMO.  but then, there's no atomic way to do that, as noted ;)

There are two options:

1. the double-rename-directory approach:

- download update into "$target.tmp" (where $target =
"/var/lib/spamassassin/3.002000/updates_spamassassin_org" or whatever)

- perform lints etc. on that

- rename '/var/lib/spamassassin/3.002000/updates_spamassassin_org',
'/var/lib/spamassassin/3.002000/updates_spamassassin_org.old' or die

- rename '/var/lib/spamassassin/3.002000/updates_spamassassin_org.tmp',
'/var/lib/spamassassin/3.002000/updates_spamassassin_org' or rollback old dir
and die

This is generally best UNIXy practice I think.  There's a much, much smaller
race window -- two rename() syscalls.  however the spamassassin script would
still see an empty rules dir if it ran right between the two rename()s (since
the "include" cf file would include a nonexistent dir).


2. the "valid rules dir" flag file:

I've suggested this before for other reasons; however it helps with this one
too!  Basically it's similar to the above, except with the addition of a "this
directory contains valid rules" flag file.  The ruleset is not used unless that
flag exists.  before the rename()s, this file is unlinked; after they complete,
it's recreated.  Since the creation/deletion of a file is atomic, this would
make things atomic in turn.






Comment 4 Tony Finch 2006-12-01 06:25:11 UTC
The way my script atomically replaces the rules directory is by replacing a
symlink to the old rules with a sylmink to the new rules using rename().

(I've just had another look at the POSIX rules about replacing a directory using
rename() and it's no use for us because the directory to be replaced must be empty.)
Comment 5 Tony Finch 2006-12-01 06:28:15 UTC
Created attachment 3759 [details]
Atomic update wrapper for sa-update
Comment 6 Justin Mason 2006-12-01 06:36:26 UTC
'replacing a
symlink to the old rules with a sylmink to the new rules using rename()'

hmm, interesting trick! this may be the best option -- modify the script to
have a symlink at a certain point so that we can do this.

unfortunately though, that would need to be conditional on UNIX vs win32 --
win32 updaters obviously can't use that.
Comment 7 Tony Finch 2006-12-01 06:57:41 UTC
Another possibility that would be compatible with win32 is an elaboration of the
flag file idea. SA could glob for rulesdir/version/*/flag to find out which
directory currently contains the flag, and load the rules from there. (Note the
glob isn't atomic so it may see the flag both before and after a rename, in
which case SA should probably stat the directories and pick the newest.) When
sa-update runs it can pick an unused directory name in rulesdir/version for the
new rules, and when they have been verified it can atomically rename the flag
file from its current location into the new directory. Then wait a short time in
case SA is loading old rules, and finally delete the old rules directory.
Comment 8 Theo Van Dinter 2006-12-01 15:56:25 UTC
(In reply to comment #3)
> Theo's right, btw -- there's really no way to make the updates *really* atomic.
>  however we could certainly get it *nearer* to being atomic, I think, by
> reducing the available race window duration. ;)

Sure.  I just don't think we need to go crazy overboard here w/ flag files and
so on.  We operate in the same way as every other tool that has config files.  I
don't want to start putting in a bunch of complicated strange hacks to deal with
very uncommon problems.
Comment 9 Craig Morrison 2006-12-01 17:10:07 UTC
What's the old maxim? If it ain't broke, don't fix it?

Even on a loaded system the window isn't all *that* long. I'm not a dev here so
I really don't have any say but my 2 cents is leave it alone.

Any reasonable system admin is going to test changes first and then implement.
So I don't see what the real issue is.
Comment 10 Tony Finch 2007-05-11 09:56:11 UTC
Created attachment 3945 [details]
atomic rules update with sa-compile support

This is the current version of my update script, which includes support for
sa-compile.
Comment 11 Tony Finch 2007-05-11 09:58:48 UTC
I've marked this bug as depending on 5446 because sa-update-atomic requires the
--updatedir option for sa-compile.
Comment 12 Henrik Krohns 2019-08-01 12:02:16 UTC
Closing old stale bug. Current sa-update is atomic enough imo.