|
|
-
- This program, afs.py, allows you to experiment with the cache consistency
- behavior of the Andrew File System (AFS). The program generates random client
- traces (of file opens, reads, writes, and closes), enabling the user to see if
- they can predict what values end up in various files.
-
- Here is an example run:
-
- prompt> ./afs.py -C 2 -n 1 -s 12
-
- Server c0 c1
- file:a contains:0
- open:a [fd:0]
- write:0 value? -> 1
- close:0
- open:a [fd:0]
- read:0 -> value?
- close:0
- file:a contains:?
- prompt>
-
- The trace is fairly simple to read. On the left is the server, and each column
- shows actions being taken on each of two clients (use -C <clients> to specify
- a different number). Each client generates one random action (-n 1), which is
- either the open/read/close of a file or the open/write/close of a file. The
- contents of a file, for simplicity, is always just a single number.
-
- To generate different traces, use '-s' (for a random seed), as always. Here we
- set it to 12 to get this specific trace.
-
- In the trace, the server shows the initial contents of all the files in the
- system:
-
- file:a contains:0
-
- As you can see in this trace, there is just one file (a) and it contains the
- value 0.
-
- Time increases downwards, and what is next is client 0 (c0) opening the file
- 'a' (which returns a file descriptor, 0 in this case), writing to that
- descriptor, and then closing the file.
-
- Immediately you see the first question posed to you:
-
- write:0 value? -> 1
-
- When writing to descriptor 0, you are overwriting an existing value with the
- new value of 1. What was that old value? (pretty easy in this case: 0).
-
- Then client 1 begins doing some work (c1). It opens the file, reads it, and
- closes it. Again, we have a question to answer:
-
- read:0 -> value?
-
- When reading from this file, what value should client 1 see? Again, given AFS
- consistency, the answer is straightforward: 1 (the value placed in the file
- when c0 closed the file and updated the server).
-
- The final question in the trace is the final value of the file on the server:
-
- file:a contains:?
-
- Again, the answer here is easy: 1 (as generated by c0).
-
- To see if you have answered these questions correctly, run with the '-c' flag
- (or '--compute'), as follows:
-
- prompt> ./afs.py -C 2 -n 1 -s 12 -c
-
- Server c0 c1
- file:a contains:0
- open:a [fd:0]
- write:0 0 -> 1
- close:0
- open:a [fd:0]
- read:0 -> 1
- close:0
- file:a contains:1
- prompt>
-
- From this trace, you can see that all the question marks have been filled in
- with answers.
-
- More detail is available on what has happened too, with the '-d' ('--detail')
- flag. Here is an example that shows when each client issued a get or put of a
- file to the server:
-
- prompt> ./afs.py -C 2 -n 1 -s 12 -c -d 1
-
- Server c0 c1
- file:a contains:0
- open:a [fd:0]
- getfile:a c:c0 [0]
-
- write:0 0 -> 1
-
- close:0
- putfile:a c:c0 [1]
-
- open:a [fd:0]
- getfile:a c:c1 [1]
-
- read:0 -> 1
-
- close:0
-
- file:a contains:1
- prompt>
-
- You can show more with higher levels of detail, including cache invalidations,
- the exact client cache state after each step, and extra diagnostic
- information. We'll show these in one more example below.
-
- Random client actions are useful to generate new problems and try to solve
- them; however, in some cases it is useful to control exactly what each client
- does in order to see specific AFS behaviors. To do this, you can use the '-A'
- and '-S' flags (either together or in tandem).
-
- The '-S' flag lets you control the exact schedule of client actions. Assume our
- example above. Let's say we wish to run client 1 in entirety first; to achieve
- this end, we simply run the following:
-
- prompt> ./afs.py -C 2 -n 1 -s 12 -S 111000
-
- Server c0 c1
- file:a contains:0
- open:a [fd:0]
- read:0 -> value?
- close:0
- open:a [fd:0]
- write:0 value? -> 1
- close:0
- file:a contains:?
- prompt>
-
- The -S flag here is passed "111000" which means "run client 1, then client 1,
- then 1 again, then 0, 0, 0, and then repeat (if need be)". The result in this
- case is client 1 reading file a before client 1 writes it.
-
- The '-A' flag gives exact control over which actions the clients take. Here is
- an example:
-
- prompt> ./afs.py -s 12 -S 011100 -A oa1:r1:c1,oa1:w1:c1
-
- Server c0 c1
- file:a contains:0
- open:a [fd:1]
- open:a [fd:1]
- write:1 value? -> 1
- close:1
- read:1 -> value?
- close:1
- file:a contains:?
- prompt>
-
- In this example, we have specified the following via -A "oa1:r1:c1,oa1:w1:c1".
- The list splits each clients actions by a comma; thus, client 0 should do
- whatever "oa1:r1:c1" indicates, whereas client 1 should do whatever the string
- "oa1:w1:c1" indicates. Parsing each command string is straightforward: "oa1"
- means open file 'a' and assign it file descriptor 1; "r1" or "w1" means read
- or write file descriptor 1; "c1" means close file descriptor 1.
-
- So what value will the read on client 0 return?
-
- We can also see the cache state, callbacks, and invalidations with a few extra
- flags (-d 7):
-
- prompt> ./afs.py -s 12 -S 011100 -A oa1:r1:c1,oa1:w1:c1 -c -d 7
-
- Server c0 c1
- file:a contains:0
- open:a [fd:1]
- getfile:a c:c0 [0]
- [a: 0 (v=1,d=0,r=1)]
-
- open:a [fd:1]
- getfile:a c:c1 [0]
- [a: 0 (v=1,d=0,r=1)]
-
- write:1 0 -> 1
- [a: 1 (v=1,d=1,r=1)]
-
- close:1
- putfile:a c:c1 [1]
- callback: c:c0 file:a
- invalidate a
- [a: 0 (v=0,d=0,r=1)]
- [a: 1 (v=1,d=0,r=0)]
-
- read:1 -> 0
- [a: 0 (v=0,d=0,r=1)]
-
- close:1
-
- file:a contains:1
- prompt>
-
- From this trace, we can see what happens when client 1 closes the (modified)
- file. At that point, c1 puts the file to the server. The server knows that c0
- has the file cached, and thus sends an invalidation to c0. However, c0 already
- has the file open; as a result, the cache keeps the old contents until the
- file is closed.
-
- You can see this in tracking the cache contents throughout the trace
- (available with the correct -d flag, in particular any value which sets the
- 3rd least significant bit to 1, such as -d 4, -d 5, -d 6, -d 7, etc.). When
- client 0 opens the file, you see the following cache state after the open is
- finished:
-
- [a: 0 (v=1,d=0,r=1)]
-
- This means file 'a' is in the cache with value '0', and has three bits of
- state associated with it: v (valid), d (dirty), and r (reference count). The
- valid bit tracks whether the contents are valid; it is now, because the cache
- has not been invalidated by a callback (yet). The dirty bit changes when the
- file has been written to and must be flushed back to the server when
- closed. Finally, the reference count tracks how many times the file has been
- opened (but not yet closed); this is used to ensure the client gets the old
- value of the file until it's been closed by all readers and then re-opened.
-
- The full list of options is available here:
-
- Options:
- -h, --help show this help message and exit
- -s SEED, --seed=SEED the random seed
- -C NUMCLIENTS, --clients=NUMCLIENTS
- number of clients
- -n NUMSTEPS, --numsteps=NUMSTEPS
- ops each client will do
- -f NUMFILES, --numfiles=NUMFILES
- number of files in server
- -r READRATIO, --readratio=READRATIO
- ratio of reads/writes
- -A ACTIONS, --actions=ACTIONS
- client actions exactly specified, e.g.,
- oa1:r1:c1,oa1:w1:c1 specifies two clients; each opens
- the file a, client 0 reads it whereas client 1 writes
- it, and then each closes it
- -S SCHEDULE, --schedule=SCHEDULE
- exact schedule to run; 01 alternates round robin
- between clients 0 and 1. Left unspecified leads to
- random scheduling
- -p, --printstats print extra stats
- -c, --compute compute answers for me
- -d DETAIL, --detail=DETAIL
- detail level when giving answers (1:server
- actions,2:invalidations,4:client cache,8:extra
- labels); OR together for multiple
-
- Read the AFS chapter, and answer the questions at the back, or just explore
- this simulator more on your own to increase your understanding of AFS.
-
|