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
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 struct logheader lh;
47 };
48 struct log log;
49
50 static void recover_from_log(void);
51 static void commit();
52
53 void
54 initlog(int dev, struct superblock *sb)
55 {
56 if (sizeof(struct logheader) >= BSIZE)
57 panic("initlog: too big logheader");
58
59 initlock(&log.lock, "log");
60 log.start = sb->logstart;
61 log.dev = dev;
62 recover_from_log();
63 }
64
65
66 static void
67 install_trans(int recovering)
68 {
69 int tail;
70
71 for (tail = 0; tail < log.lh.n; tail++) {
72 if(recovering) {
73 printf("recovering tail %d dst %d\n", tail, log.lh.block[tail]);
74 }
75 struct buf *lbuf = bread(log.dev, log.start+tail+1);
76 struct buf *dbuf = bread(log.dev, log.lh.block[tail]);
77 memmove(dbuf->data, lbuf->data, BSIZE);
78 bwrite(dbuf);
79 if(recovering == 0)
80 bunpin(dbuf);
81 brelse(lbuf);
82 brelse(dbuf);
83 }
84 }
85
86
87 static void
88 read_head(void)
89 {
90 struct buf *buf = bread(log.dev, log.start);
91 struct logheader *lh = (struct logheader *) (buf->data);
92 int i;
93 log.lh.n = lh->n;
94 for (i = 0; i < log.lh.n; i++) {
95 log.lh.block[i] = lh->block[i];
96 }
97 brelse(buf);
98 }
99
100
101
102
103 static void
104 write_head(void)
105 {
106 struct buf *buf = bread(log.dev, log.start);
107 struct logheader *hb = (struct logheader *) (buf->data);
108 int i;
109 hb->n = log.lh.n;
110 for (i = 0; i < log.lh.n; i++) {
111 hb->block[i] = log.lh.block[i];
112 }
113 bwrite(buf);
114 brelse(buf);
115 }
116
117 static void
118 recover_from_log(void)
119 {
120 read_head();
121 install_trans(1);
122 log.lh.n = 0;
123 write_head();
124 }
125
126
127 void
128 begin_op(void)
129 {
130 acquire(&log.lock);
131 while(1){
132 if(log.committing){
133 sleep(&log, &log.lock);
134 } else if(log.lh.n + (log.outstanding+1)*MAXOPBLOCKS > LOGBLOCKS){
135
136 sleep(&log, &log.lock);
137 } else {
138 log.outstanding += 1;
139 release(&log.lock);
140 break;
141 }
142 }
143 }
144
145
146
147 void
148 end_op(void)
149 {
150 int do_commit = 0;
151
152 acquire(&log.lock);
153 log.outstanding -= 1;
154 if(log.committing)
155 panic("log.committing");
156 if(log.outstanding == 0){
157 do_commit = 1;
158 log.committing = 1;
159 } else {
160
161
162
163 wakeup(&log);
164 }
165 release(&log.lock);
166
167 if(do_commit){
168
169
170 commit();
171 acquire(&log.lock);
172 log.committing = 0;
173 wakeup(&log);
174 release(&log.lock);
175 }
176 }
177
178
179 static void
180 write_log(void)
181 {
182 int tail;
183
184 for (tail = 0; tail < log.lh.n; tail++) {
185 struct buf *to = bread(log.dev, log.start+tail+1);
186 struct buf *from = bread(log.dev, log.lh.block[tail]);
187 memmove(to->data, from->data, BSIZE);
188 bwrite(to);
189 brelse(from);
190 brelse(to);
191 }
192 }
193
194 static void
195 commit()
196 {
197 if (log.lh.n > 0) {
198 write_log();
199 write_head();
200 install_trans(0);
201 log.lh.n = 0;
202 write_head();
203 }
204 }
205
206
207
208
209
210
211
212
213
214
215 void
216 log_write(struct buf *b)
217 {
218 int i;
219
220 acquire(&log.lock);
221 if (log.lh.n >= LOGBLOCKS)
222 panic("too big a transaction");
223 if (log.outstanding < 1)
224 panic("log_write outside of trans");
225
226 for (i = 0; i < log.lh.n; i++) {
227 if (log.lh.block[i] == b->blockno)
228 break;
229 }
230 log.lh.block[i] = b->blockno;
231 if (i == log.lh.n) {
232 bpin(b);
233 log.lh.n++;
234 }
235 release(&log.lock);
236 }
237