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