sapling/eden/fs/utils/ProcessAccessLog.h
Chad Austin b55e4dbb58 introduce a ProcessAccessLog
Summary:
Add a ProcessAccessLog that supports cheaply tracking pids passed
into FUSE. It's a write-many, read-maybe access pattern, so the code
is careful to add as little latency as possible on the hot path.

Reviewed By: strager

Differential Revision: D9477839

fbshipit-source-id: 6928c1d09d55c2b0c0958ac2cb0dc91ec21b370c
2018-09-05 15:06:58 -07:00

89 lines
2.4 KiB
C++

/*
* Copyright (c) 2018-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#pragma once
#include <folly/Synchronized.h>
#include <unistd.h>
#include <chrono>
#include "eden/fs/utils/BucketedLog.h"
namespace facebook {
namespace eden {
class ProcessNameCache;
/**
* An inexpensive mechanism for counting accesses by pids. Intended for counting
* FUSE and Thrift calls from external processes.
*
* The first time a thread calls recordAccess, that thread is then coupled to
* this particular ProcessAccessLog, even if it calls recordAccess on another
* ProcessAccessLog instance. Thus, use one ProcessAccessLog per pool of
* threads.
*/
class ProcessAccessLog {
public:
explicit ProcessAccessLog(std::shared_ptr<ProcessNameCache> processNameCache);
~ProcessAccessLog();
/**
* Records an access by a process ID. The first call to recordAccess by a
* particular thread binds that thread to this access log. Future recordAccess
* calls on that thread will accumulate within this access log.
*
* Process IDs passed to recordAccess are also inserted into the
* ProcessNameCache.
*/
void recordAccess(pid_t pid);
/**
* Returns the number of times each pid was passed to recordAccess() in
* `lastNSeconds`.
*
* Note: ProcessAccessLog buckets by whole seconds, so this number should be
* considered an approximation.
*/
std::unordered_map<pid_t, size_t> getAllAccesses(
std::chrono::seconds lastNSeconds);
private:
// Data for one second.
struct Bucket {
void clear();
/**
* Returns whether the added pid is newly observed or not in the `isNew` out
* parameter.
*/
void add(pid_t pid, bool& isNew);
void merge(const Bucket& other);
std::unordered_map<pid_t, size_t> accessCounts;
};
// Keep up to ten seconds of data, but use a power of two so BucketedLog
// generates smaller, faster code.
static constexpr uint64_t kBucketCount = 16;
using Buckets = BucketedLog<Bucket, kBucketCount>;
struct State {
Buckets buckets;
};
const std::shared_ptr<ProcessNameCache> processNameCache_;
folly::Synchronized<State> state_;
friend struct ThreadLocalBucket;
};
} // namespace eden
} // namespace facebook