]> git.sesse.net Git - plocate/commitdiff
Move AccessRXCache into its own file.
authorSteinar H. Gunderson <steinar+git@gunderson.no>
Thu, 15 Oct 2020 22:36:20 +0000 (00:36 +0200)
committerSteinar H. Gunderson <steinar+git@gunderson.no>
Thu, 15 Oct 2020 22:36:20 +0000 (00:36 +0200)
access_rx_cache.cpp [new file with mode: 0644]
access_rx_cache.h [new file with mode: 0644]
meson.build
plocate.cpp

diff --git a/access_rx_cache.cpp b/access_rx_cache.cpp
new file mode 100644 (file)
index 0000000..c6f5634
--- /dev/null
@@ -0,0 +1,74 @@
+#include "access_rx_cache.h"
+
+#include "io_uring_engine.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utility>
+
+using namespace std;
+
+void AccessRXCache::check_access(const char *filename, bool allow_async, function<void(bool)> cb)
+{
+       lock_guard<mutex> lock(mu);
+       if (engine == nullptr || !engine->get_supports_stat()) {
+               allow_async = false;
+       }
+
+       for (const char *end = strchr(filename + 1, '/'); end != nullptr; end = strchr(end + 1, '/')) {
+               string parent_path(filename, end - filename);  // string_view from C++20.
+               auto cache_it = cache.find(parent_path);
+               if (cache_it != cache.end()) {
+                       // Found in the cache.
+                       if (!cache_it->second) {
+                               cb(false);
+                               return;
+                       }
+                       continue;
+               }
+
+               if (!allow_async) {
+                       bool ok = access(parent_path.c_str(), R_OK | X_OK) == 0;
+                       cache.emplace(parent_path, ok);
+                       if (!ok) {
+                               cb(false);
+                               return;
+                       }
+                       continue;
+               }
+
+               // We want to call access(), but it could block on I/O. io_uring doesn't support
+               // access(), but we can do a dummy asynchonous statx() to populate the kernel's cache,
+               // which nearly always makes the next access() instantaneous.
+
+               // See if there's already a pending stat that matches this,
+               // or is a subdirectory.
+               auto it = pending_stats.lower_bound(parent_path);
+               if (it != pending_stats.end() && it->first.size() >= parent_path.size() &&
+                   it->first.compare(0, parent_path.size(), parent_path) == 0) {
+                       it->second.emplace_back(PendingStat{ filename, move(cb) });
+               } else {
+                       it = pending_stats.emplace(filename, vector<PendingStat>{}).first;
+                       engine->submit_stat(filename, [this, it, filename{ strdup(filename) }, cb{ move(cb) }] {
+                               // The stat returned, so now do the actual access() calls.
+                               // All of them should be in cache, so don't fire off new statx()
+                               // calls during that check.
+                               check_access(filename, /*allow_async=*/false, move(cb));
+                               free(filename);
+
+                               // Call all others that waited for the same stat() to finish.
+                               // They may fire off new stat() calls if needed.
+                               vector<PendingStat> pending = move(it->second);
+                               pending_stats.erase(it);
+                               for (PendingStat &ps : pending) {
+                                       check_access(ps.filename.c_str(), /*allow_async=*/true, move(ps.cb));
+                               }
+                       });
+               }
+               return;  // The rest will happen in async context.
+       }
+
+       // Passed all checks.
+       cb(true);
+}
diff --git a/access_rx_cache.h b/access_rx_cache.h
new file mode 100644 (file)
index 0000000..8757b94
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _ACCESS_RX_CACHE_H
+#define _ACCESS_RX_CACHE_H 1
+
+#include <functional>
+#include <map>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+class IOUringEngine;
+
+class AccessRXCache {
+public:
+       AccessRXCache(IOUringEngine *engine)
+               : engine(engine) {}
+       void check_access(const char *filename, bool allow_async, std::function<void(bool)> cb);
+
+private:
+       std::unordered_map<std::string, bool> cache;
+       struct PendingStat {
+               std::string filename;
+               std::function<void(bool)> cb;
+       };
+       std::map<std::string, std::vector<PendingStat>> pending_stats;
+       IOUringEngine *engine;
+       std::mutex mu;
+};
+
+#endif  // !defined(_ACCESS_RX_CACHE_H)
index 7c6755bcd695e01af23b410d05fc8599e9d63713..d6d0e99b55fbe4127c82e38dda78e81bc2b35fc8 100644 (file)
@@ -12,7 +12,7 @@ if not uringdep.found()
        add_project_arguments('-DWITHOUT_URING', language: 'cpp')
 endif
 
