proxygen
SlidingBloomReplayCache.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
10 
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 
15 #include <fstream>
16 
17 #include <boost/chrono/duration.hpp>
18 #include <folly/Conv.h>
19 #include <folly/hash/Hash.h>
20 
22 
23 #include <cmath>
24 
25 using namespace folly::hash;
26 
27 namespace fizz {
28 namespace server {
29 const static int kBitsPerByte = 0x8;
30 const static unsigned int kBucketCount = 12;
31 const static unsigned int kHashCount = 4;
32 
33 // You can only have as many buckets as you have bits in your cell
34 static_assert(
35  kBucketCount <= sizeof(SlidingBloomReplayCache::CellType) * kBitsPerByte,
36  "Bucket count greater than cell bit count");
37 
38 /*
39  * This is largely tasked with calculating the appropriate bitSize to use given
40  * the parameters.
41  *
42  * For a given Bloom Filter, its false positive probability can be expressed as
43  *
44  * p = (1 - e^(-kn/m))^k
45  * k = number of hash functions
46  * n = number of items in the filter
47  * m = size of the filter (bitSize)
48  *
49  * n can be expanded to rps * ttl / buckets (the TTL is split into buckets, each
50  * handling ttl/bucket seconds)
51  *
52  * Solving for m:
53  * m = (k * rps * ttl) / (buckets * ln(1 - p^(1/k))
54  */
55 
56 SlidingBloomReplayCache::SlidingBloomReplayCache(
57  int64_t ttlInSecs,
58  size_t requestsPerSecond,
59  double acceptableFPR,
60  folly::EventBase* evb)
61  : folly::AsyncTimeout(evb) {
62  if (acceptableFPR <= 0.0 || acceptableFPR >= 1.0) {
63  throw std::runtime_error("false positive rate must lie between 0 and 1");
64  }
65 
66  // Do all calculations with doubles.
67  double ttlDouble = ttlInSecs;
68  double rpsDouble = requestsPerSecond;
69  double hashCountDouble = kHashCount;
70  double bucketCountDouble = kBucketCount;
71  double dividend = -hashCountDouble * rpsDouble * ttlDouble;
72  double root = pow(acceptableFPR, 1.0 / hashCountDouble);
73  double divisor = bucketCountDouble * log(1.0 - root);
74  bitSize_ = dividend / divisor;
75  VLOG(8) << "Initializing with bitSize = " << bitSize_;
76 
78  std::chrono::milliseconds(((ttlInSecs * 1000) / kBucketCount) + 1);
79 
80  // Reset bit buffer
81  bitBuf_.reset(new CellType[bitSize_]());
82 
83  // Initialize current bucket
84  currentBucket_ = 0;
85 
86  // Set up hashers
87  for (unsigned int i = 0; i < kHashCount; i++) {
88  hashers_.push_back(
89  [seed = RandomNumGenerator<uint64_t>().generateRandom()](
90  const unsigned char* buf, size_t len) -> uint64_t {
91  return SpookyHashV2::Hash64((const void*)buf, len, seed);
92  });
93  }
94 
95  // Schedule reaping function (if evb given)
96  if (evb) {
98  } else {
99  VLOG(8) << "Started replay cache without reaping";
100  }
101 }
102 
104  CellType mask = (static_cast<CellType>(1)) << currentBucket_;
105 
106  for (auto& hasher : hashers_) {
107  size_t idx = hasher(query.data(), query.size()) % bitSize_;
108 
109  bitBuf_[idx] |= mask;
110  }
111 }
112 
115 
116  for (auto& hasher : hashers_) {
117  size_t idx = hasher(query.data(), query.size()) % bitSize_;
118 
119  ret &= bitBuf_[idx];
120  }
121 
122  return (ret != 0);
123 }
124 
127  CellType mask = (static_cast<CellType>(1)) << currentBucket_;
128 
129  for (auto& hasher : hashers_) {
130  size_t idx = hasher(query.data(), query.size()) % bitSize_;
131 
132  ret &= bitBuf_[idx];
133  bitBuf_[idx] |= mask;
134  }
135 
136  return (ret != 0);
137 }
138 
140  folly::ByteRange query) {
143 }
144 
146  VLOG(8) << "Clearing bit " << bucket << ", current bucket is "
147  << currentBucket_;
148 
149  CellType mask = ~((static_cast<CellType>(1)) << bucket);
150  for (size_t i = 0; i < bitSize_; ++i) {
151  bitBuf_[i] &= mask;
152  }
153 }
154 
156  // Clear the soon to be occupied bucket
157  clearBucket((currentBucket_ + 1) % kBucketCount);
158 
159  // Increment current bucket
160  currentBucket_ = (currentBucket_ + 1) % kBucketCount;
161 }
162 
164  clear();
166 }
167 } // namespace server
168 }; // namespace fizz
static const int kBitsPerByte
LogLevel max
Definition: LogLevel.cpp:31
static const int seed
bool test(folly::ByteRange query) const
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
constexpr size_type size() const
Definition: Range.h:431
static const unsigned int kBucketCount
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
constexpr Iter data() const
Definition: Range.h:446
folly::Future< ReplayCacheResult > check(folly::ByteRange) override
Definition: Actions.h:16
bool scheduleTimeout(uint32_t milliseconds)
static const unsigned int kHashCount