This source file includes following definitions.
- initlog
- install_trans
- read_head
- write_head
- recover_from_log
- begin_op
- end_op
- write_log
- commit
- log_write
- sys_sync
1 #include "types.h"
2 #include "riscv.h"
3 #include "defs.h"
4 #include "param.h"
5 #include "spinlock.h"
6 #include "sleeplock.h"
7 #include "fs.h"
8 #include "buf.h"
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 struct logheader {
36 int n;
37 int block[LOGBLOCKS];
38 };
39
40 struct log {
41 struct spinlock lock;
42 int start;
43 int outstanding;
44 int committing;
45 int dev;
46 int ncommit;
47 struct logheader lh;
48 };
49 struct log log;
50
51 static void recover_from_log(void);
52 static void commit();
53
54 void
55 initlog(int dev, struct superblock *sb)
56 {
57 if (sizeof(struct logheader) >= BSIZE)
58 panic("initlog: too big logheader");
59
60 initlock(&log.lock, "log");
61 log.start = sb->logstart;
62 log.dev = dev;
63 recover_from_log();
64 }
65
66
67 static void
68 install_trans(int recovering)
69 {
70 int tail;
71
72 for (tail = 0; tail < log.lh.n; tail++) {
73 if (recovering) {
74 printk("recovering tail %d dst %d\n", tail, log.lh.block[tail]);
75 }
76 struct buf *lbuf = bread(log.dev, log.start + tail + 1);
77 struct buf *dbuf = bread(log.dev, log.lh.block[tail]);
78 memmove(dbuf->data, lbuf->data, BSIZE);
79 bwrite(dbuf);
80 if (recovering == 0)
81 bunpin(dbuf);
82 brelse(lbuf);
83 brelse(dbuf);
84 }
85 }
86
87
88 static void
89 read_head(void)
90 {
91 struct buf *buf = bread(log.dev, log.start);
92 struct logheader *lh = (struct logheader *)(buf->data);
93 int i;
94 log.lh.n = lh->n;
95 for (i = 0; i < log.lh.n; i++) {
96 log.lh.block[i] = lh->block[i];
97 }
98 brelse(buf);
99 }
100
101
102
103
104 static void
105 write_head(void)
106 {
107 struct buf *buf = bread(log.dev, log.start);
108 struct logheader *hb = (struct logheader *)(buf->data);
109 int i;
110 hb->n = log.lh.n;
111 for (i = 0; i < log.lh.n; i++) {
112 hb->block[i] = log.lh.block[i];
113 }
114 bwrite(buf);
115 brelse(buf);
116 }
117
118 static void
119 recover_from_log(void)
120 {
121 read_head();
122 install_trans(1);
123 log.lh.n = 0;
124 write_head();
125 }
126
127
128 void
129 begin_op(void)
130 {
131 acquire(&log.lock);
132 while (1) {
133 if (log.committing) {
134 sleep_prepare(&log);
135 release(&log.lock);
136 sleep();
137 acquire(&log.lock);
138 } else if (log.lh.n + (log.outstanding + 1) * MAXOPBLOCKS > LOGBLOCKS) {
139
140 sleep_prepare(&log);
141 release(&log.lock);
142 sleep();
143 acquire(&log.lock);
144 } else {
145 log.outstanding += 1;
146 release(&log.lock);
147 break;
148 }
149 }
150 }
151
152
153
154 void
155 end_op(void)
156 {
157 int do_commit = 0;
158
159 acquire(&log.lock);
160 log.outstanding -= 1;
161 if (log.committing)
162 panic("log.committing");
163 if (log.outstanding == 0) {
164 do_commit = 1;
165 log.committing = 1;
166 } else {
167
168
169
170 wakeup(&log);
171 }
172 release(&log.lock);
173
174 if (do_commit) {
175
176
177 commit();
178 acquire(&log.lock);
179 log.committing = 0;
180 log.ncommit += 1;
181 wakeup(&log);
182 release(&log.lock);
183 }
184 }
185
186
187 static void
188 write_log(void)
189 {
190 int tail;
191
192 for (tail = 0; tail < log.lh.n; tail++) {
193 struct buf *to = bread(log.dev, log.start + tail + 1);
194 struct buf *from = bread(log.dev, log.lh.block[tail]);
195 memmove(to->data, from->data, BSIZE);
196 bwrite(to);
197 brelse(from);
198 brelse(to);
199 }
200 }
201
202 static void
203 commit()
204 {
205 if (log.lh.n > 0) {
206 write_log();
207 write_head();
208 install_trans(0);
209 log.lh.n = 0;
210 write_head();
211 }
212 }
213
214
215
216
217
218
219
220
221
222
223 void
224 log_write(struct buf *b)
225 {
226 int i;
227
228 acquire(&log.lock);
229 if (log.lh.n >= LOGBLOCKS)
230 panic("too big a transaction");
231 if (log.outstanding < 1)
232 panic("log_write outside of trans");
233
234 for (i = 0; i < log.lh.n; i++) {
235 if (log.lh.block[i] == b->blockno)
236 break;
237 }
238 log.lh.block[i] = b->blockno;
239 if (i == log.lh.n) {
240 bpin(b);
241 log.lh.n++;
242 }
243 release(&log.lock);
244 }
245
246 uint64
247 sys_sync(void)
248 {
249 acquire(&log.lock);
250 if (log.committing || log.outstanding > 0) {
251 int n = log.ncommit + 1;
252 while (log.ncommit < n) {
253 sleep_prepare(&log);
254 release(&log.lock);
255 sleep();
256 acquire(&log.lock);
257 }
258 }
259 release(&log.lock);
260 return 0;
261 }