]> git.ipfire.org Git - thirdparty/squid.git/blob - src/DiskIO/DiskThreads/DiskThreadsDiskFile.cc
Enable source-formatting tools to collapse multiple whitelines in the source to one.
[thirdparty/squid.git] / src / DiskIO / DiskThreads / DiskThreadsDiskFile.cc
1 /*
2 * $Id$
3 *
4 * DEBUG: section 79 Disk IO Routines
5 * AUTHOR: Robert Collins
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
34 */
35
36
37 #include "squid.h"
38 #include "DiskThreadsDiskFile.h"
39 #include "DiskIO/IORequestor.h"
40 #include "DiskIO/ReadRequest.h"
41 #include "DiskIO/WriteRequest.h"
42 #include "Generic.h"
43 #include "globals.h"
44 #include "StatCounters.h"
45 #include "Store.h"
46 #include "protos.h"
47
48 #if HAVE_ERRNO_H
49 #include <errno.h>
50 #endif
51
52 /* === PUBLIC =========================================================== */
53
54 CBDATA_CLASS_INIT(DiskThreadsDiskFile);
55 void *
56 DiskThreadsDiskFile::operator new (size_t)
57 {
58 CBDATA_INIT_TYPE(DiskThreadsDiskFile);
59 DiskThreadsDiskFile *result = cbdataAlloc(DiskThreadsDiskFile);
60 /*
61 * We used to call squidaio_init() here, but if the first transaction
62 * is to unlink a file (e.g., if Squid starts up over the disk space
63 * limit) then "squidaio" won't be initialized yet.
64 */
65
66 return result;
67 }
68
69 void
70 DiskThreadsDiskFile::operator delete(void *address)
71 {
72 DiskThreadsDiskFile *t = static_cast<DiskThreadsDiskFile *>(address);
73 cbdataFree(t);
74 }
75
76 DiskThreadsDiskFile::DiskThreadsDiskFile(char const *aPath, DiskThreadsIOStrategy *anIO):fd(-1), errorOccured (false), IO(anIO),
77 inProgressIOs (0)
78 {
79 assert (aPath);
80 debugs(79, 3, "UFSFile::UFSFile: " << aPath);
81 path_ = xstrdup (aPath);
82 }
83
84 DiskThreadsDiskFile::~DiskThreadsDiskFile()
85 {
86 safe_free (path_);
87 doClose();
88 }
89
90 void
91 DiskThreadsDiskFile::open(int flags, mode_t mode, RefCount<IORequestor> callback)
92 {
93 ++statCounter.syscalls.disk.opens;
94 #if !ASYNC_OPEN
95
96 fd = file_open(path_, flags);
97
98 if (fd < 0) {
99 debugs(79, 3, "DiskThreadsDiskFile::open: got failure (" << errno << ")");
100 errorOccured = true;
101 return;
102 }
103
104 #endif
105 ++Opening_FD;
106
107 ioRequestor = callback;
108
109 ++inProgressIOs;
110
111 #if ASYNC_OPEN
112
113 aioOpen(path_, flags, mode, DiskThreadsDiskFile::OpenDone, this);
114
115 #else
116
117 openDone(fd, NULL, fd, 0);
118
119 #endif
120 }
121
122 void
123 DiskThreadsDiskFile::read(ReadRequest * request)
124 {
125 debugs(79, 3, "DiskThreadsDiskFile::read: " << this << ", size " << request->len);
126 assert (fd > -1);
127 assert (ioRequestor.getRaw());
128 ++statCounter.syscalls.disk.reads;
129 ++inProgressIOs;
130 #if ASYNC_READ
131
132 aioRead(fd, request->offset, request->len, ReadDone, new IoResult<ReadRequest>(this, request));
133 #else
134
135 file_read(fd, request->buf, request->len, request->offset, ReadDone, new IoResult<ReadRequest>(this, request));
136 #endif
137 }
138
139 void
140 DiskThreadsDiskFile::create(int flags, mode_t mode, RefCount<IORequestor> callback)
141 {
142 ++statCounter.syscalls.disk.opens;
143 #if !ASYNC_CREATE
144
145 int fd = file_open(path_, flags);
146
147 if (fd < 0) {
148 debugs(79, 3, "DiskThreadsDiskFile::create: got failure (" << errno << ")");
149 errorOccured = true;
150 return;
151 }
152
153 #endif
154 ++Opening_FD;
155
156 ioRequestor = callback;
157
158 ++inProgressIOs;
159
160 #if ASYNC_CREATE
161
162 aioOpen(path_, flags, mode, DiskThreadsDiskFile::OpenDone, this);
163
164 #else
165
166 openDone (fd, NULL, fd, 0);
167
168 #endif
169 }
170
171 bool
172 DiskThreadsDiskFile::error() const
173 {
174 return errorOccured;
175 }
176
177 void
178 DiskThreadsDiskFile::OpenDone(int fd, void *cbdata, const char *buf, int aio_return, int aio_errno)
179 {
180 DiskThreadsDiskFile *myFile = static_cast<DiskThreadsDiskFile *>(cbdata);
181 myFile->openDone (fd, buf, aio_return, aio_errno);
182 }
183
184 void
185 DiskThreadsDiskFile::openDone(int unused, const char *unused2, int anFD, int errflag)
186 {
187 debugs(79, 3, "DiskThreadsDiskFile::openDone: FD " << anFD << ", errflag " << errflag);
188 --Opening_FD;
189
190 fd = anFD;
191
192 if (errflag || fd < 0) {
193 errno = errflag;
194 debugs(79, DBG_CRITICAL, "DiskThreadsDiskFile::openDone: " << xstrerror());
195 debugs(79, DBG_IMPORTANT, "\t" << path_);
196 errorOccured = true;
197 } else {
198 ++store_open_disk_fd;
199 commSetCloseOnExec(fd);
200 fd_open(fd, FD_FILE, path_);
201 }
202
203 IORequestor::Pointer t = ioRequestor;
204 --inProgressIOs;
205 t->ioCompletedNotification();
206
207 debugs(79, 3, "DiskThreadsDiskFile::openDone: exiting");
208 }
209
210 void DiskThreadsDiskFile::doClose()
211 {
212 if (fd > -1) {
213 ++statCounter.syscalls.disk.closes;
214 #if ASYNC_CLOSE
215
216 aioClose(fd);
217 fd_close(fd);
218 #else
219
220 aioCancel(fd);
221 file_close(fd);
222 #endif
223
224 --store_open_disk_fd;
225 fd = -1;
226 }
227 }
228
229 void
230 DiskThreadsDiskFile::close()
231 {
232 debugs(79, 3, "DiskThreadsDiskFile::close: " << this << " closing for " << ioRequestor.getRaw());
233
234 if (!ioInProgress()) {
235 doClose();
236 assert (ioRequestor != NULL);
237 ioRequestor->closeCompleted();
238 return;
239 } else {
240 debugs(79, DBG_CRITICAL, HERE << "DiskThreadsDiskFile::close: " <<
241 "did NOT close because ioInProgress() is true. now what?");
242 }
243 }
244
245 bool
246 DiskThreadsDiskFile::canRead() const
247 {
248 debugs(79, 3, "DiskThreadsDiskFile::canRead: fd is " << fd);
249 return fd > -1;
250 }
251
252 void
253 DiskThreadsDiskFile::write(WriteRequest * writeRequest)
254 {
255 debugs(79, 3, "DiskThreadsDiskFile::write: FD " << fd);
256 ++statCounter.syscalls.disk.writes;
257 ++inProgressIOs;
258 #if ASYNC_WRITE
259
260 aioWrite(fd, writeRequest->offset, (char *)writeRequest->buf, writeRequest->len, WriteDone, new IoResult<WriteRequest>(this, writeRequest),
261 writeRequest->free_func);
262 #else
263
264 file_write(fd, writeRequest->offset, (char *)writeRequest->buf, writeRequest->len, WriteDone, new IoResult<WriteRequest>(this, writeRequest),
265 writeRequest->free_func);
266 #endif
267 }
268
269 bool
270 DiskThreadsDiskFile::canWrite() const
271 {
272 return fd > -1;
273 }
274
275 bool
276 DiskThreadsDiskFile::ioInProgress() const
277 {
278 return inProgressIOs > 0;
279 }
280
281 /* === STATIC =========================================================== */
282
283 #if ASYNC_READ
284 void
285 DiskThreadsDiskFile::ReadDone(int fd, void *my_data, const char *buf, int len, int errflag)
286 #else
287 void
288 DiskThreadsDiskFile::ReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
289 #endif
290 {
291 IoResult<ReadRequest> * result = static_cast<IoResult<ReadRequest> *>(my_data);
292 assert (result);
293 result->file->readDone(fd, buf, len, errflag, result->request);
294 delete result;
295 }
296
297 void
298 DiskThreadsDiskFile::readDone(int rvfd, const char *buf, int len, int errflag, RefCount<ReadRequest> request)
299 {
300 debugs(79, 3, "DiskThreadsDiskFile::readDone: FD " << rvfd);
301 assert (fd == rvfd);
302
303 ssize_t rlen;
304
305 if (errflag) {
306 debugs(79, 3, "DiskThreadsDiskFile::readDone: got failure (" << errflag << ")");
307 rlen = -1;
308 } else {
309 rlen = (ssize_t) len;
310 }
311
312 #if ASYNC_READ
313 /* translate errflag from errno to Squid disk error */
314 errno = errflag;
315
316 if (errflag)
317 errflag = DISK_ERROR;
318 else
319 errflag = DISK_OK;
320
321 #else
322
323 if (errflag == DISK_EOF)
324 errflag = DISK_OK; /* EOF is signalled by len == 0, not errors... */
325
326 #endif
327
328 --inProgressIOs;
329
330 ioRequestor->readCompleted(buf, rlen, errflag, request);
331 }
332
333 void
334 DiskThreadsDiskFile::
335 #if ASYNC_WRITE
336 WriteDone(int fd, void *my_data, const char *buf, int len, int errflag)
337 #else
338 WriteDone(int fd, int errflag, size_t len, void *my_data)
339 #endif
340 {
341 IoResult<WriteRequest> * result = static_cast<IoResult<WriteRequest> *>(my_data);
342 assert (result);
343 result->file->writeDone(fd, errflag, len, result->request);
344 delete result;
345 }
346
347 void
348 DiskThreadsDiskFile::writeDone(int rvfd, int errflag, size_t len, RefCount<WriteRequest> request)
349 {
350 assert (rvfd == fd);
351 static int loop_detect = 0;
352
353 #if ASYNC_WRITE
354 /* Translate from errno to Squid disk error */
355
356 if (errflag)
357 errflag = errflag == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR;
358 else
359 errflag = DISK_OK;
360
361 #endif
362
363 debugs(79, 3, "DiskThreadsDiskFile::writeDone: FD " << fd << ", len " << len << ", err=" << errflag);
364
365 assert(++loop_detect < 10);
366
367 --inProgressIOs;
368
369 ioRequestor->writeCompleted(errflag, len, request);
370
371 --loop_detect;
372 }
373
374 /** \cond AUTODOCS-IGNORE */
375 template <class RT>
376 cbdata_type IoResult<RT>::CBDATA_IoResult = CBDATA_UNKNOWN;
377 /** \endcond */
378
379 template<class RT>
380 void *
381 IoResult<RT>::operator new(size_t unused)
382 {
383 CBDATA_INIT_TYPE(IoResult);
384 IoResult<RT> *result = cbdataAlloc(IoResult);
385 return result;
386 }
387
388 template <class RT>
389 void
390 IoResult<RT>::operator delete(void *address)
391 {
392 cbdataFree(address);
393 }