From Fedora Project Wiki
(Announcing the Change proposal)
No edit summary
Line 14: Line 14:
[[Category:ChangeAnnounced]]
[[Category:ChangeAnnounced]]


# Changes to <code>rpm</code>: in a fork of the main repo. No PR yet.
# Changes to <code>rpm</code>: published in https://github.com/rpm-software-management/rpm/pull/1470
# Changes to <code>librepo</code>: in a fork of the main repo. No PR yet.
# Changes to <code>librepo</code>: published in https://github.com/rpm-software-management/librepo/pull/222
# New package dnf-plugin-cow:
# New package dnf-plugin-cow:
## Code is written
## Code is written
Line 128: Line 128:
# A copy-on-write filesystem; this Change is primarily targeting btrfs, but RPM with CoW should work with XFS as well (untested)
# A copy-on-write filesystem; this Change is primarily targeting btrfs, but RPM with CoW should work with XFS as well (untested)
# Most package install paths and the dnf package cache on the same filesystem / subvolume.
# Most package install paths and the dnf package cache on the same filesystem / subvolume.
# <code>rpm</code> with Copy on Write patch set: https://github.com/malmond77/rpm/tree/cow
# <code>rpm</code> with Copy on Write patch set: https://github.com/rpm-software-management/rpm/pull/1470
# <code>librepo</code> with transcoding support: https://github.com/malmond77/librepo/tree/transcode_cow
# <code>librepo</code> with transcoding support: https://github.com/rpm-software-management/librepo/pull/222
# dnf-plugin-reflink (a new package): https://github.com/facebookincubator/dnf-plugin-cow/
# dnf-plugin-reflink (a new package): https://github.com/facebookincubator/dnf-plugin-cow/



Revision as of 17:20, 30 December 2020

DNF/RPM Copy on Write enablement for all variants

Summary

RPM Copy on Write provides a better experience for Fedora Users as it reduces the amount of I/O and offsets CPU cost of package decompression. RPM Copy on Write uses reflinking capabilities in btrfs, which is the default filesystem in Fedora 33.

Owners

Current status

  1. Changes to rpm: published in https://github.com/rpm-software-management/rpm/pull/1470
  2. Changes to librepo: published in https://github.com/rpm-software-management/librepo/pull/222
  3. New package dnf-plugin-cow:
    1. Code is written
    2. Github repo needs to be published
    3. Plugin needs to be packaged in Fedora
  • Targeted release: Fedora 34
  • Last updated: 2020-12-30
  • FESCo issue: <will be assigned by the Wrangler>
  • Tracker bug: <will be assigned by the Wrangler>
  • Release notes tracker: <will be assigned by the Wrangler>

Detailed description

Installing and upgrading software packages is a standard part of managing the lifecycle of any operating system. For the entire lifecycle of Fedora, all software is packaged and distributed using the RPM file fomat. This proposal changes how software is downloaded and installed, leaving the distribution process unmodified.

Current process

  1. Resolve packaging request into a list of packages and operations
  2. Download and verify new packages
  3. Install and/or upgrade packages sequentially using RPM files, decompressing, and writing a copy of the new files to storage.

New process

  1. Resolve packaging request into a list of packages and operations
  2. Download and decompress packages into a locally optimized rpm file
  3. Install and/or upgrade packages sequentially using RPM files, using reference linking (reflinking) to reuse data already on disk.

The outcome is intended to be the same, but the order of operations is different.

  1. Decompression happens inline with download. This has a positive effect on resource usage: downloads are typically limited by bandwidth. Decompression and writing the full data into a single file per rpm is essentially free. Additionally: if there is more than one download at a time, a multi-CPU system can be better utilized. All compression types supported in RPM work because this uses the rpm I/O functions.
  2. RPMs are cached on local storage between downloading and installation time as normal. This allows DNF to defer actual RPM installation to when all the RPM are available. This is unchanged.
  3. The file format for RPMs is different with Copy on Write. The headers are identical, but the payload is different. There is also a footer.
    1. Files are converted (“transcoded”) locally during download using /usr/bin/rpm2extents (part of rpm codebase). The format is not intended to be “portable” - i.e. copying the files from the cache is not supported.
    2. Regular RPMs use a compressed .cpio based payload. In contrast, extent based RPMs contain uncompressed data aligned to the fundamental page size of the architecture, e.g. 4KiB on x86_64. This alignment is required for FICLONERANGE to work. Only files are represented in the payload, other directory entries like symlinks, device nodes etc are constructed entirely from rpm header information. Files are referenced by their digest, so identical files are de-duplicated.
    3. The footer currently has three sections
      1. Table of original (rpm) file digests, used to validate the integrity of the download in dnf.
      2. Table of digest → offset used when actually installing files.
      3. Signature 8 bytes at the end of the file, used to differentiate between traditional RPMs and extent based.

