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