proxygen
wangle::MultiFilePoller Class Reference

#include <MultiFilePoller.h>

Classes

struct  CallbackDetail
 
class  CallbackId
 

Public Types

using CallbackArg = std::unordered_map< std::string, std::string >
 
using Callback = folly::Function< void(const CallbackArg &newData) noexcept >
 

Public Member Functions

 MultiFilePoller (std::chrono::milliseconds pollInterval)
 
 ~MultiFilePoller ()=default
 
CallbackId registerFile (std::string path, Callback cb)
 
CallbackId registerFiles (const std::vector< std::string > &paths, Callback cb)
 
void cancelCallback (const CallbackId &cbId)
 

Private Types

using StringReferences = std::vector< std::reference_wrapper< const std::string >>
 

Private Member Functions

void onFileUpdated (const std::string &triggeredPath)
 
size_t getNextCallbackId ()
 

Private Attributes

folly::SharedMutex rwlock_
 
size_t lastCallbackId_ = 0
 
std::unordered_map< std::string, std::vector< size_t > > pathsToCallbackIds_
 
std::unordered_map< size_t, CallbackDetailidsToCallbacks_
 
wangle::FilePoller poller_
 

Detailed Description

An extension to wangle::FilePoller with the ability to register one or more callback on a file, and to track one or more file in a callback, and to deliver cached file data to callbacks.

Definition at line 32 of file MultiFilePoller.h.

Member Typedef Documentation

using wangle::MultiFilePoller::Callback = folly::Function<void(const CallbackArg& newData) noexcept>

Definition at line 58 of file MultiFilePoller.h.

A callback: (1) takes as argument a map from a file path to its latest content. Unreadable paths will not show up in the map. (2) is triggered when any file it registers is changed, in the context of FilePoller thread. (3) once registered, cannot have its file list or callback pointer changed. To make changes, cancel the existing one and register a new one. Caveat: (1) If there are N files registered, in worst case the first N-1 callbacks would not get latest content of all N files. It's up to the callback to determine what to do for those cases. (2) Once a file, say, F, changes, not only F, but all files needed to trigger all callbacks that use F will be read. For example, Callback A needs files {a, b}; Callback B needs files {b, c}; Callback C needs files {d, e}; File {a} changes -> Reads {a, b} -> Calls A(a, b). File {b} changes -> Reads {a, b, c} -> Calls A(a, b), B(b, c). File {c} changes -> Reads {b, c} -> Calls B(b, c). File {d} or {e} changes -> Reads {d, e} -> Calls C(d, e).

Definition at line 57 of file MultiFilePoller.h.

using wangle::MultiFilePoller::StringReferences = std::vector<std::reference_wrapper<const std::string>>
private

Definition at line 115 of file MultiFilePoller.h.

Constructor & Destructor Documentation

wangle::MultiFilePoller::MultiFilePoller ( std::chrono::milliseconds  pollInterval)
explicit
Parameters
pollIntervalInterval between polls. Setting a value less than 1_s may cause undesirable behavior because the minimum granularity for wangle::FilePoller to detect mtime difference is 1_s.

Definition at line 27 of file MultiFilePoller.cpp.

28  : poller_(pollInterval) {}
wangle::FilePoller poller_
wangle::MultiFilePoller::~MultiFilePoller ( )
default

Member Function Documentation

void wangle::MultiFilePoller::cancelCallback ( const CallbackId cbId)

Cancel the specified Callback. May throw std::out_of_range if not found.

Parameters
cbIdID of the callback returned when registering it.

Definition at line 72 of file MultiFilePoller.cpp.

References wangle::MultiFilePoller::CallbackId::id_, idsToCallbacks_, pathsToCallbackIds_, poller_, wangle::FilePoller::removeFileToTrack(), and rwlock_.

