Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review of the fuse mount chain of command #368

Merged
merged 6 commits into from
Jan 28, 2020
Merged

Conversation

fredbi
Copy link
Contributor

@fredbi fredbi commented Jan 23, 2020

Tracing

  • storage/gcs: added logging and debug traces

  • cmd(CLI): refactored logger injection, added more commands subject to log level setting

  • core: enabled fuse internal debug logger (experimental, since it is quite verbose)

  • cafs: injected logger

Tuning/user experimentation

  • cmd(CLI): added new options to tune fuse mount cache size and prefetch behavior (e.g. --cache-size 100MB, --prefetch 3)

  • core: bundle conveys new options down to cafs factory

Refactoring & readability

  • core: refactored NewXXXFS to suppress redundant staging path and logging (following initial idea from PR#354)

  • core: refactored RO mount for readability

  • cafs: more godoc, resolved question marks left in code

  • cafs: refactoring of struct factories, chunkReader and writer, more options to control LRU cache and prefetch behavior

  • cafs: refactored hasher ("helpers") for readability

Testing

  • cmd(CLI): re-enacted fuse CLI e2e testing (runs on CI)

  • cafs: added more unit tests on freelists, hasher and ReadAt with concurrency testing

Fixes

  • core: fixed spurious warnings on fs (extended attributes, flush on RO mount)

  • cafs: enabled evicted LRU buffers to be relinquished to freelist

  • cafs: fixed concurrency issues with corrupted relinquished buffers

  • cafs: fixed leaf hash verification for ReadAt

Performance improvements

  • cafs: set up cache for resolved leaf keys from root
  • cafs: more efficient prefetching, with much less waste of work and prefetching blobs with tunable look-ahead

Memory footprint reduction

  • core: relinquished unused RadixTree after ro fs construction

  • cafs: adapted freelist buffers to leaf size, not systematically max size

CI changes

  • cafs: cafs tests are memory hungry: run them in CI separately with different settings (less parallelism, no race)
  • hack/fuse_demo: adapted fuse mount detection, since we slightly changed the mount signature (see below)

Other enhancements

  • core: set fuse moumt subtype to "datamon" and "datamon-mutable", so it appears as such in the output of the "mount" UNIX command

Signed-off-by: Frederic BIDON [email protected]

@fredbi
Copy link
Contributor Author

fredbi commented Jan 23, 2020

Still working on the prefetch stuff. Also experimenting with some read chunking of a single leaf

**Tracing**
* storage/gcs: added logging and debug traces

* cmd(CLI): refactored logger injection, added more commands subject to log level setting

* core: enabled fuse internal debug logger (experimental, since it is quite verbose)

* cafs: injected logger

**Tuning/user experimentation**
* cmd(CLI): added new options to tune fuse mount cache size and prefetch behavior (e.g. --cache-size 100MB, --prefetch 3)

* core: bundle conveys new options down to cafs factory

**Refactoring & readability**
* core: refactored NewXXXFS to suppress redundant staging path and logging (following initial idea from PR#354)
* core: refactored RO mount for readability

* cafs: more godoc, resolved question marks left in code
* cafs: refactoring of struct factories, chunkReader and writer, more options to control LRU cache and prefetch behavior
* cafs: refactored hasher ("helpers") for readability

**Testing**
* cmd(CLI): re-enacted fuse CLI e2e testing (runs on CI)

* cafs: added more unit tests on freelists, hasher and ReadAt with concurrency testing

**Fixes**
* core: fixed spurious warnings on fs (extended attributes, flush on RO mount)

* cafs: enabled evicted LRU buffers to be relinquished to freelist
* cafs: fixed concurrency issues with corrupted relinquished buffers
* cafs: fixed leaf hash verification for ReadAt

**Performance improvements**
* cafs: set up cache for resolved leaf keys from root
* cafs: more efficient prefetching, with much less waste of work and prefetching blobs with tunable look-ahead

**Memory footprint reduction**
* core: relinquished unused RadixTree after ro fs construction

* cafs: adapted freelist buffers to leaf size, not systematically max size

**CI changes**
* cafs: cafs tests are memory hungry: run them in CI separately with different settings (less parallelism, no race)
* hack/fuse_demo: adapted fuse mount detection, since we slightly changed the mount signature (see below)

**Other enhancements**
* core: set fuse moumt subtype to "datamon" and "datamon-mutable", so it appears as such in the output of the "mount" UNIX command

Signed-off-by: Frederic BIDON <[email protected]>
Signed-off-by: Frederic BIDON <[email protected]>
@fredbi fredbi marked this pull request as ready for review January 24, 2020 18:20
r.fetchingLatch.Lock()
defer r.fetchingLatch.Unlock()

if _, beingFetched := r.fetching[index+1]; !beingFetched {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just have a hash map of the keys in flight, start a goroutine that waits for the key to be removed from the map and be present in the cache. If we implement a different prefetch scheme the logic will still hold true.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this, but came to recursive decision making about prefetching, reassessing the current situation every time the process requests a new leaf.

Indeed, this is a moving target: new keys to fetch ahead are discovered as the reading goes: every time a leaf is cached, I jump next, and assess the new next fetch-ahead list.

Moreover, the cache cannot guarantee to hold buffers fetched ahead: sometimes (a few as I could, and only when we have much more readers than available cache entries) the prefetch work is wasted (must more uncommon event than in the previous implementation, though) and the leaft must be read again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so basically, the doPrefetch is here to:
i) decide whether to prefetch or not
ii) manage the current list of leafs being prefetched
iii) use the buffer cache as the referee on whether to consider work done or declare it wasted

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow-up note: open discussion thread

