]>
Commit | Line | Data |
---|---|---|
cd748f27 | 1 | |
2 | /* | |
262a0e14 | 3 | * $Id$ |
cd748f27 | 4 | * |
5 | * DEBUG: section 79 Storage Manager UFS Interface | |
6 | * AUTHOR: Duane Wessels | |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
cd748f27 | 9 | * ---------------------------------------------------------- |
10 | * | |
2b6662ba | 11 | * Squid is the result of efforts by numerous individuals from |
12 | * the Internet community; see the CONTRIBUTORS file for full | |
13 | * details. Many organizations have provided support for Squid's | |
14 | * development; see the SPONSORS file for full details. Squid is | |
15 | * Copyrighted (C) 2001 by the Regents of the University of | |
16 | * California; see the COPYRIGHT file for full details. Squid | |
17 | * incorporates software developed and/or copyrighted by other | |
18 | * sources; see the CREDITS file for full details. | |
cd748f27 | 19 | * |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
26ac0430 | 24 | * |
cd748f27 | 25 | * This program is distributed in the hope that it will be useful, |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
26ac0430 | 29 | * |
cd748f27 | 30 | * You should have received a copy of the GNU General Public License |
31 | * along with this program; if not, write to the Free Software | |
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
33 | * | |
34 | */ | |
35 | ||
36 | #include "squid.h" | |
e6ccf245 | 37 | #include "Store.h" |
4d6d905e | 38 | #include "ufscommon.h" |
b9ae18aa | 39 | #include "Generic.h" |
40 | #include "DiskIO/DiskFile.h" | |
41 | #include "DiskIO/DiskIOStrategy.h" | |
42 | #include "DiskIO/ReadRequest.h" | |
43 | #include "DiskIO/WriteRequest.h" | |
cd748f27 | 44 | |
d3b3ab85 | 45 | #include "SwapDir.h" |
cd748f27 | 46 | |
d3b3ab85 | 47 | bool |
b9ae18aa | 48 | UFSStrategy::shedLoad() |
d3b3ab85 | 49 | { |
b9ae18aa | 50 | return io->shedLoad(); |
d3b3ab85 | 51 | } |
62e76326 | 52 | |
59b2d47f | 53 | int |
b9ae18aa | 54 | UFSStrategy::load() |
59b2d47f | 55 | { |
b9ae18aa | 56 | return io->load(); |
57 | } | |
58 | ||
59 | UFSStrategy::UFSStrategy (DiskIOStrategy *anIO) : io(anIO) | |
60 | {} | |
61 | ||
62 | UFSStrategy::~UFSStrategy () | |
63 | { | |
64 | delete io; | |
59b2d47f | 65 | } |
66 | ||
d3b3ab85 | 67 | StoreIOState::Pointer |
4fcc8876 | 68 | UFSStrategy::createState(SwapDir *SD, StoreEntry *e, StoreIOState::STIOCB * callback, void *callback_data) const |
d3b3ab85 | 69 | { |
59b2d47f | 70 | return new UFSStoreState (SD, e, callback, callback_data); |
d3b3ab85 | 71 | } |
72 | ||
62e76326 | 73 | DiskFile::Pointer |
b9ae18aa | 74 | UFSStrategy::newFile (char const *path) |
d3b3ab85 | 75 | { |
b9ae18aa | 76 | return io->newFile(path); |
d3b3ab85 | 77 | } |
cd748f27 | 78 | |
b9ae18aa | 79 | |
59b2d47f | 80 | void |
b9ae18aa | 81 | UFSStrategy::unlinkFile(char const *path) |
59b2d47f | 82 | { |
b9ae18aa | 83 | io->unlinkFile(path); |
59b2d47f | 84 | } |
85 | ||
86 | CBDATA_CLASS_INIT(UFSStoreState); | |
72711e31 | 87 | |
d3b3ab85 | 88 | void * |
59b2d47f | 89 | UFSStoreState::operator new (size_t) |
d3b3ab85 | 90 | { |
59b2d47f | 91 | CBDATA_INIT_TYPE(UFSStoreState); |
92 | return cbdataAlloc(UFSStoreState); | |
d3b3ab85 | 93 | } |
62e76326 | 94 | |
d3b3ab85 | 95 | void |
59b2d47f | 96 | UFSStoreState::operator delete (void *address) |
d3b3ab85 | 97 | { |
d3b3ab85 | 98 | cbdataFree(address); |
d3b3ab85 | 99 | } |
cd748f27 | 100 | |
cd748f27 | 101 | void |
59b2d47f | 102 | UFSStoreState::ioCompletedNotification() |
cd748f27 | 103 | { |
d3b3ab85 | 104 | if (opening) { |
62e76326 | 105 | opening = false; |
bf8fe701 | 106 | debugs(79, 3, "UFSStoreState::ioCompletedNotification: dirno " << |
107 | swap_dirn << ", fileno "<< std::setfill('0') << std::hex << | |
108 | std::setw(8) << swap_filen << " status "<< std::setfill(' ') << | |
109 | std::dec << theFile->error()); | |
110 | ||
59b2d47f | 111 | assert (FILE_MODE(mode) == O_RDONLY); |
112 | openDone(); | |
113 | ||
62e76326 | 114 | return; |
d3b3ab85 | 115 | } |
62e76326 | 116 | |
d3b3ab85 | 117 | if (creating) { |
62e76326 | 118 | creating = false; |
bf8fe701 | 119 | debugs(79, 3, "UFSStoreState::ioCompletedNotification: dirno " << |
120 | swap_dirn << ", fileno "<< std::setfill('0') << std::hex << | |
121 | std::setw(8) << swap_filen << " status "<< std::setfill(' ') << | |
122 | std::dec << theFile->error()); | |
123 | ||
59b2d47f | 124 | openDone(); |
125 | ||
62e76326 | 126 | return; |
d3b3ab85 | 127 | } |
62e76326 | 128 | |
59b2d47f | 129 | assert (!(closing ||opening)); |
bf8fe701 | 130 | debugs(79, 3, "diskd::ioCompleted: dirno " << swap_dirn << ", fileno "<< |
131 | std::setfill('0') << std::hex << std::setw(8) << swap_filen << | |
132 | " status "<< std::setfill(' ') << std::dec << theFile->error()); | |
133 | ||
59b2d47f | 134 | /* Ok, notification past open means an error has occured */ |
135 | assert (theFile->error()); | |
1e0d7905 | 136 | tryClosing(); |
d3b3ab85 | 137 | } |
cd748f27 | 138 | |
d3b3ab85 | 139 | void |
59b2d47f | 140 | UFSStoreState::openDone() |
d3b3ab85 | 141 | { |
1e0d7905 | 142 | if (closing) |
143 | debugs(0,0,HERE << "already closing in openDone()!?"); | |
144 | ||
59b2d47f | 145 | if (theFile->error()) { |
1e0d7905 | 146 | tryClosing(); |
59b2d47f | 147 | return; |
148 | } | |
149 | ||
150 | if (FILE_MODE(mode) == O_WRONLY) { | |
1e0d7905 | 151 | drainWriteQueue(); |
152 | ||
59b2d47f | 153 | } else if ((FILE_MODE(mode) == O_RDONLY) && !closing) { |
154 | if (kickReadQueue()) | |
155 | return; | |
156 | } | |
157 | ||
1e0d7905 | 158 | if (flags.try_closing) |
159 | tryClosing(); | |
59b2d47f | 160 | |
bf8fe701 | 161 | debugs(79, 3, "UFSStoreState::openDone: exiting"); |
d3b3ab85 | 162 | } |
163 | ||
164 | void | |
59b2d47f | 165 | UFSStoreState::closeCompleted() |
d3b3ab85 | 166 | { |
59b2d47f | 167 | assert (closing); |
bf8fe701 | 168 | debugs(79, 3, "UFSStoreState::closeCompleted: dirno " << swap_dirn << |
169 | ", fileno "<< std::setfill('0') << std::hex << std::setw(8) << | |
170 | swap_filen << " status "<< std::setfill(' ') << std::dec << | |
171 | theFile->error()); | |
62e76326 | 172 | |
1e0d7905 | 173 | if (theFile->error()) { |
174 | debugs(79,3,HERE<< "theFile->error() ret " << theFile->error()); | |
3e2cded3 | 175 | doCloseCallback(DISK_ERROR); |
1e0d7905 | 176 | } else { |
3e2cded3 | 177 | doCloseCallback(DISK_OK); |
1e0d7905 | 178 | } |
59b2d47f | 179 | |
180 | closing = false; | |
181 | } | |
182 | ||
1e0d7905 | 183 | /* |
184 | * DPW 2006-05-24 | |
185 | * This close function is called by the higher layer when it has finished | |
186 | * reading/writing everything, or otherwise wants to close the swap | |
187 | * file. In the case of writing and using aufs storage, close() might | |
188 | * be called before any/all data is written, and even before the open | |
189 | * callback occurs. Thus, we use our tryClosing() method, which knows | |
190 | * when it is safe to actually signal the lower layer for closing. | |
191 | */ | |
59b2d47f | 192 | void |
193 | UFSStoreState::close() | |
194 | { | |
bf8fe701 | 195 | debugs(79, 3, "UFSStoreState::close: dirno " << swap_dirn << ", fileno "<< |
196 | std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen); | |
1e0d7905 | 197 | tryClosing(); |
d3b3ab85 | 198 | } |
199 | ||
200 | void | |
201 | UFSStoreState::read_(char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) | |
202 | { | |
203 | assert(read.callback == NULL); | |
204 | assert(read.callback_data == NULL); | |
205 | assert(!reading); | |
206 | assert(!closing); | |
207 | assert (callback); | |
62e76326 | 208 | |
d3b3ab85 | 209 | if (!theFile->canRead()) { |
bf8fe701 | 210 | debugs(79, 3, "UFSStoreState::read_: queueing read because theFile can't read"); |
62e76326 | 211 | queueRead (buf, size, offset, callback, callback_data); |
212 | return; | |
cd748f27 | 213 | } |
62e76326 | 214 | |
d3b3ab85 | 215 | read.callback = callback; |
216 | read.callback_data = cbdataReference(callback_data); | |
bf8fe701 | 217 | debugs(79, 3, "UFSStoreState::read_: dirno " << swap_dirn << ", fileno "<< |
218 | std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen); | |
d3b3ab85 | 219 | offset_ = offset; |
220 | read_buf = buf; | |
221 | reading = true; | |
b9ae18aa | 222 | theFile->read(new ReadRequest(buf,offset,size)); |
d3b3ab85 | 223 | } |
62e76326 | 224 | |
cd748f27 | 225 | |
1e0d7905 | 226 | /* |
227 | * DPW 2006-05-24 | |
228 | * This, the public write interface, places the write request at the end | |
229 | * of the pending_writes queue to ensure correct ordering of writes. | |
230 | * We could optimize things a little if there are no other pending | |
231 | * writes and just do the write directly. But for now we'll keep the | |
232 | * code simpler and always go through the pending_writes queue. | |
233 | */ | |
cd748f27 | 234 | void |
528b2c61 | 235 | UFSStoreState::write(char const *buf, size_t size, off_t offset, FREE * free_func) |
d3b3ab85 | 236 | { |
bf8fe701 | 237 | debugs(79, 3, "UFSStoreState::write: dirn " << swap_dirn << ", fileno "<< |
238 | std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen); | |
62e76326 | 239 | |
1e0d7905 | 240 | if (theFile->error()) { |
241 | debugs(79,1,HERE << "avoid write on theFile with error"); | |
242 | debugs(79,1,HERE << "calling free_func for " << (void*) buf); | |
243 | free_func((void*)buf); | |
244 | return; | |
245 | } | |
246 | ||
247 | queueWrite(buf, size, offset, free_func); | |
248 | drainWriteQueue(); | |
249 | } | |
250 | ||
251 | ||
252 | /* | |
253 | * DPW 2006-05-24 | |
254 | * This, the private write method, calls the lower level write for the | |
255 | * first write request in the pending_writes queue. doWrite() is only | |
256 | * called by drainWriteQueue(). | |
257 | */ | |
258 | void | |
259 | UFSStoreState::doWrite() | |
260 | { | |
261 | debugs(79, 3, HERE << this << " UFSStoreState::doWrite"); | |
262 | ||
263 | assert(theFile->canWrite()); | |
264 | ||
265 | _queued_write *q = (_queued_write *)linklistShift(&pending_writes); | |
266 | ||
267 | if (q == NULL) { | |
268 | debugs(79, 3, HERE << this << " UFSStoreState::doWrite queue is empty"); | |
269 | return; | |
270 | } | |
271 | ||
272 | if (theFile->error()) { | |
273 | debugs(79,1,HERE << "avoid write on theFile with error"); | |
274 | debugs(79,3,HERE << "calling free_func for " << (void*) q->buf); | |
275 | /* | |
276 | * DPW 2006-05-24 | |
277 | * Note "free_func" is memNodeWriteComplete(), which doesn't | |
278 | * really free the memory. Instead it clears the node's | |
279 | * write_pending flag. | |
280 | */ | |
281 | q->free_func((void*)q->buf); | |
9db2e213 | 282 | delete q; |
62e76326 | 283 | return; |
d3b3ab85 | 284 | } |
62e76326 | 285 | |
1e0d7905 | 286 | /* |
287 | * DPW 2006-05-24 | |
288 | * UFSStoreState has a 'writing' flag that we used to set here, | |
289 | * but it wasn't really used anywhere. In fact, some lower | |
290 | * layers such as DISKD allow multiple outstanding writes, which | |
291 | * makes the boolean writing flag meaningless. We would need | |
292 | * a counter to keep track of writes going out and write callbacks | |
293 | * coming in. For now let's just not use the writing flag at | |
294 | * all. | |
295 | */ | |
296 | debugs(79, 3, HERE << this << " calling theFile->write(" << q->size << ")"); | |
297 | ||
298 | theFile->write(new WriteRequest(q->buf, q->offset, q->size, q->free_func)); | |
9db2e213 | 299 | delete q; |
d3b3ab85 | 300 | } |
301 | ||
302 | void | |
b9ae18aa | 303 | UFSStoreState::readCompleted(const char *buf, int len, int errflag, RefCount<ReadRequest> result) |
d3b3ab85 | 304 | { |
b9ae18aa | 305 | assert (result.getRaw()); |
d3b3ab85 | 306 | reading = false; |
bf8fe701 | 307 | debugs(79, 3, "UFSStoreState::readCompleted: dirno " << swap_dirn << |
308 | ", fileno "<< std::setfill('0') << std::hex << std::setw(8) << | |
309 | swap_filen << " len "<< std::setfill(' ') << std::dec << len); | |
62e76326 | 310 | |
d3b3ab85 | 311 | if (len > 0) |
62e76326 | 312 | offset_ += len; |
313 | ||
d3b3ab85 | 314 | STRCB *callback = read.callback; |
62e76326 | 315 | |
d3b3ab85 | 316 | assert(callback); |
62e76326 | 317 | |
d3b3ab85 | 318 | read.callback = NULL; |
62e76326 | 319 | |
d3b3ab85 | 320 | void *cbdata; |
62e76326 | 321 | |
59b2d47f | 322 | /* A note: |
323 | * diskd IO queues closes via the diskd queue. So close callbacks | |
324 | * occur strictly after reads and writes. | |
325 | * ufs doesn't queue, it simply completes, so close callbacks occur | |
326 | * strictly after reads and writes. | |
327 | * aufs performs closes syncronously, so close events must be managed | |
328 | * to force strict ordering. | |
329 | * The below does this: | |
1e0d7905 | 330 | * closing is set when theFile->close() has been called, and close only triggers |
59b2d47f | 331 | * when no io's are pending. |
332 | * writeCompleted likewise. | |
333 | */ | |
d3b3ab85 | 334 | if (!closing && cbdataReferenceValidDone(read.callback_data, &cbdata)) { |
62e76326 | 335 | if (len > 0 && read_buf != buf) |
336 | memcpy(read_buf, buf, len); | |
337 | ||
e5de8b13 | 338 | callback(cbdata, read_buf, len, this); |
1e0d7905 | 339 | } |
340 | ||
8bc0c94b | 341 | if (flags.try_closing || (theFile != NULL && theFile->error()) ) |
1e0d7905 | 342 | tryClosing(); |
d3b3ab85 | 343 | } |
344 | ||
345 | void | |
b9ae18aa | 346 | UFSStoreState::writeCompleted(int errflag, size_t len, RefCount<WriteRequest> writeRequest) |
d3b3ab85 | 347 | { |
26ac0430 AJ |
348 | debugs(79, 3, "UFSStoreState::writeCompleted: dirno " << swap_dirn << ", fileno " << |
349 | std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen << | |
350 | ", len " << len ); | |
1e0d7905 | 351 | /* |
352 | * DPW 2006-05-24 | |
353 | * See doWrites() for why we don't update UFSStoreState::writing | |
354 | * here anymore. | |
355 | */ | |
62e76326 | 356 | |
59b2d47f | 357 | offset_ += len; |
358 | ||
359 | if (theFile->error()) { | |
1e0d7905 | 360 | debugs(79,2,HERE << "UFSStoreState::writeCompleted" << |
361 | " detected an error, will try to close"); | |
362 | tryClosing(); | |
59b2d47f | 363 | } |
bdf5b250 | 364 | |
365 | /* | |
366 | * DPW 2007-04-12 | |
367 | * I'm seeing disk files remain open under vanilla UFS storage | |
368 | * because storeClose() gets called before the last write is | |
369 | * complete. I guess we have to check for the try_closing | |
370 | * flag here. | |
371 | */ | |
372 | if (flags.try_closing) { | |
26ac0430 AJ |
373 | debugs(72, 2, HERE << "UFSStoreState::writeCompleted" << |
374 | " flags.try_closing is set"); | |
375 | tryClosing(); | |
bdf5b250 | 376 | } |
d3b3ab85 | 377 | } |
378 | ||
379 | void | |
3e2cded3 | 380 | UFSStoreState::doCloseCallback(int errflag) |
cd748f27 | 381 | { |
bf8fe701 | 382 | debugs(79, 3, "storeUfsIOCallback: errflag=" << errflag); |
1e0d7905 | 383 | /* |
384 | * DPW 2006-05-24 | |
385 | * When we signal the higher layer with this callback, it might unlock | |
386 | * the StoreEntry and its associated data. We must "free" any queued | |
387 | * I/Os (especially writes) now, otherwise the StoreEntry's mem_node's | |
388 | * will have their write_pending flag set, and we'll get an assertion. | |
389 | */ | |
390 | freePending(); | |
59b2d47f | 391 | STIOCB *theCallback = callback; |
d3b3ab85 | 392 | callback = NULL; |
d3b3ab85 | 393 | |
59b2d47f | 394 | void *cbdata; |
d3b3ab85 | 395 | |
59b2d47f | 396 | if (cbdataReferenceValidDone(callback_data, &cbdata) && theCallback) |
e5de8b13 | 397 | theCallback(cbdata, errflag, this); |
7fbb6b8f | 398 | |
1e0d7905 | 399 | /* |
400 | * We are finished with theFile since the lower layer signalled | |
401 | * us that the file has been closed. This must be the last line, | |
402 | * as theFile may be the only object holding us in memory. | |
7fbb6b8f | 403 | */ |
1e0d7905 | 404 | theFile = NULL; // refcounted |
59b2d47f | 405 | } |
d3b3ab85 | 406 | |
407 | /* ============= THE REAL UFS CODE ================ */ | |
408 | ||
59b2d47f | 409 | UFSStoreState::UFSStoreState(SwapDir * SD, StoreEntry * anEntry, STIOCB * callback_, void *callback_data_) : opening (false), creating (false), closing (false), reading(false), writing(false), pending_reads(NULL), pending_writes (NULL) |
410 | { | |
411 | swap_filen = anEntry->swap_filen; | |
412 | swap_dirn = SD->index; | |
413 | mode = O_BINARY; | |
414 | callback = callback_; | |
415 | callback_data = cbdataReference(callback_data_); | |
416 | e = anEntry; | |
1e0d7905 | 417 | flags.write_draining = false; |
418 | flags.try_closing = false; | |
59b2d47f | 419 | } |
62e76326 | 420 | |
d3b3ab85 | 421 | UFSStoreState::~UFSStoreState() |
1e0d7905 | 422 | { |
423 | assert(pending_reads == NULL); | |
424 | assert(pending_writes == NULL); | |
425 | } | |
426 | ||
427 | void | |
428 | UFSStoreState::freePending() | |
d3b3ab85 | 429 | { |
430 | _queued_read *qr; | |
62e76326 | 431 | |
d3b3ab85 | 432 | while ((qr = (_queued_read *)linklistShift(&pending_reads))) { |
62e76326 | 433 | cbdataReferenceDone(qr->callback_data); |
434 | delete qr; | |
d3b3ab85 | 435 | } |
436 | ||
1e0d7905 | 437 | debugs(79,3,HERE << "UFSStoreState::freePending: freed pending reads"); |
438 | ||
5aeabf95 | 439 | _queued_write *qw; |
62e76326 | 440 | |
5aeabf95 | 441 | while ((qw = (_queued_write *)linklistShift(&pending_writes))) { |
62e76326 | 442 | if (qw->free_func) |
443 | qw->free_func(const_cast<char *>(qw->buf)); | |
444 | delete qw; | |
d3b3ab85 | 445 | } |
1e0d7905 | 446 | |
447 | debugs(79,3,HERE << "UFSStoreState::freePending: freed pending writes"); | |
d3b3ab85 | 448 | } |
449 | ||
450 | bool | |
451 | UFSStoreState::kickReadQueue() | |
452 | { | |
453 | _queued_read *q = (_queued_read *)linklistShift(&pending_reads); | |
62e76326 | 454 | |
d3b3ab85 | 455 | if (NULL == q) |
62e76326 | 456 | return false; |
457 | ||
4a7a3d56 | 458 | debugs(79, 3, "UFSStoreState::kickReadQueue: reading queued request of " << q->size << " bytes"); |
62e76326 | 459 | |
d3b3ab85 | 460 | void *cbdata; |
62e76326 | 461 | |
d3b3ab85 | 462 | if (cbdataReferenceValidDone(q->callback_data, &cbdata)) |
62e76326 | 463 | read_(q->buf, q->size, q->offset, q->callback, cbdata); |
464 | ||
d3b3ab85 | 465 | delete q; |
62e76326 | 466 | |
d3b3ab85 | 467 | return true; |
468 | } | |
469 | ||
d3b3ab85 | 470 | void |
471 | UFSStoreState::queueRead(char *buf, size_t size, off_t offset, STRCB *callback, void *callback_data) | |
472 | { | |
bf8fe701 | 473 | debugs(79, 3, "UFSStoreState::queueRead: queueing read"); |
d3b3ab85 | 474 | assert(opening); |
475 | assert (pending_reads == NULL); | |
476 | _queued_read *q = new _queued_read; | |
477 | q->buf = buf; | |
478 | q->size = size; | |
479 | q->offset = offset; | |
480 | q->callback = callback; | |
481 | q->callback_data = cbdataReference(callback_data); | |
482 | linklistPush(&pending_reads, q); | |
483 | } | |
484 | ||
1e0d7905 | 485 | /* |
486 | * DPW 2006-05-24 | |
487 | * drainWriteQueue() is a loop around doWrite(). | |
488 | */ | |
489 | void | |
490 | UFSStoreState::drainWriteQueue() | |
cd748f27 | 491 | { |
2eaddcc2 | 492 | /* |
493 | * DPW 2007-04-12 | |
494 | * We might find that flags.write_draining is already set | |
495 | * because schemes like diskd can process I/O acks | |
496 | * before sending another I/O request. e.g. the following | |
497 | * sequence of events: open request -> write request -> | |
498 | * drainWriteQueue() -> queue full -> callbacks -> openDone() -> | |
499 | * drainWriteQueue(). | |
500 | */ | |
501 | if (flags.write_draining) | |
26ac0430 | 502 | return; |
62e76326 | 503 | |
1e0d7905 | 504 | if (!theFile->canWrite()) |
505 | return; | |
62e76326 | 506 | |
1e0d7905 | 507 | flags.write_draining = true; |
62e76326 | 508 | |
1e0d7905 | 509 | while (pending_writes != NULL) { |
510 | doWrite(); | |
511 | } | |
512 | ||
513 | flags.write_draining = false; | |
514 | ||
515 | if (flags.try_closing) | |
516 | tryClosing(); | |
517 | } | |
518 | ||
519 | /* | |
520 | * DPW 2006-05-24 | |
521 | * This blows. DiskThreadsDiskFile::close() won't actually do the close | |
522 | * if ioInProgress() is true. So we have to check it here. Maybe someday | |
523 | * DiskThreadsDiskFile::close() will be modified to have a return value, | |
524 | * or will remember to do the close for us. | |
525 | */ | |
526 | void | |
527 | UFSStoreState::tryClosing() | |
528 | { | |
529 | debugs(79,3,HERE << this << " tryClosing()" << | |
530 | " closing = " << closing << | |
531 | " flags.try_closing = " << flags.try_closing << | |
532 | " ioInProgress = " << theFile->ioInProgress()); | |
533 | ||
534 | if (theFile->ioInProgress()) { | |
26ac0430 AJ |
535 | debugs(79, 3, HERE << this << |
536 | " won't close since ioInProgress is true, bailing"); | |
1e0d7905 | 537 | flags.try_closing = true; |
538 | return; | |
539 | } | |
540 | ||
541 | closing = true; | |
542 | flags.try_closing = false; | |
543 | theFile->close(); | |
d3b3ab85 | 544 | } |
545 | ||
546 | void | |
528b2c61 | 547 | UFSStoreState::queueWrite(char const *buf, size_t size, off_t offset, FREE * free_func) |
d3b3ab85 | 548 | { |
1e0d7905 | 549 | debugs(79, 3, HERE << this << " UFSStoreState::queueWrite: queueing write of size " << size); |
62e76326 | 550 | |
5aeabf95 | 551 | _queued_write *q; |
d3b3ab85 | 552 | q = new _queued_write; |
553 | q->buf = buf; | |
554 | q->size = size; | |
555 | q->offset = offset; | |
556 | q->free_func = free_func; | |
557 | linklistPush(&pending_writes, q); | |
558 | } | |
559 | ||
560 | StoreIOState::Pointer | |
4fcc8876 | 561 | UFSStrategy::open(SwapDir * SD, StoreEntry * e, StoreIOState::STFNCB * file_callback, |
562 | StoreIOState::STIOCB * callback, void *callback_data) | |
d3b3ab85 | 563 | { |
59b2d47f | 564 | assert (((UFSSwapDir *)SD)->IO == this); |
bf8fe701 | 565 | debugs(79, 3, "UFSStrategy::open: fileno "<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << e->swap_filen); |
62e76326 | 566 | |
d3b3ab85 | 567 | /* to consider: make createstate a private UFSStrategy call */ |
568 | StoreIOState::Pointer sio = createState (SD, e, callback, callback_data); | |
62e76326 | 569 | |
d3b3ab85 | 570 | sio->mode |= O_RDONLY; |
62e76326 | 571 | |
d3b3ab85 | 572 | UFSStoreState *state = dynamic_cast <UFSStoreState *>(sio.getRaw()); |
62e76326 | 573 | |
d3b3ab85 | 574 | assert (state); |
62e76326 | 575 | |
d3b3ab85 | 576 | char *path = ((UFSSwapDir *)SD)->fullPath(e->swap_filen, NULL); |
577 | ||
578 | DiskFile::Pointer myFile = newFile (path); | |
62e76326 | 579 | |
b9ae18aa | 580 | if (myFile.getRaw() == NULL) |
581 | return NULL; | |
582 | ||
d3b3ab85 | 583 | state->theFile = myFile; |
62e76326 | 584 | |
d3b3ab85 | 585 | state->opening = true; |
62e76326 | 586 | |
d3b3ab85 | 587 | myFile->open (sio->mode, 0644, state); |
62e76326 | 588 | |
d3b3ab85 | 589 | if (myFile->error()) |
62e76326 | 590 | return NULL; |
591 | ||
d3b3ab85 | 592 | return sio; |
593 | } | |
594 | ||
595 | StoreIOState::Pointer | |
4fcc8876 | 596 | UFSStrategy::create(SwapDir * SD, StoreEntry * e, StoreIOState::STFNCB * file_callback, |
597 | StoreIOState::STIOCB * callback, void *callback_data) | |
d3b3ab85 | 598 | { |
59b2d47f | 599 | assert (((UFSSwapDir *)SD)->IO == this); |
d3b3ab85 | 600 | /* Allocate a number */ |
601 | sfileno filn = ((UFSSwapDir *)SD)->mapBitAllocate(); | |
bf8fe701 | 602 | debugs(79, 3, "UFSStrategy::create: fileno "<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << filn); |
62e76326 | 603 | |
d3b3ab85 | 604 | /* Shouldn't we handle a 'bitmap full' error here? */ |
605 | ||
606 | StoreIOState::Pointer sio = createState (SD, e, callback, callback_data); | |
607 | ||
608 | sio->mode |= O_WRONLY | O_CREAT | O_TRUNC; | |
62e76326 | 609 | |
d3b3ab85 | 610 | sio->swap_filen = filn; |
611 | ||
612 | UFSStoreState *state = dynamic_cast <UFSStoreState *>(sio.getRaw()); | |
62e76326 | 613 | |
d3b3ab85 | 614 | assert (state); |
62e76326 | 615 | |
d3b3ab85 | 616 | char *path = ((UFSSwapDir *)SD)->fullPath(filn, NULL); |
62e76326 | 617 | |
d3b3ab85 | 618 | DiskFile::Pointer myFile = newFile (path); |
62e76326 | 619 | |
b9ae18aa | 620 | if (myFile.getRaw() == NULL) { |
621 | ((UFSSwapDir *)SD)->mapBitReset (filn); | |
622 | return NULL; | |
623 | } | |
624 | ||
d3b3ab85 | 625 | state->theFile = myFile; |
62e76326 | 626 | |
d3b3ab85 | 627 | state->creating = true; |
62e76326 | 628 | |
d3b3ab85 | 629 | myFile->create (state->mode, 0644, state); |
62e76326 | 630 | |
d3b3ab85 | 631 | if (myFile->error()) { |
62e76326 | 632 | ((UFSSwapDir *)SD)->mapBitReset (filn); |
633 | return NULL; | |
d3b3ab85 | 634 | } |
62e76326 | 635 | |
d3b3ab85 | 636 | /* now insert into the replacement policy */ |
637 | ((UFSSwapDir *)SD)->replacementAdd(e); | |
62e76326 | 638 | |
d3b3ab85 | 639 | return sio; |
cd748f27 | 640 | } |
59b2d47f | 641 | |
b9ae18aa | 642 | int |
643 | UFSStrategy::callback() | |
59b2d47f | 644 | { |
b9ae18aa | 645 | return io->callback(); |
59b2d47f | 646 | } |
647 | ||
648 | void | |
b9ae18aa | 649 | UFSStrategy::init() |
650 | { | |
651 | io->init(); | |
652 | } | |
59b2d47f | 653 | |
654 | void | |
b9ae18aa | 655 | UFSStrategy::sync() |
656 | { | |
657 | io->sync(); | |
658 | } | |
59b2d47f | 659 | |
b9ae18aa | 660 | void |
661 | UFSStrategy::statfs(StoreEntry & sentry)const | |
59b2d47f | 662 | { |
b9ae18aa | 663 | io->statfs(sentry); |
59b2d47f | 664 | } |
665 |