From 025092f157922d0bf341235e18f9f5b2b183f038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= Date: Fri, 24 Jan 2014 18:27:36 +0100 Subject: [PATCH 1/2] Feature #2672: Disable cache for federation slave nodes --- include/DocumentPool.h | 2 +- include/GroupPool.h | 3 +- include/PoolSQL.h | 25 +++++- include/UserPool.h | 3 +- include/VMTemplatePool.h | 2 +- include/ZonePool.h | 3 +- src/cluster/ClusterPool.cc | 2 +- src/datastore/DatastorePool.cc | 2 +- src/group/GroupPool.cc | 5 +- src/host/HostPool.cc | 2 +- src/image/ImagePool.cc | 2 +- src/nebula/Nebula.cc | 8 +- src/pool/PoolSQL.cc | 135 +++++++++++++++++++++++++++++---- src/um/UserPool.cc | 5 +- src/vm/VirtualMachinePool.cc | 2 +- src/vnm/VirtualNetworkPool.cc | 2 +- src/zone/ZonePool.cc | 4 +- 17 files changed, 172 insertions(+), 35 deletions(-) diff --git a/include/DocumentPool.h b/include/DocumentPool.h index e6b0c2695b..883cdb97d9 100644 --- a/include/DocumentPool.h +++ b/include/DocumentPool.h @@ -27,7 +27,7 @@ class DocumentPool : public PoolSQL { public: - DocumentPool(SqlDB * db) : PoolSQL(db, Document::table, false){}; + DocumentPool(SqlDB * db) : PoolSQL(db, Document::table, true, false){}; ~DocumentPool(){}; diff --git a/include/GroupPool.h b/include/GroupPool.h index 363135c0a4..fafc0d669a 100644 --- a/include/GroupPool.h +++ b/include/GroupPool.h @@ -28,7 +28,8 @@ class GroupPool : public PoolSQL public: GroupPool(SqlDB * db, vector hook_mads, - const string& remotes_location); + const string& remotes_location, + bool cache); ~GroupPool(){}; diff --git a/include/PoolSQL.h b/include/PoolSQL.h index f1c1b86744..2dbe1a13f3 100644 --- a/include/PoolSQL.h +++ b/include/PoolSQL.h @@ -45,9 +45,10 @@ public: * @param _db a pointer to the database * @param _table the name of the table supporting the pool (to set the oid * counter). If null the OID counter is not updated. + * @param cache True to enable the cache * @param cache_by_name True if the objects can be retrieved by name */ - PoolSQL(SqlDB * _db, const char * _table, bool cache_by_name); + PoolSQL(SqlDB * _db, const char * _table, bool cache, bool cache_by_name); virtual ~PoolSQL(); @@ -368,6 +369,11 @@ private: */ map pool; + /** + * Whether or not this pool uses the cache + */ + bool cache; + /** * Whether or not this pool uses the name_pool index */ @@ -415,6 +421,23 @@ private: */ void replace(); + /** + * Cleans all the objects in the cache, except the ones locked. + * The object with the given oid will not be ignored if locked, the + * method will wait for it to be unlocked and ensure it is erased from + * the cache + * + * @param oid + */ + void flush_cache(int oid); + + /** + * Same as flush_cache(int), but with the object name-uid key + * + * @param name_key + */ + void flush_cache(const string& name_key); + /** * Generate an index key for the object * @param name of the object diff --git a/include/UserPool.h b/include/UserPool.h index 23051f7000..6b9b41bde5 100644 --- a/include/UserPool.h +++ b/include/UserPool.h @@ -42,7 +42,8 @@ public: UserPool(SqlDB * db, time_t __session_expiration_time, vector hook_mads, - const string& remotes_location); + const string& remotes_location, + bool cache); ~UserPool(){}; diff --git a/include/VMTemplatePool.h b/include/VMTemplatePool.h index 026dca5458..1f16d2c4fd 100644 --- a/include/VMTemplatePool.h +++ b/include/VMTemplatePool.h @@ -27,7 +27,7 @@ class VMTemplatePool : public PoolSQL { public: - VMTemplatePool(SqlDB * db) : PoolSQL(db, VMTemplate::table, true){}; + VMTemplatePool(SqlDB * db) : PoolSQL(db, VMTemplate::table, true, true){}; ~VMTemplatePool(){}; diff --git a/include/ZonePool.h b/include/ZonePool.h index c91c1c5c90..34e166f566 100644 --- a/include/ZonePool.h +++ b/include/ZonePool.h @@ -26,7 +26,8 @@ using namespace std; class ZonePool : public PoolSQL { public: - ZonePool(SqlDB * db); + ZonePool(SqlDB * db, + bool cache); ~ZonePool(){}; diff --git a/src/cluster/ClusterPool.cc b/src/cluster/ClusterPool.cc index d36dcc8c28..8284ac456e 100644 --- a/src/cluster/ClusterPool.cc +++ b/src/cluster/ClusterPool.cc @@ -33,7 +33,7 @@ const int ClusterPool::ALL_RESOURCES = 10; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -ClusterPool::ClusterPool(SqlDB * db):PoolSQL(db, Cluster::table, true) +ClusterPool::ClusterPool(SqlDB * db):PoolSQL(db, Cluster::table, true, true) { ostringstream oss; string error_str; diff --git a/src/datastore/DatastorePool.cc b/src/datastore/DatastorePool.cc index c3d358ae34..8cee553741 100644 --- a/src/datastore/DatastorePool.cc +++ b/src/datastore/DatastorePool.cc @@ -39,7 +39,7 @@ const int DatastorePool::FILE_DS_ID = 2; /* -------------------------------------------------------------------------- */ DatastorePool::DatastorePool(SqlDB * db): - PoolSQL(db, Datastore::table, true) + PoolSQL(db, Datastore::table, true, true) { ostringstream oss; string error_str; diff --git a/src/group/GroupPool.cc b/src/group/GroupPool.cc index e2bce9336c..bed4739aa2 100644 --- a/src/group/GroupPool.cc +++ b/src/group/GroupPool.cc @@ -39,8 +39,9 @@ const int GroupPool::USERS_ID = 1; GroupPool::GroupPool(SqlDB * db, vector hook_mads, - const string& remotes_location) - :PoolSQL(db, Group::table, true) + const string& remotes_location, + bool cache) + :PoolSQL(db, Group::table, cache, true) { ostringstream oss; string error_str; diff --git a/src/host/HostPool.cc b/src/host/HostPool.cc index 70bb2cd07a..6ed31d4f6c 100644 --- a/src/host/HostPool.cc +++ b/src/host/HostPool.cc @@ -41,7 +41,7 @@ HostPool::HostPool(SqlDB* db, const string& hook_location, const string& remotes_location, time_t expire_time) - : PoolSQL(db, Host::table, true) + : PoolSQL(db, Host::table, true, true) { _monitor_expiration = expire_time; diff --git a/src/image/ImagePool.cc b/src/image/ImagePool.cc index abb3dd9318..6974929157 100644 --- a/src/image/ImagePool.cc +++ b/src/image/ImagePool.cc @@ -41,7 +41,7 @@ ImagePool::ImagePool( const string& remotes_location, const vector& _inherit_image_attrs, const vector& _inherit_datastore_attrs) - :PoolSQL(db, Image::table, true) + :PoolSQL(db, Image::table, true, true) { // Init static defaults _default_type = __default_type; diff --git a/src/nebula/Nebula.cc b/src/nebula/Nebula.cc index 40551905f3..83f4b68e48 100644 --- a/src/nebula/Nebula.cc +++ b/src/nebula/Nebula.cc @@ -607,6 +607,8 @@ void Nebula::start(bool bootstrap_only) bool vm_submit_on_hold; + bool cache = !is_federation_slave(); + vector vm_hooks; vector host_hooks; vector vnet_hooks; @@ -623,7 +625,7 @@ void Nebula::start(bool bootstrap_only) clpool = new ClusterPool(db); docpool = new DocumentPool(db); - zonepool= new ZonePool(db); + zonepool= new ZonePool(db, cache); nebula_configuration->get("VM_HOOK", vm_hooks); nebula_configuration->get("HOST_HOOK", host_hooks); @@ -667,10 +669,10 @@ void Nebula::start(bool bootstrap_only) remotes_location, inherit_vnet_attrs); - gpool = new GroupPool(db, group_hooks, remotes_location); + gpool = new GroupPool(db, group_hooks, remotes_location, cache); nebula_configuration->get("SESSION_EXPIRATION_TIME", expiration_time); - upool = new UserPool(db, expiration_time, user_hooks, remotes_location); + upool = new UserPool(db, expiration_time, user_hooks, remotes_location, cache); nebula_configuration->get("DEFAULT_IMAGE_TYPE", default_image_type); nebula_configuration->get("DEFAULT_DEVICE_PREFIX", diff --git a/src/pool/PoolSQL.cc b/src/pool/PoolSQL.cc index b3c300525e..30aae011a5 100644 --- a/src/pool/PoolSQL.cc +++ b/src/pool/PoolSQL.cc @@ -51,8 +51,8 @@ int PoolSQL::init_cb(void *nil, int num, char **values, char **names) /* -------------------------------------------------------------------------- */ -PoolSQL::PoolSQL(SqlDB * _db, const char * _table, bool cache_by_name): - db(_db), lastOID(-1), table(_table), uses_name_pool(cache_by_name) +PoolSQL::PoolSQL(SqlDB * _db, const char * _table, bool _cache, bool cache_by_name): + db(_db), lastOID(-1), table(_table), cache(_cache), uses_name_pool(cache_by_name) { ostringstream oss; @@ -176,6 +176,11 @@ PoolObjectSQL * PoolSQL::get( lock(); + if (!cache) + { + flush_cache(oid); + } + index = pool.find(oid); if ( index != pool.end() ) @@ -252,11 +257,14 @@ PoolObjectSQL * PoolSQL::get( objectsql->lock(); } - oid_queue.push(objectsql->oid); - - if ( pool.size() > MAX_POOL_SIZE ) + if (cache) { - replace(); + oid_queue.push(objectsql->oid); + + if ( pool.size() > MAX_POOL_SIZE ) + { + replace(); + } } unlock(); @@ -274,16 +282,23 @@ PoolObjectSQL * PoolSQL::get(const string& name, int ouid, bool olock) PoolObjectSQL * objectsql; int rc; - - lock(); + string name_key; if ( uses_name_pool == false ) { - unlock(); return 0; } - index = name_pool.find(key(name,ouid)); + lock(); + + name_key = key(name,ouid); + + if (!cache) + { + flush_cache(name_key); + } + + index = name_pool.find(name_key); if ( index != name_pool.end() && index->second->isValid() == true ) { @@ -342,11 +357,14 @@ PoolObjectSQL * PoolSQL::get(const string& name, int ouid, bool olock) objectsql->lock(); } - oid_queue.push(objectsql->oid); - - if ( pool.size() > MAX_POOL_SIZE ) + if (cache) { - replace(); + oid_queue.push(objectsql->oid); + + if ( pool.size() > MAX_POOL_SIZE ) + { + replace(); + } } unlock(); @@ -446,6 +464,95 @@ void PoolSQL::replace() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +void PoolSQL::flush_cache(int oid) +{ + int rc; + PoolObjectSQL * tmp_ptr; + + map::iterator it; + + for (it = pool.begin(); it != pool.end(); ) + { + // The object we are looking for in ::get(). Will wait until it is + // unlocked() + if (it->second->oid == oid) + { + it->second->lock(); + } + else + { + // Any other locked object is just ignored + rc = pthread_mutex_trylock(&(it->second->mutex)); + + if ( rc == EBUSY ) // In use by other thread + { + it++; + continue; + } + } + + tmp_ptr = it->second; + + // map::erase does not invalidate the iterator, except for the current + // one + pool.erase(it++); + + if ( uses_name_pool ) + { + string okey = key(tmp_ptr->name,tmp_ptr->uid); + name_pool.erase(okey); + } + + delete tmp_ptr; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void PoolSQL::flush_cache(const string& name_key) +{ + int rc; + PoolObjectSQL * tmp_ptr; + + map::iterator it; + + for (it = name_pool.begin(); it != name_pool.end(); ) + { + string okey = key(it->second->name, it->second->uid); + + // The object we are looking for in ::get(). Will wait until it is + // unlocked() + if (name_key == okey) + { + it->second->lock(); + } + else + { + // Any other locked object is just ignored + rc = pthread_mutex_trylock(&(it->second->mutex)); + + if ( rc == EBUSY ) // In use by other thread + { + it++; + continue; + } + } + + tmp_ptr = it->second; + + // map::erase does not invalidate the iterator, except for the current + // one + name_pool.erase(it++); + pool.erase(tmp_ptr->oid); + + delete tmp_ptr; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void PoolSQL::clean() { map::iterator it; diff --git a/src/um/UserPool.cc b/src/um/UserPool.cc index 90c0407b02..63e488b88f 100644 --- a/src/um/UserPool.cc +++ b/src/um/UserPool.cc @@ -55,8 +55,9 @@ string UserPool::oneadmin_name; UserPool::UserPool(SqlDB * db, time_t __session_expiration_time, vector hook_mads, - const string& remotes_location): - PoolSQL(db, User::table, true) + const string& remotes_location, + bool cache): + PoolSQL(db, User::table, cache, true) { int one_uid = -1; int server_uid = -1; diff --git a/src/vm/VirtualMachinePool.cc b/src/vm/VirtualMachinePool.cc index 361a27620f..70ac7514f1 100644 --- a/src/vm/VirtualMachinePool.cc +++ b/src/vm/VirtualMachinePool.cc @@ -38,7 +38,7 @@ VirtualMachinePool::VirtualMachinePool( vector& restricted_attrs, time_t expire_time, bool on_hold) - : PoolSQL(db, VirtualMachine::table, false) + : PoolSQL(db, VirtualMachine::table, true, false) { const VectorAttribute * vattr; diff --git a/src/vnm/VirtualNetworkPool.cc b/src/vnm/VirtualNetworkPool.cc index 9d53dd2d6d..8d2666386d 100644 --- a/src/vnm/VirtualNetworkPool.cc +++ b/src/vnm/VirtualNetworkPool.cc @@ -38,7 +38,7 @@ VirtualNetworkPool::VirtualNetworkPool( vector hook_mads, const string& remotes_location, const vector& _inherit_attrs): - PoolSQL(db, VirtualNetwork::table, true) + PoolSQL(db, VirtualNetwork::table, true, true) { istringstream iss; size_t pos = 0; diff --git a/src/zone/ZonePool.cc b/src/zone/ZonePool.cc index 5e971cf356..753fbebd62 100644 --- a/src/zone/ZonePool.cc +++ b/src/zone/ZonePool.cc @@ -20,8 +20,8 @@ /* -------------------------------------------------------------------------- */ -ZonePool::ZonePool(SqlDB * db) - :PoolSQL(db, Zone::table, true) +ZonePool::ZonePool(SqlDB * db, bool cache) + :PoolSQL(db, Zone::table, cache, true) { if (get_lastOID() == -1) //lastOID is set in PoolSQL::init_cb { From ab479bdc7281465cdc3b1b805fe56b2657ae9b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= Date: Mon, 27 Jan 2014 17:44:27 +0100 Subject: [PATCH 2/2] Feature #2672: Disable ACL cache for federation slave nodes --- include/AclManager.h | 67 ++++++++++++++++++++++++++++-- src/acl/AclManager.cc | 96 +++++++++++++++++++++++++++++++++++++++++-- src/nebula/Nebula.cc | 10 ++++- 3 files changed, 164 insertions(+), 9 deletions(-) diff --git a/include/AclManager.h b/include/AclManager.h index c7e410d6e9..10df70ee7d 100644 --- a/include/AclManager.h +++ b/include/AclManager.h @@ -28,15 +28,18 @@ using namespace std; class PoolObjectAuth; +extern "C" void * acl_action_loop(void *arg); + /** * This class manages the ACL rules and the authorization engine */ -class AclManager : public Callbackable +class AclManager : public Callbackable, public ActionListener { public: - AclManager(SqlDB * _db); + AclManager(SqlDB * _db, bool _refresh_cache, time_t timer_period); - AclManager():db(0),lastOID(0) + AclManager() + :db(0),lastOID(0), refresh_cache(false) { pthread_mutex_init(&mutex, 0); }; @@ -44,11 +47,14 @@ public: virtual ~AclManager(); /** - * Loads the ACL rule set from the DB + * Loads the ACL rule set from the DB, and starts the refresh loop is + * refresh_cache is set * @return 0 on success. */ int start(); + void finalize(); + /* ---------------------------------------------------------------------- */ /* Rule management */ /* ---------------------------------------------------------------------- */ @@ -181,6 +187,20 @@ public: */ virtual int dump(ostringstream& oss); + // ---------------------------------------- + // Refresh loop thread + // ---------------------------------------- + + /** + * Gets the AclManager thread identification. The thread is only + * initialized if the refresh_cache flag is true. + * @return pthread_t for the manager thread (that in the action loop). + */ + pthread_t get_thread_id() const + { + return acl_thread; + }; + protected: // ---------------------------------------- @@ -379,6 +399,45 @@ private: * Callback to set the lastOID */ int init_cb(void *nil, int num, char **values, char **names); + + // ---------------------------------------- + // Refresh loop thread + // ---------------------------------------- + + /** + * Flag to refresh the cache periodically + */ + bool refresh_cache; + + /** + * Timer period for the cache refresh loop. + */ + time_t timer_period; + + /** + * Thread id for the ACL Manager + */ + pthread_t acl_thread; + + /** + * Action engine for the Manager + */ + ActionManager am; + + /** + * Function to execute the Manager action loop method within a new pthread + * (requires C linkage) + */ + friend void * acl_action_loop(void *arg); + + /** + * The action function executed when an action is triggered. + * @param action the name of the action + * @param arg arguments for the action function + */ + void do_action( + const string & action, + void * arg); }; #endif /*ACL_MANAGER_H*/ diff --git a/src/acl/AclManager.cc b/src/acl/AclManager.cc index d514b023b2..4f80bc540c 100644 --- a/src/acl/AclManager.cc +++ b/src/acl/AclManager.cc @@ -48,7 +48,9 @@ int AclManager::init_cb(void *nil, int num, char **values, char **names) /* -------------------------------------------------------------------------- */ -AclManager::AclManager(SqlDB * _db) : db(_db), lastOID(-1) +AclManager::AclManager(SqlDB * _db, bool _refresh_cache, time_t _timer_period) + : db(_db), lastOID(-1), refresh_cache(_refresh_cache), + timer_period(_timer_period) { ostringstream oss; @@ -99,6 +101,31 @@ AclManager::AclManager(SqlDB * _db) : db(_db), lastOID(-1) error_str); } + + am.addListener(this); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +extern "C" void * acl_action_loop(void *arg) +{ + AclManager * aclm; + + if ( arg == 0 ) + { + return 0; + } + + NebulaLog::log("ACL",Log::INFO,"ACL Manager started."); + + aclm = static_cast(arg); + + aclm->am.loop(aclm->timer_period,0); + + NebulaLog::log("ACL",Log::INFO,"ACL Manager stopped."); + + return 0; } /* -------------------------------------------------------------------------- */ @@ -106,10 +133,42 @@ AclManager::AclManager(SqlDB * _db) : db(_db), lastOID(-1) int AclManager::start() { - acl_rules.clear(); - acl_rules_oids.clear(); + int rc; - return select(); + NebulaLog::log("ACL",Log::INFO,"Starting ACL Manager..."); + + rc = select(); + + if (refresh_cache) + { + pthread_attr_t pattr; + + pthread_attr_init (&pattr); + pthread_attr_setdetachstate (&pattr, PTHREAD_CREATE_JOINABLE); + + rc += pthread_create(&acl_thread,&pattr,acl_action_loop,(void *) this); + } + else + { + NebulaLog::log("ACL",Log::INFO,"ACL Manager started."); + } + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void AclManager::finalize() +{ + if (refresh_cache) + { + am.trigger(ACTION_FINALIZE,0); + } + else + { + NebulaLog::log("ACL",Log::INFO,"ACL Manager stopped."); + } } /* -------------------------------------------------------------------------- */ @@ -1007,8 +1066,15 @@ int AclManager::select() set_callback(static_cast(&AclManager::select_cb)); + lock(); + + acl_rules.clear(); + acl_rules_oids.clear(); + rc = db->exec(oss,this); + unlock(); + unset_callback(); return rc; @@ -1079,3 +1145,25 @@ int AclManager::dump(ostringstream& oss) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + +void AclManager::do_action(const string &action, void * arg) +{ + if (action == ACTION_TIMER) + { + select(); + } + else if (action == ACTION_FINALIZE) + { + NebulaLog::log("ACL",Log::INFO,"Stopping ACL Manager..."); + } + else + { + ostringstream oss; + oss << "Unknown action name: " << action; + + NebulaLog::log("ACL", Log::ERROR, oss); + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/nebula/Nebula.cc b/src/nebula/Nebula.cc index 83f4b68e48..1c8a265366 100644 --- a/src/nebula/Nebula.cc +++ b/src/nebula/Nebula.cc @@ -911,9 +911,11 @@ void Nebula::start(bool bootstrap_only) } // ---- ACL Manager ---- + bool refresh_acl_cache = is_federation_slave(); + try { - aclm = new AclManager(db); + aclm = new AclManager(db, refresh_acl_cache, timer_period); } catch (bad_alloc&) { @@ -1060,6 +1062,7 @@ void Nebula::start(bool bootstrap_only) rm->finalize(); hm->finalize(); imagem->finalize(); + aclm->finalize(); //sleep to wait drivers??? @@ -1073,6 +1076,11 @@ void Nebula::start(bool bootstrap_only) pthread_join(hm->get_thread_id(),0); pthread_join(imagem->get_thread_id(),0); + if(refresh_acl_cache) + { + pthread_join(aclm->get_thread_id(),0); + } + //XML Library xmlCleanupParser();