Unlinkd is used only by UFS storage.  Bug before the change, Squid
always started unlinkd if it is built, even if it is not needed.
Moreover, unlinkd was started in non-daemon mode.

The patch adds unlinks() method for SwapDir to determine if it uses
unlinkd.  Unlinkd is started iff:

* Squid is running in daemon mode
* a configured cache_dir uses unlinkd

After the change, unlinkdClose() may be called when unlinkd was never
started.  The patch removes a warning which was printed in this case
on Windows.
---
 src/SwapDir.h               |    2 ++
 src/fs/ufs/store_dir_ufs.cc |    6 ++++++
 src/fs/ufs/ufscommon.h      |    1 +
 src/main.cc                 |    3 ++-
 src/protos.h                |    1 +
 src/unlinkd.cc              |   21 +++++++++++++++++++--
 6 files changed, 31 insertions(+), 3 deletions(-)

diff --git src/SwapDir.h src/SwapDir.h
index 723443c..b5772d8 100644
--- src/SwapDir.h
+++ src/SwapDir.h
@@ -115,40 +115,42 @@ SQUIDCEXTERN void storeDirLRUDelete(StoreEntry *);
 SQUIDCEXTERN void storeDirLRUAdd(StoreEntry *);
 SQUIDCEXTERN int storeDirGetBlkSize(const char *path, int *blksize);
 SQUIDCEXTERN int storeDirGetUFSStats(const char *, int *, int *, int *, int *);
 
 /// manages a single cache_dir
 class SwapDir : public Store
 {
 
 public:
     typedef RefCount<SwapDir> Pointer;
 
     SwapDir(char const *aType);
     virtual ~SwapDir();
     virtual void reconfigure() = 0;
     char const *type() const;
 
     virtual bool needsDiskStrand() const; ///< needs a dedicated kid process
     virtual bool active() const; ///< may be used in this strand
     /// whether stat should be reported by this SwapDir
     virtual bool doReportStat() const { return active(); }
+    /// whether SwapDir unlinks files a lot and may benefit from unlinkd
+    virtual bool unlinks() const { return false; }
 
     /* official Store interface functions */
     virtual void diskFull();
 
     virtual StoreEntry * get(const cache_key *);
 
     virtual void get(String const, STOREGETCLIENT, void * cbdata);
 
     virtual uint64_t maxSize() const { return max_size;}
 
     virtual uint64_t minSize() const;
 
     virtual int64_t maxObjectSize() const { return max_objsize; }
 
     virtual void stat (StoreEntry &anEntry) const;
     virtual StoreSearch *search(String const url, HttpRequest *) = 0;
 
     /* migrated from store_dir.cc */
     bool objectSizeIsAcceptable(int64_t objsize) const;
 
diff --git src/fs/ufs/store_dir_ufs.cc src/fs/ufs/store_dir_ufs.cc
index 129629c..439a33b 100644
--- src/fs/ufs/store_dir_ufs.cc
+++ src/fs/ufs/store_dir_ufs.cc
@@ -1284,40 +1284,46 @@ UFSSwapDir::unlinkFile(sfileno f)
            std::hex << std::uppercase << std::setw(8) << f << " '" <<
            fullPath(f,NULL) << "'");
     /* commonUfsDirMapBitReset(this, f); */
     IO->unlinkFile(fullPath(f,NULL));
 }
 
 void
 UFSSwapDir::unlink(StoreEntry & e)
 {
     debugs(79, 3, "storeUfsUnlink: dirno " << index  << ", fileno "<<
            std::setfill('0') << std::hex << std::uppercase << std::setw(8) << e.swap_filen);
     if (e.swap_status == SWAPOUT_DONE && EBIT_TEST(e.flags, ENTRY_VALIDATED)) {
         cur_size -= fs.blksize * sizeInBlocks(e.swap_file_sz);
         --n_disk_objects;
     }
     replacementRemove(&e);
     mapBitReset(e.swap_filen);
     UFSSwapDir::unlinkFile(e.swap_filen);
 }
 