Signed-off-by: Frederic BIDON <[email protected]>
.circleci/config.yml Outdated Show resolved Hide resolved
@ransomw1c
Copy link
Contributor

meta-review: where, as a project, do we stand on the "one idea per commit" practice advocated by some?

my first impression upon reading the description and noticing the size of the diff is that this could probably be separated out into a few merge requests?

i know this is extra effort on the person preparing the requests, and we've seen that needing to rebase several commits for merge all at once can lead to errors. yet i still suppose that the benefits to the project that would result from getting this landed as a sequence of commits in the history of master could result in both a clearer review now as well as a clearer record of the changes for later.

@kerneltime
Copy link
Contributor

I have to go over tests but the changes overall are in the right direction. Will continue to review.

cmd/datamon/cmd/flags.go Outdated Show resolved Hide resolved
@@ -78,10 +78,14 @@ func (a AuthMock) Principal(_ string) (model.Contributor, error) {
}, nil
}

func testContext() string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: cruft?

@ransomw1c
Copy link
Contributor

of the physical layout conventions so far, the name.go and name_options.go is my favorite. usually disinterested in physical layout.

@ransomw1c
Copy link
Contributor

ransomw1c commented Jan 25, 2020

i'm going to have to split this review up over a couple of days..

.. have given a reasonably diligent first read to everything except cafs and fuse changes, and i have read the cafs changes in part, leaving a few comments. the

cafs: more efficient prefetching, with much less waste of work and prefetching blobs with tunable look-ahead

in particular is something i get the gist of – namely,

cache leaf keys in memory corresponding to a given root key to avoid looking up leaf keys for the same root twice

and is a desirable addition – the desirable conceptual addition distinct from fixes and logging and so forth. i need to give it one more pass so that i'm clearer on all specifics.


the fuse changes are just logging and readability?

overall, quite pleased to see this patch appear.

@fredbi
Copy link
Contributor Author

fredbi commented Jan 25, 2020

the fuse changes are just logging and readability?

Mostly yes. There are some small changes, though:

  • relinquish to GC the RadixTree used for fs construction after fs initialization
  • explicitly set the ReadOnly: true as a fuse option
  • sign fuse mount as fuse.datamon or fuse.datamon-mutable so this appear in mount commands
  • stubbed Xattr methods to avoid spurious warnings when this feature is not going to be ever supported
  • stubbed Flush method on Read-Only mount to avoid (unblocking) meaningless errors reported
  • fixed wrong error reporting logic on on mutable mount on "...open file will retry this" warning
  • fixed logic of the isDir() func, which was in fact doing isNotDir

pipeErr, err := cmd.StderrPipe()
require.NoError(t, err)

// combine stdout & stderr, tee this output to os.Stdout and return pipe reader for output scanning
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we want to test if the output of a cli command is correctly being routed to STDOUT, we might want to keep the separation of what gets logged to which channel. Since operations such a list needs to be piped in shell to other unix tools, we have to add a test to make sure the output is to STD OUT.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok will remove the combined output

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kerneltime after some more inspection, it so happens that I am asserting on both output...
I am deferring the more accurate separate assertions on stderr and stdout as a TODO (see #374).
Deferred.

Copy link
Contributor

@ransomw1c ransomw1c left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm,

although i suggest waiting on approval from Ritesh before landing

@kerneltime
Copy link
Contributor

Will merge this in once tests pass.

@kerneltime kerneltime merged commit 5bb49f6 into master Jan 28, 2020
@kerneltime kerneltime deleted the review-ro-mount branch January 28, 2020 23:10
@fredbi fredbi mentioned this pull request Apr 2, 2020
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants