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