comparison roundup/backends/back_anydbm.py @ 2239:c8a06e10e2c6

much faster anydbm filter(), but it breaks most filtering tests
author Richard Jones <richard@users.sourceforge.net>
date Mon, 26 Apr 2004 00:46:34 +0000
parents f624fc20f8fe
children 7d5398391610
comparison
equal deleted inserted replaced
2238:df0444e39bc3 2239:c8a06e10e2c6
13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17 # 17 #
18 #$Id: back_anydbm.py,v 1.142 2004-04-25 22:19:15 richard Exp $ 18 #$Id: back_anydbm.py,v 1.143 2004-04-26 00:46:34 richard Exp $
19 '''This module defines a backend that saves the hyperdatabase in a 19 '''This module defines a backend that saves the hyperdatabase in a
20 database chosen by anydbm. It is guaranteed to always be available in python 20 database chosen by anydbm. It is guaranteed to always be available in python
21 versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several 21 versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several
22 serious bugs, and is not available) 22 serious bugs, and is not available)
23 ''' 23 '''
1660 else: 1660 else:
1661 l.append((OTHER, k, v)) 1661 l.append((OTHER, k, v))
1662 filterspec = l 1662 filterspec = l
1663 1663
1664 # now, find all the nodes that are active and pass filtering 1664 # now, find all the nodes that are active and pass filtering
1665 l = [] 1665 matches = []
1666 cldb = self.db.getclassdb(cn) 1666 cldb = self.db.getclassdb(cn)
1667 try: 1667 try:
1668 # TODO: only full-scan once (use items()) 1668 # TODO: only full-scan once (use items())
1669 for nodeid in self.getnodeids(cldb): 1669 for nodeid in self.getnodeids(cldb):
1670 node = self.db.getnode(cn, nodeid, cldb) 1670 node = self.db.getnode(cn, nodeid, cldb)
1722 elif t == OTHER: 1722 elif t == OTHER:
1723 # straight value comparison for the other types 1723 # straight value comparison for the other types
1724 if node[k] != v: 1724 if node[k] != v:
1725 break 1725 break
1726 else: 1726 else:
1727 l.append((nodeid, node)) 1727 matches.append([nodeid, node])
1728 finally: 1728 finally:
1729 cldb.close() 1729 cldb.close()
1730 l.sort()
1731 1730
1732 # filter based on full text search 1731 # filter based on full text search
1733 if search_matches is not None: 1732 if search_matches is not None:
1734 k = [] 1733 k = []
1735 for v in l: 1734 for v in matches:
1736 if search_matches.has_key(v[0]): 1735 if search_matches.has_key(v[0]):
1737 k.append(v) 1736 k.append(v)
1738 l = k 1737 matches = k
1739 1738
1740 # now, sort the result 1739 # add sorting information to the match entries
1741 def sortfun(a, b, sort=sort, group=group, properties=self.getprops(), 1740 directions = []
1742 db = self.db, cl=self): 1741 for dir, prop in sort, group:
1743 a_id, an = a 1742 if dir is None or prop is None:
1744 b_id, bn = b 1743 continue
1745 # sort by group and then sort 1744 directions.append(dir)
1746 for dir, prop in group, sort: 1745 propclass = props[prop]
1747 if dir is None or prop is None: continue 1746 for entry in matches:
1748 1747 itemid = entry[-2]
1749 # sorting is class-specific 1748 item = entry[-1]
1750 propclass = properties[prop]
1751
1752 # handle the properties that might be "faked" 1749 # handle the properties that might be "faked"
1753 # also, handle possible missing properties 1750 # also, handle possible missing properties
1754 try: 1751 try:
1755 if not an.has_key(prop): 1752 v = self.get(itemid, prop)
1756 an[prop] = cl.get(a_id, prop)
1757 av = an[prop]
1758 except KeyError: 1753 except KeyError:
1759 # the node doesn't have a value for this property 1754 # the node doesn't have a value for this property
1760 if isinstance(propclass, Multilink): av = [] 1755 if isinstance(propclass, Multilink): v = []
1761 else: av = '' 1756 else: v = None
1762 try: 1757 s.append((v, itemid, item))
1763 if not bn.has_key(prop): 1758 continue
1764 bn[prop] = cl.get(b_id, prop) 1759
1765 bv = bn[prop]
1766 except KeyError:
1767 # the node doesn't have a value for this property
1768 if isinstance(propclass, Multilink): bv = []
1769 else: bv = ''
1770
1771 # String and Date values are sorted in the natural way
1772 if isinstance(propclass, String): 1760 if isinstance(propclass, String):
1773 # clean up the strings
1774 if av and av[0] in string.uppercase:
1775 av = av.lower()
1776 if bv and bv[0] in string.uppercase:
1777 bv = bv.lower()
1778 if (isinstance(propclass, String) or
1779 isinstance(propclass, Date)):
1780 # it might be a string that's really an integer 1761 # it might be a string that's really an integer
1781 try: 1762 try: tv = int(v)
1782 av = int(av) 1763 except: v = v.lower()
1783 bv = int(bv) 1764 else: v = tv
1784 except:
1785 pass
1786 if dir == '+':
1787 r = cmp(av, bv)
1788 if r != 0: return r
1789 elif dir == '-':
1790 r = cmp(bv, av)
1791 if r != 0: return r
1792
1793 # Link properties are sorted according to the value of
1794 # the "order" property on the linked nodes if it is
1795 # present; or otherwise on the key string of the linked
1796 # nodes; or finally on the node ids.
1797 elif isinstance(propclass, Link): 1765 elif isinstance(propclass, Link):
1798 link = db.classes[propclass.classname] 1766 link = self.db.classes[propclass.classname]
1799 if av is None and bv is not None: return -1
1800 if av is not None and bv is None: return 1
1801 if av is None and bv is None: continue
1802 if link.getprops().has_key('order'): 1767 if link.getprops().has_key('order'):
1803 if dir == '+': 1768 v = link.get(v, 'order')
1804 r = cmp(link.get(av, 'order'),
1805 link.get(bv, 'order'))
1806 if r != 0: return r
1807 elif dir == '-':
1808 r = cmp(link.get(bv, 'order'),
1809 link.get(av, 'order'))
1810 if r != 0: return r
1811 elif link.getkey(): 1769 elif link.getkey():
1812 key = link.getkey() 1770 key = link.getkey()
1813 if dir == '+': 1771 v = link.get(v, key)
1814 r = cmp(link.get(av, key), link.get(bv, key)) 1772 entry.insert(0, v)
1815 if r != 0: return r 1773
1816 elif dir == '-': 1774 if directions:
1817 r = cmp(link.get(bv, key), link.get(av, key)) 1775 # sort using the first one or two columns
1818 if r != 0: return r 1776 def sortfun(a, b, directions=directions, n=range(len(directions))):
1777 for i in n:
1778 if a[i] == b[i]: continue
1779 if directions[i] == '-':
1780 return cmp(a[i],b[i])
1819 else: 1781 else:
1820 if dir == '+': 1782 return cmp(b[i],a[i])
1821 r = cmp(av, bv) 1783 return 0
1822 if r != 0: return r 1784 matches.sort(sortfun)
1823 elif dir == '-': 1785
1824 r = cmp(bv, av) 1786 # pull the id out of the individual entries
1825 if r != 0: return r 1787 matches = [entry[-2] for entry in matches]
1826
1827 else:
1828 # all other types just compare
1829 if dir == '+':
1830 r = cmp(av, bv)
1831 elif dir == '-':
1832 r = cmp(bv, av)
1833 if r != 0: return r
1834
1835 # end for dir, prop in sort, group:
1836 # if all else fails, compare the ids
1837 return cmp(a[0], b[0])
1838
1839 l.sort(sortfun)
1840 l = [i[0] for i in l]
1841 if __debug__: 1788 if __debug__:
1842 self.db.stats['filtering'] += (time.time() - start_t) 1789 self.db.stats['filtering'] += (time.time() - start_t)
1843 return l 1790 return matches
1844 1791
1845 def count(self): 1792 def count(self):
1846 '''Get the number of nodes in this class. 1793 '''Get the number of nodes in this class.
1847 1794
1848 If the returned integer is 'numnodes', the ids of all the nodes 1795 If the returned integer is 'numnodes', the ids of all the nodes

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