Mercurial > p > roundup > code
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): |
