def shutdown(self, tid=None): """Free `Repository` instances bound to a given thread identifier""" if tid: assert tid == threading._get_ident() with self._lock: repositories = self._cache.pop(tid, {}) for reponame, repos in repositories.iteritems(): repos.close()
def shutdown(self, tid=None): if tid: assert tid == threading._get_ident() try: self._lock.acquire() repositories = self._cache.pop(tid, {}) for reponame, repos in repositories.iteritems(): repos.close() finally: self._lock.release()
def get_cnx(self, connector, kwargs, timeout=None): cnx = None log = kwargs.get('log') key = unicode(kwargs) start = time.time() tid = threading._get_ident() # Get a Connection, either directly or a deferred one with self._available: # First choice: Return the same cnx already used by the thread if (tid, key) in self._active: cnx, num = self._active[(tid, key)] num += 1 else: if self._waiters == 0: cnx = self._take_cnx(connector, kwargs, key, tid) if not cnx: self._waiters += 1 self._available.wait() self._waiters -= 1 cnx = self._take_cnx(connector, kwargs, key, tid) num = 1 if cnx: self._active[(tid, key)] = (cnx, num) deferred = num == 1 and isinstance(cnx, tuple) err = None if deferred: # Potentially lenghty operations must be done without lock held op, cnx = cnx try: if op == 'ping': cnx.ping() elif op == 'close': cnx.close() if op in ('close', 'create'): cnx = connector.get_connection(**kwargs) except TracError, e: err = e cnx = None except Exception, e: if log: log.error('Exception caught on %s', op, exc_info=True) err = e cnx = None
def get_repository(self, reponame): """Retrieve the appropriate `Repository` for the given repository name. :param reponame: the key for specifying the repository. If no name is given, take the default repository. :return: if no corresponding repository was defined, simply return `None`. :raises InvalidRepository: if the repository cannot be opened. """ reponame = reponame or '' repoinfo = self.get_all_repositories().get(reponame, {}) if 'alias' in repoinfo: reponame = repoinfo['alias'] repoinfo = self.get_all_repositories().get(reponame, {}) rdir = repoinfo.get('dir') if not rdir: return None rtype = repoinfo.get('type') or self.default_repository_type # get a Repository for the reponame (use a thread-level cache) with self.env.db_transaction: # prevent possible deadlock, see #4465 with self._lock: tid = threading._get_ident() if tid in self._cache: repositories = self._cache[tid] else: repositories = self._cache[tid] = {} repos = repositories.get(reponame) if not repos: if not os.path.isabs(rdir): rdir = os.path.join(self.env.path, rdir) connector = self._get_connector(rtype) repos = connector.get_repository(rtype, rdir, repoinfo.copy()) repositories[reponame] = repos return repos
def get_repository(self, reponame): """Retrieve the appropriate `Repository` for the given repository name. :param reponame: the key for specifying the repository. If no name is given, take the default repository. :return: if no corresponding repository was defined, simply return `None`. :raises InvalidRepository: if the repository cannot be opened. """ reponame = reponame or '' repoinfo = self.get_all_repositories().get(reponame, {}) if 'alias' in repoinfo: reponame = repoinfo['alias'] repoinfo = self.get_all_repositories().get(reponame, {}) rdir = repoinfo.get('dir') if not rdir: return None rtype = repoinfo.get('type') or self.repository_type # get a Repository for the reponame (use a thread-level cache) with self.env.db_transaction: # prevent possible deadlock, see #4465 with self._lock: tid = threading._get_ident() if tid in self._cache: repositories = self._cache[tid] else: repositories = self._cache[tid] = {} repos = repositories.get(reponame) if not repos: if not os.path.isabs(rdir): rdir = os.path.join(self.env.path, rdir) connector = self._get_connector(rtype) repos = connector.get_repository(rtype, rdir, repoinfo.copy()) repositories[reponame] = repos return repos
def get_repository(self, reponame): """Retrieve the appropriate Repository for the given name. :param reponame: the key for specifying the repository. If no name is given, take the default repository. :return: if no corresponding repository was defined, simply return `None`. """ reponame = reponame or '' repoinfo = self.get_all_repositories().get(reponame, {}) if 'alias' in repoinfo: reponame = repoinfo['alias'] repoinfo = self.get_all_repositories().get(reponame, {}) rdir = repoinfo.get('dir') if not rdir: return None rtype = repoinfo.get('type') or self.repository_type # get a Repository for the reponame (use a thread-level cache) db = self.env.get_db_cnx() # prevent possible deadlock, see #4465 try: self._lock.acquire() tid = threading._get_ident() if tid in self._cache: repositories = self._cache[tid] else: repositories = self._cache[tid] = {} repos = repositories.get(reponame) if not repos: if not os.path.isabs(rdir): rdir = os.path.join(self.env.path, rdir) connector = self._get_connector(rtype) repos = connector.get_repository(rtype, rdir, repoinfo.copy()) repositories[reponame] = repos return repos finally: self._lock.release()
def dispatch_request(environ, start_response): """Main entry point for the Trac web interface. :param environ: the WSGI environment dict :param start_response: the WSGI callback for starting the response """ global _warn_setuptools if _warn_setuptools is False: _warn_setuptools = True warn_setuptools_issue(out=environ.get('wsgi.errors')) # SCRIPT_URL is an Apache var containing the URL before URL rewriting # has been applied, so we can use it to reconstruct logical SCRIPT_NAME script_url = environ.get('SCRIPT_URL') if script_url is not None: path_info = environ.get('PATH_INFO') if not path_info: environ['SCRIPT_NAME'] = script_url else: # mod_wsgi squashes slashes in PATH_INFO (!) script_url = _slashes_re.sub('/', script_url) path_info = _slashes_re.sub('/', path_info) if script_url.endswith(path_info): environ['SCRIPT_NAME'] = script_url[:-len(path_info)] # If the expected configuration keys aren't found in the WSGI environment, # try looking them up in the process environment variables environ.setdefault('trac.env_path', os.getenv('TRAC_ENV')) environ.setdefault('trac.env_parent_dir', os.getenv('TRAC_ENV_PARENT_DIR')) environ.setdefault('trac.env_index_template', os.getenv('TRAC_ENV_INDEX_TEMPLATE')) environ.setdefault('trac.template_vars', os.getenv('TRAC_TEMPLATE_VARS')) environ.setdefault('trac.locale', '') environ.setdefault('trac.base_url', os.getenv('TRAC_BASE_URL')) locale.setlocale(locale.LC_ALL, environ['trac.locale']) # Determine the environment env_path = environ.get('trac.env_path') if not env_path: env_parent_dir = environ.get('trac.env_parent_dir') env_paths = environ.get('trac.env_paths') if env_parent_dir or env_paths: # The first component of the path is the base name of the # environment path_info = environ.get('PATH_INFO', '').lstrip('/').split('/') env_name = path_info.pop(0) if not env_name: # No specific environment requested, so render an environment # index page send_project_index(environ, start_response, env_parent_dir, env_paths) return [] errmsg = None # To make the matching patterns of request handlers work, we append # the environment name to the `SCRIPT_NAME` variable, and keep only # the remaining path in the `PATH_INFO` variable. script_name = environ.get('SCRIPT_NAME', '') try: script_name = unicode(script_name, 'utf-8') # (as Href expects unicode parameters) environ['SCRIPT_NAME'] = Href(script_name)(env_name) environ['PATH_INFO'] = '/' + '/'.join(path_info) if env_parent_dir: env_path = os.path.join(env_parent_dir, env_name) else: env_path = get_environments(environ).get(env_name) if not env_path or not os.path.isdir(env_path): errmsg = 'Environment not found' except UnicodeDecodeError: errmsg = 'Invalid URL encoding (was %r)' % script_name if errmsg: start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', str(len(errmsg)))]) return [errmsg] if not env_path: raise EnvironmentError('The environment options "TRAC_ENV" or ' '"TRAC_ENV_PARENT_DIR" or the mod_python ' 'options "TracEnv" or "TracEnvParentDir" are ' 'missing. Trac requires one of these options ' 'to locate the Trac environment(s).') run_once = environ['wsgi.run_once'] env = env_error = None try: env = open_environment(env_path, use_cache=not run_once) if env.base_url_for_redirect: environ['trac.base_url'] = env.base_url # Web front-end type and version information if not hasattr(env, 'webfrontend'): mod_wsgi_version = environ.get('mod_wsgi.version') if mod_wsgi_version: mod_wsgi_version = ( "%s (WSGIProcessGroup %s WSGIApplicationGroup %s)" % ('.'.join([str(x) for x in mod_wsgi_version ]), environ.get('mod_wsgi.process_group'), environ.get('mod_wsgi.application_group') or '%{GLOBAL}')) environ.update({ 'trac.web.frontend': 'mod_wsgi', 'trac.web.version': mod_wsgi_version }) env.webfrontend = environ.get('trac.web.frontend') if env.webfrontend: env.webfrontend_version = environ['trac.web.version'] except Exception as e: env_error = e req = RequestWithSession(environ, start_response) translation.make_activable(lambda: req.locale, env.path if env else None) try: return _dispatch_request(req, env, env_error) finally: translation.deactivate() if env and not run_once: env.shutdown(threading._get_ident()) # Now it's a good time to do some clean-ups # # Note: enable the '##' lines as soon as there's a suspicion # of memory leak due to uncollectable objects (typically # objects with a __del__ method caught in a cycle) # ##gc.set_debug(gc.DEBUG_UNCOLLECTABLE) unreachable = gc.collect()
def get_cnx(self, connector, kwargs, timeout=None): cnx = None log = kwargs.get('log') key = unicode(kwargs) start = time.time() tid = threading._get_ident() # Get a Connection, either directly or a deferred one with self._available: # First choice: Return the same cnx already used by the thread if (tid, key) in self._active: cnx, num = self._active[(tid, key)] num += 1 else: if self._waiters == 0: cnx = self._take_cnx(connector, kwargs, key, tid) if not cnx: self._waiters += 1 self._available.wait() self._waiters -= 1 cnx = self._take_cnx(connector, kwargs, key, tid) num = 1 if cnx: self._active[(tid, key)] = (cnx, num) deferred = num == 1 and isinstance(cnx, tuple) exc_info = (None, None, None) if deferred: # Potentially lengthy operations must be done without lock held op, cnx = cnx try: if op == 'ping': cnx.ping() elif op == 'close': cnx.close() if op in ('close', 'create'): cnx = connector.get_connection(**kwargs) except TracError: exc_info = sys.exc_info() cnx = None except Exception: exc_info = sys.exc_info() if log: log.error('Exception caught on %s', op, exc_info=True) cnx = None if cnx and not isinstance(cnx, tuple): if deferred: # replace placeholder with real Connection with self._available: self._active[(tid, key)] = (cnx, num) return PooledConnection(self, cnx, key, tid, log) if deferred: # cnx couldn't be reused, clear placeholder with self._available: del self._active[(tid, key)] if op == 'ping': # retry return self.get_cnx(connector, kwargs) # if we didn't get a cnx after wait(), something's fishy... if isinstance(exc_info[1], TracError): raise exc_info[0], exc_info[1], exc_info[2] timeout = time.time() - start errmsg = _("Unable to get database connection within %(time)d seconds.", time=timeout) if exc_info[1]: errmsg += " (%s)" % exception_to_unicode(exc_info[1]) raise TimeoutError(errmsg)
'trac.web.version': mod_wsgi_version}) env.webfrontend = environ.get('trac.web.frontend') if env.webfrontend: env.systeminfo.append((env.webfrontend, environ['trac.web.version'])) except Exception, e: env_error = e req = RequestWithSession(environ, start_response) translation.make_activable(lambda: req.locale, env.path if env else None) try: return _dispatch_request(req, env, env_error) finally: translation.deactivate() if env and not run_once: env.shutdown(threading._get_ident()) # Now it's a good time to do some clean-ups # # Note: enable the '##' lines as soon as there's a suspicion # of memory leak due to uncollectable objects (typically # objects with a __del__ method caught in a cycle) # ##gc.set_debug(gc.DEBUG_UNCOLLECTABLE) unreachable = gc.collect() ##env.log.debug("%d unreachable objects found.", unreachable) ##uncollectable = len(gc.garbage) ##if uncollectable: ## del gc.garbage[:] ## env.log.warn("%d uncollectable objects found.", uncollectable)
if env is not None else Request(environ, start_response) except Exception, e: log = environ.get('wsgi.errors') if log: log.write("[FAIL] [Trac] Entry point '%s' " "Method 'create_request' Reason %s" % (bootstrap_ep, repr(exception_to_unicode(e)))) if req is None: req = RequestWithSession(environ, start_response) translation.make_activable(lambda: req.locale, env.path if env else None) try: return _dispatch_request(req, env, env_error) finally: translation.deactivate() if env and not run_once: env.shutdown(threading._get_ident()) # Now it's a good time to do some clean-ups # # Note: enable the '##' lines as soon as there's a suspicion # of memory leak due to uncollectable objects (typically # objects with a __del__ method caught in a cycle) # ##gc.set_debug(gc.DEBUG_UNCOLLECTABLE) unreachable = gc.collect() ##env.log.debug("%d unreachable objects found.", unreachable) ##uncollectable = len(gc.garbage) ##if uncollectable: ## del gc.garbage[:] ## env.log.warn("%d uncollectable objects found.", uncollectable)
def dispatch_request(environ, start_response): """Main entry point for the Trac web interface. :param environ: the WSGI environment dict :param start_response: the WSGI callback for starting the response """ global _warn_setuptools if _warn_setuptools is False: _warn_setuptools = True warn_setuptools_issue(out=environ.get('wsgi.errors')) # SCRIPT_URL is an Apache var containing the URL before URL rewriting # has been applied, so we can use it to reconstruct logical SCRIPT_NAME script_url = environ.get('SCRIPT_URL') if script_url is not None: path_info = environ.get('PATH_INFO') if not path_info: environ['SCRIPT_NAME'] = script_url else: # mod_wsgi squashes slashes in PATH_INFO (!) script_url = _slashes_re.sub('/', script_url) path_info = _slashes_re.sub('/', path_info) if script_url.endswith(path_info): environ['SCRIPT_NAME'] = script_url[:-len(path_info)] # If the expected configuration keys aren't found in the WSGI environment, # try looking them up in the process environment variables environ.setdefault('trac.env_path', os.getenv('TRAC_ENV')) environ.setdefault('trac.env_parent_dir', os.getenv('TRAC_ENV_PARENT_DIR')) environ.setdefault('trac.env_index_template', os.getenv('TRAC_ENV_INDEX_TEMPLATE')) environ.setdefault('trac.template_vars', os.getenv('TRAC_TEMPLATE_VARS')) environ.setdefault('trac.locale', '') environ.setdefault('trac.base_url', os.getenv('TRAC_BASE_URL')) locale.setlocale(locale.LC_ALL, environ['trac.locale']) # Determine the environment env_path = environ.get('trac.env_path') if not env_path: env_parent_dir = environ.get('trac.env_parent_dir') env_paths = environ.get('trac.env_paths') if env_parent_dir or env_paths: # The first component of the path is the base name of the # environment path_info = environ.get('PATH_INFO', '').lstrip('/').split('/') env_name = path_info.pop(0) if not env_name: # No specific environment requested, so render an environment # index page send_project_index(environ, start_response, env_parent_dir, env_paths) return [] errmsg = None # To make the matching patterns of request handlers work, we append # the environment name to the `SCRIPT_NAME` variable, and keep only # the remaining path in the `PATH_INFO` variable. script_name = environ.get('SCRIPT_NAME', '') try: script_name = unicode(script_name, 'utf-8') # (as Href expects unicode parameters) environ['SCRIPT_NAME'] = Href(script_name)(env_name) environ['PATH_INFO'] = '/' + '/'.join(path_info) if env_parent_dir: env_path = os.path.join(env_parent_dir, env_name) else: env_path = get_environments(environ).get(env_name) if not env_path or not os.path.isdir(env_path): errmsg = 'Environment not found' except UnicodeDecodeError: errmsg = 'Invalid URL encoding (was %r)' % script_name if errmsg: start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', str(len(errmsg)))]) return [errmsg] if not env_path: raise EnvironmentError('The environment options "TRAC_ENV" or ' '"TRAC_ENV_PARENT_DIR" or the mod_python ' 'options "TracEnv" or "TracEnvParentDir" are ' 'missing. Trac requires one of these options ' 'to locate the Trac environment(s).') run_once = environ['wsgi.run_once'] env = env_error = None try: env = open_environment(env_path, use_cache=not run_once) if env.base_url_for_redirect: environ['trac.base_url'] = env.base_url # Web front-end type and version information if not hasattr(env, 'webfrontend'): mod_wsgi_version = environ.get('mod_wsgi.version') if mod_wsgi_version: mod_wsgi_version = ( "%s (WSGIProcessGroup %s WSGIApplicationGroup %s)" % ('.'.join([str(x) for x in mod_wsgi_version]), environ.get('mod_wsgi.process_group'), environ.get('mod_wsgi.application_group') or '%{GLOBAL}')) environ.update({ 'trac.web.frontend': 'mod_wsgi', 'trac.web.version': mod_wsgi_version}) env.webfrontend = environ.get('trac.web.frontend') if env.webfrontend: env.webfrontend_version = environ['trac.web.version'] except Exception as e: env_error = e req = RequestWithSession(environ, start_response) translation.make_activable(lambda: req.locale, env.path if env else None) try: return _dispatch_request(req, env, env_error) finally: translation.deactivate() if env and not run_once: env.shutdown(threading._get_ident()) # Now it's a good time to do some clean-ups # # Note: enable the '##' lines as soon as there's a suspicion # of memory leak due to uncollectable objects (typically # objects with a __del__ method caught in a cycle) # ##gc.set_debug(gc.DEBUG_UNCOLLECTABLE) unreachable = gc.collect()