comparison roundup/backends/rdbms_common.py @ 4490:559d9a2a0191

Fixed bug in filter_iter refactoring (lazy multilinks)... ...in rare cases this would result in duplicate multilinks to the same node. We're now going the safe route and doing lazy evaluation only for read-only access, whenever updates are done we fetch everything.
author Ralf Schlatterbeck <schlatterbeck@users.sourceforge.net>
date Sat, 16 Apr 2011 11:02:01 +0000
parents 22bc0426e348
children f8e85cf5f0fe
comparison
equal deleted inserted replaced
4489:47bd330e3d17 4490:559d9a2a0191
1078 if issubclass(propklass, k): 1078 if issubclass(propklass, k):
1079 return v 1079 return v
1080 1080
1081 raise ValueError('%r is not a hyperdb property class' % propklass) 1081 raise ValueError('%r is not a hyperdb property class' % propklass)
1082 1082
1083 def getnode(self, classname, nodeid): 1083 def _materialize_multilink(self, classname, nodeid, node, propname):
1084 """ evaluation of single Multilink (lazy eval may have skipped this)
1085 """
1086 if propname not in node:
1087 sql = 'select linkid from %s_%s where nodeid=%s'%(classname,
1088 propname, self.arg)
1089 self.sql(sql, (nodeid,))
1090 # extract the first column from the result
1091 # XXX numeric ids
1092 items = [int(x[0]) for x in self.cursor.fetchall()]
1093 items.sort ()
1094 node[propname] = [str(x) for x in items]
1095
1096 def _materialize_multilinks(self, classname, nodeid, node, props=None):
1097 """ get all Multilinks of a node (lazy eval may have skipped this)
1098 """
1099 cl = self.classes[classname]
1100 props = props or [pn for (pn, p) in cl.properties.iteritems()
1101 if isinstance(p, Multilink)]
1102 for propname in props:
1103 if propname not in node:
1104 self._materialize_multilink(classname, nodeid, node, propname)
1105
1106 def getnode(self, classname, nodeid, fetch_multilinks=True):
1084 """ Get a node from the database. 1107 """ Get a node from the database.
1108 For optimisation optionally we don't fetch multilinks
1109 (lazy Multilinks).
1110 But for internal database operations we need them.
1085 """ 1111 """
1086 # see if we have this node cached 1112 # see if we have this node cached
1087 key = (classname, nodeid) 1113 key = (classname, nodeid)
1088 if key in self.cache: 1114 if key in self.cache:
1089 # push us back to the top of the LRU 1115 # push us back to the top of the LRU
1090 self._cache_refresh(key) 1116 self._cache_refresh(key)
1091 if __debug__: 1117 if __debug__:
1092 self.stats['cache_hits'] += 1 1118 self.stats['cache_hits'] += 1
1093 # return the cached information 1119 # return the cached information
1120 if fetch_multilinks:
1121 self._materialize_multilinks(classname, nodeid, self.cache[key])
1094 return self.cache[key] 1122 return self.cache[key]
1095 1123
1096 if __debug__: 1124 if __debug__:
1097 self.stats['cache_misses'] += 1 1125 self.stats['cache_misses'] += 1
1098 start_t = time.time() 1126 start_t = time.time()
1121 continue 1149 continue
1122 value = values[col] 1150 value = values[col]
1123 if value is not None: 1151 if value is not None:
1124 value = self.to_hyperdb_value(props[name].__class__)(value) 1152 value = self.to_hyperdb_value(props[name].__class__)(value)
1125 node[name] = value 1153 node[name] = value
1154
1155 if fetch_multilinks and mls:
1156 self._materialize_multilinks(classname, nodeid, node, mls)
1126 1157
1127 # save off in the cache 1158 # save off in the cache
1128 key = (classname, nodeid) 1159 key = (classname, nodeid)
1129 self._cache_save(key, node) 1160 self._cache_save(key, node)
1130 1161
1614 """ 1645 """
1615 if propname == 'id': 1646 if propname == 'id':
1616 return nodeid 1647 return nodeid
1617 1648
1618 # get the node's dict 1649 # get the node's dict
1619 d = self.db.getnode(self.classname, nodeid) 1650 d = self.db.getnode(self.classname, nodeid, fetch_multilinks=False)
1620 # handle common case -- that property is in dict -- first 1651 # handle common case -- that property is in dict -- first
1621 # if None and one of creator/creation actor/activity return None 1652 # if None and one of creator/creation actor/activity return None
1622 if propname in d: 1653 if propname in d:
1623 r = d [propname] 1654 r = d [propname]
1624 # return copy of our list 1655 # return copy of our list
1638 # get the property (raises KeyError if invalid) 1669 # get the property (raises KeyError if invalid)
1639 prop = self.properties[propname] 1670 prop = self.properties[propname]
1640 1671
1641 # lazy evaluation of Multilink 1672 # lazy evaluation of Multilink
1642 if propname not in d and isinstance(prop, Multilink): 1673 if propname not in d and isinstance(prop, Multilink):
1643 sql = 'select linkid from %s_%s where nodeid=%s'%(self.classname, 1674 self.db._materialize_multilink(self.classname, nodeid, d, propname)
1644 propname, self.db.arg)
1645 self.db.sql(sql, (nodeid,))
1646 # extract the first column from the result
1647 # XXX numeric ids
1648 items = [int(x[0]) for x in self.db.cursor.fetchall()]
1649 items.sort ()
1650 d[propname] = [str(x) for x in items]
1651 1675
1652 # handle there being no value in the table for the property 1676 # handle there being no value in the table for the property
1653 if propname not in d or d[propname] is None: 1677 if propname not in d or d[propname] is None:
1654 if default is _marker: 1678 if default is _marker:
1655 if isinstance(prop, Multilink): 1679 if isinstance(prop, Multilink):

Roundup Issue Tracker: http://roundup-tracker.org/