1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
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 <fb303/ServiceData.h>
20 #include <fb303/detail/QuantileStatWrappers.h>
21 #include <folly/synchronization/Hazptr.h>
22
23 namespace facebook::fb303::detail {
24
25 template <size_t N>
26 class DynamicQuantileStatWrapper<N>::MapHolder
27 : public folly::hazptr_obj_base<DynamicQuantileStatWrapper<N>::MapHolder> {
28 public:
29 std::unordered_map<
30 DynamicQuantileStatWrapper<N>::SubkeyArray,
31 std::shared_ptr<QuantileStat>,
32 DynamicQuantileStatWrapper<N>::SubkeyArrayHash>
33 map;
34 };
35
36 template <size_t N>
DynamicQuantileStatWrapper(std::string keyFormat,folly::Range<const ExportType * > stats,folly::Range<const double * > quantiles,folly::Range<const size_t * > timeseriesLengths)37 DynamicQuantileStatWrapper<N>::DynamicQuantileStatWrapper(
38 std::string keyFormat,
39 folly::Range<const ExportType*> stats,
40 folly::Range<const double*> quantiles,
41 folly::Range<const size_t*> timeseriesLengths)
42 : format_(std::move(keyFormat)), stats_(new MapHolder()) {
43 spec_.stats.insert(spec_.stats.end(), stats.begin(), stats.end());
44 spec_.quantiles.insert(
45 spec_.quantiles.end(), quantiles.begin(), quantiles.end());
46 spec_.timeseriesLengths.insert(
47 spec_.timeseriesLengths.end(),
48 timeseriesLengths.begin(),
49 timeseriesLengths.end());
50 }
51
52 template <size_t N>
53 template <typename... Args>
addValue(double value,std::chrono::steady_clock::time_point now,Args &&...subkeys)54 void DynamicQuantileStatWrapper<N>::addValue(
55 double value,
56 std::chrono::steady_clock::time_point now,
57 Args&&... subkeys) {
58 const SubkeyArray subkeyArray{{std::forward<Args>(subkeys)...}};
59
60 folly::hazptr_holder<> h = folly::make_hazard_pointer<>();
61 auto mapPtr = h.protect(stats_);
62
63 auto it = mapPtr->map.find(subkeyArray);
64 if (it != mapPtr->map.end()) {
65 it->second->addValue(value, now);
66 return;
67 }
68
69 auto key = folly::svformat(format_, SubkeyArray(subkeyArray));
70 auto stat = ServiceData::get()->getQuantileStat(
71 key, spec_.stats, spec_.quantiles, spec_.timeseriesLengths);
72
73 MapHolder* newMap = nullptr;
74 do {
75 if (newMap) {
76 delete newMap;
77 }
78 mapPtr = h.protect(stats_);
79 newMap = new MapHolder(*mapPtr);
80 newMap->map[subkeyArray] = stat;
81 } while (
82 !stats_.compare_exchange_weak(mapPtr, newMap, std::memory_order_acq_rel));
83 h.reset_protection();
84 mapPtr->retire();
85 stat->addValue(value, now);
86 }
87
88 template <size_t N>
89 template <typename... Args>
addValue(double value,Args &&...subkeys)90 void DynamicQuantileStatWrapper<N>::addValue(double value, Args&&... subkeys) {
91 addValue(
92 value, std::chrono::steady_clock::now(), std::forward<Args>(subkeys)...);
93 }
94
95 } // namespace facebook::fb303::detail
96