diff options
Diffstat (limited to 'src/serialize.cpp')
-rw-r--r-- | src/serialize.cpp | 328 |
1 files changed, 234 insertions, 94 deletions
diff --git a/src/serialize.cpp b/src/serialize.cpp index 3c54b933d..099151191 100644 --- a/src/serialize.cpp +++ b/src/serialize.cpp @@ -1,178 +1,318 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2012-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "anope.h" #include "serialize.h" #include "modules.h" -#include "account.h" -#include "bots.h" -#include "regchannel.h" -#include "xline.h" -#include "access.h" +#include "event.h" using namespace Serialize; -std::vector<Anope::string> Type::TypeOrder; -std::map<Anope::string, Type *> Serialize::Type::Types; -std::list<Serializable *> *Serializable::SerializableItems; +std::unordered_map<ID, Object *> Serialize::objects; -void Serialize::RegisterTypes() -{ - static Type nc("NickCore", NickCore::Unserialize), na("NickAlias", NickAlias::Unserialize), bi("BotInfo", BotInfo::Unserialize), - ci("ChannelInfo", ChannelInfo::Unserialize), access("ChanAccess", ChanAccess::Unserialize), - akick("AutoKick", AutoKick::Unserialize), memo("Memo", Memo::Unserialize), xline("XLine", XLine::Unserialize); -} +std::vector<FieldBase *> Serialize::serializableFields; + +std::multimap<Anope::string, Anope::string> Serialize::child_types; -void Serialize::CheckTypes() +static ID curid; + + +Object *Serialize::GetID(ID id) { - for (std::map<Anope::string, Serialize::Type *>::const_iterator it = Serialize::Type::GetTypes().begin(), it_end = Serialize::Type::GetTypes().end(); it != it_end; ++it) - { - Serialize::Type *t = it->second; - t->Check(); - } + auto it = objects.find(id); + if (it != objects.end()) + return it->second; + return nullptr; } -Serializable::Serializable(const Anope::string &serialize_type) : last_commit(0), last_commit_time(0), id(0), redis_ignore(0) +void Serialize::Clear() { - if (SerializableItems == NULL) - SerializableItems = new std::list<Serializable *>(); - SerializableItems->push_back(this); + std::unordered_map<ID, Object *> o; + objects.swap(o); - this->s_type = Type::Find(serialize_type); + for (const std::pair<ID, Object *> &p : o) + delete p.second; +} - this->s_iter = SerializableItems->end(); - --this->s_iter; +void Serialize::Unregister(Module *m) +{ + for (TypeBase *s : ServiceManager::Get()->FindServices<Serialize::TypeBase *>()) + if (s->GetOwner() == m) + s->Unregister(); - FOREACH_MOD(OnSerializableConstruct, (this)); + for (FieldBase *field : serializableFields) + if (field->GetOwner() == m) + field->Unregister(); } -Serializable::Serializable(const Serializable &other) : last_commit(0), last_commit_time(0), id(0), redis_ignore(0) +std::vector<Edge> Object::GetRefs(TypeBase *type) { - SerializableItems->push_back(this); - this->s_iter = SerializableItems->end(); - --this->s_iter; + std::vector<Edge> refs; + EventReturn result = EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializeGetRefs, this, type, refs); + if (result == EVENT_ALLOW) + return refs; - this->s_type = other.s_type; + if (type == nullptr) + { + refs.clear(); + for (const std::pair<TypeBase *, std::vector<Edge>> &p : edges) + { + const std::vector<Edge> &e = p.second; + refs.insert(refs.end(), e.begin(), e.end()); + } + return refs; + } - FOREACH_MOD(OnSerializableConstruct, (this)); + auto it = edges.find(type); + if (it != edges.end()) + return it->second; + return std::vector<Edge>(); } -Serializable::~Serializable() +Object::Object(TypeBase *type) { - FOREACH_MOD(OnSerializableDestruct, (this)); + ID i; + EventReturn result = EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializableGetId, i); + if (result != EVENT_ALLOW) + { + while (GetID(++curid)); + i = curid; + } + + id = i; + objects[id] = this; + + this->s_type = type; + + type->objects.insert(this); + + Log(LOG_DEBUG_2) << "Creating object id #" << id << " address " << static_cast<void *>(this) << " type " << type->GetName(); - SerializableItems->erase(this->s_iter); + EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializableCreate, this); } -Serializable &Serializable::operator=(const Serializable &) +Object::Object(TypeBase *type, ID i) { - return *this; + this->id = i; + objects[i] = this; + + this->s_type = type; + + type->objects.insert(this); + + Log(LOG_DEBUG_2) << "Creating object from id #" << id << " address " << static_cast<void *>(this) << " type " << type->GetName(); } -void Serializable::QueueUpdate() +Object::~Object() { - /* Schedule updater */ - FOREACH_MOD(OnSerializableUpdate, (this)); + Log(LOG_DEBUG_2) << "Destructing object id #" << id << " address " << static_cast<void *>(this) << " type " << s_type->GetName(); - /* Check for modifications now - this can delete this object! */ - FOREACH_MOD(OnSerializeCheck, (this->GetSerializableType())); + /* Remove in memory edges */ + cont: + for (const std::pair<TypeBase *, std::vector<Edge>> &p : edges) + for (const Edge &edge : p.second) + { + if (!edge.direction) + { + Log(LOG_DEBUG_2) << "Removing edge from object id #" << edge.other->id << " type " << edge.other->GetSerializableType()->GetName() << " on field " << edge.field->serialize_name; + edge.other->RemoveEdge(this, edge.field); + } + else + { + Log(LOG_DEBUG_2) << "Removing edge to object id #" << edge.other->id << " type " << edge.other->GetSerializableType()->GetName() << " on field " << edge.field->serialize_name; + this->RemoveEdge(edge.other, edge.field); + } + goto cont; + } + + objects.erase(id); + s_type->objects.erase(this); } -bool Serializable::IsCached(Serialize::Data &data) +void Object::Delete() { - return this->last_commit == data.Hash(); + Log(LOG_DEBUG_2) << "Deleting object id #" << id << " type " << s_type->GetName(); + + /* Delete dependant objects */ + for (const Edge &edge : GetRefs(nullptr)) + { + Object *other = edge.other; + FieldBase *field = edge.field; + + if (edge.direction) + continue; + + if (field->depends) + { + Log(LOG_DEBUG_2) << "Deleting dependent object #" << other->id << " type " << other->GetSerializableType()->GetName() << " due to edge on " << field->serialize_name; + other->Delete(); + } + else + { + Log(LOG_DEBUG_2) << "Unsetting field " << field->serialize_name << " on object #" << other->id << " type " << other->GetSerializableType()->GetName(); + field->UnsetS(other); + } + } + + EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializableDelete, this); + + delete this; } -void Serializable::UpdateCache(Serialize::Data &data) +void Object::AddEdge(Object *other, FieldBase *field) { - this->last_commit = data.Hash(); + // field = the field on 'this' object + this->edges[other->GetSerializableType()].emplace_back(other, field, true); + // field = the field on the other object + other->edges[this->GetSerializableType()].emplace_back(this, field, false); } -bool Serializable::IsTSCached() +void Object::RemoveEdge(Object *other, FieldBase *field) { - return this->last_commit_time == Anope::CurTime; + std::vector<Edge> &myedges = this->edges[other->GetSerializableType()]; + auto it = std::find(myedges.begin(), myedges.end(), Edge(other, field, true)); + if (it != myedges.end()) + myedges.erase(it); + else + Log(LOG_DEBUG_2) << "Unable to locate edge for removal on #" << this->id << " type " << s_type->GetName() << " -> #" << other->id << " type " << other->GetSerializableType()->GetName(); + + std::vector<Edge> &theiredges = other->edges[this->GetSerializableType()]; + it = std::find(theiredges.begin(), theiredges.end(), Edge(this, field, false)); + if (it != theiredges.end()) + theiredges.erase(it); + else + Log(LOG_DEBUG_2) << "Unable to locate edge for removal on #" << this->id << " type " << s_type->GetName() << " <- #" << other->id << " type " << other->GetSerializableType()->GetName(); } -void Serializable::UpdateTS() +TypeBase::TypeBase(Module *o, const Anope::string &n) : Service(o, TypeBase::NAME, n), name(n), owner(o) { - this->last_commit_time = Anope::CurTime; } -const std::list<Serializable *> &Serializable::GetItems() +TypeBase::~TypeBase() { - return *SerializableItems; + if (!Serialize::GetObjects<Object *>(this->GetName()).empty()) + throw CoreException("Type destructing with objects still alive"); } -Type::Type(const Anope::string &n, unserialize_func f, Module *o) : name(n), unserialize(f), owner(o), timestamp(0) +void TypeBase::Unregister() { - TypeOrder.push_back(this->name); - Types[this->name] = this; + Log(LOG_DEBUG_2) << "Unregistering type " << this->GetName(); - FOREACH_MOD(OnSerializeTypeCreate, (this)); + for (Object *obj : GetObjects<Object *>(this->GetName())) + obj->Delete(); + + for (FieldBase *field : serializableFields) + { + if (field->serialize_type == this->GetName()) + { + field->Unregister(); + } + } } -Type::~Type() +Serialize::FieldBase *TypeBase::GetField(const Anope::string &fname) { - /* null the type of existing serializable objects of this type */ - if (Serializable::SerializableItems != NULL) - for (std::list<Serializable *>::iterator it = Serializable::SerializableItems->begin(); it != Serializable::SerializableItems->end(); ++it) - { - Serializable *s = *it; + /* is this too slow? */ + for (FieldBase *fb : ServiceManager::Get()->FindServices<FieldBase *>()) + if (fb->serialize_type == this->GetName() && fb->serialize_name == fname) + return fb; - if (s->s_type == this) - s->s_type = NULL; - } + Log(LOG_DEBUG_2) << "GetField() for unknown field " << fname << " on " << this->GetName(); - std::vector<Anope::string>::iterator it = std::find(TypeOrder.begin(), TypeOrder.end(), this->name); - if (it != TypeOrder.end()) - TypeOrder.erase(it); - Types.erase(this->name); + return nullptr; } -Serializable *Type::Unserialize(Serializable *obj, Serialize::Data &data) +std::vector<Serialize::FieldBase *> TypeBase::GetFields() { - return this->unserialize(obj, data); + std::vector<Serialize::FieldBase *> fields; + + for (FieldBase *fb : ServiceManager::Get()->FindServices<FieldBase *>()) + if (fb->serialize_type == this->GetName()) + fields.push_back(fb); + + return fields; } -void Type::Check() +TypeBase *TypeBase::Find(const Anope::string &name) { - FOREACH_MOD(OnSerializeCheck, (this)); + return ServiceManager::Get()->FindService<TypeBase *>(name); } -time_t Type::GetTimestamp() const +FieldBase::FieldBase(Module *c, const Anope::string &n, const Anope::string &t, bool d) + : Service(c, FieldBase::NAME) + , serialize_type(t) + , serialize_name(n) + , depends(d) { - return this->timestamp; + serializableFields.push_back(this); } -void Type::UpdateTimestamp() +FieldBase::~FieldBase() { - this->timestamp = Anope::CurTime; + auto it = std::find(serializableFields.begin(), serializableFields.end(), this); + if (it != serializableFields.end()) + serializableFields.erase(it); } -Type *Serialize::Type::Find(const Anope::string &name) +void FieldBase::Unregister() { - std::map<Anope::string, Type *>::iterator it = Types.find(name); - if (it != Types.end()) - return it->second; - return NULL; + Log(LOG_DEBUG_2) << "Unregistering field " << serialize_name << " on " << serialize_type; + + /* find edges on this field */ + for (Object *s : Serialize::GetObjects<Object *>(serialize_type)) + { + for (const std::pair<TypeBase *, std::vector<Edge>> &p : s->edges) + for (const Edge &edge : p.second) + if (edge.direction && edge.field == this) + { + Log(LOG_DEBUG_2) << "Removing edge on #" << s->id << " type " << s->GetSerializableType()->GetName() << " -> #" << edge.other->id << " type " << edge.other->GetSerializableType()->GetName(); + s->RemoveEdge(edge.other, edge.field); + + goto cont; + } + cont:; + } } -const std::vector<Anope::string> &Type::GetTypeOrder() +void Serialize::SetParent(const Anope::string &child, const Anope::string &parent) { - return TypeOrder; + child_types.insert(std::make_pair(parent, child)); } -const std::map<Anope::string, Serialize::Type *>& Type::GetTypes() +std::vector<Serialize::TypeBase *> Serialize::GetTypes(const Anope::string &name) { - return Types; -} + std::vector<Serialize::TypeBase *> v; + Serialize::TypeBase *t = Serialize::TypeBase::Find(name); + if (t != nullptr) + v.push_back(t); + else + Log(LOG_DEBUG_2) << "GetTypes for unknown type " << name; + + auto its = child_types.equal_range(name); + for (; its.first != its.second; ++its.first) + { + t = Serialize::TypeBase::Find(its.first->second); + if (t != nullptr) + v.push_back(t); + } + + return v; +} |