-executable('plocate', ['plocate.cpp', 'io_uring_engine.cpp', 'turbopfor.cpp', 'parse_trigrams.cpp', 'serializer.cpp'],
+executable('plocate', ['plocate.cpp', 'io_uring_engine.cpp', 'turbopfor.cpp', 'parse_trigrams.cpp', 'serializer.cpp', 'access_rx_cache.cpp'],
        dependencies: [uringdep, zstddep, threaddep],
        install: true,
        install_mode: ['rwxr-sr-x', 'root', 'mlocate'])
index c270e79eff24f99481dca08ae47b4cc7abdf6651..0d59076e8fc99efb4829384da1894e99c4399867 100644 (file)
@@ -1,3 +1,4 @@
+#include "access_rx_cache.h"
 #include "db.h"
 #include "dprintf.h"
 #include "io_uring_engine.h"
@@ -20,7 +21,6 @@
 #include <iterator>
 #include <limits>
 #include <locale.h>
-#include <map>
 #include <memory>
 #include <mutex>
 #include <regex.h>
@@ -80,87 +80,6 @@ bool matches(const Needle &needle, const char *haystack)
        }
 }
 
-class AccessRXCache {
-public:
-       AccessRXCache(IOUringEngine *engine)
-               : engine(engine) {}
-       void check_access(const char *filename, bool allow_async, function<void(bool)> cb);
-
-private:
-       unordered_map<string, bool> cache;
-       struct PendingStat {
-               string filename;
-               function<void(bool)> cb;
-       };
-       map<string, vector<PendingStat>> pending_stats;
-       IOUringEngine *engine;
-       mutex mu;
-};
-
-void AccessRXCache::check_access(const char *filename, bool allow_async, function<void(bool)> cb)
-{
-       lock_guard<mutex> lock(mu);
-       if (engine == nullptr || !engine->get_supports_stat()) {
-               allow_async = false;
-       }
-
-       for (const char *end = strchr(filename + 1, '/'); end != nullptr; end = strchr(end + 1, '/')) {
-               string parent_path(filename, end - filename);  // string_view from C++20.
-               auto cache_it = cache.find(parent_path);
-               if (cache_it != cache.end()) {
-                       // Found in the cache.
-                       if (!cache_it->second) {
-                               cb(false);
-                               return;
-                       }
-                       continue;
-               }
-
-               if (!allow_async) {
-                       bool ok = access(parent_path.c_str(), R_OK | X_OK) == 0;
-                       cache.emplace(parent_path, ok);
-                       if (!ok) {
-                               cb(false);
-                               return;
-                       }
-                       continue;
-               }
-
-               // We want to call access(), but it could block on I/O. io_uring doesn't support
-               // access(), but we can do a dummy asynchonous statx() to populate the kernel's cache,
-               // which nearly always makes the next access() instantaneous.
-
-               // See if there's already a pending stat that matches this,
-               // or is a subdirectory.
-               auto it = pending_stats.lower_bound(parent_path);
-               if (it != pending_stats.end() && it->first.size() >= parent_path.size() &&
-                   it->first.compare(0, parent_path.size(), parent_path) == 0) {
-                       it->second.emplace_back(PendingStat{ filename, move(cb) });
-               } else {
-                       it = pending_stats.emplace(filename, vector<PendingStat>{}).first;
-                       engine->submit_stat(filename, [this, it, filename{ strdup(filename) }, cb{ move(cb) }] {
-                               // The stat returned, so now do the actual access() calls.
-                               // All of them should be in cache, so don't fire off new statx()
-                               // calls during that check.
-                               check_access(filename, /*allow_async=*/false, move(cb));
-                               free(filename);
-
-                               // Call all others that waited for the same stat() to finish.
-                               // They may fire off new stat() calls if needed.
-                               vector<PendingStat> pending = move(it->second);
-                               pending_stats.erase(it);
-                               for (PendingStat &ps : pending) {
-                                       check_access(ps.filename.c_str(), /*allow_async=*/true, move(ps.cb));
-                               }
-                       });
-               }
-               return;  // The rest will happen in async context.
-       }
-
-       // Passed all checks.
-       cb(true);
-}
-
 class Corpus {
 public:
        Corpus(int fd, IOUringEngine *engine);