Initial rework of internal management for overflowing errors
parent
33ad0c1967
commit
cb6f88c6bb
|
|
@ -63,26 +63,22 @@ size_t ErrorManager::count_internal(ErrorFilter filter) const {
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool ErrorManager::beforeAddCheck(APIError::ErrorType type) {
|
||||
if(enforceLimit()) { // The enforceLimit will add the "TooManyErrors" error for us if necessary
|
||||
// We need to decide whether to add this error or drop it
|
||||
// We would have to remove something if we added this error
|
||||
if(APIError::SeverityForType(type) < lowestCurrentSeverity())
|
||||
return false; // Don't add this one, we are already full of higher priority items
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures errors is always at most errorLimit - 1 in size.
|
||||
* Returns true if any errors were removed in the process of doing so.
|
||||
*/
|
||||
bool ErrorManager::enforceLimit() {
|
||||
if(errors.size() + 1 < errorLimit)
|
||||
return false;
|
||||
// Remove all TooManyErrors before checking
|
||||
errors.remove_if([](icsneo::APIError err){ return err.getType == icsneo::APIError::TooManyErrors; });
|
||||
|
||||
bool hasTooManyWarningAlready = count_internal(ErrorFilter(APIError::TooManyErrors)) != 0;
|
||||
size_t amountToRemove = (errors.size() + (hasTooManyWarningAlready ? 1 : 2)) - errorLimit;
|
||||
// We are not overflowing
|
||||
if(errors.size() < errorLimit)
|
||||
return false;
|
||||
|
||||
size_t amountToRemove = errors.size() + 1 - errorLimit;
|
||||
|
||||
discardLeastSevere(amountToRemove);
|
||||
if(!hasTooManyWarningAlready)
|
||||
errors.emplace_back(APIError::TooManyErrors);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +100,7 @@ void ErrorManager::discardLeastSevere(size_t count) {
|
|||
if(count == 0)
|
||||
return;
|
||||
|
||||
// Erase needed Info level errors, starting from the beginning
|
||||
ErrorFilter infoFilter(APIError::Severity::Info);
|
||||
auto it = errors.begin();
|
||||
while(it != errors.end()) {
|
||||
|
|
@ -116,6 +113,7 @@ void ErrorManager::discardLeastSevere(size_t count) {
|
|||
}
|
||||
}
|
||||
|
||||
// Erase needed Warning level errors, starting from the beginning
|
||||
if(count != 0) {
|
||||
ErrorFilter warningFilter(APIError::Severity::Warning);
|
||||
it = errors.begin();
|
||||
|
|
@ -130,6 +128,7 @@ void ErrorManager::discardLeastSevere(size_t count) {
|
|||
}
|
||||
}
|
||||
|
||||
// Erase needed Error level errors, starting from the beginning
|
||||
if(count != 0) {
|
||||
ErrorFilter errorFilter(APIError::Severity::Error);
|
||||
it = errors.begin();
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ public:
|
|||
void discard(ErrorFilter filter = ErrorFilter());
|
||||
|
||||
void setErrorLimit(size_t newLimit) {
|
||||
if(newLimit == errorLimit)
|
||||
return;
|
||||
|
||||
if(newLimit < 10) {
|
||||
add(APIError::ParameterOutOfRange);
|
||||
return;
|
||||
|
|
@ -53,39 +56,76 @@ public:
|
|||
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
errorLimit = newLimit;
|
||||
enforceLimit();
|
||||
if(enforceLimit())
|
||||
add(APIError::TooManyErrors);
|
||||
}
|
||||
|
||||
size_t getErrorLimit() const { return errorLimit; }
|
||||
|
||||
private:
|
||||
ErrorManager() {}
|
||||
// Used by functions for threadsafety
|
||||
mutable std::mutex mutex;
|
||||
|
||||
// Stores all errors
|
||||
std::list<APIError> errors;
|
||||
size_t errorLimit = 10000;
|
||||
|
||||
size_t count_internal(ErrorFilter filter = ErrorFilter()) const;
|
||||
|
||||
// If errors is not full, add the error at the end
|
||||
// Otherwise, remove the least significant errors, push the error to the back and push a APIError::TooManyErrors to the back (in that order)
|
||||
void add_internal(APIError error) {
|
||||
if(!beforeAddCheck(error.getType()))
|
||||
return;
|
||||
errors.push_back(error);
|
||||
// Ensure the error list is at most exactly full (size of errorLimit - 1, leaving room for a potential APIError::TooManyErrors)
|
||||
enforceLimit();
|
||||
|
||||
// We are exactly full, either because the list was truncated or because we were simply full before
|
||||
if(errors.size() == errorLimit - 1) {
|
||||
// If the error is worth adding
|
||||
if(APIError::SeverityForType(error.getType()) >= lowestCurrentSeverity()) {
|
||||
discardLeastSevere(1);
|
||||
errors.push_back(error);
|
||||
}
|
||||
|
||||
errors.push_back(APIError(APIError::TooManyErrors));
|
||||
} else {
|
||||
errors.push_back(error);
|
||||
}
|
||||
}
|
||||
void add_internal(APIError::ErrorType type) {
|
||||
if(!beforeAddCheck(type))
|
||||
return;
|
||||
errors.emplace_back(type);
|
||||
// Ensure the error list is at most exactly full (size of errorLimit - 1, leaving room for a potential APIError::TooManyErrors)
|
||||
enforceLimit();
|
||||
|
||||
// We are exactly full, either because the list was truncated or because we were simply full before
|
||||
if(errors.size() == errorLimit - 1) {
|
||||
// If the error is worth adding
|
||||
if(APIError::SeverityForType(type) >= lowestCurrentSeverity()) {
|
||||
discardLeastSevere(1);
|
||||
errors.emplace_back(type);
|
||||
}
|
||||
|
||||
errors.push_back(APIError(APIError::TooManyErrors));
|
||||
} else {
|
||||
errors.emplace_back(type);
|
||||
}
|
||||
}
|
||||
void add_internal(APIError::ErrorType type, const Device* forDevice) {
|
||||
if(!beforeAddCheck(type))
|
||||
return;
|
||||
errors.emplace_back(type, forDevice);
|
||||
// Ensure the error list is at most exactly full (size of errorLimit - 1, leaving room for a potential APIError::TooManyErrors)
|
||||
enforceLimit();
|
||||
}
|
||||
|
||||
bool beforeAddCheck(APIError::ErrorType type); // Returns whether the error should be added
|
||||
// We are exactly full, either because the list was truncated or because we were simply full before
|
||||
if(errors.size() == errorLimit - 1) {
|
||||
// If the error is worth adding
|
||||
if(APIError::SeverityForType(type) >= lowestCurrentSeverity()) {
|
||||
discardLeastSevere(1);
|
||||
errors.emplace_back(type);
|
||||
}
|
||||
|
||||
errors.push_back(APIError(APIError::TooManyErrors));
|
||||
} else {
|
||||
errors.emplace_back(type, forDevice);
|
||||
}
|
||||
}
|
||||
|
||||
bool enforceLimit(); // Returns whether the limit enforcement resulted in an overflow
|
||||
|
||||
|
|
|
|||
|
|
@ -617,7 +617,7 @@ extern void DLLExport icsneo_discardDeviceErrors(const neodevice_t* device);
|
|||
|
||||
/**
|
||||
* \brief Set the number of errors which will be held in the API managed buffer before icsneo::APIError::TooManyErrors
|
||||
* \param[in] newLimit The new limit. Must be >10.
|
||||
* \param[in] newLimit The new limit. Must be >10. 1 error slot is always reserved for a potential icsneo::APIError::TooManyErrors, so (newLimit - 1) other errors can be stored.
|
||||
*
|
||||
* If the error limit is reached, an icsneo::APIError::TooManyErrors will be flagged.
|
||||
*
|
||||
|
|
@ -628,10 +628,8 @@ extern void DLLExport icsneo_discardDeviceErrors(const neodevice_t* device);
|
|||
extern void DLLExport icsneo_setErrorLimit(size_t newLimit);
|
||||
|
||||
/**
|
||||
* \brief Set the number of errors which will be held in the API managed buffer before icsneo::APIError::TooManyErrors
|
||||
* \brief Get the number of errors which can be held in the API managed buffer
|
||||
* \returns The current limit.
|
||||
*
|
||||
* If the error limit is reached, an icsneo::APIError::TooManyErrors will be flagged.
|
||||
*/
|
||||
extern size_t DLLExport icsneo_getErrorLimit(void);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue