mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-04-22 04:07:12 +02:00
162 lines
4.5 KiB
C++
162 lines
4.5 KiB
C++
/************************************************************************************
|
|
*
|
|
* D++, A Lightweight C++ library for Discord
|
|
*
|
|
* Copyright 2021 Craig Edwards and D++ contributors
|
|
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
************************************************************************************/
|
|
#include <dpp/discord.h>
|
|
#include <mutex>
|
|
#include <iostream>
|
|
#include <variant>
|
|
#include <dpp/cache.h>
|
|
#include <dpp/guild.h>
|
|
|
|
namespace dpp {
|
|
|
|
std::unordered_map<managed*, time_t> deletion_queue;
|
|
std::mutex deletion_mutex;
|
|
|
|
#define cache_helper(type, cache_name, setter, getter, counter) \
|
|
cache* cache_name = nullptr; \
|
|
type * setter (snowflake id) { \
|
|
return cache_name ? ( type * ) cache_name ->find(id) : nullptr; \
|
|
} \
|
|
cache* getter () { \
|
|
if (! cache_name ) { \
|
|
cache_name = new cache(); \
|
|
} \
|
|
return cache_name ; \
|
|
} \
|
|
uint64_t counter () { \
|
|
return ( cache_name ? cache_name ->count() : 0 ); \
|
|
}
|
|
|
|
|
|
/* Because other threads and systems may run for a short while after an event is received, we don't immediately
|
|
* delete pointers when objects are replaced. We put them into a queue, and periodically delete pointers in the
|
|
* queue. This also rehashes unordered_maps to ensure they free their memory.
|
|
*/
|
|
void garbage_collection() {
|
|
time_t now = time(NULL);
|
|
bool repeat = false;
|
|
{
|
|
std::lock_guard<std::mutex> delete_lock(deletion_mutex);
|
|
do {
|
|
repeat = false;
|
|
for (auto g = deletion_queue.begin(); g != deletion_queue.end(); ++g) {
|
|
if (now > g->second + 60) {
|
|
delete g->first;
|
|
deletion_queue.erase(g);
|
|
repeat = true;
|
|
break;
|
|
}
|
|
}
|
|
} while (repeat);
|
|
if (deletion_queue.size() == 0) {
|
|
deletion_queue = {};
|
|
}
|
|
}
|
|
dpp::get_user_cache()->rehash();
|
|
dpp::get_channel_cache()->rehash();
|
|
dpp::get_guild_cache()->rehash();
|
|
dpp::get_role_cache()->rehash();
|
|
dpp::get_emoji_cache()->rehash();
|
|
}
|
|
|
|
cache::cache() {
|
|
cache_map = new cache_container();
|
|
}
|
|
|
|
cache::~cache() {
|
|
delete cache_map;
|
|
}
|
|
|
|
uint64_t cache::count() {
|
|
std::lock_guard<std::mutex> lock(this->cache_mutex);
|
|
return cache_map->size();
|
|
}
|
|
|
|
std::mutex& cache::get_mutex() {
|
|
return this->cache_mutex;
|
|
}
|
|
|
|
cache_container& cache::get_container() {
|
|
return *(this->cache_map);
|
|
}
|
|
|
|
void cache::store(managed* object) {
|
|
if (!object) {
|
|
return;
|
|
}
|
|
std::lock_guard<std::mutex> lock(this->cache_mutex);
|
|
auto existing = cache_map->find(object->id);
|
|
if (existing == cache_map->end()) {
|
|
(*cache_map)[object->id] = object;
|
|
} else if (object != existing->second) {
|
|
/* Flag old pointer for deletion and replace */
|
|
std::lock_guard<std::mutex> delete_lock(deletion_mutex);
|
|
deletion_queue[existing->second] = time(NULL);
|
|
(*cache_map)[object->id] = object;
|
|
}
|
|
}
|
|
|
|
size_t cache::bytes() {
|
|
std::lock_guard<std::mutex> lock(cache_mutex);
|
|
return sizeof(this) + (cache_map->bucket_count() * sizeof(size_t));
|
|
}
|
|
|
|
void cache::rehash() {
|
|
std::lock_guard<std::mutex> lock(cache_mutex);
|
|
cache_container* n = new cache_container();
|
|
n->reserve(cache_map->size());
|
|
for (auto t = cache_map->begin(); t != cache_map->end(); ++t) {
|
|
n->insert(*t);
|
|
}
|
|
delete cache_map;
|
|
cache_map = n;
|
|
}
|
|
|
|
void cache::remove(managed* object) {
|
|
if (!object) {
|
|
return;
|
|
}
|
|
std::lock_guard<std::mutex> lock(cache_mutex);
|
|
std::lock_guard<std::mutex> delete_lock(deletion_mutex);
|
|
auto existing = cache_map->find(object->id);
|
|
if (existing != cache_map->end()) {
|
|
cache_map->erase(existing);
|
|
deletion_queue[object] = time(NULL);
|
|
}
|
|
}
|
|
|
|
managed* cache::find(snowflake id) {
|
|
std::lock_guard<std::mutex> lock(cache_mutex);
|
|
auto r = cache_map->find(id);
|
|
if (r != cache_map->end()) {
|
|
return r->second;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
cache_helper(user, user_cache, find_user, get_user_cache, get_user_count);
|
|
cache_helper(channel, channel_cache, find_channel, get_channel_cache, get_channel_count);
|
|
cache_helper(role, role_cache, find_role, get_role_cache, get_role_count);
|
|
cache_helper(guild, guild_cache, find_guild, get_guild_cache, get_guild_count);
|
|
cache_helper(emoji, emoji_cache, find_emoji, get_emoji_cache, get_emoji_count);
|
|
|
|
};
|