72  {
73  std::vector<std::string> pathsToErase;
75 
76  auto pos = idsToCallbacks_.find(cbId.id_);
77  if (pos == idsToCallbacks_.end()) {
78  throw std::out_of_range(
79  to<std::string>("Callback ", cbId.id_, " not found"));
80  }
81 
82  // Remove the callback ID from its registered paths.
83  for (const auto& path : pos->second.files_) {
84  auto& callbackIds = pathsToCallbackIds_[path];
85  callbackIds.erase(
86  std::remove(callbackIds.begin(), callbackIds.end(), cbId.id_));
87  // If the path has no more callbacks, erase it from map.
88  if (callbackIds.empty()) {
90  pathsToErase.emplace_back(path);
91  }
92  }
93  // Remove the callback.
94  idsToCallbacks_.erase(cbId.id_);
95  // Remove callback-less paths from pathsToCallbackIds_, if any, at last.
96  for (const auto& path : pathsToErase) {
97  pathsToCallbackIds_.erase(path);
98  }
99 }
std::unordered_map< std::string, std::vector< size_t > > pathsToCallbackIds_
wangle::FilePoller poller_
void removeFileToTrack(const std::string &fileName)
Definition: FilePoller.cpp:133
std::unordered_map< size_t, CallbackDetail > idsToCallbacks_
folly::SharedMutex rwlock_
size_t wangle::MultiFilePoller::getNextCallbackId ( )
private

Find an unused size_t value as callback Id. Caller must acquire wlock.

Definition at line 30 of file MultiFilePoller.cpp.

References idsToCallbacks_, and lastCallbackId_.

Referenced by registerFiles().

30  {
31  size_t ret = lastCallbackId_;
32  // Order of callback cancellation is arbitrary, so the next available
33  // callbackId might not be lastCallbackId_+1.
34  while (++ret != lastCallbackId_) {
35  if (idsToCallbacks_.find(ret) == idsToCallbacks_.end()) {
36  lastCallbackId_ = ret; // Assume write lock is acquired.
37  return ret;
38  }
39  }
40  throw std::runtime_error("Run out of callback ID.");
41 }
std::unordered_map< size_t, CallbackDetail > idsToCallbacks_
void wangle::MultiFilePoller::onFileUpdated ( const std::string triggeredPath)
private

The callback dispatcher to be registered to wangle::FilePoller.

Definition at line 101 of file MultiFilePoller.cpp.

References data, idsToCallbacks_, folly::gen::move, pathsToCallbackIds_, folly::readFile(), rwlock_, and string.

Referenced by registerFiles().

101  {
102  VLOG(4) << "onFileUpdated(" << triggeredPath << ").";
103 
104  // A temporary read cache. Not worth it making it permanent because
105  // files do not change frequently.
106  std::unordered_map<std::string, std::string> filePathsToFileContents;
108 
109  const auto& callbacks = pathsToCallbackIds_.find(triggeredPath);
110  if (callbacks == pathsToCallbackIds_.end()) {
111  return;
112  }
113 
114  for (const auto& cbId : callbacks->second) {
115  const auto& cbEnt = idsToCallbacks_.find(cbId);
116  // Lazily read all files needed by the callback.
117  for (const auto& path : cbEnt->second.files_) {
118  if (filePathsToFileContents.find(path) == filePathsToFileContents.end()) {
120  if (readFile(path.get().c_str(), data)) {
121  filePathsToFileContents.emplace(path, std::move(data));
122  } else {
123  VLOG(4) << "Failed to read file " << path.get();
124  }
125  }
126  }
127  cbEnt->second.cb_(filePathsToFileContents);
128  }
129 }
bool readFile(int fd, Container &out, size_t num_bytes=std::numeric_limits< size_t >::max())
Definition: FileUtil.h:125
std::unordered_map< std::string, std::vector< size_t > > pathsToCallbackIds_
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::unordered_map< size_t, CallbackDetail > idsToCallbacks_
folly::SharedMutex rwlock_
const char * string
Definition: Conv.cpp:212
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43
MultiFilePoller::CallbackId wangle::MultiFilePoller::registerFile ( std::string  path,
Callback  cb 
)

