Kea 2.7.5
monitored_duration_store.cc
Go to the documentation of this file.
1// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
12
13using namespace isc;
14using namespace isc::dhcp;
15using namespace isc::util;
16using namespace boost::posix_time;
17
18namespace isc {
19namespace perfmon {
20
22 const Duration& interval_duration)
23 : family_(family),
24 interval_duration_(interval_duration),
25 durations_(),
26 mutex_(new std::mutex) {
27 if (family != AF_INET && family_ != AF_INET6) {
28 isc_throw(BadValue, "MonitoredDurationStore - invalid family "
29 << family_ << ", must be AF_INET or AF_INET6");
30 }
31
32 if (interval_duration_ <= DurationDataInterval::ZERO_DURATION()) {
33 isc_throw(BadValue, "MonitoredDurationStore - invalid interval_duration "
34 << interval_duration_ << ", must be greater than zero");
35 }
36}
37
38void
39MonitoredDurationStore::validateKey(const std::string& label, DurationKeyPtr key) const {
40 if (!key) {
41 isc_throw(BadValue, "MonitoredDurationStore::" << label << " - key is empty");
42 }
43
44 if (key->getFamily() != family_) {
45 isc_throw(BadValue, "MonitoredDurationStore::" << label
46 << " - family mismatch, key is " << (family_ == AF_INET ?
47 "v6, store is v4" : "v4, store is v6"));
48 }
49}
50
53 validateKey("addDurationSample", key);
54
55
56 MultiThreadingLock lock(*mutex_);
57 auto& index = durations_.get<DurationKeyTag>();
58 auto duration_iter = index.find(boost::make_tuple(key->getQueryType(),
59 key->getResponseType(),
60 key->getStartEventLabel(),
61 key->getStopEventLabel(),
62 key->getSubnetId()));
63
64 if (duration_iter != index.end()) {
65 bool should_report = false;
66
67 // Modify updates in place and only re-indexes if keys change.
68 bool modified = index.modify(duration_iter,
69 [sample, &should_report](MonitoredDurationPtr mond) {
70 should_report = mond->addSample(sample);
71 });
72
73 if (!modified) {
74 // Possible but unlikely.
76 "MonitoredDurationStore::addDurationSample - modify failed for: "
77 << key->getLabel());
78 }
79
80 // If it's time to report return a copy otherwise an empty pointer.
81 return (should_report ? MonitoredDurationPtr(new MonitoredDuration(**duration_iter))
83 }
84
85 // It doesn't exist, add it.
86 MonitoredDurationPtr mond(new MonitoredDuration(*key, interval_duration_));
87 static_cast<void>(mond->addSample(sample));
88 auto ret = durations_.insert(mond);
89 if (ret.second == false) {
90 // Shouldn't be possible.
92 "MonitoredDurationStore::addDurationSample: duration already exists for: "
93 << mond->getLabel());
94 }
95
96 // Nothing to report.
97 return (MonitoredDurationPtr());
98}
99
102 validateKey("addDuration", key);
103
104 // Create the duration instance.
106 try {
107 mond.reset(new MonitoredDuration(*key, interval_duration_));
108 } catch (const std::exception& ex) {
109 isc_throw(BadValue, "MonitoredDurationStore::addDuration failed: " << ex.what());
110 }
111
112 // Now lock and insert the new duration.
113 {
114 MultiThreadingLock lock(*mutex_);
115 auto ret = durations_.insert(mond);
116 if (ret.second == false) {
118 "MonitoredDurationStore::addDuration: duration already exists for: "
119 << mond->getLabel());
120 }
121 }
122
123 // Return a copy of what we inserted.
124 return (MonitoredDurationPtr(new MonitoredDuration(*mond)));
125}
126
127
130 validateKey("getDuration", key);
131
132 MultiThreadingLock lock(*mutex_);
133 const auto& index = durations_.get<DurationKeyTag>();
134 auto duration_iter = index.find(boost::make_tuple(key->getQueryType(),
135 key->getResponseType(),
136 key->getStartEventLabel(),
137 key->getStopEventLabel(),
138 key->getSubnetId()));
139
140 return (duration_iter == index.end() ? MonitoredDurationPtr()
141 : MonitoredDurationPtr(new MonitoredDuration(**duration_iter)));
142}
143
144void
146 validateKey("updateDuration", duration);
147
148 MultiThreadingLock lock(*mutex_);
149 auto& index = durations_.get<DurationKeyTag>();
150 auto duration_iter = index.find(boost::make_tuple(duration->getQueryType(),
151 duration->getResponseType(),
152 duration->getStartEventLabel(),
153 duration->getStopEventLabel(),
154 duration->getSubnetId()));
155
156 if (duration_iter == index.end()) {
157 isc_throw(InvalidOperation, "MonitoredDurationStore::updateDuration duration not found: "
158 << duration->getLabel());
159 }
160
161 // Use replace() which only re-indexes if keys change.
162 index.replace(duration_iter, MonitoredDurationPtr(new MonitoredDuration(*duration)));
163}
164
165void
167 validateKey("deleteDuration", key);
168
169 MultiThreadingLock lock(*mutex_);
170 auto& index = durations_.get<DurationKeyTag>();
171 auto duration_iter = index.find(boost::make_tuple(key->getQueryType(),
172 key->getResponseType(),
173 key->getStartEventLabel(),
174 key->getStopEventLabel(),
175 key->getSubnetId()));
176
177 if (duration_iter == index.end()) {
178 // Not there, just return.
179 return;
180 }
181
182 // Remove the duration from the store.
183 durations_.erase(duration_iter);
184}
185
188 MultiThreadingLock lock(*mutex_);
189 const auto& index = durations_.get<DurationKeyTag>();
191 for (auto const& mond : index) {
192 collection->push_back(MonitoredDurationPtr(new MonitoredDuration(*mond)));
193 }
194
195 return (collection);
196}
197
198void
200 MultiThreadingLock lock(*mutex_);
201 durations_.clear();
202}
203
206 MultiThreadingLock lock(*mutex_);
207 const auto& index = durations_.get<IntervalStartTag>();
208 // We want to find the oldest interval that is less than interval_duration in the past.
209 auto duration_iter = index.lower_bound(dhcp::PktEvent::now() - interval_duration_);
210 return (duration_iter == index.end() ? MonitoredDurationPtr()
211 : MonitoredDurationPtr(new MonitoredDuration(**duration_iter)));
212}
213
215MonitoredDurationStore::getOverdueReports(const Timestamp& since /* = PktEvent::now() */) {
216 MultiThreadingLock lock(*mutex_);
217 // We use a lower bound of MIN + 1us to avoid dormant durations
218 static Timestamp lower_limit_time(PktEvent::MIN_TIME() + microseconds(1));
219
220 // We want to find anything since the start of time who's start time
221 // is more than interval_duration_ in the past.
222 const auto& index = durations_.get<IntervalStartTag>();
223 auto lower_limit = index.lower_bound(lower_limit_time);
224 auto upper_limit = index.upper_bound(since - interval_duration_);
225
227 for (auto duration_iter = lower_limit; duration_iter != upper_limit; ++duration_iter) {
228 collection->push_back(MonitoredDurationPtr(new MonitoredDuration(**duration_iter)));
229 }
230
231 return (collection);
232}
233
234} // end of namespace perfmon
235} // end of namespace isc
236
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown when an unexpected error condition occurs.
static boost::posix_time::ptime now()
Fetch the current UTC system time, microsecond precision.
Definition pkt.h:117
static boost::posix_time::ptime & MIN_TIME()
Fetches the minimum timestamp.
Definition pkt.h:132
Exception thrown when an attempt was made to add a duplicate duration to the store.
static const Duration & ZERO_DURATION()
Get a duration of zero.
MonitoredDurationCollectionPtr getOverdueReports(const Timestamp &since=dhcp::PktEvent::now())
Fetches all durations that are overdue to report.
void deleteDuration(DurationKeyPtr key)
Removes the duration from the store.
MonitoredDurationPtr addDuration(DurationKeyPtr key)
Creates a new duration and adds it to the store.
MonitoredDurationStore(uint16_t family, const Duration &interval_duration)
Constructor.
MonitoredDurationCollectionPtr getAll()
Fetches all of the durations (in order by target)
void clear()
Removes all durations from the store.
MonitoredDurationPtr getReportsNext()
Fetches the duration which is due to report next.
MonitoredDurationPtr getDuration(DurationKeyPtr key)
Fetches a duration from the store for a given key.
MonitoredDurationPtr addDurationSample(DurationKeyPtr key, const Duration &sample)
Adds a sample to a duration in-place.
void updateDuration(MonitoredDurationPtr &duration)
Updates a duration in the store.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::posix_time::time_duration Duration
boost::shared_ptr< MonitoredDurationCollection > MonitoredDurationCollectionPtr
Type for a pointer to a collection of MonitoredDurationPtrs.
boost::shared_ptr< DurationKey > DurationKeyPtr
Defines a pointer to a DurationKey instance.
boost::posix_time::ptime Timestamp
boost::shared_ptr< MonitoredDuration > MonitoredDurationPtr
std::vector< MonitoredDurationPtr > MonitoredDurationCollection
Type for a collection of MonitoredDurationPtrs.
Defines the logger used by the top-level component of kea-lfc.
Tag for index by primary key (DurationKey).
Tag for index by interval start time.
RAII lock object to protect the code in the same scope with a mutex.