# HG changeset patch # User Sylvain Thénault # Date 1268322599 -3600 # Node ID e34cbd85d14da9d48199df7929cd8047c5dee83f # Parent b67838d18a4f7ad9ce0ab2fc34571b86952fa3e8# Parent 2a16dbf5002c4c2ca1d8f2fe61bd4fc1cffdd2a4 merge diff -r 2a16dbf5002c -r e34cbd85d14d _gcdebug.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/_gcdebug.py Thu Mar 11 16:49:59 2010 +0100 @@ -0,0 +1,87 @@ + +import gc, types, weakref + +from cubicweb.schema import CubicWebRelationSchema, CubicWebEntitySchema + +listiterator = type(iter([])) + +IGNORE_CLASSES = ( + type, tuple, dict, list, set, frozenset, type(len), + weakref.ref, weakref.WeakKeyDictionary, + listiterator, + property, classmethod, + types.ModuleType, types.FunctionType, types.MethodType, + types.MemberDescriptorType, types.GetSetDescriptorType, + ) + +def _get_counted_class(obj, classes): + for cls in classes: + if isinstance(obj, cls): + return cls + raise AssertionError() + +def gc_info(countclasses, + ignoreclasses=IGNORE_CLASSES, + viewreferrersclasses=(), showobjs=False): + gc.collect() + gc.collect() + counters = {} + ocounters = {} + for obj in gc.get_objects(): + if isinstance(obj, countclasses): + cls = _get_counted_class(obj, countclasses) + try: + counters[cls.__name__] += 1 + except KeyError: + counters[cls.__name__] = 1 + elif not isinstance(obj, ignoreclasses): + try: + key = '%s.%s' % (obj.__class__.__module__, + obj.__class__.__name__) + except AttributeError: + key = str(obj) + try: + ocounters[key] += 1 + except KeyError: + ocounters[key] = 1 + if isinstance(obj, viewreferrersclasses): + print ' ', obj, referrers(obj, showobjs) + return counters, ocounters, gc.garbage + + +def referrers(obj, showobj=False, maxlevel=1): + objreferrers = _referrers(obj, maxlevel) + try: + return sorted(set((type(x), showobj and x or getattr(x, '__name__', '%#x' % id(x))) + for x in objreferrers)) + except TypeError: + s = set() + unhashable = [] + for x in objreferrers: + try: + s.add(x) + except TypeError: + unhashable.append(x) + return sorted(s) + unhashable + +def _referrers(obj, maxlevel, _seen=None, _level=0): + interesting = [] + if _seen is None: + _seen = set() + for x in gc.get_referrers(obj): + if id(x) in _seen: + continue + _seen.add(id(x)) + if isinstance(x, types.FrameType): + continue + if isinstance(x, (CubicWebRelationSchema, CubicWebEntitySchema)): + continue + if isinstance(x, (list, tuple, set, dict, listiterator)): + if _level >= maxlevel: + pass + #interesting.append(x) + else: + interesting += _referrers(x, maxlevel, _seen, _level+1) + else: + interesting.append(x) + return interesting diff -r 2a16dbf5002c -r e34cbd85d14d server/repository.py --- a/server/repository.py Wed Mar 10 12:52:33 2010 +0100 +++ b/server/repository.py Thu Mar 11 16:49:59 2010 +0100 @@ -365,10 +365,15 @@ def stats(self): # XXX restrict to managers session? import threading results = {} - for hits, misses, title in ( - (self.querier.cache_hit, self.querier.cache_miss, 'rqlt_st'), - (self.system_source.cache_hit, self.system_source.cache_miss, 'sql'), + querier = self.querier + source = self.system_source + for size, maxsize, hits, misses, title in ( + (len(querier._rql_cache), self.config['rql-cache-size'], + querier.cache_hit, querier.cache_miss, 'rqlt_st'), + (len(source._cache), self.config['rql-cache-size'], + source.cache_hit, source.cache_miss, 'sql'), ): + results['%s_cache_size' % title] = '%s / %s' % (size, maxsize) results['%s_cache_hit' % title] = hits results['%s_cache_miss' % title] = misses results['%s_cache_hit_percent' % title] = (hits * 100) / (hits + misses) diff -r 2a16dbf5002c -r e34cbd85d14d server/session.py --- a/server/session.py Wed Mar 10 12:52:33 2010 +0100 +++ b/server/session.py Thu Mar 11 16:49:59 2010 +0100 @@ -569,6 +569,7 @@ self.error('thread %s still alive after 10 seconds, will close ' 'session anyway', thread) self.rollback() + del self._threaddata # transaction data/operations management ################################## @@ -767,7 +768,7 @@ def close(self): """do not close pool on session close, since they are shared now""" - self.rollback() + self.parent_session.close() def user_data(self): """returns a dictionnary with this user's information""" diff -r 2a16dbf5002c -r e34cbd85d14d web/request.py --- a/web/request.py Wed Mar 10 12:52:33 2010 +0100 +++ b/web/request.py Thu Mar 11 16:49:59 2010 +0100 @@ -287,7 +287,11 @@ if breadcrumbs is None: breadcrumbs = SizeConstrainedList(10) self.set_session_data('breadcrumbs', breadcrumbs) - breadcrumbs.append(self.url()) + breadcrumbs.append(self.url()) + else: + url = self.url() + if breadcrumbs[-1] != url: + breadcrumbs.append(url) def last_visited_page(self): breadcrumbs = self.get_session_data('breadcrumbs', None) diff -r 2a16dbf5002c -r e34cbd85d14d web/views/debug.py --- a/web/views/debug.py Wed Mar 10 12:52:33 2010 +0100 +++ b/web/views/debug.py Thu Mar 11 16:49:59 2010 +0100 @@ -27,13 +27,13 @@ class ProcessInformationView(StartupView): + """display various web server /repository information""" __regid__ = 'info' __select__ = none_rset() & match_user_groups('managers') title = _('server information') def call(self, **kwargs): - """display server information""" req = self._cw dtformat = req.property_value('ui.datetime-format') _ = req._ @@ -111,24 +111,59 @@ class RegistryView(StartupView): + """display vregistry content""" __regid__ = 'registry' __select__ = StartupView.__select__ & match_user_groups('managers') title = _('registry') def call(self, **kwargs): - """The default view representing the instance's management""" self.w(u'

