]> git.ipfire.org Git - thirdparty/squid.git/blob - src/unlinkd.cc
Merged from trunk
[thirdparty/squid.git] / src / unlinkd.cc
1
2 /*
3 * $Id$
4 *
5 * DEBUG: section 02 Unlink Daemon
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
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.
24 *
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.
29 *
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-old.h"
37 #include "SquidTime.h"
38 #include "StatCounters.h"
39 #include "SwapDir.h"
40 #include "fde.h"
41 #include "xusleep.h"
42
43 /* This code gets linked to Squid */
44
45 static int unlinkd_wfd = -1;
46 static int unlinkd_rfd = -1;
47
48 static void * hIpc;
49 static pid_t pid;
50
51 #define UNLINKD_QUEUE_LIMIT 20
52
53 void
54 unlinkdUnlink(const char *path)
55 {
56 char buf[MAXPATHLEN];
57 int l;
58 int bytes_written;
59 static int queuelen = 0;
60
61 if (unlinkd_wfd < 0) {
62 debug_trap("unlinkdUnlink: unlinkd_wfd < 0");
63 safeunlink(path, 0);
64 return;
65 }
66
67 /*
68 * If the queue length is greater than our limit, then we pause
69 * for a small amount of time, hoping that unlinkd has some
70 * feedback for us. Maybe it just needs a slice of the CPU's
71 * time.
72 */
73 if (queuelen >= UNLINKD_QUEUE_LIMIT) {
74 #if defined(USE_EPOLL) || defined(USE_KQUEUE) || defined(USE_DEVPOLL)
75 /*
76 * DPW 2007-04-23
77 * We can't use fd_set when using epoll() or kqueue(). In
78 * these cases we block for 10 ms.
79 */
80 xusleep(10000);
81 #else
82 /*
83 * DPW 2007-04-23
84 * When we can use select, block for up to 100 ms.
85 */
86 struct timeval to;
87 fd_set R;
88 FD_ZERO(&R);
89 FD_SET(unlinkd_rfd, &R);
90 to.tv_sec = 0;
91 to.tv_usec = 100000;
92 select(unlinkd_rfd + 1, &R, NULL, NULL, &to);
93 #endif
94 }
95
96 /*
97 * If there is at least one outstanding unlink request, then
98 * try to read a response. If there's nothing to read we'll
99 * get an EWOULDBLOCK or whatever. If we get a response, then
100 * decrement the queue size by the number of newlines read.
101 */
102 if (queuelen > 0) {
103 int bytes_read;
104 int i;
105 char rbuf[512];
106 bytes_read = read(unlinkd_rfd, rbuf, 511);
107
108 if (bytes_read > 0) {
109 rbuf[bytes_read] = '\0';
110
111 for (i = 0; i < bytes_read; ++i)
112 if ('\n' == rbuf[i])
113 --queuelen;
114
115 assert(queuelen >= 0);
116 }
117 }
118
119 l = strlen(path);
120 assert(l < MAXPATHLEN);
121 xstrncpy(buf, path, MAXPATHLEN);
122 buf[l] = '\n';
123 ++l;
124 bytes_written = write(unlinkd_wfd, buf, l);
125
126 if (bytes_written < 0) {
127 debugs(2, 1, "unlinkdUnlink: write FD " << unlinkd_wfd << " failed: " << xstrerror());
128 safeunlink(path, 0);
129 return;
130 } else if (bytes_written != l) {
131 debugs(2, 1, "unlinkdUnlink: FD " << unlinkd_wfd << " only wrote " << bytes_written << " of " << l << " bytes");
132 safeunlink(path, 0);
133 return;
134 }
135
136 ++statCounter.unlink.requests;
137 /*
138 * Increment this syscalls counter here, even though the syscall
139 * is executed by the helper process. We try to be consistent
140 * in counting unlink operations.
141 */
142 ++statCounter.syscalls.disk.unlinks;
143 ++queuelen;
144 }
145
146 void
147 unlinkdClose(void)
148 #if _SQUID_MSWIN_
149 {
150
151 if (unlinkd_wfd > -1) {
152 debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd);
153 shutdown(unlinkd_wfd, SD_BOTH);
154 comm_close(unlinkd_wfd);
155
156 if (unlinkd_wfd != unlinkd_rfd)
157 comm_close(unlinkd_rfd);
158
159 unlinkd_wfd = -1;
160
161 unlinkd_rfd = -1;
162 }
163
164 if (hIpc) {
165 if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
166 getCurrentTime();
167 debugs(2, 1, "unlinkdClose: WARNING: (unlinkd," << pid << "d) didn't exit in 5 seconds");
168 }
169
170 CloseHandle(hIpc);
171 }
172 }
173 #else
174 {
175
176 if (unlinkd_wfd < 0)
177 return;
178
179 debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd);
180
181 file_close(unlinkd_wfd);
182
183 if (unlinkd_wfd != unlinkd_rfd)
184 file_close(unlinkd_rfd);
185
186 unlinkd_wfd = -1;
187
188 unlinkd_rfd = -1;
189 }
190
191 #endif
192
193 bool
194 unlinkdNeeded(void)
195 {
196 // we should start unlinkd if there are any cache_dirs using it
197 for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
198 const RefCount<SwapDir> sd = Config.cacheSwap.swapDirs[i];
199 if (sd->unlinkdUseful())
200 return true;
201 }
202
203 return false;
204 }
205
206 void
207 unlinkdInit(void)
208 {
209 if (unlinkd_wfd >= 0)
210 return; // unlinkd already started
211
212 const char *args[2];
213 Ip::Address localhost;
214
215 args[0] = "(unlinkd)";
216 args[1] = NULL;
217 localhost.SetLocalhost();
218
219 pid = ipcCreate(
220 #if USE_POLL && _SQUID_OSF_
221 /* pipes and poll() don't get along on DUNIX -DW */
222 IPC_STREAM,
223 #elif _SQUID_MSWIN_
224 /* select() will fail on a pipe */
225 IPC_TCP_SOCKET,
226 #else
227 /* We currently need to use FIFO.. see below */
228 IPC_FIFO,
229 #endif
230 Config.Program.unlinkd,
231 args,
232 "unlinkd",
233 localhost,
234 &unlinkd_rfd,
235 &unlinkd_wfd,
236 &hIpc);
237
238 if (pid < 0)
239 fatal("Failed to create unlinkd subprocess");
240
241 xusleep(250000);
242
243 fd_note(unlinkd_wfd, "squid -> unlinkd");
244
245 fd_note(unlinkd_rfd, "unlinkd -> squid");
246
247 commUnsetFdTimeout(unlinkd_rfd);
248 commUnsetFdTimeout(unlinkd_wfd);
249
250 /*
251 * unlinkd_rfd should already be non-blocking because of
252 * ipcCreate. We change unlinkd_wfd to blocking mode because
253 * we never want to lose an unlink request, and we don't have
254 * code to retry if we get EWOULDBLOCK. Unfortunately, we can
255 * do this only for the IPC_FIFO case.
256 */
257 assert(fd_table[unlinkd_rfd].flags.nonblocking);
258
259 if (FD_PIPE == fd_table[unlinkd_wfd].type)
260 commUnsetNonBlocking(unlinkd_wfd);
261
262 debugs(2, 1, "Unlinkd pipe opened on FD " << unlinkd_wfd);
263
264 #if _SQUID_MSWIN_
265
266 debugs(2, 4, "Unlinkd handle: 0x" << std::hex << hIpc << std::dec << ", PID: " << pid);
267
268 #endif
269
270 }