Project

General

Profile

Actions

Bug #8624

closed

[FUSE] arv-mount `by_tag` directory only shows 100 tags and tags that exist are not accessible

Added by Joshua Randall about 8 years ago. Updated over 6 years ago.

Status:
Resolved
Priority:
Normal
Assigned To:
Category:
SDKs
Target version:
Story points:
0.5

Description

When I look in the `by_tag` directory under a keep mount, I only see 100 tags in the directory.

# arv-mount /tmp/keep
# ls /tmp/keep/by_tag | wc -l
100

However, I actually have 54225 tags:

# arv link list -f '[["head_kind","=","arvados#collection"],["link_class","=","tag"]]' -l 0
{
 "kind":"arvados#linkList",
 "etag":"",
 "self_link":"",
 "offset":0,
 "limit":0,
 "items":[],
 "items_available":54225
}

I could see how it might be reasonable to limit the number of tags shown (or even not to allow listing until they are accessed, as in the `by_id` directory).

However, that doesn't seem to be what is happening, as tags that exist are not accessible:

# ls /tmp/keep/by_tag/lanelet:17559_7#3
ls: cannot access /tmp/keep/by_tag/lanelet:17559_7#3: No such file or directory


Subtasks 1 (0 open1 closed)

Task #11891: Review 8624-fuse-tagsResolvedRadhika Chippada03/03/2016Actions
Actions #1

Updated by Joshua Randall about 8 years ago

No big mystery here - the API call to list the links does not specify a limit and does not check items_available, but seems to just assume the API server returned everything: https://github.com/curoverse/arvados/blob/master/services/fuse/arvados_fuse/fusedir.py#L671-L679

Actions #2

Updated by Joshua Randall about 8 years ago

I've confirmed that adding `limit=1000` to the API list query (fusedir.py:673) results in a `by_tag` directory with 1000 entries. So, one aspect to the solution to this would be to implement a loop that retrieves all available tags (although in my opinion it would be better to do that within the python SDK a la #8502 as it is common pattern that is needed often).

673c673
<                 select=['name'], distinct=True
---
>                 select=['name'], distinct=True, limit=1000