Add a callback to trigger when the specified file changes.

Parameters
pathThe path to monitor.
cbThe callback to trigger.
Returns
An ID of the callback, used for cancellation.

Definition at line 43 of file MultiFilePoller.cpp.

References folly::gen::move, and registerFiles().

45  {
46  return registerFiles({std::move(path)}, std::move(cb));
47 }
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
CallbackId registerFiles(const std::vector< std::string > &paths, Callback cb)
MultiFilePoller::CallbackId wangle::MultiFilePoller::registerFiles ( const std::vector< std::string > &  paths,
Callback  cb 
)

Add a callback to trigger when any of the files in paths changes.

Parameters
pathsThe list of paths to monitor. Must be non-empty.
cbThe callback to trigger. @ return An ID of the callback, used for cancellation.

Definition at line 49 of file MultiFilePoller.cpp.

References wangle::FilePoller::addFileToTrack(), getNextCallbackId(), idsToCallbacks_, join, folly::gen::move, onFileUpdated(), pathsToCallbackIds_, poller_, and rwlock_.

Referenced by registerFile().

51  {
52  VLOG(4) << "registerFiles({" << join(", ", paths) << "}, cb=" << &cb << ")";
53  if (paths.empty()) {
54  throw std::invalid_argument("Argument paths must be non-empty.");
55  }
56  StringReferences cbPaths;
58  auto cbId = getNextCallbackId();
59  // Create the bi-directional relation between path and callback.
60  for (const auto& path : paths) {
61  pathsToCallbackIds_[path].push_back(cbId);
62  // Use reference to key of pathsToCallbackIds_ map to avoid duplicates.
63  const auto& key = pathsToCallbackIds_.find(path)->first;
64  cbPaths.push_back(key);
65  poller_.addFileToTrack(key, [=] { onFileUpdated(key); });
66  }
67  idsToCallbacks_.emplace(cbId,
68  CallbackDetail(std::move(cbPaths), std::move(cb)));
69  return MultiFilePoller::CallbackId(cbId);
70 }
std::unordered_map< std::string, std::vector< size_t > > pathsToCallbackIds_
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
void onFileUpdated(const std::string &triggeredPath)
void addFileToTrack(const std::string &fileName, Cob yCob, Cob nCob=nullptr, Condition condition=fileTouchedCondInternal)
Definition: FilePoller.cpp:115
std::vector< std::reference_wrapper< const std::string >> StringReferences
wangle::FilePoller poller_
std::unordered_map< size_t, CallbackDetail > idsToCallbacks_
folly::SharedMutex rwlock_
#define join

Member Data Documentation

std::unordered_map<size_t, CallbackDetail> wangle::MultiFilePoller::idsToCallbacks_
private

Definition at line 129 of file MultiFilePoller.h.

Referenced by cancelCallback(), getNextCallbackId(), onFileUpdated(), and registerFiles().

size_t wangle::MultiFilePoller::lastCallbackId_ = 0
private

Definition at line 127 of file MultiFilePoller.h.

Referenced by getNextCallbackId().

std::unordered_map<std::string, std::vector<size_t> > wangle::MultiFilePoller::pathsToCallbackIds_
private

Definition at line 128 of file MultiFilePoller.h.

Referenced by cancelCallback(), onFileUpdated(), and registerFiles().

wangle::FilePoller wangle::MultiFilePoller::poller_
private

Definition at line 132 of file MultiFilePoller.h.

Referenced by cancelCallback(), and registerFiles().

folly::SharedMutex wangle::MultiFilePoller::rwlock_
private

Definition at line 126 of file MultiFilePoller.h.

Referenced by cancelCallback(), onFileUpdated(), and registerFiles().


The documentation for this class was generated from the following files: