[Libreoffice-commits] online.git: loolwsd/LOOLWSD.cpp loolwsd/Util.cpp loolwsd/Util.hpp

Tor Lillqvist tml at collabora.com
Thu Sep 29 14:59:09 UTC 2016


 loolwsd/LOOLWSD.cpp |    6 ++++
 loolwsd/Util.cpp    |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 loolwsd/Util.hpp    |    7 ++++
 3 files changed, 85 insertions(+), 1 deletion(-)

New commits:
commit 86bd8426d06590d2a10d7bb8e2e64aa468bb2309
Author: Tor Lillqvist <tml at collabora.com>
Date:   Thu Sep 29 17:47:28 2016 +0300

    More work on disk space monitoring
    
    Monitor the disk space on important file systems: The ones where
    cached tiles are stored and where the chroot jails are created. Those
    might be the same file system of course, the code checks and doesn't
    do needless work.
    
    The check is done whenever a new loolkit process is taken into use and
    a new chroot jail it constructed, and whenever a new client session
    connects to a document. We don't check more often than once a minute,
    though.
    
    Still need to add code to guard against running out of diska space
    when saving documents back to where they were opened from. For that
    presumably need to enhance the Storage abstraction.

diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index aa45795..57ad7f9 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -186,6 +186,7 @@ static void forkChildren(const int number)
 
     if (number > 0)
     {
+        Util::checkDiskSpace("");
         const std::string aMessage = "spawn " + std::to_string(number) + "\n";
         Log::debug("MasterToForKit: " + aMessage.substr(0, aMessage.length() - 1));
         IoUtil::writeFIFO(LOOLWSD::ForKitWritePipe, aMessage);
@@ -716,6 +717,8 @@ private:
             Log::trace("Sending to Client [" + status + "].");
             ws->sendFrame(status.data(), (int) status.size());
 
+            Util::checkDiskSpace("");
+
             // Let messages flow
             IoUtil::SocketProcessor(ws,
                 [&session](const std::vector<char>& payload)
@@ -1766,6 +1769,9 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
     else if (ChildRoot[ChildRoot.size() - 1] != '/')
         ChildRoot += '/';
 
+    Util::checkDiskSpace(ChildRoot);
+    Util::checkDiskSpace(Cache + "/.");
+
     if (FileServerRoot.empty())
         FileServerRoot = Poco::Path(Application::instance().commandPath()).parent().parent().toString();
     FileServerRoot = Poco::Path(FileServerRoot).absolute().toString();
diff --git a/loolwsd/Util.cpp b/loolwsd/Util.cpp
index c3a5786..2ff8532 100644
--- a/loolwsd/Util.cpp
+++ b/loolwsd/Util.cpp
@@ -14,7 +14,9 @@
 #include <csignal>
 #include <sys/poll.h>
 #include <sys/prctl.h>
+#include <sys/stat.h>
 #include <sys/uio.h>
+#include <sys/vfs.h>
 #include <unistd.h>
 
 #include <atomic>
@@ -110,7 +112,7 @@ namespace
 {
     void alertAllUsersAndLog(const std::string& message, const std::string& cmd, const std::string& kind)
     {
-        Log::error(message + " Removing.");
+        Log::error(message);
         Util::alertAllUsers(cmd, kind);
     }
 }
@@ -210,6 +212,75 @@ namespace Util
         }
     }
 
+    void checkDiskSpace(const std::string& path)
+    {
+        static std::mutex mutex;
+        std::lock_guard<std::mutex> lock(mutex);
+
+        struct fs
+        {
+            fs(const std::string& p, dev_t d)
+                : path(p), dev(d)
+            {
+            }
+
+            fs(dev_t d)
+                : fs("", d)
+            {
+            }
+
+            std::string path;
+            dev_t dev;
+        };
+
+        struct fsComparator
+        {
+            bool operator() (const fs& lhs, const fs& rhs) const
+            {
+                return (lhs.dev < rhs.dev);
+            }
+        };
+
+        static std::set<fs, fsComparator> filesystems;
+
+        if (path != "")
+        {
+            std::string dirPath = path;
+            std::string::size_type lastSlash = dirPath.rfind('/');
+            assert(lastSlash != std::string::npos);
+            dirPath = dirPath.substr(0, lastSlash + 1) + ".";
+
+            struct stat s;
+            if (stat(dirPath.c_str(), &s) == -1)
+                return;
+            filesystems.insert(fs(dirPath, s.st_dev));
+        }
+
+        static std::chrono::steady_clock::time_point lastCheck;
+        std::chrono::steady_clock::time_point now(std::chrono::steady_clock::now());
+
+        // Don't check disk space more often that once a minute
+        if (std::chrono::duration_cast<std::chrono::seconds>(now - lastCheck).count() < 60)
+            return;
+
+        lastCheck = now;
+
+        for (auto& i: filesystems)
+        {
+            struct stat s;
+            struct statfs sfs;
+            if (stat(i.path.c_str(), &s) == -1 ||
+                statfs(i.path.c_str(), &sfs) == -1)
+                continue;
+
+            if (static_cast<double>(sfs.f_bavail) / sfs.f_blocks <= 0.05)
+            {
+                alertAllUsersAndLog("File system of " + i.path + " dangerously low on disk space", "internal", "diskfull");
+                break;
+            }
+        }
+    }
+
     const char *signalName(const int signo)
     {
         switch (signo)
diff --git a/loolwsd/Util.hpp b/loolwsd/Util.hpp
index 53c28a9..04673d0 100644
--- a/loolwsd/Util.hpp
+++ b/loolwsd/Util.hpp
@@ -73,6 +73,13 @@ namespace Util
     }
 #endif
 
+    // Check disk space on a list of file systems. The list is initially empty, and each call to the
+    // function with a non-empty 'path' adds the file system that path is located on to the list, if
+    // not already there. If the free space on any of the file systems in question is below 5%, call
+    // 'alertAllUsers("internal", "diskfull")'. The check will be made no more often than once a
+    // minute.
+    void checkDiskSpace(const std::string& path);
+
     /// Assert that a lock is already taken.
     template <typename T>
     void assertIsLocked(T& lock)


More information about the Libreoffice-commits mailing list