comparison roundup/backends/back_anydbm.py @ 869:6d98bec4e52e

fixed the journal bloat from multilink changes we just log the add or remove operations, not the whole list
author Richard Jones <richard@users.sourceforge.net>
date Sun, 14 Jul 2002 23:18:20 +0000
parents 37fb48c3a136
children de3da99a7c02
comparison
equal deleted inserted replaced
868:e8162a199d81 869:6d98bec4e52e
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.46 2002-07-14 06:06:34 richard Exp $ 18 #$Id: back_anydbm.py,v 1.47 2002-07-14 23:18:20 richard Exp $
19 ''' 19 '''
20 This module defines a backend that saves the hyperdatabase in a database 20 This module defines a backend that saves the hyperdatabase in a database
21 chosen by anydbm. It is guaranteed to always be available in python 21 chosen by anydbm. It is guaranteed to always be available in python
22 versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several 22 versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several
23 serious bugs, and is not available) 23 serious bugs, and is not available)
874 874
875 node = self.db.getnode(self.classname, nodeid) 875 node = self.db.getnode(self.classname, nodeid)
876 if node.has_key(self.db.RETIRED_FLAG): 876 if node.has_key(self.db.RETIRED_FLAG):
877 raise IndexError 877 raise IndexError
878 num_re = re.compile('^\d+$') 878 num_re = re.compile('^\d+$')
879 for key, value in propvalues.items(): 879
880 # if the journal value is to be different, store it in here
881 journalvalues = {}
882
883 for propname, value in propvalues.items():
880 # check to make sure we're not duplicating an existing key 884 # check to make sure we're not duplicating an existing key
881 if key == self.key and node[key] != value: 885 if propname == self.key and node[propname] != value:
882 try: 886 try:
883 self.lookup(value) 887 self.lookup(value)
884 except KeyError: 888 except KeyError:
885 pass 889 pass
886 else: 890 else:
887 raise ValueError, 'node with key "%s" exists'%value 891 raise ValueError, 'node with key "%s" exists'%value
888 892
889 # this will raise the KeyError if the property isn't valid 893 # this will raise the KeyError if the property isn't valid
890 # ... we don't use getprops() here because we only care about 894 # ... we don't use getprops() here because we only care about
891 # the writeable properties. 895 # the writeable properties.
892 prop = self.properties[key] 896 prop = self.properties[propname]
893 897
894 # if the value's the same as the existing value, no sense in 898 # if the value's the same as the existing value, no sense in
895 # doing anything 899 # doing anything
896 if node.has_key(key) and value == node[key]: 900 if node.has_key(propname) and value == node[propname]:
897 del propvalues[key] 901 del propvalues[propname]
898 continue 902 continue
899 903
900 # do stuff based on the prop type 904 # do stuff based on the prop type
901 if isinstance(prop, Link): 905 if isinstance(prop, Link):
902 link_class = self.properties[key].classname 906 link_class = self.properties[propname].classname
903 # if it isn't a number, it's a key 907 # if it isn't a number, it's a key
904 if type(value) != type(''): 908 if type(value) != type(''):
905 raise ValueError, 'link value must be String' 909 raise ValueError, 'link value must be String'
906 if not num_re.match(value): 910 if not num_re.match(value):
907 try: 911 try:
908 value = self.db.classes[link_class].lookup(value) 912 value = self.db.classes[link_class].lookup(value)
909 except (TypeError, KeyError): 913 except (TypeError, KeyError):
910 raise IndexError, 'new property "%s": %s not a %s'%( 914 raise IndexError, 'new property "%s": %s not a %s'%(
911 key, value, self.properties[key].classname) 915 propname, value, self.properties[propname].classname)
912 916
913 if not self.db.hasnode(link_class, value): 917 if not self.db.hasnode(link_class, value):
914 raise IndexError, '%s has no node %s'%(link_class, value) 918 raise IndexError, '%s has no node %s'%(link_class, value)
915 919
916 if self.do_journal and self.properties[key].do_journal: 920 if self.do_journal and self.properties[propname].do_journal:
917 # register the unlink with the old linked node 921 # register the unlink with the old linked node
918 if node[key] is not None: 922 if node[propname] is not None:
919 self.db.addjournal(link_class, node[key], 'unlink', 923 self.db.addjournal(link_class, node[propname], 'unlink',
920 (self.classname, nodeid, key)) 924 (self.classname, nodeid, propname))
921 925
922 # register the link with the newly linked node 926 # register the link with the newly linked node
923 if value is not None: 927 if value is not None:
924 self.db.addjournal(link_class, value, 'link', 928 self.db.addjournal(link_class, value, 'link',
925 (self.classname, nodeid, key)) 929 (self.classname, nodeid, propname))
926 930
927 elif isinstance(prop, Multilink): 931 elif isinstance(prop, Multilink):
928 if type(value) != type([]): 932 if type(value) != type([]):
929 raise TypeError, 'new property "%s" not a list of ids'%key 933 raise TypeError, 'new property "%s" not a list of'\
930 link_class = self.properties[key].classname 934 ' ids'%propname
935 link_class = self.properties[propname].classname
931 l = [] 936 l = []
932 for entry in value: 937 for entry in value:
933 # if it isn't a number, it's a key 938 # if it isn't a number, it's a key
934 if type(entry) != type(''): 939 if type(entry) != type(''):
935 raise ValueError, 'new property "%s" link value ' \ 940 raise ValueError, 'new property "%s" link value ' \
936 'must be a string'%key 941 'must be a string'%propname
937 if not num_re.match(entry): 942 if not num_re.match(entry):
938 try: 943 try:
939 entry = self.db.classes[link_class].lookup(entry) 944 entry = self.db.classes[link_class].lookup(entry)
940 except (TypeError, KeyError): 945 except (TypeError, KeyError):
941 raise IndexError, 'new property "%s": %s not a %s'%( 946 raise IndexError, 'new property "%s": %s not a %s'%(
942 key, entry, self.properties[key].classname) 947 propname, entry,
948 self.properties[propname].classname)
943 l.append(entry) 949 l.append(entry)
944 value = l 950 value = l
945 propvalues[key] = value 951 propvalues[propname] = value
952
953 # figure the journal entry for this property
954 add = []
955 remove = []
946 956
947 # handle removals 957 # handle removals
948 if node.has_key(key): 958 if node.has_key(propname):
949 l = node[key] 959 l = node[propname]
950 else: 960 else:
951 l = [] 961 l = []
952 for id in l[:]: 962 for id in l[:]:
953 if id in value: 963 if id in value:
954 continue 964 continue
955 # register the unlink with the old linked node 965 # register the unlink with the old linked node
956 if self.do_journal and self.properties[key].do_journal: 966 if self.do_journal and self.properties[propname].do_journal:
957 self.db.addjournal(link_class, id, 'unlink', 967 self.db.addjournal(link_class, id, 'unlink',
958 (self.classname, nodeid, key)) 968 (self.classname, nodeid, propname))
959 l.remove(id) 969 l.remove(id)
970 remove.append(id)
960 971
961 # handle additions 972 # handle additions
962 for id in value: 973 for id in value:
963 if not self.db.hasnode(link_class, id): 974 if not self.db.hasnode(link_class, id):
964 raise IndexError, '%s has no node %s'%( 975 raise IndexError, '%s has no node %s'%(link_class, id)
965 link_class, id)
966 if id in l: 976 if id in l:
967 continue 977 continue
968 # register the link with the newly linked node 978 # register the link with the newly linked node
969 if self.do_journal and self.properties[key].do_journal: 979 if self.do_journal and self.properties[propname].do_journal:
970 self.db.addjournal(link_class, id, 'link', 980 self.db.addjournal(link_class, id, 'link',
971 (self.classname, nodeid, key)) 981 (self.classname, nodeid, propname))
972 l.append(id) 982 l.append(id)
983 add.append(id)
984
985 # figure the journal entry
986 l = []
987 if add:
988 l.append(('add', add))
989 if remove:
990 l.append(('remove', remove))
991 if l:
992 journalvalues[propname] = tuple(l)
973 993
974 elif isinstance(prop, String): 994 elif isinstance(prop, String):
975 if value is not None and type(value) != type(''): 995 if value is not None and type(value) != type(''):
976 raise TypeError, 'new property "%s" not a string'%key 996 raise TypeError, 'new property "%s" not a string'%propname
977 997
978 elif isinstance(prop, Password): 998 elif isinstance(prop, Password):
979 if not isinstance(value, password.Password): 999 if not isinstance(value, password.Password):
980 raise TypeError, 'new property "%s" not a Password'% key 1000 raise TypeError, 'new property "%s" not a Password'%propname
981 propvalues[key] = value 1001 propvalues[propname] = value
982 1002
983 elif value is not None and isinstance(prop, Date): 1003 elif value is not None and isinstance(prop, Date):
984 if not isinstance(value, date.Date): 1004 if not isinstance(value, date.Date):
985 raise TypeError, 'new property "%s" not a Date'% key 1005 raise TypeError, 'new property "%s" not a Date'% propname
986 propvalues[key] = value 1006 propvalues[propname] = value
987 1007
988 elif value is not None and isinstance(prop, Interval): 1008 elif value is not None and isinstance(prop, Interval):
989 if not isinstance(value, date.Interval): 1009 if not isinstance(value, date.Interval):
990 raise TypeError, 'new property "%s" not an Interval'% key 1010 raise TypeError, 'new property "%s" not an '\
991 propvalues[key] = value 1011 'Interval'%propname
992 1012 propvalues[propname] = value
993 node[key] = value 1013
1014 node[propname] = value
994 1015
995 # nothing to do? 1016 # nothing to do?
996 if not propvalues: 1017 if not propvalues:
997 return 1018 return
998 1019
999 # do the set, and journal it 1020 # do the set, and journal it
1000 self.db.setnode(self.classname, nodeid, node) 1021 self.db.setnode(self.classname, nodeid, node)
1022
1001 if self.do_journal: 1023 if self.do_journal:
1024 propvalues.update(journalvalues)
1002 self.db.addjournal(self.classname, nodeid, 'set', propvalues) 1025 self.db.addjournal(self.classname, nodeid, 'set', propvalues)
1003 1026
1004 self.fireReactors('set', nodeid, oldvalues) 1027 self.fireReactors('set', nodeid, oldvalues)
1005 1028
1006 def retire(self, nodeid): 1029 def retire(self, nodeid):
1613 properties['superseder'] = hyperdb.Multilink(classname) 1636 properties['superseder'] = hyperdb.Multilink(classname)
1614 Class.__init__(self, db, classname, **properties) 1637 Class.__init__(self, db, classname, **properties)
1615 1638
1616 # 1639 #
1617 #$Log: not supported by cvs2svn $ 1640 #$Log: not supported by cvs2svn $
1641 #Revision 1.46 2002/07/14 06:06:34 richard
1642 #Did some old TODOs
1643 #
1618 #Revision 1.45 2002/07/14 04:03:14 richard 1644 #Revision 1.45 2002/07/14 04:03:14 richard
1619 #Implemented a switch to disable journalling for a Class. CGI session 1645 #Implemented a switch to disable journalling for a Class. CGI session
1620 #database now uses it. 1646 #database now uses it.
1621 # 1647 #
1622 #Revision 1.44 2002/07/14 02:05:53 richard 1648 #Revision 1.44 2002/07/14 02:05:53 richard

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