%s

' % _("Registry's content")) keys = sorted(self._cw.vreg) - self.w(u'

%s

\n' % ' - '.join('%s' - % (key, key) for key in keys)) + url = self._cw.url() + self.w(u'

%s

\n' % ' - '.join('%s' + % (url, key, key) for key in keys)) for key in keys: - self.w(u'

%s

' % (key, key)) - items = self._cw.vreg[key].items() - if items: - self.w(u'') - for key, value in sorted(items): - self.w(u'' - % (key, xml_escape(repr(value)))) - self.w(u'
%s%s
\n') + self.w(u'

%s

' % (key, key)) + if self._cw.vreg[key]: + values = sorted(self._cw.vreg[key].iteritems()) + self.wview('pyvaltable', pyvalue=[(key, xml_escape(repr(val))) + for key, val in values]) else: self.w(u'

Empty

\n') + + +class GCView(StartupView): + """display garbage collector information""" + __regid__ = 'gc' + __select__ = StartupView.__select__ & match_user_groups('managers') + title = _('garbage') + + def call(self, **kwargs): + from cubicweb._gcdebug import gc_info + from rql.stmts import Union + from cubicweb.appobject import AppObject + from cubicweb.rset import ResultSet + from cubicweb.dbapi import Connection, Cursor + from cubicweb.web.request import CubicWebRequestBase + lookupclasses = (AppObject, + Union, ResultSet, + Connection, Cursor, + CubicWebRequestBase) + try: + from cubicweb.server.session import Session, ChildSession, InternalSession + lookupclasses += (InternalSession, ChildSession, Session) + except ImportError: + pass # no server part installed + self.w(u'

%s

' % _('Garbage collection information')) + counters, ocounters, garbage = gc_info(lookupclasses, + viewreferrersclasses=()) + self.w(u'

%s

' % _('Looked up classes')) + values = sorted(counters.iteritems(), key=lambda x: x[1], reverse=True) + self.wview('pyvaltable', pyvalue=values) + self.w(u'

%s

' % _('Most referenced classes')) + values = sorted(ocounters.iteritems(), key=lambda x: x[1], reverse=True) + self.wview('pyvaltable', pyvalue=values[:self._cw.form.get('nb', 20)]) + if garbage: + self.w(u'

%s

' % _('Unreachable objects')) + values = sorted(xml_escape(repr(o) for o in garbage)) + self.wview('pyvallist', pyvalue=values) diff -r 2a16dbf5002c -r e34cbd85d14d web/views/pyviews.py --- a/web/views/pyviews.py Wed Mar 10 12:52:33 2010 +0100 +++ b/web/views/pyviews.py Thu Mar 11 16:49:59 2010 +0100 @@ -17,18 +17,23 @@ def call(self, pyvalue, headers=None): if headers is None: headers = self._cw.form.get('headers') - self.w(u'\n') + w = self.w + w(u'
\n') if headers: - self.w(u'') + w(u'') + w(u'') for header in headers: - self.w(u'' % header) - self.w(u'\n') + w(u'' % header) + w(u'\n') + w(u'') + w(u'') for row in pyvalue: - self.w(u'') + w(u'') for cell in row: - self.w(u'' % cell) - self.w(u'\n') - self.w(u'
%s
%s
%s
\n') + w(u'%s' % cell) + w(u'\n') + w(u'') + w(u'\n') class PyValListView(View):