proxygen
FilePoller.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <wangle/util/FilePoller.h>
17 
18 #include <atomic>
19 #include <sys/stat.h>
20 
21 #include <folly/Conv.h>
22 #include <folly/Memory.h>
23 #include <folly/Singleton.h>
24 
25 using namespace folly;
26 
27 namespace wangle {
28 
29 namespace {
30 // Class that manages poller Ids and a function scheduler. The function
31 // scheduler will keep running if a FilePoller is hanging on to it, even
32 // if this context is destroyed.
33 class PollerContext {
34  public:
35  PollerContext() : nextPollerId(1) {
36  scheduler = std::make_shared<folly::FunctionScheduler>();
37  scheduler->setThreadName("file-poller");
38  scheduler->start();
39  }
40 
41  const std::shared_ptr<folly::FunctionScheduler>& getScheduler() {
42  return scheduler;
43  }
44 
45  uint64_t getNextId() {
46  return nextPollerId++;
47  }
48 
49  private:
50  std::shared_ptr<folly::FunctionScheduler> scheduler;
51  std::atomic<uint64_t> nextPollerId;
52 };
53 
54 folly::Singleton<PollerContext> contextSingleton([] {
55  return new PollerContext();
56 });
57 }
58 
59 folly::ThreadLocal<bool> FilePoller::ThreadProtector::polling_([] {
60  return new bool(false);
61 });
62 
63 constexpr std::chrono::milliseconds FilePoller::kDefaultPollInterval;
64 
65 FilePoller::FilePoller(std::chrono::milliseconds pollInterval) {
66  init(pollInterval);
67 }
68 
69 FilePoller::~FilePoller() { stop(); }
70 
71 void FilePoller::init(std::chrono::milliseconds pollInterval) {
72  auto context = contextSingleton.try_get();
73  if (!context) {
74  LOG(ERROR) << "Poller context requested after destruction.";
75  return;
76  }
77  pollerId_ = context->getNextId();
78  scheduler_ = context->getScheduler();
79  scheduler_->addFunction(
80  [this] { this->checkFiles(); },
81  pollInterval,
82  folly::to<std::string>(pollerId_));
83 }
84 
86  if (scheduler_) {
87  scheduler_->cancelFunctionAndWait(
88  folly::to<std::string>(pollerId_));
89  }
90 }
91 
92 void FilePoller::checkFiles() noexcept {
93  std::lock_guard<std::mutex> lg(filesMutex_);
95  for (auto& fData : fileDatum_) {
96  auto modData = getFileModData(fData.first);
97  auto& fileData = fData.second;
98  if (fileData.condition(fileData.modData, modData) && fileData.yCob) {
99  fileData.yCob();
100  } else if (fileData.nCob) {
101  fileData.nCob();
102  }
103  fileData.modData = modData;
104  }
105 }
106 
107 void FilePoller::initFileData(
108  const std::string& fName,
109  FileData& fData) noexcept {
110  auto modData = getFileModData(fName);
111  fData.modData.exists = modData.exists;
112  fData.modData.modTime = modData.modTime;
113 }
114 
115 void FilePoller::addFileToTrack(
116  const std::string& fileName,
117  Cob yCob,
118  Cob nCob,
119  Condition condition) {
120  if (fileName.empty()) {
121  // ignore empty file paths
122  return;
123  }
124  if (ThreadProtector::inPollerThread()) {
125  LOG(ERROR) << "Adding files from a callback is disallowed";
126  return;
127  }
128  std::lock_guard<std::mutex> lg(filesMutex_);
129  fileDatum_[fileName] = FileData(yCob, nCob, condition);
130  initFileData(fileName, fileDatum_[fileName]);
131 }
132 
133 void FilePoller::removeFileToTrack(const std::string& fileName) {
134  if (fileName.empty()) {
135  // ignore
136  return;
137  }
138  if (ThreadProtector::inPollerThread()) {
139  LOG(ERROR) << "Adding files from a callback is disallowed";
140  return;
141  }
142  std::lock_guard<std::mutex> lg(filesMutex_);
143  fileDatum_.erase(fileName);
144 }
145 
146 FilePoller::FileModificationData FilePoller::getFileModData(
147  const std::string& path) noexcept {
148  struct stat info;
149  int ret = stat(path.c_str(), &info);
150  if (ret != 0) {
151  return FileModificationData{false, 0};
152  }
153  return FileModificationData{true, info.st_mtime};
154 }
155 }
std::function< bool(const FileModificationData &, const FileModificationData &)> Condition
Definition: FilePoller.h:54
std::atomic< uint64_t > nextPollerId
Definition: FilePoller.cpp:51
def info()
Definition: deadlock.py:447
context
Definition: CMakeCache.txt:563
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
void init()
std::shared_ptr< folly::FunctionScheduler > scheduler
Definition: FilePoller.cpp:50
void init(int *argc, char ***argv, bool removeFlags)
Definition: Init.cpp:34
static void stop()
const char * string
Definition: Conv.cpp:212
std::function< void()> Cob
Definition: FilePoller.h:50