Mercurial > libervia-backend
comparison src/memory/memory.py @ 943:71926ec2114d
core (memory): entities cache improvments:
- entities cache is no more limited to bare jid
- resources are now automatically updated in bare jid cache
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 28 Mar 2014 18:07:17 +0100 |
parents | 5b2d2f1f05d0 |
children | e1842ebcb2f3 |
comparison
equal
deleted
inserted
replaced
942:598fc223cf59 | 943:71926ec2114d |
---|---|
110 | 110 |
111 def __init__(self, host): | 111 def __init__(self, host): |
112 info(_("Memory manager init")) | 112 info(_("Memory manager init")) |
113 self.initialized = defer.Deferred() | 113 self.initialized = defer.Deferred() |
114 self.host = host | 114 self.host = host |
115 self.entitiesCache = {} # XXX: keep presence/last resource/other data in cache | 115 self._entities_cache = {} # XXX: keep presence/last resource/other data in cache |
116 # /!\ an entity is not necessarily in roster | 116 # /!\ an entity is not necessarily in roster |
117 self.subscriptions = {} | 117 self.subscriptions = {} |
118 self.server_features = {} # used to store discovery's informations | 118 self.server_features = {} # used to store discovery's informations |
119 self.server_identities = {} | 119 self.server_identities = {} |
120 self.config = self.parseMainConf() | 120 self.config = self.parseMainConf() |
121 self.__fixLocalDir() | 121 self.__fixLocalDir() |
218 | 218 |
219 def startProfileSession(self, profile): | 219 def startProfileSession(self, profile): |
220 """"Iniatialise session for a profile | 220 """"Iniatialise session for a profile |
221 @param profile: %(doc_profile)s""" | 221 @param profile: %(doc_profile)s""" |
222 info(_("[%s] Profile session started" % profile)) | 222 info(_("[%s] Profile session started" % profile)) |
223 self.entitiesCache[profile] = {} | 223 self._entities_cache[profile] = {} |
224 | 224 |
225 def purgeProfileSession(self, profile): | 225 def purgeProfileSession(self, profile): |
226 """Delete cache of data of profile | 226 """Delete cache of data of profile |
227 @param profile: %(doc_profile)s""" | 227 @param profile: %(doc_profile)s""" |
228 info(_("[%s] Profile session purge" % profile)) | 228 info(_("[%s] Profile session purge" % profile)) |
229 self.params.purgeProfile(profile) | 229 self.params.purgeProfile(profile) |
230 try: | 230 try: |
231 del self.entitiesCache[profile] | 231 del self._entities_cache[profile] |
232 except KeyError: | 232 except KeyError: |
233 error(_("Trying to purge roster status cache for a profile not in memory: [%s]") % profile) | 233 error(_("Trying to purge roster status cache for a profile not in memory: [%s]") % profile) |
234 | 234 |
235 def save_xml(self, filename=None): | 235 def save_xml(self, filename=None): |
236 """Save parameters template to xml file""" | 236 """Save parameters template to xml file""" |
367 warning(_("Features of %s not available, maybe they haven't been asked yet?") % jid_) | 367 warning(_("Features of %s not available, maybe they haven't been asked yet?") % jid_) |
368 return None | 368 return None |
369 | 369 |
370 def _getLastResource(self, jid_s, profile_key): | 370 def _getLastResource(self, jid_s, profile_key): |
371 jid_ = jid.JID(jid_s) | 371 jid_ = jid.JID(jid_s) |
372 return self.getLastResource(jid_, profile_key) | 372 return self.getLastResource(jid_, profile_key) or "" |
373 | 373 |
374 | 374 |
375 def getLastResource(self, jid_, profile_key): | 375 def getLastResource(self, entity_jid, profile_key): |
376 """Return the last resource used by a jid_ | 376 """Return the last resource used by an entity |
377 @param jid_: bare jid | 377 @param entity_jid: entity jid |
378 @param profile_key: %(doc_profile_key)s""" | 378 @param profile_key: %(doc_profile_key)s""" |
379 profile = self.getProfileName(profile_key) | 379 data = self.getEntityData(entity_jid.userhostJID(), [C.ENTITY_LAST_RESOURCE], profile_key) |
380 if not profile or not self.host.isConnected(profile): | 380 try: |
381 error(_('Asking jid_s for a non-existant or not connected profile')) | 381 return data[C.ENTITY_LAST_RESOURCE] |
382 return "" | |
383 entity = jid_.userhost() | |
384 if not entity in self.entitiesCache[profile]: | |
385 info(_("Entity not in cache")) | |
386 return "" | |
387 try: | |
388 return self.entitiesCache[profile][entity]["last_resource"] | |
389 except KeyError: | 382 except KeyError: |
390 return "" | 383 return None |
391 | 384 |
392 def getPresenceStatus(self, profile_key): | 385 def _getPresenceStatuses(self, profile_key): |
393 profile = self.getProfileName(profile_key) | 386 ret = self.getPresenceStatuses(profile_key) |
394 if not profile: | 387 return {entity.full():data for entity, data in ret.iteritems()} |
395 error(_('Asking contacts for a non-existant profile')) | 388 |
396 return {} | 389 def getPresenceStatuses(self, profile_key): |
390 """Get all the presence status of a profile | |
391 @param profile_key: %(doc_profile_key)s | |
392 @return: presence data: key=entity JID, value=presence data for this entity | |
393 """ | |
394 profile = self.getProfileName(profile_key) | |
395 if not profile: | |
396 raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile')) | |
397 entities_presence = {} | 397 entities_presence = {} |
398 for entity in self.entitiesCache[profile]: | 398 for entity in self._entities_cache[profile]: |
399 if "presence" in self.entitiesCache[profile][entity]: | 399 if "presence" in self._entities_cache[profile][entity]: |
400 entities_presence[entity] = self.entitiesCache[profile][entity]["presence"] | 400 entities_presence[entity] = self._entities_cache[profile][entity]["presence"] |
401 | 401 |
402 debug("Memory getPresenceStatus (%s)", entities_presence) | 402 debug("Memory getPresenceStatus (%s)", entities_presence) |
403 return entities_presence | 403 return entities_presence |
404 | 404 |
405 def setPresenceStatus(self, entity_jid, show, priority, statuses, profile_key): | 405 def setPresenceStatus(self, entity_jid, show, priority, statuses, profile_key): |
406 """Change the presence status of an entity""" | 406 """Change the presence status of an entity |
407 profile = self.getProfileName(profile_key) | 407 @param entity_jid: jid.JID of the entity |
408 if not profile: | 408 @param show: show status |
409 error(_('Trying to add presence status to a non-existant profile')) | 409 @param priotity: priotity |
410 return | 410 @param statuses: dictionary of statuses |
411 entity_data = self.entitiesCache[profile].setdefault(entity_jid.userhost(), {}) | 411 @param profile_key: %(doc_profile_key)s |
412 resource = jid.parse(entity_jid.full())[2] or '' | 412 """ |
413 profile = self.getProfileName(profile_key) | |
414 if not profile: | |
415 raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile')) | |
416 entity_data = self._getEntitiesData(entity_jid, profile)[entity_jid] | |
417 resource = entity_jid.resource | |
413 if resource: | 418 if resource: |
414 entity_data["last_resource"] = resource | 419 entity_data[C.ENTITY_LAST_RESOURCE] = resource |
415 if not "last_resource" in entity_data: | 420 entity_data.setdefault("presence", {})[resource or ''] = (show, priority, statuses) |
416 entity_data["last_resource"] = '' | 421 |
417 | 422 def _getEntitiesData(self, entity_jid, profile): |
418 entity_data.setdefault("presence", {})[resource] = (show, priority, statuses) | 423 """Get data dictionary for entities |
424 @param entity_jid: JID of the entity, or C.ENTITY_ALL for all entities) | |
425 @param profile: %(doc_profile)s | |
426 @return: entities_data (key=jid, value=entity_data) | |
427 @raise: exceptions.ProfileNotInCacheError if profile is not in cache | |
428 """ | |
429 if not profile in self._entities_cache: | |
430 raise exceptions.ProfileNotInCacheError | |
431 if entity_jid == C.ENTITY_ALL: | |
432 entities_data = self._entities_cache[profile] | |
433 else: | |
434 entity_data = self._entities_cache[profile].setdefault(entity_jid, {}) | |
435 entities_data = {entity_jid: entity_data} | |
436 return entities_data | |
437 | |
438 def _updateEntityResources(self, entity_jid, profile): | |
439 """Add a known resource to bare entity_jid cache | |
440 @param entity_jid: full entity_jid (with resource) | |
441 @param profile: %(doc_profile)s | |
442 """ | |
443 assert(entity_jid.resource) | |
444 entity_data = self._getEntitiesData(entity_jid.userhostJID(), profile)[entity_jid.userhostJID()] | |
445 resources = entity_data.setdefault('resources', set()) | |
446 resources.add(entity_jid.resource) | |
419 | 447 |
420 def updateEntityData(self, entity_jid, key, value, profile_key): | 448 def updateEntityData(self, entity_jid, key, value, profile_key): |
421 """Set a misc data for an entity | 449 """Set a misc data for an entity |
422 @param entity_jid: JID of the entity, or '@ALL@' to update all entities) | 450 @param entity_jid: JID of the entity, or C.ENTITY_ALL to update all entities) |
423 @param key: key to set (eg: "type") | 451 @param key: key to set (eg: "type") |
424 @param value: value for this key (eg: "chatroom"), or C.PROF_KEY_NONE to delete | 452 @param value: value for this key (eg: "chatroom") |
425 @param profile_key: %(doc_profile_key)s | 453 @param profile_key: %(doc_profile_key)s |
426 """ | 454 """ |
427 profile = self.getProfileName(profile_key) | 455 profile = self.getProfileName(profile_key) |
428 if not profile: | 456 if not profile: |
429 raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile')) | 457 raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile')) |
430 if not profile in self.entitiesCache: | 458 entities_data = self._getEntitiesData(entity_jid, profile) |
431 raise exceptions.ProfileNotInCacheError | 459 if entity_jid.resource and entity_jid != C.ENTITY_ALL: |
432 if entity_jid == "@ALL@": | 460 self._updateEntityResources(entity_jid, profile) |
433 entities_map = self.entitiesCache[profile] | 461 |
434 else: | 462 for jid_ in entities_data: |
435 entity = entity_jid.userhost() | 463 entity_data = entities_data[jid_] |
436 self.entitiesCache[profile].setdefault(entity, {}) | 464 if value == C.PROF_KEY_NONE and key in entity_data: |
437 entities_map = {entity: self.entitiesCache[profile][entity]} | 465 del entity_data[key] |
438 for entity in entities_map: | |
439 entity_map = entities_map[entity] | |
440 if value == C.PROF_KEY_NONE and key in entity_map: | |
441 del entity_map[key] | |
442 else: | 466 else: |
443 entity_map[key] = value | 467 entity_data[key] = value |
444 if isinstance(value, basestring): | 468 if isinstance(value, basestring): |
445 self.host.bridge.entityDataUpdated(entity, key, value, profile) | 469 self.host.bridge.entityDataUpdated(jid_.full(), key, value, profile) |
470 | |
471 def delEntityData(self, entity_jid, key, profile_key): | |
472 """Delete data for an entity | |
473 @param entity_jid: JID of the entity, or C.ENTITY_ALL to delete data from all entities) | |
474 @param key: key to delete (eg: "type") | |
475 @param profile_key: %(doc_profile_key)s | |
476 """ | |
477 entities_data = self._getEntitiesData(entity_jid, profile_key) | |
478 for entity_jid in entities_data: | |
479 entity_data = entities_data[entity_jid] | |
480 try: | |
481 del entity_data[key] | |
482 except KeyError: | |
483 debug("Key [%s] doesn't exist for [%s] in entities_cache" % (key, entity_jid.full())) | |
446 | 484 |
447 def getEntityData(self, entity_jid, keys_list, profile_key): | 485 def getEntityData(self, entity_jid, keys_list, profile_key): |
448 """Get a list of cached values for entity | 486 """Get a list of cached values for entity |
449 @param entity_jid: JID of the entity | 487 @param entity_jid: JID of the entity |
450 @param keys_list: list of keys to get, empty list for everything | 488 @param keys_list: list of keys to get, empty list for everything |
451 @param profile_key: %(doc_profile_key)s | 489 @param profile_key: %(doc_profile_key)s |
452 @return: dict withs values for each key in keys_list. | 490 @return: dict withs values for each key in keys_list. |
453 if there is no value of a given key, resulting dict will | 491 if there is no value of a given key, resulting dict will |
454 have nothing with that key nether | 492 have nothing with that key nether |
455 @raise: exceptions.UnknownEntityError if entity is not in cache | 493 @raise: exceptions.UnknownEntityError if entity is not in cache |
456 exceptions.ProfileNotInCacheError if profile is not in cache | |
457 """ | 494 """ |
458 profile = self.getProfileName(profile_key) | 495 profile = self.getProfileName(profile_key) |
459 if not profile: | 496 if not profile: |
460 raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile')) | 497 raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile')) |
461 if not profile in self.entitiesCache: | 498 entity_data = self._getEntitiesData(entity_jid, profile)[entity_jid] |
462 raise exceptions.ProfileNotInCacheError | |
463 if not entity_jid.userhost() in self.entitiesCache[profile]: | |
464 raise exceptions.UnknownEntityError(entity_jid.userhost()) | |
465 entity_data = self.entitiesCache[profile][entity_jid.userhost()] | |
466 if not keys_list: | 499 if not keys_list: |
467 return entity_data | 500 return entity_data |
468 ret = {} | 501 ret = {} |
469 for key in keys_list: | 502 for key in keys_list: |
470 if key in entity_data: | 503 if key in entity_data: |
471 ret[key] = entity_data[key] | 504 ret[key] = entity_data[key] |
472 return ret | 505 return ret |
473 | 506 |
474 def delEntityCache(self, entity_jid, profile_key): | 507 def delEntityCache(self, entity_jid, delete_all_resources=True, profile_key=C.PROF_KEY_NONE): |
475 """Remove cached data for entity | 508 """Remove cached data for entity |
476 @param entity_jid: JID of the entity | 509 @param entity_jid: JID of the entity to delete |
477 """ | 510 @param delete_all_resources: if True also delete all known resources form cache |
478 profile = self.getProfileName(profile_key) | 511 @param profile_key: %(doc_profile_key)s |
479 try: | 512 """ |
480 del self.entitiesCache[profile][entity_jid.userhost()] | 513 profile = self.getProfileName(profile_key) |
481 except KeyError: | 514 if not profile: |
482 pass | 515 raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile')) |
516 to_delete = set([entity_jid]) | |
517 | |
518 if delete_all_resources: | |
519 if entity_jid.resource: | |
520 raise ValueError(_("Need a bare jid to delete all resources")) | |
521 entity_data = self._getEntitiesData(entity_jid, profile)[entity_jid] | |
522 resources = entity_data.setdefault('resources', set()) | |
523 to_delete.update([jid.JID("%s/%s" % (entity_jid.userhost(), resource)) for resource in resources]) | |
524 | |
525 for entity in to_delete: | |
526 try: | |
527 del self._entities_cache[profile][entity] | |
528 except KeyError: | |
529 debug("Can't delete entity [%s]: not in cache" % entity.full()) | |
483 | 530 |
484 def addWaitingSub(self, type_, entity_jid, profile_key): | 531 def addWaitingSub(self, type_, entity_jid, profile_key): |
485 """Called when a subcription request is received""" | 532 """Called when a subcription request is received""" |
486 profile = self.getProfileName(profile_key) | 533 profile = self.getProfileName(profile_key) |
487 assert profile | 534 assert profile |