]> git.ipfire.org Git - thirdparty/squid.git/blob - src/unlinkd.cc
Renamed squid.h to squid-old.h and config.h to squid.h.
[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 bytes_written = write(unlinkd_wfd, buf, l);
124
125 if (bytes_written < 0) {
126 debugs(2, 1, "unlinkdUnlink: write FD " << unlinkd_wfd << " failed: " << xstrerror());
127 safeunlink(path, 0);
128 return;
129 } else if (bytes_written != l) {
130 debugs(2, 1, "unlinkdUnlink: FD " << unlinkd_wfd << " only wrote " << bytes_written << " of " << l << " bytes");
131 safeunlink(path, 0);
132 return;
133 }
134
135 ++statCounter.unlink.requests;
136 /*
137 * Increment this syscalls counter here, even though the syscall
138 * is executed by the helper process. We try to be consistent
139 * in counting unlink operations.
140 */
141 ++statCounter.syscalls.disk.unlinks;
142 queuelen++;
143 }
144
145 void
146 unlinkdClose(void)
147 #if _SQUID_MSWIN_
148 {
149
150 if (unlinkd_wfd > -1) {
151 debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd);
152 shutdown(unlinkd_wfd, SD_BOTH);
153 comm_close(unlinkd_wfd);
154
155 if (unlinkd_wfd != unlinkd_rfd)
156 comm_close(unlinkd_rfd);
157
158 unlinkd_wfd = -1;
159
160 unlinkd_rfd = -1;
161 }
162
163 if (hIpc) {
164 if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
165 getCurrentTime();
166 debugs(2, 1, "unlinkdClose: WARNING: (unlinkd," << pid << "d) didn't exit in 5 seconds");
167 }
168
169 CloseHandle(hIpc);
170 }
171 }
172 #else
173 {
174
175 if (unlinkd_wfd < 0)
176 return;
177
178 debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd);
179
180 file_close(unlinkd_wfd);
181
182 if (unlinkd_wfd != unlinkd_rfd)
183 file_close(unlinkd_rfd);
184
185 unlinkd_wfd = -1;
186
187 unlinkd_rfd = -1;
188 }
189
190 #endif
191
192 bool
193 unlinkdNeeded(void)
194 {
195 // we should start unlinkd if there are any cache_dirs using it
196 for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
197 const RefCount<SwapDir> sd = Config.cacheSwap.swapDirs[i];
198 if (sd->unlinkdUseful())
199 return true;
200 }
201
202 return false;
203 }
204
205 void
206 unlinkdInit(void)
207 {
208 if (unlinkd_wfd >= 0)
209 return; // unlinkd already started
210
211 const char *args[2];
212 Ip::Address localhost;
213
214 args[0] = "(unlinkd)";
215 args[1] = NULL;
216 localhost.SetLocalhost();
217
218 pid = ipcCreate(
219 #if USE_POLL && _SQUID_OSF_
220 /* pipes and poll() don't get along on DUNIX -DW */
221 IPC_STREAM,
222 #elif _SQUID_MSWIN_
223 /* select() will fail on a pipe */
224 IPC_TCP_SOCKET,
225 #else
226 /* We currently need to use FIFO.. see below */
227 IPC_FIFO,
228 #endif
229 Config.Program.unlinkd,
230 args,
231 "unlinkd",
232 localhost,
233 &unlinkd_rfd,
234 &unlinkd_wfd,
235 &hIpc);
236
237 if (pid < 0)
238 fatal("Failed to create unlinkd subprocess");
239
240 xusleep(250000);
241
242 fd_note(unlinkd_wfd, "squid -> unlinkd");
243
244 fd_note(unlinkd_rfd, "unlinkd -> squid");
245
246 commUnsetFdTimeout(unlinkd_rfd);
247 commUnsetFdTimeout(unlinkd_wfd);
248
249 /*
250 * unlinkd_rfd should already be non-blocking because of
251 * ipcCreate. We change unlinkd_wfd to blocking mode because
252 * we never want to lose an unlink request, and we don't have
253 * code to retry if we get EWOULDBLOCK. Unfortunately, we can
254 * do this only for the IPC_FIFO case.
255 */
256 assert(fd_table[unlinkd_rfd].flags.nonblocking);
257
258 if (FD_PIPE == fd_table[unlinkd_wfd].type)
259 commUnsetNonBlocking(unlinkd_wfd);
260
261 debugs(2, 1, "Unlinkd pipe opened on FD " << unlinkd_wfd);
262
263 #if _SQUID_MSWIN_
264
265 debugs(2, 4, "Unlinkd handle: 0x" << std::hex << hIpc << std::dec << ", PID: " << pid);
266
267 #endif
268
269 }