[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnue] r7058 - in trunk/gnue-appserver/src: . classrep language
From: |
johannes |
Subject: |
[gnue] r7058 - in trunk/gnue-appserver/src: . classrep language |
Date: |
Wed, 23 Feb 2005 10:54:25 -0600 (CST) |
Author: johannes
Date: 2005-02-23 10:54:24 -0600 (Wed, 23 Feb 2005)
New Revision: 7058
Modified:
trunk/gnue-appserver/src/classrep/Base.py
trunk/gnue-appserver/src/data.py
trunk/gnue-appserver/src/geasInstance.py
trunk/gnue-appserver/src/geasList.py
trunk/gnue-appserver/src/geasRpcServer.py
trunk/gnue-appserver/src/geasSession.py
trunk/gnue-appserver/src/language/Object.py
trunk/gnue-appserver/src/language/ObjectList.py
trunk/gnue-appserver/src/language/Session.py
Log:
Some improvements and fixes of memory leaks
Modified: trunk/gnue-appserver/src/classrep/Base.py
===================================================================
--- trunk/gnue-appserver/src/classrep/Base.py 2005-02-23 16:53:58 UTC (rev
7057)
+++ trunk/gnue-appserver/src/classrep/Base.py 2005-02-23 16:54:24 UTC (rev
7058)
@@ -25,7 +25,6 @@
import helpers
from gnue import appserver
from gnue.common.apps import errors
-from gnue.appserver.language.Object import Object
# =============================================================================
# Exceptions
@@ -390,7 +389,7 @@
"""
if self.__object is None:
- self.__object = Object (self._session, self.classname, self.gnue_id)
+ self.__object = self._session.get (self.classname, self.gnue_id)
result = self.__object
Modified: trunk/gnue-appserver/src/data.py
===================================================================
--- trunk/gnue-appserver/src/data.py 2005-02-23 16:53:58 UTC (rev 7057)
+++ trunk/gnue-appserver/src/data.py 2005-02-23 16:54:24 UTC (rev 7058)
@@ -528,9 +528,17 @@
def _createResultSet (connections, database, content, conditions, order):
datasource = _createDatasource (connections, database, content, order)
- return datasource.createResultSet (_conditionTree (conditions))
+ condition = _conditionTree (conditions)
+ try:
+ return datasource.createResultSet (condition)
+ finally:
+ # If we have a condition, make sure to have all it's elements collectable
+ # by the garbage collector
+ if condition is not None:
+ condition.breakReferences ()
+
# -----------------------------------------------------------------------------
# Create a condition tree of a given condition
# -----------------------------------------------------------------------------
Modified: trunk/gnue-appserver/src/geasInstance.py
===================================================================
--- trunk/gnue-appserver/src/geasInstance.py 2005-02-23 16:53:58 UTC (rev
7057)
+++ trunk/gnue-appserver/src/geasInstance.py 2005-02-23 16:54:24 UTC (rev
7058)
@@ -320,47 +320,52 @@
for name in [x.encode ('ascii') for x in params.keys ()]:
paramDef = proceduredef.parameters [name]
parameters [name] = self.__convert (params [name], paramDef,
- ParameterValueError)
+ ParameterValueError)
engine = getLanguageAdapter (proceduredef.gnue_language)
cx = engine.createNewContext ()
- # describe the context
- cx.shortname = '%s.%s' % (self.__classdef.fullName,
proceduredef.fullName)
- cx.description = proceduredef.gnue_comment
+ try:
+ # describe the context
+ cx.shortname = '%s.%s' % (self.__classdef.fullName,
proceduredef.fullName)
+ cx.description = proceduredef.gnue_comment
- # the object itself and the session
- cx.bindObject ('self', obj)
- cx.bindObject ('session', sess)
+ # the object itself and the session
+ cx.bindObject ('self', obj)
+ cx.bindObject ('session', sess)
- if namespace is not None:
- for (key, value) in namespace.items ():
- cx.bindObject (key, value)
+ if namespace is not None:
+ for (key, value) in namespace.items ():
+ cx.bindObject (key, value)
- # language interface, session functions
- cx.bindFunction ('find', sess.find)
- cx.bindFunction ('setcontext', sess.setcontext)
- cx.bindFunction ('new', sess.new)
- cx.bindFunction ('message', sess.message)
+ # language interface, session functions
+ cx.bindFunction ('find', sess.find)
+ cx.bindFunction ('setcontext', sess.setcontext)
+ cx.bindFunction ('new', sess.new)
+ cx.bindFunction ('message', sess.message)
- # direct access to RPC API func.
- cx.bindFunction ('direct_request', self.__session.request)
- cx.bindFunction ('direct_fetch', self.__session.fetch)
- cx.bindFunction ('direct_load', self.__session.load)
- cx.bindFunction ('direct_store', self.__session.store)
- cx.bindFunction ('direct_call', self.__session.call)
+ # direct access to RPC API func.
+ cx.bindFunction ('direct_request', self.__session.request)
+ cx.bindFunction ('direct_fetch', self.__session.fetch)
+ cx.bindFunction ('direct_load', self.__session.load)
+ cx.bindFunction ('direct_store', self.__session.store)
+ cx.bindFunction ('direct_call', self.__session.call)
- # set context for the procedure
- sess.setcontext (proceduredef.module.gnue_name)
+ # set context for the procedure
+ sess.setcontext (proceduredef.module.gnue_name)
- method = cx.buildFunction (proceduredef.gnue_name, proceduredef.gnue_code,
- parameters)
- result = method (**parameters)
- if (proceduredef.gnue_type is None) != (result is None):
- if result is not None or not proceduredef.gnue_nullable:
- raise ResultTypeError, (proceduredef.fullName, proceduredef.gnue_type,
- result)
+ method = cx.buildFunction (proceduredef.gnue_name,
proceduredef.gnue_code,
+ parameters)
+ result = method (**parameters)
+ if (proceduredef.gnue_type is None) != (result is None):
+ if result is not None or not proceduredef.gnue_nullable:
+ raise ResultTypeError, (proceduredef.fullName,
proceduredef.gnue_type,
+ result)
+ finally:
+ method._context = None
+ cx.release ()
+
return result
# ---------------------------------------------------------------------------
Modified: trunk/gnue-appserver/src/geasList.py
===================================================================
--- trunk/gnue-appserver/src/geasList.py 2005-02-23 16:53:58 UTC (rev
7057)
+++ trunk/gnue-appserver/src/geasList.py 2005-02-23 16:54:24 UTC (rev
7058)
@@ -281,7 +281,11 @@
self.__instances = []
self.__unsorted = []
+ if self.__condition is not None:
+ self.__condition.breakReferences ()
+ self.__condition = None
+
# ---------------------------------------------------------------------------
# Evaluate an exist condition for an instance
# ---------------------------------------------------------------------------
Modified: trunk/gnue-appserver/src/geasRpcServer.py
===================================================================
--- trunk/gnue-appserver/src/geasRpcServer.py 2005-02-23 16:53:58 UTC (rev
7057)
+++ trunk/gnue-appserver/src/geasRpcServer.py 2005-02-23 16:54:24 UTC (rev
7058)
@@ -25,6 +25,7 @@
import os
import sys
import signal
+import gc
import gnue.paths
@@ -38,6 +39,9 @@
from gnue.appserver import geasSessionManager
from gnue.appserver import geasConfiguration
+
+_GC_DEBUG = True # Set this to True to activate garbage collection debugging
+
# =============================================================================
# RPC application class
# =============================================================================
@@ -215,8 +219,13 @@
# Daemonize (if appropriate)
GServerApp.run (self)
+ if _GC_DEBUG:
+ gc.enable ()
+ gc.set_debug (gc.DEBUG_LEAK)
+
try:
signal.signal (signal.SIGHUP, self._hangupServer)
+ signal.signal (signal.SIGUSR1, self._gcCheck)
except AttributeError:
pass
@@ -262,7 +271,51 @@
if self.sm:
self.sm.updateRepository ()
+ # ---------------------------------------------------------------------------
+ # Check the current state of the garbage collection
+ # ---------------------------------------------------------------------------
+ def _gcCheck (self, signal, frame):
+ """
+ This function starts a garbage collection, and lists all unreachable
+ objects not collected.
+ """
+
+ if not _GC_DEBUG:
+ print o(u_("Debugging garbage collection not activated."))
+ return
+
+ r = gc.collect ()
+
+ gf = open ('garbage.log', 'w')
+
+ print "=" * 70
+ print "GARBAGE:", r, ":"
+ gf.write ('GARBAGE: %d\n' % r)
+
+ n = 0
+ for x in gc.garbage:
+ n += 1
+ s = str(x)
+ if len(s) > 75: s = s[:75]
+ print type(x),"\n ", s
+ gf.write ("%s: %s\n" % (type (x), repr (x)))
+
+ from gnue.common.datasources import GConditions
+ if isinstance (x, GConditions.GCondition):
+ gf.write ("Referrer of: %s\n" % x)
+ for y in gc.get_referrers (x):
+ gf.write ("--> %s: %s\n" % (type (y), y))
+
+ gf.write ("%s\n" % ("-" * 70))
+
+ gf.close ()
+ del gc.garbage [:]
+
+ print "-" * 70
+ print "GC dump done", n
+
+
# ---------------------------------------------------------------------------
# Self test
# ---------------------------------------------------------------------------
Modified: trunk/gnue-appserver/src/geasSession.py
===================================================================
--- trunk/gnue-appserver/src/geasSession.py 2005-02-23 16:53:58 UTC (rev
7057)
+++ trunk/gnue-appserver/src/geasSession.py 2005-02-23 16:54:24 UTC (rev
7058)
@@ -265,10 +265,10 @@
if self.locale:
i18n.setcurrentlocale (self.locale)
- for item in self.__lists.values ():
- item.close ()
+ for key in self.__lists.keys ():
+ self.__lists [key].close ()
+ del self.__lists [key]
- self.__lists = {}
self.__dirtyInstances = {}
self.filters = {}
@@ -728,6 +728,8 @@
else:
asTrees.append (tree)
+ cTree.breakReferences ()
+
# now create the final trees
dbCond = None
asCond = None
Modified: trunk/gnue-appserver/src/language/Object.py
===================================================================
--- trunk/gnue-appserver/src/language/Object.py 2005-02-23 16:53:58 UTC (rev
7057)
+++ trunk/gnue-appserver/src/language/Object.py 2005-02-23 16:54:24 UTC (rev
7058)
@@ -49,18 +49,18 @@
# Constructor
# -------------------------------------------------------------------------
- def __init__ (self, session, classname, objectId = None):
+ def __init__ (self, session, classname, objectId = None, definition = None):
# we won't trigger __setattr__ here ...
- self.__dict__ ['objectId'] = objectId
- self.__dict__ ['_Object__session'] = session
- self.__dict__ ['_Object__class'] = classname
- self.__dict__ ['_Object__sm'] = session.getSessionManager ()
- self.__dict__ ['_Object__sid'] = session.getSessionId ()
- self.__dict__ ['_Object__datatype'] = {}
+ self.__dict__ ['objectId'] = objectId
+ self.__dict__ ['_Object__session'] = session
+ self.__dict__ ['_Object__class'] = classname
+ self.__dict__ ['_Object__sid'] = session.getSessionId ()
+ self.__dict__ ['_Object__definition'] = definition or {}
if self.objectId is None:
# Create new object
- res = self.__sm.store (self.__sid, self.__class, [None], [], [[]])
+ sm = session.getSessionManager ()
+ res = sm.store (self.__sid, self.__class, [None], [], [[]])
self.objectId = res [0]
self.__dict__ ['gnue_id'] = self.objectId
@@ -75,20 +75,20 @@
gBeginFunc (6)
name = self.__session.qualify (attr)
+ key = name.lower ()
- if name == "gnue_id":
+ if key == "gnue_id":
result = self.objectId
gEndFunc (6, result)
return result
+ sm = self.__session.getSessionManager ()
+
try:
- # TODO: move the datatype-dictionary into the session, but keep a
- # per-instance pointer to it. This way we could reduce the amount of
- # loads to a per-class/per-session minimum
- if not self.__datatype.has_key (name):
- self.__datatype [name] = self.__sm.load (self.__sid, self.__class,
- [''], [name]) [0][0]
- datatype = self.__datatype [name]
+ if not self.__definition.has_key (key):
+ self.__definition [key] = sm.load (self.__sid, self.__class, [''],
+ [name]) [0][0]
+ datatype = self.__definition [key]
except KeyError:
raise MemberNotFoundError, (self.__class, name)
@@ -97,16 +97,18 @@
result = Procedure (self.__session, self.objectId, self.__class, name)
else:
- res = self.__sm.load (self.__sid, self.__class, [self.objectId], [name])
+ res = sm.load (self.__sid, self.__class, [self.objectId], [name])
value = res [0][0]
# Convert reference fields to object references
if '_' in datatype and value is not None:
- result = Object (self.__session, datatype, value)
+ cDef = self.__session.getClassDefinition (datatype)
+ result = Object (self.__session, datatype, value, cDef)
elif value is None:
if '_' in datatype:
- result = NullObject (self.__session, datatype)
+ cDef = self.__session.getClassDefinition (datatype)
+ result = NullObject (self.__session, datatype, cDef)
else:
result = None
@@ -114,6 +116,7 @@
result = value
gEndFunc (6, result)
+
return result
@@ -133,14 +136,16 @@
elif attr == 'gnue_id':
self.__dict__ ['objectId'] = value
- if not self.__dict__.has_key (attr) or attr == 'gnue_id':
+ if not self.__dict__.has_key (attr) or attr.lower () == 'gnue_id':
name = self.__session.qualify (attr)
+ key = name.lower ()
+ sm = self.__session.getSessionManager ()
try:
- if not self.__datatype.has_key (name):
- self.__datatype [name] = self.__sm.load (self.__sid, self.__class,
+ if not self.__definition.has_key (key):
+ self.__definition [key] = sm.load (self.__sid, self.__class,
[''], [name]) [0][0]
- datatype = self.__datatype [name]
+ datatype = self.__definition [key]
except KeyError:
raise MemberNotFoundError, (self.__class, name)
@@ -154,8 +159,7 @@
else:
__value = value
- self.__sm.store (self.__sid, self.__class, [self.objectId], [name],
- [[__value]])
+ sm.store (self.__sid, self.__class, [self.objectId], [name], [[__value]])
gEndFunc (6, hasResult = False)
@@ -214,7 +218,8 @@
gBeginFunc (6)
- self.__sm.delete (self.__sid, self.__class, [self.objectId])
+ sm = self.__session.getSessionManager ()
+ sm.delete (self.__sid, self.__class, [self.objectId])
self.objectId = None
gEndFunc (6, hasResult = False)
@@ -231,13 +236,12 @@
# Constructor
# ---------------------------------------------------------------------------
- def __init__ (self, session, classname):
+ def __init__ (self, session, classname, definition):
- self.__session = session
- self.__class = classname
- self.__sm = session.getSessionManager ()
- self.__sid = session.getSessionId ()
- self.__datatype = {}
+ self.__session = session
+ self.__class = classname
+ self.__sid = session.getSessionId ()
+ self.__definition = definition
# ---------------------------------------------------------------------------
@@ -257,11 +261,15 @@
gBeginFunc (6)
name = self.__session.qualify (attr)
- if not self.__datatype.has_key (name):
- self.__datatype [name] = self.__sm.load (self.__sid, self.__class,
+ key = name.lower ()
+ if not self.__definition.has_key (key):
+ sm = self.__session.getSessionManager ()
+ self.__definition [key] = sm.load (self.__sid, self.__class,
[''], [name]) [0][0]
- if '_' in self.__datatype [name]:
- self.__class = self.__datatype [name]
+ if '_' in self.__definition [key]:
+ self.__class = self.__definition [key]
+ self.__definition = self.__session.getClassDefinition (self.__class)
+
result = self
else:
result = None
Modified: trunk/gnue-appserver/src/language/ObjectList.py
===================================================================
--- trunk/gnue-appserver/src/language/ObjectList.py 2005-02-23 16:53:58 UTC
(rev 7057)
+++ trunk/gnue-appserver/src/language/ObjectList.py 2005-02-23 16:54:24 UTC
(rev 7058)
@@ -34,11 +34,12 @@
# -------------------------------------------------------------------------
# Constructor
# -------------------------------------------------------------------------
- def __init__ (self, session, classname, cond, sort, properties):
+ def __init__ (self, session, classname, cond, sort, properties, definition):
self.classname = classname
self.conditions = cond
self.sortOrder = sort
self.properties = properties
+ self.definition = definition
self.__session = session
self.__list = []
@@ -117,7 +118,7 @@
rset = sm.fetch (sid, self.__list_id, len (self.__list),
self.__cacheStep,0)
for row in rset:
- obj = Object (self.__session, self.classname, row [0])
+ obj = Object (self.__session, self.classname, row [0], self.definition)
self.__list.append (obj)
# We double the cache-size for the next call to fetch (). This boosts
Modified: trunk/gnue-appserver/src/language/Session.py
===================================================================
--- trunk/gnue-appserver/src/language/Session.py 2005-02-23 16:53:58 UTC
(rev 7057)
+++ trunk/gnue-appserver/src/language/Session.py 2005-02-23 16:54:24 UTC
(rev 7058)
@@ -42,59 +42,134 @@
msg = u_("Message '%s' not found") % message
errors.ApplicationError.__init__ (self, msg)
+
# ===========================================================================
# CLASS session: implement a session of the language interface
# ===========================================================================
+
class Session:
# -------------------------------------------------------------------------
# Constructor
# -------------------------------------------------------------------------
+
def __init__ (self, sessionManager, sessionId, params = {}):
+ """
+ Create an instance of a language interface session
+
+ @param sessionManager: the session manager to be used
+ @param sessionId: id of the session encapsulated by the instance
+ @param params: dictionary of session parameters
+ """
+
self.__sm = sessionManager
self.__session_id = sessionId
self.__context = None
self.parameters = params
+ self.classdefs = {}
# -------------------------------------------------------------------------
# Get the session's sessionManager
# -------------------------------------------------------------------------
+
def getSessionManager (self):
+ """
+ This function returns the session manager this session is bound to
+ @return: session manager instance
+ """
+
return self.__sm
+
# -------------------------------------------------------------------------
# Get the session's id
# -------------------------------------------------------------------------
+
def getSessionId (self):
+ """
+ This function returns the id of this session in the session manager.
+ @return: id of the session
+ """
+
return self.__session_id
+
# -------------------------------------------------------------------------
+ # Get or created the class definition dictionary for a given class
+ # -------------------------------------------------------------------------
+
+ def getClassDefinition (self, classname):
+ """
+ This function returns the class definition dictionary for a given
+ classname. If it does not exist it will be created. Such a dictionary
+ contains the datatype per class-element (property/procedure).
+
+ @param classname: name of the class to return a definition dictionary for
+ @return: class definition dictionary for the requested class
+ """
+
+ return {}
+
+ key = classname.lower ()
+ if not self.classdefs.has_key (key):
+ self.classdefs [key] = {}
+
+ return self.classdefs [key]
+
+
+ # -------------------------------------------------------------------------
# Set the default context
# -------------------------------------------------------------------------
+
def setcontext (self, context):
+ """
+ This function specifies the current context of the session. All subsequent
+ calls to qualify using an unqualified name will be extended with this
+ context.
+
+ @param context: context to set
+ """
+
self.__context = context
+
# -------------------------------------------------------------------------
# Ensure the given name is fully qualified using the current context
# -------------------------------------------------------------------------
+
def qualify (self, name):
+ """
+ This function returns a fully qualified named. If the given name isn't
+ already qualified the current context will be added. If no such context is
+ available a NoContextError exception will be raised.
+ @param name: name to be returned as fully qulified name
+ @return: fully qualified name
+ """
+
+ # Although the 'in'-operation is an expensive operation, it's still faster
+ # than using string.find () here
if '_' in name:
- result = name
+ return name
+
else:
if self.__context is None:
raise NoContextError (name)
else:
- result = "%s_%s" % (self.__context, name)
+ # This looks a bit ugly but it's faster than using "%s_%s" % (...)
+ return self.__context + "_" + name
- return result
# -------------------------------------------------------------------------
# Close the session
# -------------------------------------------------------------------------
+
def close (self):
+ """
+ This function closes the encapsulated session on the session manager.
+ """
gBeginFunc (6)
@@ -108,7 +183,11 @@
# -------------------------------------------------------------------------
# Commit the current transaction
# -------------------------------------------------------------------------
+
def commit (self):
+ """
+ This function commits all pending changes of the session.
+ """
gBeginFunc (6)
@@ -121,7 +200,11 @@
# -------------------------------------------------------------------------
# Revoke the current transaction
# -------------------------------------------------------------------------
+
def rollback (self):
+ """
+ This function revokes all pending changes of the current session.
+ """
gBeginFunc (6)
@@ -130,39 +213,111 @@
gEndFunc (6, hasResult = False)
+
# -------------------------------------------------------------------------
# Return a collection of 'classname' matching the given arguments
# -------------------------------------------------------------------------
+
def find (self, classname, conditions = None,
sortorder = [('gnue_id', False)], properties = []):
+ """
+ This function returns a new collection of classes matching the given
+ conditions, having a given order and using a given set of 'preloaded'
+ properties.
+ @param classname: name of the class to be fetched
+ @param conditions: condition which must be matched. This could be a
+ dictionary, a sequence in prefix notation or a GCondition tree
+ @param sortorder: order to sort the instances. This is a sequence of
+ sort-elements where such an element could be a name, a tuple/triple or
a
+ dictionary with the keys 'name, descending, ignorecase'
+ @param properties: sequence of propertynames to be loaded for each instance
+ in the collection
+
+ @return: ObjectList instance with all matching instances of the given class
+ """
+
gBeginFunc (6)
- result = ObjectList (self, self.qualify (classname), conditions, sortorder,
- properties)
+
+ name = self.qualify (classname)
+ cdef = self.getClassDefinition (name)
+
+ result = ObjectList (self, name, conditions, sortorder, properties, cdef)
+
gEndFunc (6, result)
+
return result
+
# -------------------------------------------------------------------------
# Create a new instance of classname
# -------------------------------------------------------------------------
+
def new (self, classname):
+ """
+ This function creates a new instance of a given class.
+ @param classname: name of the class to create an instance of
+ @return: Object instance of the requested class
+ """
+
gBeginFunc (6)
- result = Object (self, self.qualify (classname))
+
+ result = self.get (classname)
+
gEndFunc (6, result)
+
return result
# -------------------------------------------------------------------------
+ # Get an instance of a class having a given objectId
+ # -------------------------------------------------------------------------
+
+ def get (self, classname, objectId = None):
+ """
+ This function returns an instance of a given class having the specified
+ objectId. If the objectId is None, a new one will be generated.
+
+ @param classname: name of the class to create an instance for
+ @param objectId: gnue_id of the instance or None to create a new one
+
+ @return: Object instance of the requested class
+ """
+
+ gBeginFunc (6)
+
+ name = self.qualify (classname)
+ cDef = self.getClassDefinition (name)
+
+ result = Object (self, name, objectId, cDef)
+
+ gEndFunc (6, result)
+
+ return result
+
+
+ # -------------------------------------------------------------------------
# Get a message from the message catalogue
# -------------------------------------------------------------------------
def message (self, messageName, *args):
+ """
+ This function returns a message from the message catalogue using the given
+ arguments. If the session has a '_language' parameter this language(s) are
+ treated with higher priority.
+ @param messageName: name of the message to be returned
+ @param args: variable arguments applied to the messaged
+
+ @return: the message as unicode string
+ """
+
gBeginFunc (6)
languages = ['C']
current = self.parameters.get ('_language', 'C')
+
if '_' in current:
add = current.split ('_') [0]
if not add in languages:
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnue] r7058 - in trunk/gnue-appserver/src: . classrep language,
johannes <=