ostree repo commit: Speed up composing trees with --tree=ref

Running `ostree commit --tree=ref=a --tree=dir=b` involves reading the
whole of a into an `OstreeMutableTree` before composing `b` on top.  This
is inefficient if a is a complete rootfs and b is just touching one file.
We process O(size of a + size of b) directories rather than
O(number of touched dirs).

This commit makes `ostree commit` more efficient at composing multiple
directories together.  With `ostree_mutable_tree_fill_empty_from_dirtree`
we create a lazy `OstreeMutableTree` which only reads the underlying
information from disk when needed.  We don't need to read all the
subdirectories just to get the checksum of a tree already checked into the
repo.

This provides great speedups when composing a rootfs out of multiple other
rootfs as we do in our build system.  We compose multiple containers
together with:

    ostree commit --tree=ref=base-rootfs --tree=ref=container1 --tree=ref=container2

and it is much faster now.

As a test I ran

    time ostree --repo=... commit --orphan --tree=ref=big-rootfs --tree=dir=modified_etc

Where modified_etc contained a modified sudoers file under /etc.  I used
`strace` to count syscalls and I seperatly took timing measurements.  To
test with a cold cache I ran

    sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

Results:

|                      | Before | After |
| -------------------- | ------ | ----- |
| Time (cold cache)    |   8.1s | 0.12s |
| Time (warm cache)    |   3.7s | 0.08s |
| `openat` calls       |  53589 |   246 |
| `fgetxattr` calls    |  78916 |     0 |

I'm not sure if this will have some negative interaction with the
`_ostree_repo_commit_modifier_apply` which is short-circuited here.  I
think it was disabled for `--tree=ref=` anyway, but I'm not certain.  All
the tests pass anyway.

I originally implemented this in terms of the `OstreeRepoFile` APIs, but
it was *way* less efficient, opening and reading many files unnecessarily.

Closes: #1643
Approved by: cgwalters
This commit is contained in:
William Manley authored and Atomic Bot committed 2018-07-09 13:10:51 +00:00
1 parent 11eb0bd227
commit c7b12a8730
5 files changed
+267 -4

No files matched your search

+11
View File
@@ -3602,6 +3602,14 @@ write_directory_to_mtree_internal (OstreeRepo *self,
if (!ostree_repo_file_ensure_resolved (repo_dir, error))
return FALSE;
/* ostree_mutable_tree_fill_from_dirtree returns FALSE if mtree isn't
* empty: in which case we're responsible for merging the trees. */
if (ostree_mutable_tree_fill_empty_from_dirtree (mtree,
ostree_repo_file_get_repo (repo_dir),
ostree_repo_file_tree_get_contents_checksum (repo_dir),
ostree_repo_file_get_checksum (repo_dir)))
return TRUE;
ostree_mutable_tree_set_metadata_checksum (mtree, ostree_repo_file_tree_get_metadata_checksum (repo_dir));
filter_result = OSTREE_REPO_COMMIT_FILTER_ALLOW;
@@ -3915,6 +3923,9 @@ ostree_repo_write_mtree (OstreeRepo *self,
const char *contents_checksum, *metadata_checksum;
g_autoptr(GFile) ret_file = NULL;
if (!ostree_mutable_tree_check_error (mtree, error))
return glnx_prefix_error (error, "mtree");
metadata_checksum = ostree_mutable_tree_get_metadata_checksum (mtree);
if (!metadata_checksum)
return glnx_throw (error, "Can't commit an empty tree");