From be6f555e047402bfee79c3861839f9810ddae044 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 11 Dec 2010 01:52:02 +0100 Subject: [PATCH] Builder: registry for model ports coded up passes compiler, but not yet unit test.... Needed to change asset::ID to encapsulate the embedded hash value --- src/include/logging.h | 10 +- src/proc/asset.hpp | 8 +- src/proc/mobject/builder/common.hpp | 17 +- .../mobject/builder/model-port-registry.cpp | 188 +++++++++++++----- .../mobject/builder/model-port-registry.hpp | 62 ++++-- src/proc/mobject/builderfacade.cpp | 8 +- src/proc/mobject/builderfacade.hpp | 1 + .../builder/model-port-registry-test.cpp | 17 +- 8 files changed, 209 insertions(+), 102 deletions(-) diff --git a/src/include/logging.h b/src/include/logging.h index d2420b0f8..d5123f48f 100644 --- a/src/include/logging.h +++ b/src/include/logging.h @@ -132,6 +132,12 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( proc, progress); NOBUG_CPP_DEFINE_FLAG_PARENT ( command, proc); /** progress log for session datastructure */ NOBUG_CPP_DEFINE_FLAG_PARENT ( session, proc); +/** progress log for the builder and build process */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( builder, proc); +/** progress log for running the engine */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( engine, proc); +/** progress log for play- and render subsystem */ +NOBUG_CPP_DEFINE_FLAG_PARENT ( play, proc); /** progress log for the gui */ NOBUG_CPP_DEFINE_FLAG_PARENT ( gui, progress); /** progress log for the support lib */ @@ -158,13 +164,13 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( config, logging); /** base flag for software testing */ NOBUG_CPP_DEFINE_FLAG_PARENT ( test, logging); -/** base flag for syncronization logging */ +/** base flag for synchronisation logging */ NOBUG_CPP_DEFINE_FLAG_PARENT ( sync, logging); // do we need subsections here? backend_mutex_sync proc_mutex_sync etc? NOBUG_CPP_DEFINE_FLAG_PARENT ( mutex_sync, sync); //locking/unlocking mutexes NOBUG_CPP_DEFINE_FLAG_PARENT ( cond_sync, sync); //waiting and signalling condition vars /** base flag for memory related logging */ NOBUG_CPP_DEFINE_FLAG_PARENT ( memory, logging); -/** memory busines of the proc layer */ +/** proc layer memory handling */ NOBUG_CPP_DEFINE_FLAG_PARENT ( proc_mem, memory); NOBUG_CPP_DEFINE_FLAG_PARENT ( mobject_mem, proc_mem); NOBUG_CPP_DEFINE_FLAG_PARENT ( builder_mem, proc_mem); diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index 80e5f2aa7..ef56fc632 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -103,11 +103,11 @@ namespace asset { template class ID { + HashVal hash_; public: - const HashVal hash; - ID (HashVal id) : hash(id) {} - ID (const KIND& asset) : hash(asset.getID()) {} - operator HashVal() const { return hash; } + ID (HashVal id) : hash_(id) {} + ID (const KIND& asset) : hash_(asset.getID()) {} + operator HashVal() const { return hash_; } static ID INVALID; }; diff --git a/src/proc/mobject/builder/common.hpp b/src/proc/mobject/builder/common.hpp index e0503499b..ed3554c4c 100644 --- a/src/proc/mobject/builder/common.hpp +++ b/src/proc/mobject/builder/common.hpp @@ -24,25 +24,14 @@ #ifndef MOBJECT_BUILDER_COMMON_H #define MOBJECT_BUILDER_COMMON_H +#include "lib/error.hpp" #include "include/logging.h" namespace mobject { - namespace builder { +namespace builder { - // TODO NOBUG_DECLARE_FLAG (builder_mem); - - } // namespace builder - -} // namespace mobject +}} // namespace mobject::builder #endif - -/* -// Local Variables: -// mode: C -// c-file-style: "gnu" -// indent-tabs-mode: nil -// End: -*/ diff --git a/src/proc/mobject/builder/model-port-registry.cpp b/src/proc/mobject/builder/model-port-registry.cpp index 2346c4b9f..86a444a70 100644 --- a/src/proc/mobject/builder/model-port-registry.cpp +++ b/src/proc/mobject/builder/model-port-registry.cpp @@ -37,7 +37,10 @@ #include "lib/error.hpp" +#include "include/logging.h" +#include "lib/sync-classlock.hpp" //#include "lib/symbol.hpp"// +#include "proc/mobject/builderfacade.hpp" #include "proc/mobject/model-port.hpp" #include "proc/mobject/builder/model-port-registry.hpp" @@ -55,47 +58,72 @@ namespace mobject { namespace builder { + namespace error = lumiera::error; - /** - * TODO type comment - */ - class ModelPortTable - : boost::noncopyable - { - - public: - }; - typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor; + typedef lib::ClassLock LockRegistry; - inline MPDescriptor - accessDescriptor() - { - - } - ModelPortRegistry& - ModelPortRegistry::setActiveInstance (ModelPortRegistry& newRegistry) + /** storage for the link to the + global Registry instance currently in charge */ + lib::OptionalRef ModelPortRegistry::theGlobalRegistry; + + + + /** globally deactivate access to model ports */ + void + ModelPortRegistry::shutdown () { - UNIMPLEMENTED ("handling of active model port registry"); + INFO (builder, "disabling ModelPort registry...."); + LockRegistry global_lock; + theGlobalRegistry.clear(); } - /** */ + /** switch the implicit link to \em the global ModelPort registry + * to point to the given implementation instance. Typically used within + * the Builder subsystem lifecycle methods, or for unit tests to use + * a test instance of the registry temporarily + * @return the registry instance previously in use or \c NULL + */ + ModelPortRegistry* + ModelPortRegistry::setActiveInstance (ModelPortRegistry& newRegistry) + { + INFO (builder, "activating new ModelPort registry."); + LockRegistry global_lock; + ModelPortRegistry *previous = theGlobalRegistry.isValid()? + &(theGlobalRegistry()) : 0; + theGlobalRegistry.link_to (newRegistry); + return previous; + } + + + /** access the globally valid registry instance. + * @throw error::State if this global registry is + * already closed or not yet initialised. */ ModelPortRegistry& ModelPortRegistry::globalInstance() { - UNIMPLEMENTED ("access the globally valid registry instance"); + LockRegistry global_lock; + if (theGlobalRegistry.isValid()) + return theGlobalRegistry(); + + throw error::State ("global model port registry is not accessible" + , LUMIERA_ERROR_BUILDER_LIFECYCLE); } - /** */ + /** does the transaction currently being built + * already contain a model port registration for the given ID? + * @note this does \em not query registration state of the + * global registry; use #isRegistered for that...*/ bool - ModelPortRegistry::contains (ID pID) const + ModelPortRegistry::contains (ID key) const { - UNIMPLEMENTED ("diagnostics querying the state of the pending transaction"); + return bool(key) + && util::contains (transaction_, key); } @@ -103,70 +131,117 @@ namespace mobject { * existing, connected and usable model port. * @note reflects the state of the publicly visible * model port registry, \em not any model ports - * being registered within a currently pending - * transaction (ongoing build process). */ + * being registered within a pending transaction + * (ongoing build process). */ bool ModelPortRegistry::isRegistered (ID key) const { - if (!key) return false; - - UNIMPLEMENTED ("query the publicly valid contents"); + return bool(key) + && util::contains (currentReg_, key); } - /** */ + /** basic access operation: access the descriptor + * of a currently valid model port. + * @note no locking (but #accessDescriptor does lock!) + * @throw error::Logic if accessing a non registered port + * @throw error::State if accessing an invalid / disconnected port + */ MPDescriptor - ModelPortRegistry::operator[] (ID key) const + ModelPortRegistry::get (ID key) const { - UNIMPLEMENTED ("access registered model port"); + if (!key) + throw error::State ("This model port is disconnected or NIL" + , LUMIERA_ERROR_UNCONNECTED_MODEL_PORT); + if (!isRegistered (key)) + throw error::Logic ("Model port was never registered, or got unregistered meanwhile." + ,LUMIERA_ERROR_INVALID_MODEL_PORT); + + MPTable::const_iterator pos = currentReg_.find (key); + ASSERT (pos != currentReg_.end()); + ASSERT (pos->second.isValid()); + return pos->second; } - /** */ + /** access \em the globally valid model port for the given pipe. + * This (static) function locks and accesses the global model port registry + * to fetch the descriptor record. Typically invoked by client code + * through the ModelPort frontend + * @throw error::State when registry is down or the model port is disconnected + * @throw error::Logic when the given key wasn't registered for a model port */ MPDescriptor ModelPortRegistry::accessDescriptor (ID key) { - UNIMPLEMENTED ("access the current global registry and fetch model port"); + LockRegistry global_lock; + return theGlobalRegistry().get(key); } - /** */ + /* === Mutations === */ + + /** create and register a new model port entry, + * within the pending transaction */ MPDescriptor - ModelPortRegistry::definePort (ID pipeA, ID element_exposing_this_port) + ModelPortRegistry::definePort (ID pipe, ID element_exposing_this_port) { - UNIMPLEMENTED ("create and register a new model port entry, within the pending transaction"); + LockRegistry global_lock; + if (contains (pipe)) + throw error::Logic ("attempt to register a model port with a pipe-ID, " + "which has already been used to register a " + "model port within this transaction (build process)." + , LUMIERA_ERROR_DUPLICATE_MODEL_PORT); + return (transaction_[pipe] = ModelPortDescriptor(pipe, element_exposing_this_port)); } - /** */ + /** remove a model port entry from the pending transaction */ void ModelPortRegistry::remove (PID key) { - UNIMPLEMENTED ("remove a model port entry from the pending transaction"); + LockRegistry global_lock; + transaction_.erase (key); } - /** */ + /** schedule removal of all registry contents. + * When the currently pending transaction is committed, + * all registered model ports will be removed */ void ModelPortRegistry::clear() { - UNIMPLEMENTED ("schedule removal of all registry contents into the pending transaction"); + LockRegistry global_lock; + transaction_.clear(); } - /** */ + /** transactional switch for new/modified model ports. + * Promote the registered model ports from the currently + * pending transaction to become the globally valid model ports + * @note automatically starts a new transaction, initialised + * with the now published mappings. + */ void ModelPortRegistry::commit() { - UNIMPLEMENTED ("transactional switch for new/modified model ports"); + LockRegistry global_lock; + MPTable newTransaction(transaction_); + TRACE (builder, "committing new ModelPort list...."); + swap (currentReg_, transaction_); + swap (transaction_, newTransaction); } - /** */ + /** discard current transaction. + * The global port registration thus + * remains unaltered. */ void ModelPortRegistry::rollback() { - UNIMPLEMENTED ("discard current transaction"); + LockRegistry global_lock; + TRACE (builder, "discarding changes to ModelPort list (rollback)...."); + MPTable newTransaction(transaction_); + swap (transaction_, newTransaction); } @@ -189,7 +264,8 @@ namespace mobject { } - /** */ + /** check if the global model port registration + * contains a mapping for the given pipe-ID*/ bool ModelPort::exists (ID key) { @@ -197,25 +273,35 @@ namespace mobject { } - /** */ + /** access the Pipe (ID) of the global model port registered + * with the ID underlying this model port. + * @throw error::Logic if no model port is registered for this Pipe-ID + */ ID ModelPort::pipe() const { - ENSURE (this->id_ == builder::ModelPortRegistry::accessDescriptor(this->id_).id); + ENSURE (this->id_ == builder::ModelPortRegistry::accessDescriptor(this->id_).id()); - return builder::ModelPortRegistry::accessDescriptor(this->id_).id; + return builder::ModelPortRegistry::accessDescriptor(this->id_).id(); } - /** */ + /** access the timeline (or similar structural element) holding + * a global pipe which corresponds to this model port + * @throw error::Logic if no model port is registered for this Pipe-ID + */ ID ModelPort::holder() const { - return builder::ModelPortRegistry::accessDescriptor(this->id_).holder; + return builder::ModelPortRegistry::accessDescriptor(this->id_).holder(); } - /** */ + /** convenience shortcut to access the stream type + * associated with the pipe-ID corresponding to this model port. + * @note no check if this model port actually is valid + * @throw error::Invalid in case of unknown/unregistered Pipe-ID + */ StreamType::ID ModelPort::streamType() const { diff --git a/src/proc/mobject/builder/model-port-registry.hpp b/src/proc/mobject/builder/model-port-registry.hpp index 53ddc6810..e0c79e77f 100644 --- a/src/proc/mobject/builder/model-port-registry.hpp +++ b/src/proc/mobject/builder/model-port-registry.hpp @@ -34,6 +34,12 @@ ** for setting up such a registry, while all other parts of the system just access the current ** model ports through the mobject::ModelPort frontend. ** + ** @note the locking is rather coarse grained; basically we're using just one + ** single global lock for all ModelPortRegistry instances and all access/mutations, + ** as well as for accessing the globally valid Registry through the ModelPort frontend. + ** Assumed that usually there is just one Registry maintained by the builder, this is + ** likely to be sufficient. + ** ** @see ModelPort ** @see OutputDesignation ** @see ModelPortRegistry_test @@ -44,10 +50,13 @@ #define PROC_MOBJECT_BUILDER_MODEL_PORT_REGISTRY_H #include "lib/error.hpp" +#include "lib/optional-ref.hpp" #include "proc/asset/pipe.hpp" #include "proc/asset/struct.hpp" #include "proc/mobject/model-port.hpp" +#include + //#include "lib/opaque-holder.hpp" //#include "lib/meta/typelist-util.hpp" @@ -87,7 +96,9 @@ namespace builder { struct ModelPortDescriptor; - static ModelPortRegistry& + static void shutdown (); + + static ModelPortRegistry* setActiveInstance (ModelPortRegistry& newRegistry); static ModelPortRegistry& @@ -104,7 +115,7 @@ namespace builder { bool isRegistered (PID) const; ModelPortDescriptor const& - operator[] (PID) const; + get (PID) const; void remove (PID); @@ -122,38 +133,51 @@ namespace builder { * Silently drop model port definition changes since the last commit. */ void rollback(); + + private: + static lib::OptionalRef theGlobalRegistry; + + typedef std::map MPTable; + + MPTable currentReg_; + MPTable transaction_; }; /** ModelPortDescriptor records are used as actual storage - * within the model port registration table; they are never - * exposed to client code directly. + * within the model port registration table; they are immutable + * value objects and never exposed to client code directly. */ - struct ModelPortRegistry::ModelPortDescriptor + class ModelPortRegistry::ModelPortDescriptor { - const PID id; - const StID holder; + PID id_; + StID holder_; - bool - isValid() const - { - return bool(id); - } + protected: + ModelPortDescriptor (PID pipe, StID element_exposing_this_port) + : id_(pipe) + , holder_(element_exposing_this_port) + { } + friend class ModelPortRegistry; + public: ModelPortDescriptor() - : id(PID::INVALID) - , holder(StID::INVALID) + : id_(PID::INVALID) + , holder_(StID::INVALID) { } // default copy operations permitted - protected: - ModelPortDescriptor (PID pipe, StID element_exposing_this_port) - : id(pipe) - , holder(element_exposing_this_port) - { } + bool + isValid() const + { + return bool(id_); + } + + const PID id() const { return id_; } + const StID holder() const { return holder_; } }; diff --git a/src/proc/mobject/builderfacade.cpp b/src/proc/mobject/builderfacade.cpp index 99eb87ed9..cbf73bbbd 100644 --- a/src/proc/mobject/builderfacade.cpp +++ b/src/proc/mobject/builderfacade.cpp @@ -26,11 +26,6 @@ namespace mobject { - namespace builder { - using ::NOBUG_FLAG(memory); - NOBUG_CPP_DEFINE_FLAG_PARENT(buildermem, memory); - } - /** * Main Operation of the Builder: @@ -42,6 +37,9 @@ namespace mobject { //////////////////////TODO } + LUMIERA_ERROR_DEFINE (BUILDER_LIFECYCLE, "Builder activated while in non operational state"); + + } // namespace mobject diff --git a/src/proc/mobject/builderfacade.hpp b/src/proc/mobject/builderfacade.hpp index 86520d483..31ab936ab 100644 --- a/src/proc/mobject/builderfacade.hpp +++ b/src/proc/mobject/builderfacade.hpp @@ -31,6 +31,7 @@ namespace mobject { + LUMIERA_ERROR_DECLARE (BUILDER_LIFECYCLE); ///< Builder activated while in non operational state /** * Provides unified access to the builder functionality. diff --git a/tests/components/proc/mobject/builder/model-port-registry-test.cpp b/tests/components/proc/mobject/builder/model-port-registry-test.cpp index 2c57df4b9..3e948c6c9 100644 --- a/tests/components/proc/mobject/builder/model-port-registry-test.cpp +++ b/tests/components/proc/mobject/builder/model-port-registry-test.cpp @@ -74,7 +74,7 @@ namespace test { struct TestContext { ModelPortRegistry registry_; - ModelPortRegistry& previous_; + ModelPortRegistry* previous_; /** setup */ TestContext() @@ -85,7 +85,10 @@ namespace test { /** tear-down */ ~TestContext() { - ModelPortRegistry::setActiveInstance (previous_); + if (previous_) + ModelPortRegistry::setActiveInstance (*previous_); + else + ModelPortRegistry::shutdown(); } }; @@ -136,10 +139,10 @@ namespace test { VERIFY_ERROR (DUPLICATE_MODEL_PORT, registry.definePort(pipeB, someTimeline) ); CHECK (registry.contains (pipeB)); - CHECK (p1.id == pipeA); - CHECK (p2.id == pipeB); - CHECK (p1.holder == someTimeline); - CHECK (p2.holder == someTimeline); + CHECK (pipeA == p1.id()); + CHECK (pipeB == p2.id()); + CHECK (someTimeline == p1.holder()); + CHECK (someTimeline == p2.holder()); registry.commit(); } @@ -205,7 +208,7 @@ namespace test { TID anotherTimeline = getTimeline ("another_test_Timeline"); MPDescriptor p1 = registry.definePort (pipeA, anotherTimeline); CHECK (registry.contains (pipeA)); - CHECK (p1.holder == anotherTimeline); + CHECK (anotherTimeline == p1.holder()); CHECK (ModelPort(pipeA).holder() != anotherTimeline); registry.remove (pipeB);