def add_comments(cls, link, comments): with cls._mutation_context(link) as lock: # adding comments requires read-modify-write, so get the lock tree = cls._load_tree(link) cids, _, _ = get_tree_details(tree) # skip any comments that are already in the stored tree and convert # to a set to remove any duplicate comments comments = { comment for comment in comments if comment._id not in cids } if not comments: return # warn on any comments whose parents are missing from the tree # because they will never be displayed unless their parent is # added. this can happen in normal operation if there are multiple # queue consumers and a child is processed before its parent. parent_ids = set(cids) | {comment._id for comment in comments} possible_orphan_comments = { comment for comment in comments if (comment.parent_id and comment.parent_id not in parent_ids) } if possible_orphan_comments: g.log.error("comment_tree_inconsistent: %s %s", link, possible_orphan_comments) g.stats.simple_event('comment_tree_inconsistent') for comment in comments: tree.setdefault(comment.parent_id, []).append(comment._id) cls._write_tree(link, tree, lock)
def by_link(cls, link, timer): key = cls._comments_key(link._id) r = g.permacache.get(key) timer.intermediate('load') if not r: # this link has not had an empty tree written for it. make an empty # tree here and return it. the downside is that until a comment is # added every time the storage for this link is requested it will # have a cache miss and fall through to cassandra return dict(cids=[], tree={}, depth={}, parents={}) if isinstance(r, dict): tree = r else: try: # We got the old version that includes cids and depth _, tree, _ = r except ValueError: # We got the even older version that includes num_children _, tree, _, _ = r cids, depth, parents = get_tree_details(tree) timer.intermediate('calculate') return dict(cids=cids, tree=tree, depth=depth, parents=parents)
def get_tree_pieces(cls, link, timer): key = cls._comments_key(link._id) tree = g.permacache.get(key) timer.intermediate('load') tree = tree or {} # assume empty tree on miss cids, depth, parents = get_tree_details(tree) timer.intermediate('calculate') return cids, tree, depth, parents
def get_tree_pieces(cls, link, timer): tree = cls._load_tree(link) timer.intermediate('load') cids, depth, parents = get_tree_details(tree) num_children = calc_num_children(tree) num_children = defaultdict(int, num_children) timer.intermediate('calculate') return cids, tree, depth, parents, num_children
def make_comment_tree(link): tree = {} def _add_comment(comment, parent): tree[comment.id] = [child.id for child in comment.children] for child in comment.children: _add_comment(child, parent=comment) tree[None] = [comment.id for comment in TREE] for comment in TREE: _add_comment(comment, parent=None) cids, depth, parents = get_tree_details(tree) num_children = calc_num_children(tree) num_children = defaultdict(int, num_children) return CommentTree(link, cids, tree, depth, parents, num_children)