diff -r 8ea54e7be3e2 -r 93c613913912 server/repository.py --- a/server/repository.py Fri Apr 24 19:46:14 2009 +0200 +++ b/server/repository.py Fri Apr 24 19:46:21 2009 +0200 @@ -60,7 +60,7 @@ remove inserted eid from repository type/source cache """ self.repo.clear_caches(self.session.query_data('pendingeids', ())) - + def rollback_event(self): """the observed connections pool has been rollbacked, remove inserted eid from repository type/source cache @@ -84,7 +84,7 @@ session.repo.system_source.fti_unindex_entity(session, entity.eid) for container in entity.fti_containers(): session.repo.index_entity(session, container) - + def commit_event(self): pass @@ -120,14 +120,14 @@ 'DELETE X %s Y WHERE NOT X eid %%(x)s, Y eid %%(y)s' % rtype, {'x': eidfrom, 'y': eidto}, 'y') - + class Repository(object): """a repository provides access to a set of persistent storages for entities and relations XXX protect pyro access """ - + def __init__(self, config, vreg=None, debug=False): self.config = config if vreg is None: @@ -155,7 +155,7 @@ for uri, source_config in config.sources().items(): if uri == 'admin': # not an actual source - continue + continue source = self.get_source(uri, source_config) self.sources_by_uri[uri] = source self.sources.append(source) @@ -214,16 +214,16 @@ source.init_creating() # close initialization pool and reopen fresh ones for proper # initialization now that we know cubes - self._get_pool().close(True) + self._get_pool().close(True) for i in xrange(config['connections-pool-size']): self._available_pools.put_nowait(ConnectionsPool(self.sources)) - + # internals ############################################################### def get_source(self, uri, source_config): source_config['uri'] = uri return get_source(source_config, self.schema, self) - + def set_schema(self, schema, resetvreg=True): schema.rebuild_infered_relations() self.info('set schema %s %#x', schema.name, id(schema)) @@ -259,7 +259,7 @@ except Exception, ex: import traceback traceback.print_exc() - raise Exception('Is the database initialised ? (cause: %s)' % + raise Exception('Is the database initialised ? (cause: %s)' % (ex.args and ex.args[0].strip() or 'unknown')), \ None, sys.exc_info()[-1] self.info('set the actual schema') @@ -277,7 +277,7 @@ session.close() self.config.init_cubes(self.get_cubes()) self.set_schema(appschema) - + def set_bootstrap_schema(self, schema): """disable hooks when setting a bootstrap schema, but restore the configuration for the next time @@ -295,7 +295,7 @@ config.schema_hooks = True config.notification_hooks = True config.application_hooks = True - + def start_looping_tasks(self): assert isinstance(self._looping_tasks, list), 'already started' for i, (interval, func) in enumerate(self._looping_tasks): @@ -308,7 +308,7 @@ def looping_task(self, interval, func): """register a function to be called every `interval` seconds. - + looping tasks can only be registered during repository initialization, once done this method will fail. """ @@ -321,7 +321,7 @@ """start function in a separated thread""" t = RepoThread(func, self._running_threads) t.start() - + #@locked def _get_pool(self): try: @@ -332,7 +332,7 @@ 'connections) or to much load on the server (in ' 'which case you can try to set a bigger ' 'connections pools size)') - + def _free_pool(self, pool): pool.rollback() self._available_pools.put_nowait(pool) @@ -382,7 +382,7 @@ ((hits + misses) * 100) / (hits + misses + nocache)) except ZeroDivisionError: pass - + def authenticate_user(self, session, login, password): """validate login / password, raise AuthenticationError on failure return associated CWUser instance on success @@ -415,9 +415,9 @@ euser.groups euser.properties return euser - + # public (dbapi) interface ################################################ - + def get_schema(self): """return the application schema. This is a public method, not requiring a session id @@ -469,7 +469,7 @@ finally: session.close() return vcconf - + @cached def source_defs(self): sources = self.config.sources().copy() @@ -526,13 +526,13 @@ finally: session.close() return True - + def connect(self, login, password, cnxprops=None): """open a connection for a given user base_url may be needed to send mails cnxtype indicate if this is a pyro connection or a in-memory connection - + raise `AuthenticationError` if the authentication failed raise `ConnectionError` if we can't open a connection """ @@ -584,7 +584,7 @@ raise finally: session.reset_pool() - + def describe(self, sessionid, eid): """return a tuple (type, source, extid) for the entity with id """ session = self._get_session(sessionid, setpool=True) @@ -618,12 +618,12 @@ self.debug('begin commit for session %s', sessionid) try: self._get_session(sessionid, setpool=True).commit() - except (ValidationError, Unauthorized): + except (ValidationError, Unauthorized): raise except: self.exception('unexpected error') raise - + def rollback(self, sessionid): """commit transaction for the session with the given id""" self.debug('begin rollback for session %s', sessionid) @@ -645,7 +645,7 @@ session.close() del self._sessions[sessionid] self.info('closed session %s for user %s', sessionid, session.user.login) - + def user_info(self, sessionid, props=None): """this method should be used by client to: * check session id validity @@ -659,9 +659,9 @@ session.change_property(prop, value) user = session.user return user.eid, user.login, user.groups, user.properties - + # public (inter-repository) interface ##################################### - + def entities_modified_since(self, etypes, mtime): """function designed to be called from an external repository which is using this one as a rql source for synchronization, and return a @@ -683,7 +683,7 @@ session.close() # session handling ######################################################## - + def close_sessions(self): """close every opened sessions""" for sessionid in self._sessions.keys(): @@ -705,7 +705,7 @@ self.close(session.id) nbclosed += 1 return nbclosed - + def internal_session(self, cnxprops=None): """return a dbapi like connection/cursor using internal user which have every rights on the repository. You'll *have to* commit/rollback @@ -716,7 +716,7 @@ session = InternalSession(self, cnxprops) session.set_pool() return session - + def _get_session(self, sessionid, setpool=False): """return the user associated to the given session identifier""" try: @@ -731,7 +731,7 @@ # * correspondance between eid and (type, source) # * correspondance between eid and local id (i.e. specific to a given source) # * searchable text indexes - + def type_and_source_from_eid(self, eid, session=None): """return a tuple (type, source, extid) for the entity with id """ try: @@ -771,15 +771,15 @@ rqlcache.pop('Any X WHERE X eid %s' % eid, None) for source in self.sources: source.clear_eid_cache(eid, etype) - + def type_from_eid(self, eid, session=None): """return the type of the entity with id """ return self.type_and_source_from_eid(eid, session)[0] - + def source_from_eid(self, eid, session=None): """return the source for the given entity's eid""" return self.sources_by_uri[self.type_and_source_from_eid(eid, session)[1]] - + def eid2extid(self, source, eid, session=None): """get local id from an eid""" etype, uri, extid = self.type_and_source_from_eid(eid, session) @@ -848,7 +848,7 @@ except: session.rollback(reset_pool) raise - + def add_info(self, session, entity, source, extid=None, complete=True): """add type and source info for an eid into the system table, and index the entity with the full text index @@ -862,11 +862,11 @@ if self.do_fti: FTIndexEntityOp(session, entity=entity) CleanupEidTypeCacheOp(session) - + def delete_info(self, session, eid): self._prepare_delete_info(session, eid) self._delete_info(session, eid) - + def _prepare_delete_info(self, session, eid): """prepare the repository for deletion of an entity: * update the fti @@ -877,7 +877,7 @@ pending = session.query_data('pendingeids', set(), setdefault=True) pending.add(eid) CleanupEidTypeCacheOp(session) - + def _delete_info(self, session, eid): """delete system information on deletion of an entity: * delete all relations on this entity @@ -886,7 +886,7 @@ etype, uri, extid = self.type_and_source_from_eid(eid, session) self._clear_eid_relations(session, etype, eid) self.system_source.delete_info(session, eid, etype, uri, extid) - + def _clear_eid_relations(self, session, etype, eid): """when a entity is deleted, build and execute rql query to delete all its relations @@ -917,7 +917,7 @@ return alreadydone.add(entity.eid) self.system_source.fti_index_entity(session, entity) - + def locate_relation_source(self, session, subject, rtype, object): subjsource = self.source_from_eid(subject, session) objsource = self.source_from_eid(object, session) @@ -928,17 +928,17 @@ else: source = subjsource return source - + def locate_etype_source(self, etype): for source in self.sources: if source.support_entity(etype, 1): return source else: raise ETypeNotSupportedBySources(etype) - + def glob_add_entity(self, session, entity): """add an entity to the repository - + the entity eid should originaly be None and a unique eid is assigned to the entity instance """ @@ -981,7 +981,7 @@ self.hm.call_hooks('after_add_relation', attr, session, entity.eid, attr, value) return entity.eid - + def glob_update_entity(self, session, entity): """replace an entity in the repository the type and the eid of an entity must not be changed @@ -1051,7 +1051,7 @@ if source.should_call_hooks: self.hm.call_hooks('after_delete_entity', etype, session, eid) # don't clear cache here this is done in a hook on commit - + def glob_add_relation(self, session, subject, rtype, object): """add a relation to the repository""" assert subject is not None @@ -1089,7 +1089,7 @@ # pyro handling ########################################################### - + def pyro_register(self, host=''): """register the repository as a pyro object""" from Pyro import core @@ -1108,7 +1108,7 @@ self.info(msg, nsgroup, nsid) self.pyro_registered = True return daemon - + def pyro_nameserver(self, host=None, group=None): """locate and bind the the name server to the daemon""" from Pyro import naming, errors @@ -1123,25 +1123,25 @@ return nameserver # multi-sources planner helpers ########################################### - + @cached def rel_type_sources(self, rtype): return [source for source in self.sources if source.support_relation(rtype) or rtype in source.dont_cross_relations] - + @cached def can_cross_relation(self, rtype): return [source for source in self.sources if source.support_relation(rtype) and rtype in source.cross_relations] - + @cached def is_multi_sources_relation(self, rtype): return any(source for source in self.sources if not source is self.system_source and source.support_relation(rtype)) - + def pyro_unregister(config): """unregister the repository from the pyro name server"""