On 6/26/17 1:07 PM, Jeff Mahoney wrote:
> On 6/20/17 12:06 PM, Edmund Nadolski wrote:
>> It's been known for a while that the use of multiple lists
>> that are periodically merged was an algorithmic problem within
>> btrfs.  There are several workloads that don't complete in any
>> reasonable amount of time (e.g. btrfs/130) and others that cause
>> soft lockups.
>>
>> The solution is to use a pair of rbtrees that do insertion merging
>> for both indirect and direct refs, with the former converting
>> refs into the latter.  The result is a btrfs/130 workload that
>> used to take several hours now takes about half of that. This
>> runtime still isn't acceptable and a future patch will address that
>> by moving the rbtrees higher in the stack so the lookups can be
>> shared across multiple calls to find_parent_nodes.
>>
>> Signed-off-by: Edmund Nadolski <enadol...@suse.com>
>> Signed-off-by: Jeff Mahoney <je...@suse.com>
> [...]
> 
>> @@ -504,37 +665,22 @@ static int resolve_indirect_refs(struct btrfs_fs_info 
>> *fs_info,
>>      return ret;
>>  }
>>  
>> -static inline int ref_for_same_block(struct prelim_ref *ref1,
>> -                                 struct prelim_ref *ref2)
>> -{
>> -    if (ref1->level != ref2->level)
>> -            return 0;
>> -    if (ref1->root_id != ref2->root_id)
>> -            return 0;
>> -    if (ref1->key_for_search.type != ref2->key_for_search.type)
>> -            return 0;
>> -    if (ref1->key_for_search.objectid != ref2->key_for_search.objectid)
>> -            return 0;
>> -    if (ref1->key_for_search.offset != ref2->key_for_search.offset)
>> -            return 0;
>> -    if (ref1->parent != ref2->parent)
>> -            return 0;
>> -
>> -    return 1;
>> -}
>> -
>>  /*
>>   * read tree blocks and add keys where required.
>>   */
>>  static int add_missing_keys(struct btrfs_fs_info *fs_info,
>> -                        struct list_head *head)
>> +                        struct preftrees *preftrees)
>>  {
>>      struct prelim_ref *ref;
>>      struct extent_buffer *eb;
>> +    struct rb_node *node = rb_first(&preftrees->indirect.root);
>> +
>> +    while (node) {
>> +            ref = rb_entry(node, struct prelim_ref, rbnode);
>> +            node = rb_next(&ref->rbnode);
>> +            if (WARN(ref->parent, "BUG: direct ref found in indirect tree"))
>> +                    return -EINVAL;
>>  
>> -    list_for_each_entry(ref, head, list) {
>> -            if (ref->parent)
>> -                    continue;
>>              if (ref->key_for_search.type)
>>                      continue;
>>              BUG_ON(!ref->wanted_disk_byte);
> 
> Hi Ed -
> 
> I missed this in earlier review, but this can't work.  We're modifying
> the ref in a way that the comparator will care about -- so the node
> would move in the tree.
> 
> It's not a fatal flaw and, in fact, leaves us an opening to fix a
> separate locking issue.

Ed and I discussed this offline.  It turns out that this is a code bug
but not a functional bug.  Once we hit add_missing_keys, we don't do any
more inserts or searches.  We only iterate over every node and remove
each as we go, so the tree order doesn't matter.  I'll post a fix shortly.

-Jeff

-- 
Jeff Mahoney
SUSE Labs

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to