Как эффективно выпустить ресурсендад? [закрыто]C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Как эффективно выпустить ресурсендад? [закрыто]

Сообщение Anonymous »

Код: Выделить всё

#pragma once

#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct OperationContext {
std::string operation_id;
EventData conflict_info;
};

class ResourceTracker {
public:
ResourceTracker() = default;
~ResourceTracker() = default;

std::pair CheckOverlap(const std::string& resource_name);

Result AddActiveRecord(const std::string& resource_name, const OperationContext& context);

Result RemoveActiveRecord(const std::string& resource_name);

private:
std::shared_mutex lock_;
std::unordered_map active_records_;
};

class ResourceNode {
public:
explicit ResourceNode(uint32_t depth);
~ResourceNode() = default;

std::pair CheckOverlap(const std::vector& path_components);

Result AddActiveRecord(const std::vector& path_components,
const OperationContext& context);

Result RemoveActiveRecord(const std::vector& path_components);

bool HasActiveRecordsUnsafe() const;

bool TryRemoveChildNode(const std::string& name);

private:
uint32_t GetBucketIndex(const std::string& resource_name);

uint32_t depth_;
std::atomic active_bucket_count_{0};
std::vector buckets_;
std::shared_mutex lock_;
std::unordered_map sub_nodes_;
};

class ResourceManager {
public:
ResourceManager(std::string prefix_type1, std::string prefix_type2);

std::pair CheckOverlap(const std::string& resource_path);

Result RegisterNewOperation(const std::shared_ptr& operation);

Result CompleteOperation(const OperationInfo& operation);

std::vector ParseResourcePath(const std::string& resource_path);

private:
std::string prefix_type1_;
std::string prefix_type2_;
std::shared_ptr root_node_;
};

uint32_t ResourceNode::GetBucketIndex(const std::string& resource_name) {
return std::hash{}(resource_name.at(0)) % CONFIG_RESOURCE_BUCKETS_NUM;
}

std::pair ResourceTracker::CheckOverlap(const std::string& resource_name) {
std::shared_lock guard(lock_);
auto itr = active_records_.find(resource_name);
if (itr == active_records_.end()) {
return {false, {}};
}
return {true, itr->second};
}

Result ResourceTracker::RemoveActiveRecord(const std::string& resource_name) {
std::unique_lock guard(lock_);
auto itr = active_records_.find(resource_name);
if (itr == active_records_.end()) {
return ERROR_NOT_FOUND;
}
active_records_.erase(itr);
return active_records_.empty();
}

Result ResourceTracker::AddActiveRecord(const std::string& resource_name,
const OperationContext& context) {
std::unique_lock guard(lock_);
bool empty_before_insert = active_records_.empty();
auto itr = active_records_.find(resource_name);
if (itr != active_records_.end() && itr->second.operation_id != context.operation_id) {

return ERROR_ALREADY_EXISTS;
}
if (itr == active_records_.end()) {
active_records_.emplace(resource_name, context);
}
return empty_before_insert;
}

ResourceNode::ResourceNode(uint32_t depth) : depth_(depth) {
for (int i = 0; i < CONFIG_RESOURCE_BUCKETS_NUM; ++i) {
buckets_.emplace_back(std::make_shared());
}
}

std::pair ResourceNode::CheckOverlap(
const std::vector& path_components) {
auto max_depth = path_components.size() - 1;
CHECK_GE(max_depth, depth_);
if (max_depth > depth_) {
std::shared_ptr  child_node;
{
std::shared_lock guard(lock_);
auto itr = sub_nodes_.find(path_components[depth_]);
if (itr == sub_nodes_.end()) {
return {};
}
child_node = itr->second;
}
return child_node->CheckOverlap(path_components);
}
// max_depth == depth_
auto bucket_index = GetBucketIndex(path_components[depth_]);
return buckets_[bucket_index]->CheckOverlap(path_components[depth_]);
}

Result ResourceNode::AddActiveRecord(const std::vector& path_components,
const OperationContext& context) {
if (path_components.empty()) {
return ERROR_INVALID_ARGUMENT;
}

auto max_depth = path_components.size() - 1;
CHECK_GE(max_depth, depth_);
if (max_depth > depth_) {
std::shared_ptr child_node;
{
std::unique_lock guard(lock_);
auto itr = sub_nodes_.find(path_components[depth_]);
if (itr == sub_nodes_.end()) {
auto ret = sub_nodes_.emplace(path_components[depth_],
std::make_shared(depth_ + 1));
CHECK(ret.second);
child_node = ret.first->second;
} else {
child_node = itr->second;
}
}
return child_node->AddActiveRecord(path_components, context);
}

// max_depth == depth_
uint32_t bucket_index = GetBucketIndex(path_components[depth_]);
auto add_ret = buckets_[bucket_index]->AddActiveRecord(path_components[depth_], context);
if (add_ret.IsOk() && add_ret.Get()) {
active_bucket_count_.fetch_add(1, std::memory_order_release);
}
return add_ret;
}

bool ResourceNode::HasActiveRecordsUnsafe() const {
return active_bucket_count_.load(std::memory_order_acquire) > 0 || !sub_nodes_.empty();
}

bool ResourceNode::TryRemoveChildNode(const std::string& name) {
std::unique_lock guard(lock_);
auto itr = sub_nodes_.find(name);
if (itr == sub_nodes_.end()) {
return !HasActiveRecordsUnsafe();
}
if (itr->second->HasActiveRecordsUnsafe()) {
return false;
}
sub_nodes_.erase(itr);
return !HasActiveRecordsUnsafe();
}

Result ResourceNode::RemoveActiveRecord(const std::vector& path_components) {
if (path_components.empty()) {
return ERROR_INVALID_ARGUMENT;
}

if (path_components.size() - 1 > depth_) {
std::unique_ptr child_node;
{
std::shared_lock guard(lock_);
auto itr = sub_nodes_.find(path_components[depth_]);
if (itr == sub_nodes_.end()) {
return ERROR_NOT_FOUND;
} else {
child_node = itr->second;
}
}
auto del_ret = child_node->RemoveActiveRecord(path_components);
if (del_ret.IsOk() && del_ret.Get()) {
return TryRemoveChildNode(path_components[depth_]);
}
return del_ret;
} else if (path_components.size() - 1 == depth_) {
auto del_ret = buckets_[GetBucketIndex(path_components[depth_])]->RemoveActiveRecord(
path_components[depth_]);
if (del_ret.IsOk()) {
active_bucket_count_.fetch_sub(1, std::memory_order_release);
if (del_ret.Get()) {
return TryRemoveChildNode(path_components[depth_]);
}
return del_ret;
}
return del_ret;
}
return ERROR_INTERNAL;
}
ОК, поэтому для приведенной выше реализации можно ли встретить следующий сценарий:
Предположим, что A/b/d/E уже добавлен через Addactiverecord
В момент времени t1, Thread1 Addactiverecord, попытка добавить/b/c и достигнуто Aut -ard -ard_ret od -let_ret leptor leptor leptor leptor leptor leptor a add_ret Buckets_ [bucket_index]-> addactiverecord (path_components [devin_], context);, но на самом деле не выполнил addactiverecord
в момент времени t2, thread2 вызывает removauctiverecord a/b/d/e и уже достиг tryRemovechildnode максимального Node, then o There-sub_nodes_. T3, Thread1 Наконец -то выполняет addactiverecord
Таким образом, новый ресурсов, добавленный Thread1, будет удален с помощью Thread2. Как эта проблема может быть решена?

Подробнее здесь: https://stackoverflow.com/questions/795 ... ffectively
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»