~0x44/nova/config-drive

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/persisted/styles.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.test.test_persisted -*-
 
2
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
 
3
# See LICENSE for details.
 
4
 
 
5
 
 
6
 
 
7
"""
 
8
Different styles of persisted objects.
 
9
"""
 
10
 
 
11
# System Imports
 
12
import types
 
13
import copy_reg
 
14
import copy
 
15
 
 
16
try:
 
17
    import cStringIO as StringIO
 
18
except ImportError:
 
19
    import StringIO
 
20
 
 
21
# Twisted Imports
 
22
from twisted.python import log
 
23
 
 
24
try:
 
25
    from new import instancemethod
 
26
except:
 
27
    from org.python.core import PyMethod
 
28
    instancemethod = PyMethod
 
29
 
 
30
oldModules = {}
 
31
 
 
32
## First, let's register support for some stuff that really ought to
 
33
## be registerable...
 
34
 
 
35
def pickleMethod(method):
 
36
    'support function for copy_reg to pickle method refs'
 
37
    return unpickleMethod, (method.im_func.__name__,
 
38
                             method.im_self,
 
39
                             method.im_class)
 
40
 
 
41
def unpickleMethod(im_name,
 
42
                    im_self,
 
43
                    im_class):
 
44
    'support function for copy_reg to unpickle method refs'
 
45
    try:
 
46
        unbound = getattr(im_class,im_name)
 
47
        if im_self is None:
 
48
            return unbound
 
49
        bound=instancemethod(unbound.im_func,
 
50
                                 im_self,
 
51
                                 im_class)
 
52
        return bound
 
53
    except AttributeError:
 
54
        log.msg("Method",im_name,"not on class",im_class)
 
55
        assert im_self is not None,"No recourse: no instance to guess from."
 
56
        # Attempt a common fix before bailing -- if classes have
 
57
        # changed around since we pickled this method, we may still be
 
58
        # able to get it by looking on the instance's current class.
 
59
        unbound = getattr(im_self.__class__,im_name)
 
60
        log.msg("Attempting fixup with",unbound)
 
61
        if im_self is None:
 
62
            return unbound
 
63
        bound=instancemethod(unbound.im_func,
 
64
                                 im_self,
 
65
                                 im_self.__class__)
 
66
        return bound
 
67
 
 
68
copy_reg.pickle(types.MethodType,
 
69
                pickleMethod,
 
70
                unpickleMethod)
 
71
 
 
72
def pickleModule(module):
 
73
    'support function for copy_reg to pickle module refs'
 
74
    return unpickleModule, (module.__name__,)
 
75
 
 
76
def unpickleModule(name):
 
77
    'support function for copy_reg to unpickle module refs'
 
78
    if oldModules.has_key(name):
 
79
        log.msg("Module has moved: %s" % name)
 
80
        name = oldModules[name]
 
81
        log.msg(name)
 
82
    return __import__(name,{},{},'x')
 
83
 
 
84
 
 
85
copy_reg.pickle(types.ModuleType,
 
86
                pickleModule,
 
87
                unpickleModule)
 
88
 
 
89
def pickleStringO(stringo):
 
90
    'support function for copy_reg to pickle StringIO.OutputTypes'
 
91
    return unpickleStringO, (stringo.getvalue(), stringo.tell())
 
92
 
 
93
def unpickleStringO(val, sek):
 
94
    x = StringIO.StringIO()
 
95
    x.write(val)
 
96
    x.seek(sek)
 
97
    return x
 
98
 
 
99
if hasattr(StringIO, 'OutputType'):
 
100
    copy_reg.pickle(StringIO.OutputType,
 
101
                    pickleStringO,
 
102
                    unpickleStringO)
 
103
 
 
104
def pickleStringI(stringi):
 
105
    return unpickleStringI, (stringi.getvalue(), stringi.tell())
 
106
 
 
107
def unpickleStringI(val, sek):
 
108
    x = StringIO.StringIO(val)
 
109
    x.seek(sek)
 
110
    return x
 
111
 
 
112
 
 
113
if hasattr(StringIO, 'InputType'):
 
114
    copy_reg.pickle(StringIO.InputType,
 
115
                pickleStringI,
 
116
                unpickleStringI)
 
117
 
 
118
class Ephemeral:
 
119
    """
 
120
    This type of object is never persisted; if possible, even references to it
 
121
    are eliminated.
 
122
    """
 
123
 
 
124
    def __getstate__(self):
 
125
        log.msg( "WARNING: serializing ephemeral %s" % self )
 
126
        import gc
 
127
        if getattr(gc, 'get_referrers', None):
 
128
            for r in gc.get_referrers(self):
 
129
                log.msg( " referred to by %s" % (r,))
 
130
        return None
 
131
 
 
132
    def __setstate__(self, state):
 
133
        log.msg( "WARNING: unserializing ephemeral %s" % self.__class__ )
 
134
        self.__class__ = Ephemeral
 
135
 
 
136
 
 
137
versionedsToUpgrade = {}
 
138
upgraded = {}
 
139
 
 
140
def doUpgrade():
 
141
    global versionedsToUpgrade, upgraded
 
142
    for versioned in versionedsToUpgrade.values():
 
143
        requireUpgrade(versioned)
 
