def __init__(self, context=None): # last add in milliseconds - used in both async and cache key self._mtime = 0 # cache buster in MICROseconds - used in cache key only self._ctime = 0 # primary storage: (long statusid) -> (object IStatusUpdate) self._status_mapping = LOBTree.LOBTree() # archive deleted: (long statusid) -> (object IStatusUpdate) self._status_archive = LOBTree.LOBTree() # index by user: (string userid) -> (object TreeSet(long statusid)) self._user_mapping = OOBTree.OOBTree() # index by tag: (string tag) -> (object TreeSet(long statusid)) self._tag_mapping = OOBTree.OOBTree() # index by microblog_context: # (string UUID) -> (object TreeSet(long statusid)) self._uuid_mapping = OOBTree.OOBTree() # keep old name for backcompat # index by content_context: # (string UUID) -> (object TreeSet(long statusid)) self._content_uuid_mapping = OOBTree.OOBTree() # index by thread (string UUID) -> (object TreeSet(long statusid)) self._threadid_mapping = OOBTree.OOBTree() # index by mentions (string UUID) -> (object TreeSet(long statusid)) self._mentions_mapping = OOBTree.OOBTree() # index all content updates: (object TreeSet(long statusid)) self._is_content_mapping = LLBTree.LLTreeSet() # index all human updates: (object TreeSet(long statusid)) self._is_human_mapping = LLBTree.LLTreeSet()
def secure(self, keyset): """Filter keyset to return only keys the current user may see. NB this may return statusupdates with a microblog_context (workspace) accessible to the user, but referencing a content_context (document) which the user may not access yet because of content workflow. Filtering that is quite costly and not done here - instead there's a postprocessing filter in activitystream just before rendering. """ return LLBTree.intersection( LLBTree.LLTreeSet(keyset), LLBTree.LLTreeSet(self.allowed_status_keys()))
def setup_human_and_content_mappings(context): """0012 adds two new indexes""" tool = queryUtility(IMicroblogTool) if not hasattr(tool, '_is_content_mapping'): logger.info("Adding missing is_content mapping to %s" % repr(tool)) tool._is_content_mapping = LLBTree.LLTreeSet() if not hasattr(tool, '_is_human_mapping'): logger.info("Adding missing is_human mapping to %s" % repr(tool)) tool._is_human_mapping = LLBTree.LLTreeSet() logger.info("Indexing statusupdates into is_content and is_human indexes") for status in tool.values(limit=None): tool._idx_is_content(status) tool._idx_is_human(status) commit()
def _idx_context(self, status): uuid = status.context_uuid if uuid: # If the key was already in the collection, there is no change # create tag treeset if not already present self._uuid_mapping.insert(uuid, LLBTree.LLTreeSet()) self._uuid_mapping[uuid].insert(status.id)
def _idx_tag(self, status): for tag in [unicode(tag) for tag in status.tags]: # If the key was already in the collection, there is no change # create tag treeset if not already present self._tag_mapping.insert(tag, LLBTree.LLTreeSet()) # add status id to tag treeset self._tag_mapping[tag].insert(status.id)
def _idx_user(self, status): userid = unicode(status.userid) # If the key was already in the collection, there is no change # create user treeset if not already present self._user_mapping.insert(userid, LLBTree.LLTreeSet()) # add status id to user treeset self._user_mapping[userid].insert(status.id)
def _idx_mentions(self, status): if not getattr(status, 'mentions', False): return mentions = status.mentions.keys() for mention in mentions: # If the key was already in the collection, there is no change # create tag treeset if not already present self._mentions_mapping.insert(mention, LLBTree.LLTreeSet()) self._mentions_mapping[mention].insert(status.id)
def _idx_threadid(self, status): if not getattr(status, 'thread_id', False): return tread_id = status.thread_id if tread_id: # If the key was already in the collection, there is no change # create tag treeset if not already present self._threadid_mapping.insert(tread_id, LLBTree.LLTreeSet()) self._threadid_mapping[tread_id].insert(status.id)
def _idx_tag(self, status): """ Update the `StatusContainer` tag index with any new tags :param status: a `StatusUpdate` object """ if status.tags is None: return for tag in [unicode(tag) for tag in status.tags]: # If the key was already in the collection, there is no change # create tag treeset if not already present self._tag_mapping.insert(tag, LLBTree.LLTreeSet()) # add status id to tag treeset self._tag_mapping[tag].insert(status.id)
def _query_mapping(self, mapping, keys): """ Calculate the union of all statusids indexed in <mapping> on any of the <keys>. Always returns an LLTreeSet ready for further processing. """ if not keys: return LLBTree.LLTreeSet() elif isinstance(keys, (str, unicode)): # convert single key to list keys = [keys] # calculate the union set of matching ids across all tags # silently discards all non-existing key ids treesets = [mapping.get(id) for id in keys if id in mapping.keys()] return LLBTree.multiunion(treesets)
def _keys_uuid(self, uuid, keyset): if uuid is None: return keyset return LLBTree.intersection(LLBTree.LLTreeSet(keyset), self._uuid_mapping[uuid])
def _keys_tag(self, tag, keyset): if tag is None: return keyset return LLBTree.intersection(LLBTree.LLTreeSet(keyset), self._tag_mapping[tag])
def _keys_mention(self, mention, keyset): if mention is None: return keyset return LLBTree.intersection(LLBTree.LLTreeSet(keyset), self._mentions_mapping[mention])
def secure(self, keyset): """Filter keyset to return only keys the current user may see.""" return LLBTree.intersection( LLBTree.LLTreeSet(keyset), LLBTree.LLTreeSet(self.allowed_status_keys()))