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

 

Introduction

Documentation

Support

Miscellaneous