The two scale problems demanded a new protocol. AFSv2โs answer is two ideas: a promise mechanism (callbacks) and a compact file name (the FID).
50.4 AFS Version 2
The big idea is the callback callback In AFS, a promise the server makes to a client that it will notify (recall) the client whenever a file the client has cached is modified by someone else. Callbacks let a client assume its cached copy is valid until told otherwise, replacing NFS-style polling (repeated GETATTR/TestAuth checks) with an interrupt-like model โ the key to AFS's scalability. When a writer closes a modified file, the server 'breaks' the callbacks of all other clients caching it, forcing them to re-fetch. defined in ch. 50 โ open in glossary : a promise from the server to tell the client whenever a file it is caching gets modified. The client no longer polls (โhas this changed?โ); it just assumes its cache is valid until the server says otherwise โ exactly the shift from polling to interrupts. That alone kills the TestAuth flood.
The second idea is the file identifier file identifier AFS's FID, the analog of an NFS file handle: {volume identifier, file identifier, uniquifier}. The uniquifier allows the volume and file IDs to be safely reused after a file is deleted. Using FIDs, the client walks a pathname one component at a time (caching each directory) rather than shipping whole pathnames for the server to traverse. defined in ch. 50 โ open in glossary (FID), AFSโs answer to the NFS file handle, so the client (not the server) walks the pathname one component at a time:
Putting both together, watch a file being read โ and then re-read almost for free:
The client walks the path one component at a time, using FIDs.
The first open() of /home/remzi/notes.txt costs several Fetches, but it
establishes callbacks on every directory and the file โ so later accesses are
entirely local, behaving just like a local disk file system. That is exactly the
scalability AFS was after.
Aside: Cache Consistency Is Not a Panacea
The baseline consistency a distributed FS provides isnโt enough for everything. If multiple clients do real concurrent updates โ say, checking code in and out of a repository โ you must use explicit file-level locking; donโt expect the file system alone to sort out conflicts. This baseline is for casual use (log in elsewhere, see a reasonable version of your files).50.5 Cache Consistency
Recall NFSโs two worries: update visibility update visibility One half of the cache consistency problem: the question of when updates made by one client become visible to other clients. If a client buffers its writes in its local cache before propagating them to the server, other clients that read the file in the meantime will see an old version โ until the buffered writes reach the server.
defined in ch. 49 โ open in glossary
(when does the server get the new version?) and the
stale cache stale cache The other half of the cache consistency problem: after one client (C2) has flushed its update F[v2] to the server, another client (C1) may still hold the old version F[v1] in its cache. Unless C1 re-validates before reading, it returns outdated data instead of the latest copy.
defined in ch. 49 โ open in glossary
(how long until others see it?). Thanks
to callbacks and whole-file caching, AFSโs answer is refreshingly simple. Between
different machines, both happen at the same instant โ when the writer calls
close():
1The callback promise
Client 1 opens F and caches it. The server records a callback for C1 on F โ a promise to tell C1 if F ever changes. C1 now trusts its cache with no further checks.
Thereโs one deliberate exception: between processes on the same machine,
writes are immediately visible (normal UNIX semantics) โ you donโt wait for a
close(). Only when you move to a different machine do you see the
close-based model. And when two machines race to modify one file, AFSโs
whole-file Store gives last writer wins last writer wins AFS's behavior when processes on different machines modify the same file concurrently โ more precisely 'last closer wins': whichever client calls close() last flushes its whole file to the server last and becomes the winning version. The result is a file produced entirely by one client or the other, never a block-level intermixing of both clients' writes (which a block-based protocol like NFS can produce, e.g. a corrupt half-and-half JPEG).
defined in ch. 50 โ open in glossary
(really
last closer wins): the surviving file is entirely one clientโs or the otherโs โ
a big contrast with NFS, whose block-by-block flushes can leave a nonsensical
mixture of two writersโ data.
Check yourself: callbacks and AFS cache consistency
1.What is a callback in AFSv2, and what problem does it solve?
2.Which analogy best captures the shift callbacks represent?
3.What is an AFS file identifier (FID), and why the 'uniquifier'?
4.Between processes on DIFFERENT machines, when does AFS make an update visible and invalidate other caches?
5.How does AFS treat writes between processes on the SAME machine?
6.If processes on two different machines modify the same file concurrently, what does AFS do?