moniker.py (12149B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\net\moniker.py 2 import weakref 3 import cPickle 4 import sys 5 import log 6 import uthread 7 from carbon.common.script.net import machoNet 8 from carbon.common.script.net.machoNetExceptions import UnMachoDestination 9 from carbon.common.script.sys import basesession 10 from carbon.common.script.sys.service import ROLE_SERVICE 11 from eveexceptions import UserError 12 allMonikers = weakref.WeakSet() 13 14 class Moniker(): 15 __guid__ = 'util.Moniker' 16 __passbyvalue__ = 1 17 __persistvar__ = ['__serviceName', 18 '__nodeID', 19 '__bindParams', 20 '__sessionCheck'] 21 22 def __init__(self, serviceName = None, bindParams = None, nodeID = None): 23 global allMonikers 24 self.__serviceName = serviceName 25 self.__bindParams = bindParams 26 self.__nodeID = nodeID 27 self.__sessionCheck = None 28 self.boundObject = None 29 allMonikers.add(self) 30 31 def __del__(self): 32 self.__ClearBoundObject() 33 34 def __str__(self): 35 if self.__class__ == Moniker: 36 name = 'Generic' 37 else: 38 name = self.__class__.__name__ 39 args = (name, 40 self.__serviceName, 41 self.__nodeID, 42 self.__bindParams) 43 return '%s moniker on service %s, node %s, params %s' % args 44 45 def SetSessionCheck(self, sessionCheck): 46 self.__sessionCheck = sessionCheck 47 48 def __PerformSessionCheck(self): 49 if self.__sessionCheck: 50 for attribute, expected in self.__sessionCheck.iteritems(): 51 if session: 52 current = getattr(session, attribute, None) 53 else: 54 current = None 55 if current != expected or not expected and current: 56 log.LogTraceback('__PerformSessionCheck: Monikers session has changed. Traceback=', toAlertSvc=0, severity=log.LGWARN) 57 raise RuntimeError('MonikerSessionCheckFailure', {'attribute': attribute, 58 'expected': expected, 59 'current': current, 60 'serviceName': self.__serviceName, 61 'bindParams': self.__bindParams}) 62 63 def ToURLString(self): 64 import binascii 65 return binascii.b2a_hex(cPickle.dumps((self.__serviceName, self.__bindParams), 1)) 66 67 def FromURLString(self, s): 68 import binascii 69 b = binascii.a2b_hex(s) 70 self.__serviceName, self.__bindParams = cPickle.loads(b) 71 72 def __getstate__(self): 73 ret = [] 74 for each in self.__persistvar__: 75 ret.append(self.__dict__['_Moniker' + each]) 76 77 return tuple(ret) 78 79 def __setstate__(self, state): 80 self.boundObject = None 81 for i in xrange(len(self.__persistvar__)): 82 self.__dict__['_Moniker' + self.__persistvar__[i]] = state[i] 83 84 if self.__nodeID is not None: 85 if machoNet.mode == 'client' or basesession.IsInClientContext(): 86 sm.services['machoNet'].SetNodeOfAddress(self.__serviceName, self.__bindParams, self.__nodeID) 87 allMonikers.add(self) 88 89 __remobsuppmeth__ = ('RegisterObjectChangeHandler', 'UnRegisterObjectChangeHandler') 90 91 def __getattr__(self, key): 92 if key in self.__remobsuppmeth__: 93 self.Bind() 94 return getattr(self.boundObject, key) 95 elif not key[0].isupper(): 96 if key.startswith('__'): 97 raise AttributeError(key) 98 self.Bind() 99 return getattr(self.boundObject, key) 100 else: 101 return MonikerCallWrap(self, key) 102 103 def __ClearBoundObject(self, disconnectDelay = 30): 104 if self.boundObject is not None and isinstance(self.boundObject, basesession.ObjectConnection): 105 try: 106 self.boundObject.DisconnectObject(disconnectDelay) 107 except AttributeError: 108 pass 109 110 self.boundObject = None 111 112 def Bind(self, sess = None, call = None): 113 localKeywords = ('machoTimeout', 'noCallThrottling') 114 done = set() 115 while 1: 116 try: 117 if self.__bindParams is None: 118 raise RuntimeError("Thou shall not use None as a Moniker's __bindParams") 119 if '__semaphoreB__' not in self.__dict__: 120 self.__semaphoreB__ = uthread.Semaphore(('moniker::Bind', self.__serviceName, self.__bindParams)) 121 self.__semaphoreB__.acquire() 122 try: 123 if not self.boundObject: 124 if self.__nodeID is None: 125 self.__ResolveImpl(sess) 126 if sess is None: 127 if session and basesession.IsInClientContext(): 128 sess = session 129 elif session and session.role == ROLE_SERVICE: 130 sess = session.GetActualSession() 131 else: 132 sess = basesession.GetServiceSession('util.Moniker') 133 else: 134 sess = sess.GetActualSession() 135 if self.__nodeID == sm.GetService('machoNet').GetNodeID(): 136 service = sess.ConnectToService(self.__serviceName) 137 self.boundObject = service.MachoGetObjectBoundToSession(self.__bindParams, sess) 138 else: 139 remotesvc = sess.ConnectToRemoteService(self.__serviceName, self.__nodeID) 140 self.__PerformSessionCheck() 141 if call is not None and call[2]: 142 c2 = {k:v for k, v in call[2].iteritems() if k not in localKeywords} 143 call = (call[0], call[1], c2) 144 self.boundObject, retval = remotesvc.MachoBindObject(self.__bindParams, call) 145 self.boundObject.persistantObjectID = (self.__serviceName, self.__bindParams) 146 return retval 147 finally: 148 done.add((self.__serviceName, self.__bindParams)) 149 self.__semaphoreB__.release() 150 151 if call is not None: 152 return self.MonikeredCall(call, sess) 153 return 154 except UpdateMoniker as e: 155 if (e.serviceName, e.bindParams) in done: 156 log.LogException() 157 raise RuntimeError('UpdateMoniker referred us to the same location twice', (e.serviceName, e.bindParams)) 158 else: 159 self.__bindParams = e.bindParams 160 self.__serviceName = e.serviceName 161 self.__nodeID = e.nodeID 162 self.Unbind() 163 sys.exc_clear() 164 165 def MonikeredCall(self, call, sess): 166 retry = 0 167 while 1: 168 try: 169 self.__PerformSessionCheck() 170 if self.boundObject is None: 171 return self.Bind(sess, call) 172 try: 173 return getattr(self.boundObject, call[0])(*call[1], **call[2]) 174 except UpdateMoniker as e: 175 self.__bindParams = e.bindParams 176 self.__serviceName = e.serviceName 177 self.__nodeID = e.nodeID 178 self.Unbind() 179 sys.exc_clear() 180 181 except UserError as e: 182 if e.msg == 'UnMachoDestination' and not retry: 183 retry = 1 184 self.Unresolve() 185 sys.exc_clear() 186 continue 187 raise 188 except UnMachoDestination: 189 if not retry: 190 retry = 1 191 self.Unresolve() 192 sys.exc_clear() 193 continue 194 raise 195 196 def QuickResolve(self): 197 if self.__nodeID is None and self.__serviceName in sm.services: 198 self.__nodeID = self.__ResolveImpl() 199 200 def Resolve(self, sess = None): 201 return self.__ResolveImpl(sess) 202 203 def __ResolveImpl(self, sess = None): 204 if '__semaphoreR__' not in self.__dict__: 205 self.__semaphoreR__ = uthread.Semaphore(('moniker::Resolve', self.__serviceName, self.__bindParams)) 206 self.__semaphoreR__.acquire() 207 try: 208 if self.__nodeID is not None: 209 return self.__nodeID 210 if machoNet.mode == 'client' or basesession.IsInClientContext(): 211 self.__nodeID = sm.services['machoNet'].GuessNodeIDFromAddress(self.__serviceName, self.__bindParams) 212 if self.__nodeID is not None: 213 return self.__nodeID 214 if not self.__nodeID: 215 self.__nodeID = sm.GetService('machoNet').LookupAddressCache(self.__serviceName, self.__bindParams) 216 if self.__nodeID is not None: 217 return self.__nodeID 218 if sess is None: 219 if session and session.role == ROLE_SERVICE: 220 sess = session.GetActualSession() 221 else: 222 sess = basesession.GetServiceSession('util.Moniker') 223 else: 224 sess = sess.GetActualSession() 225 if machoNet.mode == 'client' or basesession.IsInClientContext(): 226 service = sess.ConnectToRemoteService(self.__serviceName) 227 else: 228 service = sess.ConnectToAnyService(self.__serviceName) 229 self.__nodeID = service.MachoResolveObject(self.__bindParams) 230 if self.__nodeID is None: 231 raise RuntimeError('Resolution failure: ResolveObject returned None') 232 if machoNet.mode == 'client' or basesession.IsInClientContext(): 233 sm.services['machoNet'].SetNodeOfAddress(self.__serviceName, self.__bindParams, self.__nodeID) 234 return self.__nodeID 235 finally: 236 self.__semaphoreR__.release() 237 238 def Unresolve(self): 239 while 1: 240 self.Unbind() 241 if '__semaphoreR__' not in self.__dict__: 242 self.__semaphoreR__ = uthread.Semaphore(('moniker::Resolve', self.__serviceName, self.__bindParams)) 243 self.__semaphoreR__.acquire() 244 try: 245 if self.boundObject is None: 246 self.__nodeID = None 247 sm.services['machoNet'].SetNodeOfAddress(self.__serviceName, self.__bindParams, None) 248 return 249 finally: 250 self.__semaphoreR__.release() 251 252 def Unbind(self, disconnectDelay = 30): 253 if '__semaphoreB__' not in self.__dict__: 254 self.__semaphoreB__ = uthread.Semaphore(('moniker::Bind', self.__serviceName, self.__bindParams)) 255 self.__semaphoreB__.acquire() 256 try: 257 self.__ClearBoundObject(disconnectDelay) 258 finally: 259 self.__semaphoreB__.release() 260 261 def GetNodeID(self): 262 if self.__nodeID is None: 263 self.__ResolveImpl() 264 return self.__nodeID 265 266 def GetSelfLocal(self): 267 if self.GetNodeID() == sm.services['machoNet'].GetNodeID(): 268 self.Bind() 269 return self.boundObject.__object__ 270 raise RuntimeError('You are not local %d != %d' % (self.GetNodeID(), sm.services['machoNet'].GetNodeID())) 271 272 273 class MonikerCallWrap(): 274 275 def __init__(self, moniker, key): 276 self.moniker = moniker 277 self.key = key 278 if key[0] != key[0].upper(): 279 raise RuntimeError("This moniker has no attribute '%s'. Moniker: %s" % (key, moniker)) 280 281 def __call__(self, *args, **kw): 282 try: 283 return self.moniker.MonikeredCall((self.key, args, kw), None) 284 finally: 285 self.__dict__.clear() 286 287 288 class UpdateMoniker(Exception): 289 __passbyvalue__ = 1 290 291 def __init__(self, serviceName = None, bindParams = None, nodeID = None): 292 Exception.__init__(self, 'Update') 293 self.serviceName = serviceName 294 self.nodeID = nodeID 295 self.bindParams = bindParams