1 | /* |
2 | * Copyright 2012-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 | |
17 | #pragma once |
18 | |
19 | #include <folly/SharedMutex.h> |
20 | #include <folly/stats/detail/DigestBuilder.h> |
21 | #include <folly/stats/detail/SlidingWindow.h> |
22 | |
23 | namespace folly { |
24 | namespace detail { |
25 | |
26 | /* |
27 | * BufferedStat keeps a clock and every time period, will merge data from a |
28 | * DigestBuilder into a DigestT. Updates are made by the first appender after |
29 | * the expiry, or can be made at read time by calling update(). |
30 | */ |
31 | template <typename DigestT, typename ClockT> |
32 | class BufferedStat { |
33 | public: |
34 | using TimePoint = typename ClockT::time_point; |
35 | |
36 | BufferedStat() = delete; |
37 | |
38 | BufferedStat( |
39 | typename ClockT::duration bufferDuration, |
40 | size_t bufferSize, |
41 | size_t digestSize); |
42 | |
43 | virtual ~BufferedStat() {} |
44 | |
45 | void append(double value, TimePoint now = ClockT::now()); |
46 | |
47 | void flush(); |
48 | |
49 | protected: |
50 | // https://www.mail-archive.com/llvm-bugs@lists.llvm.org/msg18280.html |
51 | // Wrap the time point in something with a noexcept constructor. |
52 | struct TimePointHolder { |
53 | public: |
54 | TimePointHolder() noexcept {} |
55 | |
56 | TimePointHolder(TimePoint t) : tp(t) {} |
57 | |
58 | TimePoint tp; |
59 | }; |
60 | |
61 | const typename ClockT::duration bufferDuration_; |
62 | std::atomic<TimePointHolder> expiry_; |
63 | SharedMutex mutex_; |
64 | |
65 | virtual void onNewDigest( |
66 | DigestT digest, |
67 | TimePoint newExpiry, |
68 | TimePoint oldExpiry, |
69 | const std::unique_lock<SharedMutex>& g) = 0; |
70 | |
71 | // Update digest if now > expiry |
72 | std::unique_lock<SharedMutex> updateIfExpired(TimePoint now); |
73 | |
74 | // Update digest unconditionally |
75 | std::unique_lock<SharedMutex> update(); |
76 | |
77 | private: |
78 | DigestBuilder<DigestT> digestBuilder_; |
79 | |
80 | // Controls how digest updates happen in doUpdate |
81 | enum class UpdateMode { |
82 | OnExpiry, |
83 | Now, |
84 | }; |
85 | |
86 | // Update digest. If updateMode == UpdateMode::Now digest is updated |
87 | // unconditionally, else digest is updated only if expiry has passed. |
88 | void doUpdate( |
89 | TimePoint now, |
90 | const std::unique_lock<SharedMutex>& g, |
91 | UpdateMode updateMode); |
92 | |
93 | TimePoint roundUp(TimePoint t); |
94 | }; |
95 | |
96 | /* |
97 | * BufferedDigest is a BufferedStat that holds data in a single digest. |
98 | */ |
99 | template <typename DigestT, typename ClockT> |
100 | class BufferedDigest : public BufferedStat<DigestT, ClockT> { |
101 | public: |
102 | using TimePoint = typename ClockT::time_point; |
103 | |
104 | BufferedDigest( |
105 | typename ClockT::duration bufferDuration, |
106 | size_t bufferSize, |
107 | size_t digestSize); |
108 | |
109 | DigestT get(TimePoint now = ClockT::now()); |
110 | |
111 | void onNewDigest( |
112 | DigestT digest, |
113 | TimePoint newExpiry, |
114 | TimePoint oldExpiry, |
115 | const std::unique_lock<SharedMutex>& g) final; |
116 | |
117 | private: |
118 | DigestT digest_; |
119 | }; |
120 | |
121 | /* |
122 | * BufferedSlidingWindow is a BufferedStat that holds data in a SlidingWindow. |
123 | * onBufferSwap will slide the SlidingWindow and return the front of the list. |
124 | */ |
125 | template <typename DigestT, typename ClockT> |
126 | class BufferedSlidingWindow : public BufferedStat<DigestT, ClockT> { |
127 | public: |
128 | using TimePoint = typename ClockT::time_point; |
129 | |
130 | BufferedSlidingWindow( |
131 | size_t nBuckets, |
132 | typename ClockT::duration bufferDuration, |
133 | size_t bufferSize, |
134 | size_t digestSize); |
135 | |
136 | std::vector<DigestT> get(TimePoint now = ClockT::now()); |
137 | |
138 | void onNewDigest( |
139 | DigestT digest, |
140 | TimePoint newExpiry, |
141 | TimePoint oldExpiry, |
142 | const std::unique_lock<SharedMutex>& g) final; |
143 | |
144 | private: |
145 | SlidingWindow<DigestT> slidingWindow_; |
146 | }; |
147 | |
148 | } // namespace detail |
149 | } // namespace folly |
150 | |