From c9c2e1401bae1938fe392f6ee0903939b63b050c Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 30 Jun 2009 22:57:29 +0200 Subject: =?UTF-8?q?UserManager=20erweitert=20Erm=C3=B6gliche=20Caching=20d?= =?UTF-8?q?er=20User-Group-Zuordnungen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/Backends/NetworkUserBackend.cpp | 20 ++++++ src/Common/Backends/NetworkUserBackend.h | 2 + src/Common/UserBackend.h | 4 ++ src/Common/UserCache.cpp | 59 +++++++++++++++++- src/Common/UserCache.h | 8 ++- src/Common/UserManager.cpp | 18 ++++++ src/Common/UserManager.h | 2 + .../RequestHandlers/UserRequestHandlerGroup.cpp | 16 +++++ .../RequestHandlers/UserRequestHandlerGroup.h | 2 + src/mad-server.conf | 1 + src/modules/UserBackendMysql/UserBackendMysql.cpp | 71 ++++++++++++++++++++-- src/modules/UserBackendMysql/UserBackendMysql.h | 7 +++ 12 files changed, 199 insertions(+), 11 deletions(-) diff --git a/src/Common/Backends/NetworkUserBackend.cpp b/src/Common/Backends/NetworkUserBackend.cpp index 81fc94a..f75783c 100644 --- a/src/Common/Backends/NetworkUserBackend.cpp +++ b/src/Common/Backends/NetworkUserBackend.cpp @@ -188,6 +188,26 @@ boost::shared_ptr > NetworkUserBackend::getGroupUs return userList; } +boost::shared_ptr > NetworkUserBackend::getFullUserGroupList() throw(Core::Exception) { + boost::shared_ptr request(new SimpleUserRequest(application, "GetFullUserGroupList")); + application->getRequestManager()->sendRequest(connection, request); + request->wait(); + + std::pair, Core::Exception> result = request->getResult(); + if(!result.first || result.second) + throw result.second; + + boost::shared_ptr > ret(new std::multimap); + + const XmlPacket::List *list = result.first->getList("userGroupList"); + if(list) { + for(XmlPacket::List::const_iterator entry = list->begin(); entry != list->end(); ++entry) + ret->insert(std::make_pair(entry->get("uid"), entry->get("gid"))); + } + + return ret; +} + /*void NetworkUserBackend::setPassword(unsigned long uid, const std::string &password) throw(Core::Exception) { diff --git a/src/Common/Backends/NetworkUserBackend.h b/src/Common/Backends/NetworkUserBackend.h index c569ab6..66be909 100644 --- a/src/Common/Backends/NetworkUserBackend.h +++ b/src/Common/Backends/NetworkUserBackend.h @@ -77,6 +77,8 @@ class NetworkUserBackend : public UserBackend { virtual boost::shared_ptr getGroupInfoByName(const std::string &name) throw(Core::Exception); virtual boost::shared_ptr > getGroupUserList(unsigned long gid) throw(Core::Exception); + virtual boost::shared_ptr > getFullUserGroupList() throw(Core::Exception); + //virtual void setPassword(unsigned long uid, const std::string &password) throw(Core::Exception); //virtual void addUser(const UserInfo &userInfo) throw(Core::Exception); diff --git a/src/Common/UserBackend.h b/src/Common/UserBackend.h index 9983ee0..829aae7 100644 --- a/src/Common/UserBackend.h +++ b/src/Common/UserBackend.h @@ -80,6 +80,10 @@ class UserBackend { throw(Core::Exception(Core::Exception::NOT_IMPLEMENTED)); } + virtual boost::shared_ptr > getFullUserGroupList() throw(Core::Exception) { + throw(Core::Exception(Core::Exception::NOT_IMPLEMENTED)); + } + virtual void setPassword(unsigned long uid _UNUSED_PARAMETER_, const std::string &password _UNUSED_PARAMETER_) throw(Core::Exception) { throw(Core::Exception(Core::Exception::NOT_IMPLEMENTED)); } diff --git a/src/Common/UserCache.cpp b/src/Common/UserCache.cpp index 63f72dd..79f27c7 100644 --- a/src/Common/UserCache.cpp +++ b/src/Common/UserCache.cpp @@ -83,7 +83,21 @@ boost::shared_ptr UserCache::getUserInfoByName(const std::string } boost::shared_ptr > UserCache::getUserGroupList(unsigned long uid) throw(Core::Exception) { - return backend->getUserGroupList(uid); + getFullUserGroupList(); + + boost::lock_guard lock(mutex); + + if(!userGroups) + throw userGroupException; + + std::pair::const_iterator, std::multimap::const_iterator> range = userGroups->equal_range(uid); + + boost::shared_ptr > groups(new std::set); + + for(std::multimap::const_iterator group = range.first; group != range.second; ++group) + groups->insert(group->second); + + return groups; } @@ -145,8 +159,47 @@ boost::shared_ptr UserCache::getGroupInfoByName(const std::stri return boost::shared_ptr(new GroupInfo(group->second)); } -boost::shared_ptr > UserCache::getGroupUserList(unsigned long uid) throw(Core::Exception) { - return backend->getGroupUserList(uid); +boost::shared_ptr > UserCache::getGroupUserList(unsigned long gid) throw(Core::Exception) { + getFullUserGroupList(); + + boost::lock_guard lock(mutex); + + if(!userGroups) + throw userGroupException; + + std::pair::iterator, std::multimap::iterator> range = groupUsers->equal_range(gid); + + boost::shared_ptr > users(new std::set); + + for(std::multimap::iterator user = range.first; user != range.second; ++user) + users->insert(user->second); + + return users; +} + +boost::shared_ptr > UserCache::getFullUserGroupList() throw(Core::Exception) { + boost::lock_guard lock(mutex); + + if(userGroups) { + std::cerr << "Cached" << std::endl; + return userGroups; + } + else if(userGroupException) + throw userGroupException; + + try { + userGroups = backend->getFullUserGroupList(); + + groupUsers.reset(new std::multimap); + for(std::multimap::const_iterator usergroup = userGroups->begin(); usergroup != userGroups->end(); ++usergroup) + groupUsers->insert(std::make_pair(usergroup->second, usergroup->first)); + + return userGroups; + } + catch(Core::Exception e) { + userGroupException = e; + throw userGroupException; + } } } diff --git a/src/Common/UserCache.h b/src/Common/UserCache.h index 1e432fd..cec5ea5 100644 --- a/src/Common/UserCache.h +++ b/src/Common/UserCache.h @@ -47,9 +47,9 @@ class UserCache : public UserBackend, private boost::noncopyable { boost::shared_ptr > groupNames; Core::Exception groupException; - /*boost::shared_ptr > userGroups; - boost::shared_ptr > groupUsers; - Core::Exception userGroupException;*/ + boost::shared_ptr > userGroups; + boost::shared_ptr > groupUsers; + Core::Exception userGroupException; protected: virtual boost::shared_ptr > getUserList() throw(Core::Exception); @@ -62,6 +62,8 @@ class UserCache : public UserBackend, private boost::noncopyable { virtual boost::shared_ptr getGroupInfoByName(const std::string &name) throw(Core::Exception); virtual boost::shared_ptr > getGroupUserList(unsigned long gid) throw(Core::Exception); + virtual boost::shared_ptr > getFullUserGroupList() throw(Core::Exception); + virtual void setPassword(unsigned long uid, const std::string &password) throw(Core::Exception) { backend->setPassword(uid, password); } diff --git a/src/Common/UserManager.cpp b/src/Common/UserManager.cpp index 253466e..c56195d 100644 --- a/src/Common/UserManager.cpp +++ b/src/Common/UserManager.cpp @@ -189,6 +189,24 @@ boost::shared_ptr > UserManager::getGroupUserList( throw e; } +boost::shared_ptr > UserManager::getFullUserGroupList() throw(Core::Exception) { + Core::Exception e(Core::Exception::NOT_IMPLEMENTED); + + boost::lock_guard lock(mutex); + + for(BackendMap::iterator backend = backends.begin(); backend != backends.end(); ++backend) { + try { + return backend->second->getFullUserGroupList(); + } + catch(Core::Exception e2) { + if(e.getErrorCode() == Core::Exception::NOT_IMPLEMENTED && e2.getErrorCode() != Core::Exception::NOT_IMPLEMENTED) + e = e2; + } + } + + throw e; +} + void UserManager::setPassword(unsigned long uid, const std::string &password) throw(Core::Exception) { Core::Exception e(Core::Exception::NOT_IMPLEMENTED); diff --git a/src/Common/UserManager.h b/src/Common/UserManager.h index 7413970..1ba051f 100644 --- a/src/Common/UserManager.h +++ b/src/Common/UserManager.h @@ -77,6 +77,8 @@ class UserManager : boost::noncopyable { boost::shared_ptr getGroupInfoByName(const std::string &name) throw(Core::Exception); boost::shared_ptr > getGroupUserList(unsigned long gid) throw(Core::Exception); + boost::shared_ptr > getFullUserGroupList() throw(Core::Exception); + void setPassword(unsigned long uid, const std::string &password) throw(Core::Exception); void addUser(const UserInfo &userInfo) throw(Core::Exception); diff --git a/src/Server/RequestHandlers/UserRequestHandlerGroup.cpp b/src/Server/RequestHandlers/UserRequestHandlerGroup.cpp index 31d2c16..9e4d23c 100644 --- a/src/Server/RequestHandlers/UserRequestHandlerGroup.cpp +++ b/src/Server/RequestHandlers/UserRequestHandlerGroup.cpp @@ -119,6 +119,20 @@ void UserRequestHandlerGroup::handleGroupUserListRequest(boost::shared_ptr packet, Common::XmlPacket *ret, Common::Connection *connection) { + boost::shared_ptr > userGroups = application->getUserManager()->getFullUserGroupList(); + + ret->setType("OK"); + Common::XmlPacket::List *list = ret->createList("userGroupList"); + + for(std::map::const_iterator userGroup = userGroups->begin(); userGroup != userGroups->end(); ++userGroup) { + Common::XmlPacket::List::iterator entry = list->addEntry(); + + entry->set("uid", userGroup->first); + entry->set("gid", userGroup->second); + } +} + UserRequestHandlerGroup::UserRequestHandlerGroup(Application *application0) : application(application0) { registerHandler("ListUsers", boost::bind(&UserRequestHandlerGroup::handleUserListRequest, this, _1, _2, _3)); registerHandler("GetUserInfo", boost::bind(&UserRequestHandlerGroup::handleUserInfoRequest, this, _1, _2, _3)); @@ -127,6 +141,8 @@ UserRequestHandlerGroup::UserRequestHandlerGroup(Application *application0) : ap registerHandler("ListGroups", boost::bind(&UserRequestHandlerGroup::handleGroupListRequest, this, _1, _2, _3)); registerHandler("GetGroupInfo", boost::bind(&UserRequestHandlerGroup::handleGroupInfoRequest, this, _1, _2, _3)); registerHandler("ListGroupUsers", boost::bind(&UserRequestHandlerGroup::handleGroupUserListRequest, this, _1, _2, _3)); + + registerHandler("GetFullUserGroupList", boost::bind(&UserRequestHandlerGroup::handleFullUserGroupListRequest, this, _1, _2, _3)); } } diff --git a/src/Server/RequestHandlers/UserRequestHandlerGroup.h b/src/Server/RequestHandlers/UserRequestHandlerGroup.h index 744f895..a55a34f 100644 --- a/src/Server/RequestHandlers/UserRequestHandlerGroup.h +++ b/src/Server/RequestHandlers/UserRequestHandlerGroup.h @@ -41,6 +41,8 @@ class UserRequestHandlerGroup : public Common::RequestHandlers::SimpleRequestHan void handleGroupInfoRequest(boost::shared_ptr packet, Common::XmlPacket *ret, Common::Connection *connection); void handleGroupUserListRequest(boost::shared_ptr packet, Common::XmlPacket *ret, Common::Connection *connection); + void handleFullUserGroupListRequest(boost::shared_ptr packet, Common::XmlPacket *ret, Common::Connection *connection); + public: UserRequestHandlerGroup(Application *application0); }; diff --git a/src/mad-server.conf b/src/mad-server.conf index 09614c4..8ab08cc 100644 --- a/src/mad-server.conf +++ b/src/mad-server.conf @@ -24,6 +24,7 @@ UserBackendMysql { UserByName "SELECT id, gid, username, fullname FROM users WHERE username = {USER}" GroupById "SELECT id, name FROM groups WHERE id = {GID}" GroupByName "SELECT id, name FROM groups WHERE name = {GROUP}" + UserGroupTable "SELECT uid, gid FROM usergroups" } } diff --git a/src/modules/UserBackendMysql/UserBackendMysql.cpp b/src/modules/UserBackendMysql/UserBackendMysql.cpp index e6e6dda..6d64a51 100644 --- a/src/modules/UserBackendMysql/UserBackendMysql.cpp +++ b/src/modules/UserBackendMysql/UserBackendMysql.cpp @@ -28,7 +28,7 @@ #include #include - +#include namespace Mad { namespace Modules { @@ -106,6 +106,10 @@ bool UserBackendMysql::handleConfigEntry(const Core::ConfigEntry &entry, bool ha if(entry[3].empty()) queryGroupByName = entry[2][0]; } + else if(entry[2].getKey().matches("UserGroupTable")) { + if(entry[3].empty()) + queryUserGroupTable = entry[2][0]; + } else if(!entry[2].empty()) return false; } @@ -124,6 +128,7 @@ void UserBackendMysql::configFinished() { return; } + boost::lock_guard lock(mutex); mysql = mysql_init(0); mysql_real_connect(mysql, host.c_str(), username.c_str(), passwd.c_str(), db.c_str(), port, unixSocket.empty() ? 0 : unixSocket.c_str(), 0); } @@ -132,12 +137,16 @@ void UserBackendMysql::configFinished() { boost::shared_ptr > UserBackendMysql::getUserList() throw(Core::Exception) { application->getThreadManager()->detach(); + boost::unique_lock lock(mutex); + if(!mysql || mysql_ping(mysql)) throw Core::Exception(Core::Exception::NOT_AVAILABLE); mysql_real_query(mysql, queryListUsers.c_str(), queryListUsers.length()); MYSQL_RES *result = mysql_store_result(mysql); + lock.unlock(); + if(!result || mysql_num_fields(result) < 4) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -158,6 +167,8 @@ boost::shared_ptr > UserBackendM boost::shared_ptr UserBackendMysql::getUserInfo(unsigned long uid) throw(Core::Exception) { application->getThreadManager()->detach(); + boost::unique_lock lock(mutex); + if(!mysql || mysql_ping(mysql)) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -173,6 +184,8 @@ boost::shared_ptr UserBackendMysql::getUserInfo(unsigned mysql_real_query(mysql, query.c_str(), query.length()); MYSQL_RES *result = mysql_store_result(mysql); + lock.unlock(); + if(!result || mysql_num_fields(result) < 4) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -189,12 +202,14 @@ boost::shared_ptr UserBackendMysql::getUserInfo(unsigned return user; } - throw Core::Exception(Core::Exception::NOT_AVAILABLE); + throw Core::Exception(Core::Exception::NOT_FOUND); } boost::shared_ptr UserBackendMysql::getUserInfoByName(const std::string &name) throw(Core::Exception) { application->getThreadManager()->detach(); + boost::unique_lock lock(mutex); + if(!mysql || mysql_ping(mysql)) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -207,6 +222,8 @@ boost::shared_ptr UserBackendMysql::getUserInfoByName(co mysql_real_query(mysql, query.c_str(), query.length()); MYSQL_RES *result = mysql_store_result(mysql); + lock.unlock(); + if(!result || mysql_num_fields(result) < 4) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -223,12 +240,14 @@ boost::shared_ptr UserBackendMysql::getUserInfoByName(co return user; } - throw Core::Exception(Core::Exception::NOT_AVAILABLE); + throw Core::Exception(Core::Exception::NOT_FOUND); } boost::shared_ptr > UserBackendMysql::getUserGroupList(unsigned long uid) throw(Core::Exception) { application->getThreadManager()->detach(); + boost::unique_lock lock(mutex); + if(!mysql || mysql_ping(mysql)) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -242,6 +261,8 @@ boost::shared_ptr > UserBackendMysql::getUserGroup mysql_real_query(mysql, query.c_str(), query.length()); MYSQL_RES *result = mysql_store_result(mysql); + lock.unlock(); + if(!result || mysql_num_fields(result) < 1) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -257,12 +278,16 @@ boost::shared_ptr > UserBackendMysql::getUserGroup boost::shared_ptr > UserBackendMysql::getGroupList() throw(Core::Exception) { application->getThreadManager()->detach(); + boost::unique_lock lock(mutex); + if(!mysql || mysql_ping(mysql)) throw Core::Exception(Core::Exception::NOT_AVAILABLE); mysql_real_query(mysql, queryListGroups.c_str(), queryListGroups.length()); MYSQL_RES *result = mysql_store_result(mysql); + lock.unlock(); + if(!result || mysql_num_fields(result) < 2) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -280,6 +305,8 @@ boost::shared_ptr > UserBackend boost::shared_ptr UserBackendMysql::getGroupInfo(unsigned long gid) throw(Core::Exception) { application->getThreadManager()->detach(); + boost::unique_lock lock(mutex); + if(!mysql || mysql_ping(mysql)) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -295,6 +322,8 @@ boost::shared_ptr UserBackendMysql::getGroupInfo(unsign mysql_real_query(mysql, query.c_str(), query.length()); MYSQL_RES *result = mysql_store_result(mysql); + lock.unlock(); + if(!result || mysql_num_fields(result) < 2) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -303,12 +332,14 @@ boost::shared_ptr UserBackendMysql::getGroupInfo(unsign if(row) return boost::shared_ptr(new Common::GroupInfo(strtoul(row[0], 0, 10), row[1])); - throw Core::Exception(Core::Exception::NOT_AVAILABLE); + throw Core::Exception(Core::Exception::NOT_FOUND); } boost::shared_ptr UserBackendMysql::getGroupInfoByName(const std::string &name) throw(Core::Exception) { application->getThreadManager()->detach(); + boost::unique_lock lock(mutex); + if(!mysql || mysql_ping(mysql)) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -321,6 +352,8 @@ boost::shared_ptr UserBackendMysql::getGroupInfoByName( mysql_real_query(mysql, query.c_str(), query.length()); MYSQL_RES *result = mysql_store_result(mysql); + lock.unlock(); + if(!result || mysql_num_fields(result) < 2) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -329,12 +362,14 @@ boost::shared_ptr UserBackendMysql::getGroupInfoByName( if(row) return boost::shared_ptr(new Common::GroupInfo(strtoul(row[0], 0, 10), row[1])); - throw Core::Exception(Core::Exception::NOT_AVAILABLE); + throw Core::Exception(Core::Exception::NOT_FOUND); } boost::shared_ptr > UserBackendMysql::getGroupUserList(unsigned long gid) throw(Core::Exception) { application->getThreadManager()->detach(); + boost::unique_lock lock(mutex); + if(!mysql || mysql_ping(mysql)) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -348,6 +383,8 @@ boost::shared_ptr > UserBackendMysql::getGroupUser mysql_real_query(mysql, query.c_str(), query.length()); MYSQL_RES *result = mysql_store_result(mysql); + lock.unlock(); + if(!result || mysql_num_fields(result) < 1) throw Core::Exception(Core::Exception::NOT_AVAILABLE); @@ -359,6 +396,30 @@ boost::shared_ptr > UserBackendMysql::getGroupUser return users; } +boost::shared_ptr > UserBackendMysql::getFullUserGroupList() throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::unique_lock lock(mutex); + + if(!mysql || mysql_ping(mysql)) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + mysql_real_query(mysql, queryUserGroupTable.c_str(), queryUserGroupTable.length()); + MYSQL_RES *result = mysql_store_result(mysql); + + lock.unlock(); + + if(!result || mysql_num_fields(result) < 2) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + boost::shared_ptr > usergroups(new std::multimap); + + while(MYSQL_ROW row = mysql_fetch_row(result)) + usergroups->insert(std::make_pair(strtoul(row[0], 0, 10), strtoul(row[1], 0, 10))); + + return usergroups; +} + } } } diff --git a/src/modules/UserBackendMysql/UserBackendMysql.h b/src/modules/UserBackendMysql/UserBackendMysql.h index 7832e95..eadbf3b 100644 --- a/src/modules/UserBackendMysql/UserBackendMysql.h +++ b/src/modules/UserBackendMysql/UserBackendMysql.h @@ -28,6 +28,8 @@ #include +#include + namespace Mad { namespace Modules { namespace UserBackendMysql { @@ -43,9 +45,12 @@ class UserBackendMysql : public Common::UserBackend, private Core::Configurable std::string queryListUserGroups, queryListGroupUsers; std::string queryUserById, queryUserByName; std::string queryGroupById, queryGroupByName; + std::string queryUserGroupTable; MYSQL *mysql; + boost::mutex mutex; + protected: virtual bool handleConfigEntry(const Core::ConfigEntry &entry, bool); virtual void configFinished(); @@ -60,6 +65,8 @@ class UserBackendMysql : public Common::UserBackend, private Core::Configurable virtual boost::shared_ptr getGroupInfoByName(const std::string &name) throw(Core::Exception); virtual boost::shared_ptr > getGroupUserList(unsigned long gid) throw(Core::Exception); + virtual boost::shared_ptr > getFullUserGroupList() throw(Core::Exception); + public: UserBackendMysql(Common::Application *application0) : application(application0), port(0), mysql(0) { application->getConfigManager()->registerConfigurable(this); -- cgit v1.2.3