《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
10 KiB

  1. This program, afs.py, allows you to experiment with the cache consistency
  2. behavior of the Andrew File System (AFS). The program generates random client
  3. traces (of file opens, reads, writes, and closes), enabling the user to see if
  4. they can predict what values end up in various files.
  5. Here is an example run:
  6. prompt> ./afs.py -C 2 -n 1 -s 12
  7. Server c0 c1
  8. file:a contains:0
  9. open:a [fd:0]
  10. write:0 value? -> 1
  11. close:0
  12. open:a [fd:0]
  13. read:0 -> value?
  14. close:0
  15. file:a contains:?
  16. prompt>
  17. The trace is fairly simple to read. On the left is the server, and each column
  18. shows actions being taken on each of two clients (use -C <clients> to specify
  19. a different number). Each client generates one random action (-n 1), which is
  20. either the open/read/close of a file or the open/write/close of a file. The
  21. contents of a file, for simplicity, is always just a single number.
  22. To generate different traces, use '-s' (for a random seed), as always. Here we
  23. set it to 12 to get this specific trace.
  24. In the trace, the server shows the initial contents of all the files in the
  25. system:
  26. file:a contains:0
  27. As you can see in this trace, there is just one file (a) and it contains the
  28. value 0.
  29. Time increases downwards, and what is next is client 0 (c0) opening the file
  30. 'a' (which returns a file descriptor, 0 in this case), writing to that
  31. descriptor, and then closing the file.
  32. Immediately you see the first question posed to you:
  33. write:0 value? -> 1
  34. When writing to descriptor 0, you are overwriting an existing value with the
  35. new value of 1. What was that old value? (pretty easy in this case: 0).
  36. Then client 1 begins doing some work (c1). It opens the file, reads it, and
  37. closes it. Again, we have a question to answer:
  38. read:0 -> value?
  39. When reading from this file, what value should client 1 see? Again, given AFS
  40. consistency, the answer is straightforward: 1 (the value placed in the file
  41. when c0 closed the file and updated the server).
  42. The final question in the trace is the final value of the file on the server:
  43. file:a contains:?
  44. Again, the answer here is easy: 1 (as generated by c0).
  45. To see if you have answered these questions correctly, run with the '-c' flag
  46. (or '--compute'), as follows:
  47. prompt> ./afs.py -C 2 -n 1 -s 12 -c
  48. Server c0 c1
  49. file:a contains:0
  50. open:a [fd:0]
  51. write:0 0 -> 1
  52. close:0
  53. open:a [fd:0]
  54. read:0 -> 1
  55. close:0
  56. file:a contains:1
  57. prompt>
  58. From this trace, you can see that all the question marks have been filled in
  59. with answers.
  60. More detail is available on what has happened too, with the '-d' ('--detail')
  61. flag. Here is an example that shows when each client issued a get or put of a
  62. file to the server:
  63. prompt> ./afs.py -C 2 -n 1 -s 12 -c -d 1
  64. Server c0 c1
  65. file:a contains:0
  66. open:a [fd:0]
  67. getfile:a c:c0 [0]
  68. write:0 0 -> 1
  69. close:0
  70. putfile:a c:c0 [1]
  71. open:a [fd:0]
  72. getfile:a c:c1 [1]
  73. read:0 -> 1
  74. close:0
  75. file:a contains:1
  76. prompt>
  77. You can show more with higher levels of detail, including cache invalidations,
  78. the exact client cache state after each step, and extra diagnostic
  79. information. We'll show these in one more example below.
  80. Random client actions are useful to generate new problems and try to solve
  81. them; however, in some cases it is useful to control exactly what each client
  82. does in order to see specific AFS behaviors. To do this, you can use the '-A'
  83. and '-S' flags (either together or in tandem).
  84. The '-S' flag lets you control the exact schedule of client actions. Assume our
  85. example above. Let's say we wish to run client 1 in entirety first; to achieve
  86. this end, we simply run the following:
  87. prompt> ./afs.py -C 2 -n 1 -s 12 -S 111000
  88. Server c0 c1
  89. file:a contains:0
  90. open:a [fd:0]
  91. read:0 -> value?
  92. close:0
  93. open:a [fd:0]
  94. write:0 value? -> 1
  95. close:0
  96. file:a contains:?
  97. prompt>
  98. The -S flag here is passed "111000" which means "run client 1, then client 1,
  99. then 1 again, then 0, 0, 0, and then repeat (if need be)". The result in this
  100. case is client 1 reading file a before client 1 writes it.
  101. The '-A' flag gives exact control over which actions the clients take. Here is
  102. an example:
  103. prompt> ./afs.py -s 12 -S 011100 -A oa1:r1:c1,oa1:w1:c1
  104. Server c0 c1
  105. file:a contains:0
  106. open:a [fd:1]
  107. open:a [fd:1]
  108. write:1 value? -> 1
  109. close:1
  110. read:1 -> value?
  111. close:1
  112. file:a contains:?
  113. prompt>
  114. In this example, we have specified the following via -A "oa1:r1:c1,oa1:w1:c1".
  115. The list splits each clients actions by a comma; thus, client 0 should do
  116. whatever "oa1:r1:c1" indicates, whereas client 1 should do whatever the string
  117. "oa1:w1:c1" indicates. Parsing each command string is straightforward: "oa1"
  118. means open file 'a' and assign it file descriptor 1; "r1" or "w1" means read
  119. or write file descriptor 1; "c1" means close file descriptor 1.
  120. So what value will the read on client 0 return?
  121. We can also see the cache state, callbacks, and invalidations with a few extra
  122. flags (-d 7):
  123. prompt> ./afs.py -s 12 -S 011100 -A oa1:r1:c1,oa1:w1:c1 -c -d 7
  124. Server c0 c1
  125. file:a contains:0
  126. open:a [fd:1]
  127. getfile:a c:c0 [0]
  128. [a: 0 (v=1,d=0,r=1)]
  129. open:a [fd:1]
  130. getfile:a c:c1 [0]
  131. [a: 0 (v=1,d=0,r=1)]
  132. write:1 0 -> 1
  133. [a: 1 (v=1,d=1,r=1)]
  134. close:1
  135. putfile:a c:c1 [1]
  136. callback: c:c0 file:a
  137. invalidate a
  138. [a: 0 (v=0,d=0,r=1)]
  139. [a: 1 (v=1,d=0,r=0)]
  140. read:1 -> 0
  141. [a: 0 (v=0,d=0,r=1)]
  142. close:1
  143. file:a contains:1
  144. prompt>
  145. From this trace, we can see what happens when client 1 closes the (modified)
  146. file. At that point, c1 puts the file to the server. The server knows that c0
  147. has the file cached, and thus sends an invalidation to c0. However, c0 already
  148. has the file open; as a result, the cache keeps the old contents until the
  149. file is closed.
  150. You can see this in tracking the cache contents throughout the trace
  151. (available with the correct -d flag, in particular any value which sets the
  152. 3rd least significant bit to 1, such as -d 4, -d 5, -d 6, -d 7, etc.). When
  153. client 0 opens the file, you see the following cache state after the open is
  154. finished:
  155. [a: 0 (v=1,d=0,r=1)]
  156. This means file 'a' is in the cache with value '0', and has three bits of
  157. state associated with it: v (valid), d (dirty), and r (reference count). The
  158. valid bit tracks whether the contents are valid; it is now, because the cache
  159. has not been invalidated by a callback (yet). The dirty bit changes when the
  160. file has been written to and must be flushed back to the server when
  161. closed. Finally, the reference count tracks how many times the file has been
  162. opened (but not yet closed); this is used to ensure the client gets the old
  163. value of the file until it's been closed by all readers and then re-opened.
  164. The full list of options is available here:
  165. Options:
  166. -h, --help show this help message and exit
  167. -s SEED, --seed=SEED the random seed
  168. -C NUMCLIENTS, --clients=NUMCLIENTS
  169. number of clients
  170. -n NUMSTEPS, --numsteps=NUMSTEPS
  171. ops each client will do
  172. -f NUMFILES, --numfiles=NUMFILES
  173. number of files in server
  174. -r READRATIO, --readratio=READRATIO
  175. ratio of reads/writes
  176. -A ACTIONS, --actions=ACTIONS
  177. client actions exactly specified, e.g.,
  178. oa1:r1:c1,oa1:w1:c1 specifies two clients; each opens
  179. the file a, client 0 reads it whereas client 1 writes
  180. it, and then each closes it
  181. -S SCHEDULE, --schedule=SCHEDULE
  182. exact schedule to run; 01 alternates round robin
  183. between clients 0 and 1. Left unspecified leads to
  184. random scheduling
  185. -p, --printstats print extra stats
  186. -c, --compute compute answers for me
  187. -d DETAIL, --detail=DETAIL
  188. detail level when giving answers (1:server
  189. actions,2:invalidations,4:client cache,8:extra
  190. labels); OR together for multiple
  191. Read the AFS chapter, and answer the questions at the back, or just explore
  192. this simulator more on your own to increase your understanding of AFS.