memgraph/src/utils/memory_tracker.hpp
2022-03-14 15:47:41 +01:00

102 lines
3.5 KiB
C++

// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#pragma once
#include <atomic>
#include "utils/exceptions.hpp"
namespace memgraph::utils {
class OutOfMemoryException : public utils::BasicException {
public:
explicit OutOfMemoryException(const std::string &msg) : utils::BasicException(msg) {}
};
class MemoryTracker final {
private:
std::atomic<int64_t> amount_{0};
std::atomic<int64_t> peak_{0};
std::atomic<int64_t> hard_limit_{0};
// Maximum possible value of a hard limit. If it's set to 0, no upper bound on the hard limit is set.
int64_t maximum_hard_limit_{0};
void UpdatePeak(int64_t will_be);
static void LogMemoryUsage(int64_t current);
public:
void LogPeakMemoryUsage() const;
MemoryTracker() = default;
~MemoryTracker() = default;
MemoryTracker(const MemoryTracker &) = delete;
MemoryTracker &operator=(const MemoryTracker &) = delete;
MemoryTracker(MemoryTracker &&) = delete;
MemoryTracker &operator=(MemoryTracker &&) = delete;
void Alloc(int64_t size);
void Free(int64_t size);
auto Amount() const { return amount_.load(std::memory_order_relaxed); }
auto Peak() const { return peak_.load(std::memory_order_relaxed); }
auto HardLimit() const { return hard_limit_.load(std::memory_order_relaxed); }
void SetHardLimit(int64_t limit);
void TryRaiseHardLimit(int64_t limit);
void SetMaximumHardLimit(int64_t limit);
// By creating an object of this class, every allocation in its scope that goes over
// the set hard limit produces an OutOfMemoryException.
class OutOfMemoryExceptionEnabler final {
public:
OutOfMemoryExceptionEnabler(const OutOfMemoryExceptionEnabler &) = delete;
OutOfMemoryExceptionEnabler &operator=(const OutOfMemoryExceptionEnabler &) = delete;
OutOfMemoryExceptionEnabler(OutOfMemoryExceptionEnabler &&) = delete;
OutOfMemoryExceptionEnabler &operator=(OutOfMemoryExceptionEnabler &&) = delete;
OutOfMemoryExceptionEnabler();
~OutOfMemoryExceptionEnabler();
static bool CanThrow();
private:
static thread_local uint64_t counter_;
};
// By creating an object of this class, we negate the effect of every OutOfMemoryExceptionEnabler
// object. We need this object so we can guard only the smaller parts of code from exceptions while
// allowing the exception in the other parts if the OutOfMemoryExceptionEnabler is defined.
class OutOfMemoryExceptionBlocker final {
public:
OutOfMemoryExceptionBlocker(const OutOfMemoryExceptionBlocker &) = delete;
OutOfMemoryExceptionBlocker &operator=(const OutOfMemoryExceptionBlocker &) = delete;
OutOfMemoryExceptionBlocker(OutOfMemoryExceptionBlocker &&) = delete;
OutOfMemoryExceptionBlocker &operator=(OutOfMemoryExceptionBlocker &&) = delete;
OutOfMemoryExceptionBlocker();
~OutOfMemoryExceptionBlocker();
static bool IsBlocked();
private:
static thread_local uint64_t counter_;
};
};
// Global memory tracker which tracks every allocation in the application.
extern MemoryTracker total_memory_tracker;
} // namespace memgraph::utils