144
    versionedsToUpgrade = {}
 
145
    upgraded = {}
 
146
 
 
147
def requireUpgrade(obj):
 
148
    """Require that a Versioned instance be upgraded completely first.
 
149
    """
 
150
    objID = id(obj)
 
151
    if objID in versionedsToUpgrade and objID not in upgraded:
 
152
        upgraded[objID] = 1
 
153
        obj.versionUpgrade()
 
154
        return obj
 
155
 
 
156
from twisted.python import reflect
 
157
 
 
158
def _aybabtu(c):
 
159
    l = []
 
160
    for b in reflect.allYourBase(c, Versioned):
 
161
        if b not in l and b is not Versioned:
 
162
            l.append(b)
 
163
    return l
 
164
 
 
165
class Versioned:
 
166
    """
 
167
    This type of object is persisted with versioning information.
 
168
 
 
169
    I have a single class attribute, the int persistenceVersion.  After I am
 
170
    unserialized (and styles.doUpgrade() is called), self.upgradeToVersionX()
 
171
    will be called for each version upgrade I must undergo.
 
172
 
 
173
    For example, if I serialize an instance of a Foo(Versioned) at version 4
 
174
    and then unserialize it when the code is at version 9, the calls::
 
175
 
 
176
      self.upgradeToVersion5()
 
177
      self.upgradeToVersion6()
 
178
      self.upgradeToVersion7()
 
179
      self.upgradeToVersion8()
 
180
      self.upgradeToVersion9()
 
181
 
 
182
    will be made.  If any of these methods are undefined, a warning message
 
183
    will be printed.
 
184
    """
 
185
    persistenceVersion = 0
 
186
    persistenceForgets = ()
 
187
 
 
188
    def __setstate__(self, state):
 
189
        versionedsToUpgrade[id(self)] = self
 
190
        self.__dict__ = state
 
191
 
 
192
    def __getstate__(self, dict=None):
 
193
        """Get state, adding a version number to it on its way out.
 
194
        """
 
195
        dct = copy.copy(dict or self.__dict__)
 
196
        bases = _aybabtu(self.__class__)
 
197
        bases.reverse()
 
198
        bases.append(self.__class__) # don't forget me!!
 
199
        for base in bases:
 
200
            if base.__dict__.has_key('persistenceForgets'):
 
201
                for slot in base.persistenceForgets:
 
202
                    if dct.has_key(slot):
 
203
                        del dct[slot]
 
204
            if base.__dict__.has_key('persistenceVersion'):
 
205
                dct['%s.persistenceVersion' % reflect.qual(base)] = base.persistenceVersion
 
206
        return dct
 
207
 
 
208
    def versionUpgrade(self):
 
209
        """(internal) Do a version upgrade.
 
210
        """
 
211
        bases = _aybabtu(self.__class__)
 
212
        # put the bases in order so superclasses' persistenceVersion methods
 
213
        # will be called first.
 
214
        bases.reverse()
 
215
        bases.append(self.__class__) # don't forget me!!
 
216
        # first let's look for old-skool versioned's
 
217
        if self.__dict__.has_key("persistenceVersion"):
 
218
            
 
219
            # Hacky heuristic: if more than one class subclasses Versioned,
 
220
            # we'll assume that the higher version number wins for the older
 
221
            # class, so we'll consider the attribute the version of the older
 
222
            # class.  There are obviously possibly times when this will
 
223
            # eventually be an incorrect assumption, but hopefully old-school
 
224
            # persistenceVersion stuff won't make it that far into multiple
 
225
            # classes inheriting from Versioned.
 
226
            
 
227
            pver = self.__dict__['persistenceVersion']
 
228
            del self.__dict__['persistenceVersion']
 
229
            highestVersion = 0
 
230
            highestBase = None
 
231
            for base in bases:
 
232
                if not base.__dict__.has_key('persistenceVersion'):
 
233
                    continue
 
234
                if base.persistenceVersion > highestVersion:
 
235
                    highestBase = base
 
236
                    highestVersion = base.persistenceVersion
 
237
            if highestBase:
 
238
                self.__dict__['%s.persistenceVersion' % reflect.qual(highestBase)] = pver
 
239
        for base in bases:
 
240
            # ugly hack, but it's what the user expects, really
 
241
            if (Versioned not in base.__bases__ and
 
242
                not base.__dict__.has_key('persistenceVersion')):
 
243
                continue
 
244
            currentVers = base.persistenceVersion
 
245
            pverName = '%s.persistenceVersion' % reflect.qual(base)
 
246
            persistVers = (self.__dict__.get(pverName) or 0)
 
247
            if persistVers:
 
248
                del self.__dict__[pverName]
 
249
            assert persistVers <=  currentVers, "Sorry, can't go backwards in time."
 
250
            while persistVers < currentVers:
 
251
                persistVers = persistVers + 1
 
252
                method = base.__dict__.get('upgradeToVersion%s' % persistVers, None)
 
253
                if method:
 
254
                    log.msg( "Upgrading %s (of %s @ %s) to version %s" % (reflect.qual(base), reflect.qual(self.__class__), id(self), persistVers) )
 
255
                    method(self)
 
256
                else:
 
257
                    log.msg( 'Warning: cannot upgrade %s to version %s' % (base, persistVers) )