]> git.ipfire.org Git - thirdparty/squid.git/blob - src/DiskIO/DiskThreads/DiskThreadsDiskFile.cc
4ee13011a011b40f5d596a005f5bcd5b9c9a978e
[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 #include "squid.h"
37 #include "DiskThreadsDiskFile.h"
38 #include "DiskIO/IORequestor.h"
39 #include "DiskIO/ReadRequest.h"
40 #include "DiskIO/WriteRequest.h"
41 #include "Generic.h"
42 #include "globals.h"
43 #include "StatCounters.h"
44 #include "Store.h"
45 #include "protos.h"
46
47 #if HAVE_ERRNO_H
48 #include <errno.h>
49 #endif
50
51 /* === PUBLIC =========================================================== */
52
53 CBDATA_CLASS_INIT(DiskThreadsDiskFile);
54 void *
55 DiskThreadsDiskFile::operator new (size_t)
56 {
57 CBDATA_INIT_TYPE(DiskThreadsDiskFile);
58 DiskThreadsDiskFile *result = cbdataAlloc(DiskThreadsDiskFile);
59 /*
60 * We used to call squidaio_init() here, but if the first transaction
61 * is to unlink a file (e.g., if Squid starts up over the disk space
62 * limit) then "squidaio" won't be initialized yet.
63 */
64
65 return result;
66 }
67
68 void
69 DiskThreadsDiskFile::operator delete(void *address)
70 {
71 DiskThreadsDiskFile *t = static_cast<DiskThreadsDiskFile *>(address);
72 cbdataFree(t);
73 }
74
75 DiskThreadsDiskFile::DiskThreadsDiskFile(char const *aPath, DiskThreadsIOStrategy *anIO):fd(-1), errorOccured (false), IO(anIO),
76 inProgressIOs (0)
77 {
78 assert (aPath);
79 debugs(79, 3, "UFSFile::UFSFile: " << aPath);
80 path_ = xstrdup (aPath);
81 }
82
83 DiskThreadsDiskFile::~DiskThreadsDiskFile()
84 {
85 safe_free (path_);
86 doClose();
87 }
88
89 void
90 DiskThreadsDiskFile::open(int flags, mode_t mode, RefCount<IORequestor> callback)
91 {
92 ++statCounter.syscalls.disk.opens;
93 #if !ASYNC_OPEN
94
95 fd = file_open(path_, flags);
96
97 if (fd < 0) {
98 debugs(79, 3, "DiskThreadsDiskFile::open: got failure (" << errno << ")");
99 errorOccured = true;
100 return;
101 }
102
103 #endif
104 ++Opening_FD;
105
106 ioRequestor = callback;
107
108 ++inProgressIOs;
109
110 #if ASYNC_OPEN
111
112 aioOpen(path_, flags, mode, DiskThreadsDiskFile::OpenDone, this);
113
114 #else
115
116 openDone(fd, NULL, fd, 0);
117
118 #endif
119 }
120
121 void
122 DiskThreadsDiskFile::read(ReadRequest * request)
123 {
124 debugs(79, 3, "DiskThreadsDiskFile::read: " << this << ", size " << request->len);
125 assert (fd > -1);
126 assert (ioRequestor.getRaw());
127 ++statCounter.syscalls.disk.reads;
128 ++inProgressIOs;
129 #if ASYNC_READ
130
131 aioRead(fd, request->offset, request->len, ReadDone, new IoResult<ReadRequest>(this, request));
132 #else
133
134 file_read(fd, request->buf, request->len, request->offset, ReadDone, new IoResult<ReadRequest>(this, request));
135 #endif
136 }
137
138 void
139 DiskThreadsDiskFile::create(int flags, mode_t mode, RefCount<IORequestor> callback)
140 {
141 ++statCounter.syscalls.disk.opens;
142 #if !ASYNC_CREATE
143
144 int fd = file_open(path_, flags);
145
146 if (fd < 0) {
147 debugs(79, 3, "DiskThreadsDiskFile::create: got failure (" << errno << ")");
148 errorOccured = true;
149 return;
150 }
151
152 #endif
153 ++Opening_FD;
154
155 ioRequestor = callback;
156
157 ++inProgressIOs;
158
159 #if ASYNC_CREATE
160
161 aioOpen(path_, flags, mode, DiskThreadsDiskFile::OpenDone, this);
162
163 #else
164
165 openDone (fd, NULL, fd, 0);
166
167 #endif
168 }
169
170 bool
171 DiskThreadsDiskFile::error() const
172 {
173 return errorOccured;
174 }
175
176 void
177 DiskThreadsDiskFile::OpenDone(int fd, void *cbdata, const char *buf, int aio_return, int aio_errno)
178 {
179 DiskThreadsDiskFile *myFile = static_cast<DiskThreadsDiskFile *>(cbdata);
180 myFile->openDone (fd, buf, aio_return, aio_errno);
181 }
182
183 void
184 DiskThreadsDiskFile::openDone(int unused, const char *unused2, int anFD, int errflag)
185 {
186 debugs(79, 3, "DiskThreadsDiskFile::openDone: FD " << anFD << ", errflag " << errflag);
187 --Opening_FD;
188
189 fd = anFD;
190
191 if (errflag || fd < 0) {
192 errno = errflag;
193 debugs(79, DBG_CRITICAL, "DiskThreadsDiskFile::openDone: " << xstrerror());
194 debugs(79, DBG_IMPORTANT, "\t" << path_);
195 errorOccured = true;
196 } else {
197 ++store_open_disk_fd;
198 commSetCloseOnExec(fd);
199 fd_open(fd, FD_FILE, path_);
200 }
201
202 IORequestor::Pointer t = ioRequestor;
203 --inProgressIOs;
204 t->ioCompletedNotification();
205
206 debugs(79, 3, "DiskThreadsDiskFile::openDone: exiting");
207 }
208
209 void DiskThreadsDiskFile::doClose()
210 {
211 if (fd > -1) {
212 ++statCounter.syscalls.disk.closes;
213 #if ASYNC_CLOSE
214
215 aioClose(fd);
216 fd_close(fd);
217 #else
218
219 aioCancel(fd);
220 file_close(fd);
221 #endif
222
223 --store_open_disk_fd;
224 fd = -1;
225 }
226 }
227
228 void
229 DiskThreadsDiskFile::close()
230 {
231 debugs(79, 3, "DiskThreadsDiskFile::close: " << this << " closing for " << ioRequestor.getRaw());
232
233 if (!ioInProgress()) {
234 doClose();
235 assert (ioRequestor != NULL);
236 ioRequestor->closeCompleted();
237 return;
238 } else {
239 debugs(79, DBG_CRITICAL, HERE << "DiskThreadsDiskFile::close: " <<
240 "did NOT close because ioInProgress() is true. now what?");
241 }
242 }
243
244 bool
245 DiskThreadsDiskFile::canRead() const
246 {
247 debugs(79, 3, "DiskThreadsDiskFile::canRead: fd is " << fd);
248 return fd > -1;
249 }
250
251 void
252 DiskThreadsDiskFile::write(WriteRequest * writeRequest)
253 {
254 debugs(79, 3, "DiskThreadsDiskFile::write: FD " << fd);
255 ++statCounter.syscalls.disk.writes;
256 ++inProgressIOs;
257 #if ASYNC_WRITE
258
259 aioWrite(fd, writeRequest->offset, (char *)writeRequest->buf, writeRequest->len, WriteDone, new IoResult<WriteRequest>(this, writeRequest),
260 writeRequest->free_func);
261 #else
262
263 file_write(fd, writeRequest->offset, (char *)writeRequest->buf, writeRequest->len, WriteDone, new IoResult<WriteRequest>(this, writeRequest),
264 writeRequest->free_func);
265 #endif
266 }
267
268 bool
269 DiskThreadsDiskFile::canWrite() const
270 {
271 return fd > -1;
272 }
273
274 bool
275 DiskThreadsDiskFile::ioInProgress() const
276 {
277 return inProgressIOs > 0;
278 }
279
280 /* === STATIC =========================================================== */
281
282 #if ASYNC_READ
283 void
284 DiskThreadsDiskFile::ReadDone(int fd, void *my_data, const char *buf, int len, int errflag)
285 #else
286 void
287 DiskThreadsDiskFile::ReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
288 #endif
289 {
290 IoResult<ReadRequest> * result = static_cast<IoResult<ReadRequest> *>(my_data);
291 assert (result);
292 result->file->readDone(fd, buf, len, errflag, result->request);
293 delete result;
294 }
295
296 void
297 DiskThreadsDiskFile::readDone(int rvfd, const char *buf, int len, int errflag, RefCount<ReadRequest> request)
298 {
299 debugs(79, 3, "DiskThreadsDiskFile::readDone: FD " << rvfd);
300 assert (fd == rvfd);
301
302 ssize_t rlen;
303
304 if (errflag) {
305 debugs(79, 3, "DiskThreadsDiskFile::readDone: got failure (" << errflag << ")");
306 rlen = -1;
307 } else {
308 rlen = (ssize_t) len;
309 }
310
311 #if ASYNC_READ
312 /* translate errflag from errno to Squid disk error */
313 errno = errflag;
314
315 if (errflag)
316 errflag = DISK_ERROR;
317 else
318 errflag = DISK_OK;
319
320 #else
321
322 if (errflag == DISK_EOF)
323 errflag = DISK_OK; /* EOF is signalled by len == 0, not errors... */
324
325 #endif
326
327 --inProgressIOs;
328
329 ioRequestor->readCompleted(buf, rlen, errflag, request);
330 }
331
332 void
333 DiskThreadsDiskFile::
334 #if ASYNC_WRITE
335 WriteDone(int fd, void *my_data, const char *buf, int len, int errflag)
336 #else
337 WriteDone(int fd, int errflag, size_t len, void *my_data)
338 #endif
339 {
340 IoResult<WriteRequest> * result = static_cast<IoResult<WriteRequest> *>(my_data);
341 assert (result);
342 result->file->writeDone(fd, errflag, len, result->request);
343 delete result;
344 }
345
346 void
347 DiskThreadsDiskFile::writeDone(int rvfd, int errflag, size_t len, RefCount<WriteRequest> request)
348 {
349 assert (rvfd == fd);
350 static int loop_detect = 0;
351
352 #if ASYNC_WRITE
353 /* Translate from errno to Squid disk error */
354
355 if (errflag)
356 errflag = errflag == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR;
357 else
358 errflag = DISK_OK;
359
360 #endif
361
362 debugs(79, 3, "DiskThreadsDiskFile::writeDone: FD " << fd << ", len " << len << ", err=" << errflag);
363
364 assert(++loop_detect < 10);
365
366 --inProgressIOs;
367
368 ioRequestor->writeCompleted(errflag, len, request);
369
370 --loop_detect;
371 }
372
373 /** \cond AUTODOCS-IGNORE */
374 template <class RT>
375 cbdata_type IoResult<RT>::CBDATA_IoResult = CBDATA_UNKNOWN;
376 /** \endcond */
377
378 template<class RT>
379 void *
380 IoResult<RT>::operator new(size_t unused)
381 {
382 CBDATA_INIT_TYPE(IoResult);
383 IoResult<RT> *result = cbdataAlloc(IoResult);
384 return result;
385 }
386
387 template <class RT>
388 void
389 IoResult<RT>::operator delete(void *address)
390 {
391 cbdataFree(address);
392 }