Notes

  1. The headers are preserved bit for bit during transcoding. This preserves signatures. The signatures cover the main header blob, and the main header blob ensures the integrity of data in two ways:
    1. Each file with content has a digest. Originally this was md5, but today it’s usually sha256. In normal RPM this is only used to verify the integrity of files, e.g. rpm -V. With CoW we use this as a content key.
    2. There is/are one or two digests (PAYLOADDIGEST and PAYLOADDIGESTALT) covering the payload archive (compressed cpio). The header value is preserved, but transcoded RPMs do not preserve the original structure so RPM’s pre-installation verification (controlled by %_pkgverify_level will fail. dnf-plugin-cow disables this check in dnf because it verifies the whole file digest which is captured during download/transcoding. The second one is likely used for delta rpm.
  2. This is untested, and possibly incompatible with delta RPM (drpm). The process for reconstructing an rpm to install from a delta is expensive from both a CPU and I/O perspective, while only providing marginal benefits on download size. It is expected that having delta rpm enabled (which is the default) will be handled gracefully.
  3. Disk space requirements are expected to be marginally higher than before: all new packages or updates will consume their installed size before installation instead of about half their size (regular rpms with payloads still cost space).
  4. rpm-plugin-reflink will fall back to simple file copying when the destination path is not on the same filesystem/subvolume. A common example is /boot and/or /boot/efi.
  5. The system will still work on other filesystem types, but will always fall back to simple copying. This is expected to be slightly slower than not enabling CoW because the source for copying will be the decompressed data.
  6. For systems that enable transparent filesystem compression: every file will continue to be decompressed from the original rpm, and then transparently re-compressed by the filesystem. There is no effective change here. There is a future project to investigate alternate distribution mechanics to provide parallel versions of file content pre-compressed in a filesystem specific format, reducing both CPU costs and I/O. It is expected that this will result in slightly higher network utilization because filesystem compression is purposely restricted to allow random I/O.
  7. Current implementation of dnf-plugin-cow is in Python, but it looks possible to implement this in libdnf instead which would make it work in packagekit.

Performance Metrics

Ballpark performance difference is about half the duration for file download+install time. A lot of rpms are very small, so it’s difficult to see/measure. Larger RPMs give much clearer signal.

(Actual numbers/charts will be supplied in Jan 2021)

Terminology

  • Copy on Write (CoW) is a broad description of any technology that reduces or eliminates data duplication by sharing the data behind the scenes until one of the references makes changes. This has been a cornerstone technology in memory management in Unix systems. Here we are using it to specifically reference Copy on Write as supported in modern filesystems, e.g. btrfs, xfs and potentially others.
  • Reflink is the verb for duplicating stored data on a filesystem. See ioctl_ficlonerange(2) for the specific call we use on Linux
  • Extent (based RPMs) refers to how payload file data is stored in within an RPM. Normal RPMs simply contain a compressed CPIO archive. Extent based RPMs contain the raw data uncompressed, which can be referenced with reflink.

Feedback

(pending initial discussion)

Benefit to Fedora

Faster package installs and upgrades

Scope

  • Proposal owners:
    • Merge changes to rpm, librepo to enable capabilities
    • Add dnf-plugin-cow to available packages
    • Test days
    • Aid with documentation
  • Other developers:
    • rpm, librepo: review PRs as needed
  • Release engineering: https://pagure.io/releng/issue/9914
  • Policies and guidelines: N/A
  • Trademark approval: N/A

Upgrade/compatibility impact

None, RPM with CoW is not enabled by default.

Upgrades with keepcache in dnf.conf will be able to use existing packages, but it will not convert them. This only happens at download time.

If a system is configured to keep packages in the cache (keepcache in dnf.conf) and dnf-plugin-cow is removed then the packages will be unusable. Recommend dnf clean packages to resolve this.

How to test

Enable RPM with CoW with

$ sudo dnf install dnf-plugin-cow
...
$ sudo dnf install hello
...
$ hello
Hello, world!

There should be no end user visible changes, except timing.

User experience

No anticipated user visible changes in this change proposal. This makes the feature available, but does not enable it by default.

Dependencies

  1. A copy-on-write filesystem; this Change is primarily targeting btrfs, but RPM with CoW should work with XFS as well (untested)
  2. Most package install paths and the dnf package cache on the same filesystem / subvolume.
  3. rpm with Copy on Write patch set: https://github.com/rpm-software-management/rpm/pull/1470
  4. librepo with transcoding support: https://github.com/rpm-software-management/librepo/pull/222
  5. dnf-plugin-reflink (a new package): https://github.com/facebookincubator/dnf-plugin-cow/

Contingency plan

  • Contingency mechanism: will not include PR patches if not merged upstream, skip dnf-plugin-cow
  • Contingency deadline: Final freeze
  • Blocks release? No
  • Blocks product? No

Documentation

Documentation will be available at https://github.com/facebookincubator/dnf-plugin-cow in the coming weeks

Release Notes

RPM with CoW is not enabled by default. To enable it:

$ sudo dnf install dnf-plugin-cow