+bool
+UFSSwapDir::unlinks() const
+{
+    return IamWorkerProcess();
+}
+
 /*
  * Add and remove the given StoreEntry from the replacement policy in
  * use.
  */
 
 void
 UFSSwapDir::replacementAdd(StoreEntry * e)
 {
     debugs(47, 4, "UFSSwapDir::replacementAdd: added node " << e << " to dir " << index);
     repl->Add(repl, e, &e->repl);
 }
 
 
 void
 UFSSwapDir::replacementRemove(StoreEntry * e)
 {
     StorePointer SD;
 
     if (e->swap_dirn < 0)
         return;
diff --git src/fs/ufs/ufscommon.h src/fs/ufs/ufscommon.h
index 7561e8b..ae169d4 100644
--- src/fs/ufs/ufscommon.h
+++ src/fs/ufs/ufscommon.h
@@ -43,40 +43,41 @@ class StoreSearch;
 
 #include "SwapDir.h"
 
 /// \ingroup UFS
 class UFSSwapDir : public SwapDir
 {
 
 public:
     static int IsUFSDir(SwapDir* sd);
     static int DirClean(int swap_index);
     static int FilenoBelongsHere(int fn, int F0, int F1, int F2);
 
     UFSSwapDir(char const *aType, const char *aModuleType);
     virtual void init();
     virtual void create();
     virtual void dump(StoreEntry &) const;
     ~UFSSwapDir();
     virtual StoreSearch *search(String const url, HttpRequest *);
     virtual bool doubleCheck(StoreEntry &);
     virtual void unlink(StoreEntry &);
+    virtual bool unlinks() const;
     virtual void statfs(StoreEntry &)const;
     virtual void maintain();
     virtual bool canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) const;
     virtual void reference(StoreEntry &);
     virtual bool dereference(StoreEntry &);
     virtual StoreIOState::Pointer createStoreIO(StoreEntry &, StoreIOState::STFNCB *, StoreIOState::STIOCB *, void *);
     virtual StoreIOState::Pointer openStoreIO(StoreEntry &, StoreIOState::STFNCB *, StoreIOState::STIOCB *, void *);
     virtual void openLog();
     virtual void closeLog();
     virtual int writeCleanStart();
     virtual void writeCleanDone();
     virtual void logEntry(const StoreEntry & e, int op) const;
     virtual void parse(int index, char *path);
     virtual void reconfigure();
     virtual int callback();
     virtual void sync();
     virtual void swappedOut(const StoreEntry &e);
     virtual uint64_t currentSize() const { return cur_size; }
     virtual uint64_t currentCount() const { return n_disk_objects; }
 
diff --git src/main.cc src/main.cc
index 546eb92..da19f40 100644
--- src/main.cc
+++ src/main.cc
@@ -1068,41 +1068,42 @@ mainInitialize(void)
     icapLogOpen();
 #endif
 
 #if USE_IDENT
     Ident::Init();
 #endif
 
 #if SQUID_SNMP
 
     snmpInit();
 
 #endif
 #if MALLOC_DBG
 
     malloc_debug(0, malloc_debug_level);
 
 #endif
 
     if (!configured_once) {
 #if USE_UNLINKD
-        unlinkdInit();
+        if (unlinkdNeeded())
+            unlinkdInit();
 #endif
 
         urlInitialize();
         statInit();
         storeInit();
         mainSetCwd();
         /* after this point we want to see the mallinfo() output */
         do_mallinfo = 1;
         mimeInit(Config.mimeTablePathname);
         refreshInit();
 #if USE_DELAY_POOLS
         DelayPools::Init();
 #endif
 
         FwdState::initModule();
         /* register the modules in the cache manager menus */
 
         cbdataRegisterWithCacheManager();
         /* These use separate calls so that the comm loops can eventually
          * coexist.
diff --git src/protos.h src/protos.h
index 46cb7b8..00bae33 100644
--- src/protos.h
+++ src/protos.h
@@ -574,40 +574,41 @@ SQUIDCEXTERN int DebugSignal;
 
 /* AYJ debugs function to show locations being reset with memset() */
 SQUIDCEXTERN void *xmemset(void *dst, int, size_t);
 
 SQUIDCEXTERN void debug_trap(const char *);
 SQUIDCEXTERN void logsFlush(void);
 SQUIDCEXTERN const char *checkNullString(const char *p);
 
 SQUIDCEXTERN void squid_getrusage(struct rusage *r);
 
 SQUIDCEXTERN double rusage_cputime(struct rusage *r);
 
 SQUIDCEXTERN int rusage_maxrss(struct rusage *r);
 
 SQUIDCEXTERN int rusage_pagefaults(struct rusage *r);
 SQUIDCEXTERN void releaseServerSockets(void);
 SQUIDCEXTERN void PrintRusage(void);
 SQUIDCEXTERN void dumpMallocStats(void);
 
 #if USE_UNLINKD
+SQUIDCEXTERN bool unlinkdNeeded(void);
 SQUIDCEXTERN void unlinkdInit(void);
 SQUIDCEXTERN void unlinkdClose(void);
 SQUIDCEXTERN void unlinkdUnlink(const char *);
 #endif
 
 SQUIDCEXTERN AnyP::ProtocolType urlParseProtocol(const char *, const char *e = NULL);
 SQUIDCEXTERN void urlInitialize(void);
 SQUIDCEXTERN HttpRequest *urlParse(const HttpRequestMethod&, char *, HttpRequest *request = NULL);
 SQUIDCEXTERN const char *urlCanonical(HttpRequest *);
 SQUIDCEXTERN char *urlCanonicalClean(const HttpRequest *);
 SQUIDCEXTERN const char *urlCanonicalFakeHttps(const HttpRequest * request);
 SQUIDCEXTERN bool urlIsRelative(const char *);
 SQUIDCEXTERN char *urlMakeAbsolute(const HttpRequest *, const char *);
 SQUIDCEXTERN char *urlRInternal(const char *host, unsigned short port, const char *dir, const char *name);
 SQUIDCEXTERN char *urlInternal(const char *dir, const char *name);
 SQUIDCEXTERN int matchDomainName(const char *host, const char *domain);
 SQUIDCEXTERN int urlCheckRequest(const HttpRequest *);
 SQUIDCEXTERN int urlDefaultPort(AnyP::ProtocolType p);
 SQUIDCEXTERN char *urlHostname(const char *url);
 SQUIDCEXTERN void urlExtMethodConfigure(void);
diff --git src/unlinkd.cc src/unlinkd.cc
index c46e1c2..9007cab 100644
--- src/unlinkd.cc
+++ src/unlinkd.cc
@@ -18,40 +18,41 @@
  *  sources; see the CREDITS file for full details.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid.h"
 #include "SquidTime.h"
+#include "SwapDir.h"
 #include "fde.h"
 #include "xusleep.h"
 
 /* This code gets linked to Squid */
 
 static int unlinkd_wfd = -1;
 static int unlinkd_rfd = -1;
 
 static void * hIpc;
 static pid_t pid;
 
 #define UNLINKD_QUEUE_LIMIT 20
 
 void
 unlinkdUnlink(const char *path)
 {
     char buf[MAXPATHLEN];
     int l;
     int bytes_written;
     static int queuelen = 0;
@@ -139,72 +140,88 @@ unlinkdUnlink(const char *path)
     statCounter.syscalls.disk.unlinks++;
     queuelen++;
 }
 
 void
 unlinkdClose(void)
 #if _SQUID_MSWIN_
 {
 
     if (unlinkd_wfd > -1) {
         debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd);
         shutdown(unlinkd_wfd, SD_BOTH);
         comm_close(unlinkd_wfd);
 
         if (unlinkd_wfd != unlinkd_rfd)
             comm_close(unlinkd_rfd);
 
         unlinkd_wfd = -1;
 
         unlinkd_rfd = -1;
-    } else
-        debugs(2, 0, "unlinkdClose: WARNING: unlinkd_wfd is " << unlinkd_wfd);
+    }
 
     if (hIpc) {
         if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
             getCurrentTime();
             debugs(2, 1, "unlinkdClose: WARNING: (unlinkd," << pid << "d) didn't exit in 5 seconds");
         }
 
         CloseHandle(hIpc);
     }
 }
 #else
 {
 
     if (unlinkd_wfd < 0)
         return;
 
     debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd);
 
     file_close(unlinkd_wfd);
 
     if (unlinkd_wfd != unlinkd_rfd)
         file_close(unlinkd_rfd);
 
     unlinkd_wfd = -1;
 
     unlinkd_rfd = -1;
 }
 
 #endif
 
+bool
+unlinkdNeeded(void)
+{
+    // do not start unlinkd in non-daemon mode
+    if (!InDaemonMode())
+        return false;
+
+    // we should start unlinkd if there are any cache_dirs using it
+    for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
+        const RefCount<SwapDir> sd = Config.cacheSwap.swapDirs[i];
+        if (sd->unlinks())
+            return true;
+    }
+
+    return false;
+}
+
 void
 unlinkdInit(void)
 {
     const char *args[2];
     Ip::Address localhost;
 
     args[0] = "(unlinkd)";
     args[1] = NULL;
     localhost.SetLocalhost();
 
     pid = ipcCreate(
 #if USE_POLL && defined(_SQUID_OSF_)
               /* pipes and poll() don't get along on DUNIX -DW */
               IPC_STREAM,
 #elif defined(_SQUID_MSWIN_)
               /* select() will fail on a pipe */
               IPC_TCP_SOCKET,
 #else
               /* We currently need to use FIFO.. see below */
               IPC_FIFO,

Reply via email to