I also checked differences in memory usage with a limit of 100 vs 1000 (because it looks like TagsDirectory creates a TagDirectory object for each tag and I wasn't sure how expensive those are).

# arv-mount /tmp/keep_root
# cat /proc/$(ps auxwww |grep keep_root | grep -v grep | awk '{print $2}')/status | grep '^VmRSS'
VmRSS:     31604 kB
# ls /tmp/keep_root/by_tag | wc -l
100
# cat /proc/$(ps auxwww |grep keep_root | grep -v grep | awk '{print $2}')/status | grep '^VmRSS'
VmRSS:     35156 kB
# umount /tmp/keep_root
# # change to limit=1000
# arv-mount /tmp/keep_root
# cat /proc/$(ps auxwww |grep keep_root | grep -v grep | awk '{print $2}')/status | grep '^VmRSS'
VmRSS:     31592 kB
# ls /tmp/keep_root/by_tag | wc -l
1000
# cat /proc/$(ps auxwww |grep keep_root | grep -v grep | awk '{print $2}')/status | grep '^VmRSS'
VmRSS:     36984 kB

100 tag limit
35156 - 31604 kB = 3552 kB

1000 tag limit
36984 - 31592 kB = 5392 kB

Expected memory cost for each additional tag: (5392 - 3552 kB) / (1000-100) tags = 2.04 kB/tag

Given this, it seems reasonable to retain the current behavior of pre-populating TagDirectory objects unless there are more than in the vicinity of 100000-10000000 tags (at the 1m tag mark, the expected memory usage for arv-mount would be ~2GB, which seems excessive for a client that isn't likely to actually need 99.999% of those objects). I'm not understandingwhy the TagDirectory object is not simply created if and when a request is made for it. I think the only useful piece of state that it has is `self.tag` which is the name of the tag to use in the API query to get the associated collections. Since that is equal to the `name` that would be passed to the `lookup` function prior to access, I do not see any point in prepopulating those objects - it would be just as fast to have a general TagDirectory object that (like MagicDirectory) waits for the `lookup` call to do the actual API server query and prepare a list of associated CollectionDirectory objects (which also don't seem like they need to be prepopulated).

Actions #3

Updated by Joshua Randall about 8 years ago

I would also note that it appears that the list of collections that a tag is associated with is also subject to the same issue regarding only doing a single API list query and thus it would also only show the first 100 collections associated with a particular tag.

Actions #4

Updated by Joshua Randall about 8 years ago

  • Assigned To set to Joshua Randall

I've implemented the basic fix for this (retrieving items across many batches using a generator function).

However, it makes the first `ls` of the `by_tag` directory rather slow - it is now taking ~50s to list the 31749 distinct tag names on the first access, then ~1s on a subsequent access. Unfortunately, because of the poll_time=60 default, those results only stay cached for 60s after which the next query goes back to taking a long time.

# arv-mount /tmp/keep_root
# time ls /tmp/keep_root/by_tag | wc -l
31749

real    0m48.103s
user    0m0.292s
sys     0m0.015s
# sleep 30 && time ls /tmp/keep_root/by_tag | wc -l
31749

real    0m0.735s
user    0m0.304s
sys     0m0.011s
# sleep 30 && time ls /tmp/keep_root/by_tag | wc -l
31749

real    0m47.858s
user    0m0.324s
sys     0m0.018s

This wouldn't matter too much if I could just skip the `ls` and go straight to a tag subdirectory, but unfortunately the implementation makes that just as slow:

# arv-mount /tmp/keep_root
# time ls /tmp/keep_root/by_tag/lanelet\:16261_1#1
z8ta6-4zz18-st4iwlg1njdspnz

real    0m47.876s
user    0m0.000s
sys     0m0.002s

There is no good reason why an attempt to access a particular subdirectory should require first obtaining a full listing of the parent directory.

Also, FWIW, I'm starting to think that there is a fundamental problem with the API server limiting the items returned to a number as "low" as 1000. In this particular query, the payload size of all 31749 entries would be ~750kB, whereas some other individual items the API server returns (such as collections with large manifests) can be 20 times that size. Why make me do 32 queries (taking 1-2s each) to get my 750kB while allowing a single query to return 20x more data?

Now that the API server has some logic to return a sensible amount of data (rather than number of entries), perhaps the upper limit on batch size should be raised significantly (perhaps to 1m)?

Actions #5

Updated by Joshua Randall about 8 years ago

IMHO clients shouldn't really be using polling to check if there is new data - ideally some mechanism (such as etag) would allow a client to ask the API server if the resource it is accessing has changed without having to actually perform a query at all.

Actions #6

Updated by Tom Morris about 7 years ago

  • Subject changed from arv-mount `by_tag` directory only shows 100 tags and tags that exist are not accessible to [FUSE] arv-mount `by_tag` directory only shows 100 tags and tags that exist are not accessible
  • Assigned To changed from Joshua Randall to Peter Amstutz
  • Target version set to Arvados Future Sprints

Assigning to Peter for triage/grooming

Actions #7

Updated by Tom Morris almost 7 years ago

  • Assigned To deleted (Peter Amstutz)
Actions #8

Updated by Tom Morris almost 7 years ago

  • Target version changed from Arvados Future Sprints to 2017-07-05 sprint
Actions #9

Updated by Peter Amstutz almost 7 years ago

  • Assigned To set to Peter Amstutz
Actions #10

Updated by Peter Amstutz almost 7 years ago

Hey Josh, what do you think about making the tags directory "magic" similarly to the by_id directory, so the directory is only instantiated when you attempt to access it? This would remove the ability to use "ls" to list tags, but it sounds like that wouldn't be a problem for your use case. Or maybe we should fix the "tags" directory to have a full listing, but add an alternate "magic_tags" directory?

Actions #11

Updated by Peter Amstutz over 6 years ago

New behavior for by_tag/ dir. Allow 'cd' into any tag directory that exists on the server, even if it isn't returned in the listing. Also increase listing limit.

Actions #12

Updated by Radhika Chippada over 6 years ago

I am having difficulty running fuse tests in my development env. So, assuming tests are passing to you, LGTM

Actions #13

Updated by Peter Amstutz over 6 years ago

  • Status changed from New to In Progress
  • Story points set to 0.5
Actions #14

Updated by Peter Amstutz over 6 years ago

  • Target version changed from 2017-07-05 sprint to 2017-07-19 sprint
Actions #15

Updated by Peter Amstutz over 6 years ago

  • Status changed from In Progress to Resolved

Applied in changeset arvados|commit:fcf3ca5baf89bdd944e3a7dcdc1b65f8ff4945ca.

Actions #16

Updated by Radhika Chippada over 6 years ago

  • Target version changed from 2017-07-19 sprint to 2017-07-05 sprint
Actions

Also available in: Atom PDF