1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <config.h>

#include <exceptions/exceptions.h>
#include <alarm_store.h><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <util/multi_threading_mgr.h>

using namespace isc;
using namespace isc::util;

namespace isc {
namespace perfmon {

AlarmStore::AlarmStore(uint16_t family)
    : family_(family),
      alarms_(),
      mutex_(new std::mutex) {
    if (family_ != AF_INET && family_ != AF_INET6) {
        isc_throw(BadValue, "AlarmStore - invalid family "
                            << family_ << ", must be AF_INET or AF_INET6");
    }
}

void
AlarmStore::validateKey(const std::string& label, DurationKeyPtr key) const {
    if (!key) {
        isc_throw(BadValue, "AlarmStore::" << label << " - key is empty");
    }

    if (key->getFamily() != family_) {
        isc_throw(BadValue, "AlarmStore::" << label
                            << " - family mismatch, key is " << (family_ == AF_INET ?
                            "v6, store is v4" : "v4, store is v6"));
    }
}

AlarmPtr
AlarmStore::checkDurationSample(DurationKeyPtr key, const Duration& sample,
                                const Duration& report_interval) {
    validateKey("checkDurationSample", key);

    MultiThreadingLock lock(*mutex_);
    auto& index = alarms_.get<AlarmPrimaryKeyTag>();
    auto alarm_iter = index.find(*key);

    // If we find an alarm then we check the sample.  Alarm::checkSample()
    // does not alter the key so it can be done in-place.
    if (alarm_iter != index.end()) {
        bool should_report = false;
        bool modified = index.modify(alarm_iter,
                                     [sample, report_interval, &should_report](AlarmPtr alarm) {
            should_report = alarm->checkSample(sample, report_interval);
        });

        if (!modified) {
            // Possible but unlikely.
            isc_throw(Unexpected, "AlarmStore::checkDurationSample - modify failed for: " << key->getLabel());
        }

        if (should_report) {
            // Alarm state needs to be reported, return a copy of the alarm.
            return (AlarmPtr(new Alarm(**alarm_iter)));
        }
    }

    // Nothing to alarm.
    return (AlarmPtr());
}

AlarmPtr
AlarmStore::addAlarm(AlarmPtr alarm) {
    MultiThreadingLock lock(*mutex_);
    auto ret = alarms_.insert(alarm);
    if (ret.second == false) {
        isc_throw(DuplicateAlarm, "AlarmStore::addAlarm: alarm already exists for: "
                  << alarm->getLabel());
    }

    // Return a copy of what we inserted.
    return (AlarmPtr(new Alarm(*alarm)));
}

AlarmPtr
AlarmStore::addAlarm(DurationKeyPtr key, const Duration& low_water,
                     const Duration& high_water, bool enabled /* = true */) {
    validateKey("addAlarm", key);

    // Create the alarm instance.
    AlarmPtr alarm;
    try {
        alarm.reset(new Alarm(*key, low_water, high_water, enabled));
    } catch (const std::exception& ex) {
        isc_throw(BadValue, "AlarmStore::addAlarm failed: " << ex.what());
    }

    return (addAlarm(alarm));
}

AlarmPtr
AlarmStore::getAlarm(DurationKeyPtr key) {
    validateKey("getAlarm", key);

    MultiThreadingLock lock(*mutex_);
    const auto& index = alarms_.get<AlarmPrimaryKeyTag>();
    auto alarm_iter = index.find(*key);
    return (alarm_iter == index.end() ? AlarmPtr()
            : AlarmPtr(new Alarm(**alarm_iter)));
}

void
AlarmStore::updateAlarm(AlarmPtr& alarm) {
    validateKey("updateAlarm", alarm);

    MultiThreadingLock lock(*mutex_);
    auto& index = alarms_.get<AlarmPrimaryKeyTag>();
    auto alarm_iter = index.find(*alarm);
    if (alarm_iter == index.end()) {
        isc_throw(InvalidOperation, "AlarmStore::updateAlarm alarm not found: "
                  << alarm->getLabel());
    }

    // Use replace() which only re-indexes if keys change.
    index.replace(alarm_iter, AlarmPtr(new Alarm(*alarm)));
}

void
AlarmStore::deleteAlarm(DurationKeyPtr key) {
    validateKey("deleteAlarm", key);

    MultiThreadingLock lock(*mutex_);
    auto& index = alarms_.get<AlarmPrimaryKeyTag>();
    auto alarm_iter = index.find(*key);
    if (alarm_iter == index.end()) {
        // Not there, just return.
        return;
    }

    // Remove the alarm from the store.
    alarms_.erase(alarm_iter);
}

AlarmCollectionPtr
AlarmStore::getAll() {
    MultiThreadingLock lock(*mutex_);
    const auto& index = alarms_.get<AlarmPrimaryKeyTag>();
    AlarmCollectionPtr collection(new AlarmCollection());
    for (auto const& alarm : index) {
        collection->push_back(AlarmPtr(new Alarm(*alarm)));
    }

    return (collection);
}

void
AlarmStore::clear() {
    MultiThreadingLock lock(*mutex_);
    alarms_.clear();
}

} // end of namespace perfmon
} // end of namespace isc