Files
memgraph/src/memory/query_memory_control.hpp
2024-01-14 11:14:46 +01:00

156 lines
5.7 KiB
C++

// Copyright 2024 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 <cstddef>
#include <cstdint>
#include <thread>
#include <unordered_map>
#include "utils/memory_tracker.hpp"
#include "utils/query_memory_tracker.hpp"
#include "utils/skip_list.hpp"
namespace memgraph::memory {
static constexpr int64_t UNLIMITED_MEMORY{0};
#if USE_JEMALLOC
// Track memory allocations per query.
// Multiple threads can allocate inside one transaction.
// If user forgets to unregister tracking for that thread before it dies, it will continue to
// track allocations for that arena indefinitely.
// As multiple queries can be executed inside one transaction, one by one (multi-transaction)
// it is necessary to restart tracking at the beginning of new query for that transaction.
class QueriesMemoryControl {
public:
/*
Transaction id <-> tracker
*/
// Create new tracker for transaction_id with initial limit
void CreateTransactionIdTracker(uint64_t, size_t);
// Check if tracker for given transaction id exists
bool CheckTransactionIdTrackerExists(uint64_t);
// Remove current tracker for transaction_id
bool EraseTransactionIdTracker(uint64_t);
/*
Thread handlings
*/
// Map thread to transaction with given id
// This way we can know which thread belongs to which transaction
// and get correct tracker for given transaction
void UpdateThreadToTransactionId(const std::thread::id &, uint64_t);
// Remove tracking of thread from transaction.
// Important to reset if one thread gets reused for different transaction
void EraseThreadToTransactionId(const std::thread::id &, uint64_t);
// Find tracker for current thread if exists, track
// query allocation and procedure allocation if
// necessary
void TrackAllocOnCurrentThread(size_t size);
// Find tracker for current thread if exists, track
// query allocation and procedure allocation if
// necessary
void TrackFreeOnCurrentThread(size_t size);
void TryCreateTransactionProcTracker(uint64_t, int64_t, size_t);
void SetActiveProcIdTracker(uint64_t, int64_t);
void PauseProcedureTracking(uint64_t);
bool IsThreadTracked();
private:
struct TransactionId {
uint64_t id;
uint64_t cnt;
bool operator<(const TransactionId &other) const { return id < other.id; }
bool operator==(const TransactionId &other) const { return id == other.id; }
bool operator<(uint64_t other) const { return id < other; }
bool operator==(uint64_t other) const { return id == other; }
};
struct ThreadIdToTransactionId {
std::thread::id thread_id;
TransactionId transaction_id;
bool operator<(const ThreadIdToTransactionId &other) const { return thread_id < other.thread_id; }
bool operator==(const ThreadIdToTransactionId &other) const { return thread_id == other.thread_id; }
bool operator<(const std::thread::id other) const { return thread_id < other; }
bool operator==(const std::thread::id other) const { return thread_id == other; }
};
struct TransactionIdToTracker {
uint64_t transaction_id;
utils::QueryMemoryTracker tracker;
bool operator<(const TransactionIdToTracker &other) const { return transaction_id < other.transaction_id; }
bool operator==(const TransactionIdToTracker &other) const { return transaction_id == other.transaction_id; }
bool operator<(uint64_t other) const { return transaction_id < other; }
bool operator==(uint64_t other) const { return transaction_id == other; }
bool operator<(TransactionId other) const { return transaction_id < other.id; }
bool operator==(TransactionId other) const { return transaction_id == other.id; }
};
utils::SkipList<ThreadIdToTransactionId> thread_id_to_transaction_id;
utils::SkipList<TransactionIdToTracker> transaction_id_to_tracker;
};
inline QueriesMemoryControl &GetQueriesMemoryControl() {
static QueriesMemoryControl queries_memory_control_;
return queries_memory_control_;
}
#endif
// API function call for to start tracking current thread for given transaction.
// Does nothing if jemalloc is not enabled
void StartTrackingCurrentThreadTransaction(uint64_t transaction_id);
// API function call for to stop tracking current thread for given transaction.
// Does nothing if jemalloc is not enabled
void StopTrackingCurrentThreadTransaction(uint64_t transaction_id);
// API function call for try to create tracker for transaction and set it to given limit.
// Does nothing if jemalloc is not enabled. Does nothing if tracker already exists
void TryStartTrackingOnTransaction(uint64_t transaction_id, size_t limit);
// API function call to stop tracking for given transaction.
// Does nothing if jemalloc is not enabled. Does nothing if tracker doesn't exist
void TryStopTrackingOnTransaction(uint64_t transaction_id);
// Is transaction with given id tracked in memory tracker
bool IsTransactionTracked(uint64_t transaction_id);
// Creates tracker on procedure if doesn't exist. Sets query tracker
// to track procedure with id.
void CreateOrContinueProcedureTracking(uint64_t transaction_id, int64_t procedure_id, size_t limit);
// Pauses procedure tracking. This enables to continue
// tracking on procedure once procedure execution resumes.
void PauseProcedureTracking(uint64_t transaction_id);
} // namespace memgraph::memory