Toward dynamically reloading contracts...
Add the ability to dynamically unload an auxiliary evaluator (any evaluator for a given operation type except the first one registered for that operation type), and as an added convenience, add an idiomatically consistent way to check if a given index is already registered or not.
This commit is contained in:
parent
082df7ab4a
commit
c76e1f3157
4 changed files with 80 additions and 10 deletions
|
|
@ -347,6 +347,8 @@ namespace graphene { namespace chain {
|
|||
/**
|
||||
* @brief Register a new evaluator to the evaluator chain for its operation type
|
||||
* @tparam EvaluatorType An evaluator type which will be used to evaluate its declared operation type
|
||||
* @return If registering an evaluator for an operation that already has an evaluator, returns a handle for
|
||||
* the newly added evaluator which can be used to delete it later.
|
||||
*
|
||||
* This method registers a new evaluator type with tthe database. The evaluator specifies an operation type
|
||||
* which it should be used to evaluate. The evaluator will be instantiated each time an operaton of the
|
||||
|
|
@ -356,15 +358,39 @@ namespace graphene { namespace chain {
|
|||
* multiple evaluator types are registered for a given operation type, they will all execute in the order of
|
||||
* registration; however, only the return value of the first registered evaluator will be returned; return
|
||||
* values of subsequently registered evaluators will be silently dropped.
|
||||
*
|
||||
* The first evaluator registered for a given operation type is permanent, and is the only evaluator which
|
||||
* can return a value. Subsequent (auxiliary) evaluators for that operation type can be deleted at runtime
|
||||
* by calling @ref delete_evaluator() with the evaluator_handle obtained when registering the evaluator.
|
||||
*/
|
||||
template<typename EvaluatorType>
|
||||
void register_evaluator()
|
||||
optional<op_evaluator::evaluator_handle> register_evaluator()
|
||||
{
|
||||
auto& eval_ptr = _operation_evaluators[operation::tag<typename EvaluatorType::operation_type>::value];
|
||||
if (eval_ptr == nullptr)
|
||||
eval_ptr = std::make_unique<op_evaluator_impl<EvaluatorType>>();
|
||||
else
|
||||
eval_ptr->append_evaluator(std::make_unique<op_evaluator_impl<EvaluatorType>>());
|
||||
return eval_ptr->append_evaluator(std::make_unique<op_evaluator_impl<EvaluatorType>>());
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete an auxiliary evaluator
|
||||
* @param handle The evaluator handle for the evaluator to delete, as returned by @ref register_evaluator
|
||||
*
|
||||
* Auxiliary evaluators, or the second and subsequent evaluators registered for a given operation type,
|
||||
* can be deleted so that they no longer execute when operations of the relevant type are processed.
|
||||
*
|
||||
* If it may be desired to delete an auxiliary evaluator, retain the evaluator handle obtained when the
|
||||
* evaluator was initially registered and when it is necessary to delete the evaluator, pass the handle
|
||||
* to this function.
|
||||
*
|
||||
* The evaluator will have been deleted by the time this function returns.
|
||||
*/
|
||||
void delete_evaluator(op_evaluator::evaluator_handle&& handle)
|
||||
{
|
||||
if ((uint64_t)handle.get_operation_type() < _operation_evaluators.size())
|
||||
_operation_evaluators[handle.get_operation_type()]->delete_evaluator(std::move(handle));
|
||||
}
|
||||
|
||||
//////////////////// db_balance.cpp ////////////////////
|
||||
|
|
|
|||
|
|
@ -122,29 +122,62 @@ namespace graphene { namespace chain {
|
|||
|
||||
class op_evaluator
|
||||
{
|
||||
protected:
|
||||
unique_ptr<op_evaluator> next_evaluator;
|
||||
public:
|
||||
class evaluator_handle {
|
||||
// Move-only semantics, and only friends can construct
|
||||
evaluator_handle(const op_evaluator* pointer, operation::tag_type type)
|
||||
: pointer(pointer), operation_type(type) {}
|
||||
evaluator_handle(const evaluator_handle&) = delete;
|
||||
evaluator_handle& operator=(const evaluator_handle&) = delete;
|
||||
|
||||
friend class op_evaluator;
|
||||
template<typename>
|
||||
friend class op_evaluator_impl;
|
||||
|
||||
// Pointer to the handled evaluator
|
||||
const op_evaluator* pointer;
|
||||
// Tag of the handled evaluator
|
||||
operation::tag_type operation_type;
|
||||
|
||||
public:
|
||||
evaluator_handle(evaluator_handle&&) = default;
|
||||
evaluator_handle& operator=(evaluator_handle&&) = default;
|
||||
|
||||
operation::tag_type get_operation_type() const { return operation_type; }
|
||||
};
|
||||
|
||||
virtual ~op_evaluator(){}
|
||||
virtual void append_evaluator(unique_ptr<op_evaluator> next_evaluator) = 0;
|
||||
virtual evaluator_handle append_evaluator(unique_ptr<op_evaluator> next_evaluator) = 0;
|
||||
virtual void delete_evaluator(evaluator_handle&& handle) {
|
||||
if (next_evaluator.get() == handle.pointer)
|
||||
// Next evaluator in chain is the one to delete. Move its next pointer into ours, and unique_ptr will delete the one that's going away.
|
||||
next_evaluator = std::move(next_evaluator->next_evaluator);
|
||||
else
|
||||
next_evaluator->delete_evaluator(std::move(handle));
|
||||
}
|
||||
virtual operation_result evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply) = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class op_evaluator_impl : public op_evaluator
|
||||
{
|
||||
unique_ptr<op_evaluator> next_evaluator;
|
||||
public:
|
||||
virtual void append_evaluator(unique_ptr<op_evaluator> next_evaluator) override {
|
||||
if (this->next_evaluator == nullptr)
|
||||
virtual evaluator_handle append_evaluator(unique_ptr<op_evaluator> next_evaluator) override {
|
||||
if (this->next_evaluator == nullptr) {
|
||||
this->next_evaluator = std::move(next_evaluator);
|
||||
else
|
||||
this->next_evaluator->append_evaluator(std::move(next_evaluator));
|
||||
return evaluator_handle(this->next_evaluator.get(), operation::tag<typename T::operation_type>::value);
|
||||
} else {
|
||||
return this->next_evaluator->append_evaluator(std::move(next_evaluator));
|
||||
}
|
||||
}
|
||||
virtual operation_result evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply = true) override
|
||||
{
|
||||
T eval;
|
||||
auto result = eval.start_evaluate(eval_state, op, apply);
|
||||
if (next_evaluator != nullptr)
|
||||
next_evaluator->evaluate(eval_state, op, apply);
|
||||
if (this->next_evaluator != nullptr)
|
||||
this->next_evaluator->evaluate(eval_state, op, apply);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -75,6 +75,10 @@ namespace graphene { namespace db {
|
|||
const index& get_index()const { return get_index(T::space_id,T::type_id); }
|
||||
const index& get_index(uint8_t space_id, uint8_t type_id)const;
|
||||
const index& get_index(object_id_type id)const { return get_index(id.space(),id.type()); }
|
||||
template<typename T>
|
||||
const index* find_index()const { return find_index(T::space_id,T::type_id); }
|
||||
const index* find_index(object_id_type id)const { return find_index(id.space(), id.type()); }
|
||||
const index* find_index(uint8_t space_id, uint8_t type_id)const;
|
||||
/// @}
|
||||
|
||||
const object& get_object( object_id_type id )const;
|
||||
|
|
|
|||
|
|
@ -58,6 +58,13 @@ const index& object_database::get_index(uint8_t space_id, uint8_t type_id)const
|
|||
FC_ASSERT( tmp );
|
||||
return *tmp;
|
||||
}
|
||||
|
||||
const index* object_database::find_index(uint8_t space_id, uint8_t type_id) const
|
||||
{
|
||||
if (_index.size() > space_id && _index[space_id].size() > type_id)
|
||||
return _index[space_id][type_id].get();
|
||||
return nullptr;
|
||||
}
|
||||
index& object_database::get_mutable_index(uint8_t space_id, uint8_t type_id)
|
||||
{
|
||||
FC_ASSERT( _index.size() > space_id, "", ("space_id",space_id)("type_id",type_id)("index.size",_index.size()) );
|
||||
|
|
|
|||
Loading…
Reference in a new issue