{"thread":{"id":"47442","subject":"[PATCH v2] Partial clone design document","startedAt":"2017-12-14T15:24:31Z","lastAt":"2017-12-14T21:02:44Z","messageCount":5,"participants":["Jeff Hostetler","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"334807","messageId":"20171214152404.35708-1-git@jeffhostetler.com","threadId":"47442","inReplyTo":null,"subject":"[PATCH v2] Partial clone design document","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-12-14T15:24:03Z","receivedAt":"2017-12-14T15:24:31Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"From: Jeff Hostetler <jeffhost@microsoft.com>\n\nThis patch contains V2 of the partial clone design document.\nIt incorporates suggestions from the mailing list on V1 and\nelaborates on a few topics.\n\nJeff Hostetler (1):\n  partial-clone: design doc\n\n Documentation/technical/partial-clone.txt | 259 ++++++++++++++++++++++++++++++\n 1 file changed, 259 insertions(+)\n create mode 100644 Documentation/technical/partial-clone.txt\n\n-- \n2.9.3\n\n"},{"id":"334808","messageId":"20171214152404.35708-2-git@jeffhostetler.com","threadId":"47442","inReplyTo":"20171214152404.35708-1-git@jeffhostetler.com","subject":"[PATCH v2] partial-clone: design doc","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-12-14T15:24:04Z","receivedAt":"2017-12-14T15:26:36Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"From: Jeff Hostetler <jeffhost@microsoft.com>\n\nFirst draft of design document for partial clone feature.\n\nSigned-off-by: Jeff Hostetler <jeffhost@microsoft.com>\n---\n Documentation/technical/partial-clone.txt | 259 ++++++++++++++++++++++++++++++\n 1 file changed, 259 insertions(+)\n create mode 100644 Documentation/technical/partial-clone.txt\n\ndiff --git a/Documentation/technical/partial-clone.txt b/Documentation/technical/partial-clone.txt\nnew file mode 100644\nindex 0000000..731bd8c\n--- /dev/null\n+++ b/Documentation/technical/partial-clone.txt\n@@ -0,0 +1,259 @@\n+Partial Clone Design Notes\n+==========================\n+\n+The \"Partial Clone\" feature is a performance optimization for git that\n+allows git to function without having a complete copy of the repository.\n+\n+During clone and fetch operations, git normally downloads the complete\n+contents and history of the repository.  That is, during clone the client\n+receives all of the commits, trees, and blobs in the repository into a\n+local ODB.  Subsequent fetches extend the local ODB with any new objects.\n+For large repositories, this can take significant time to download and\n+large amounts of diskspace to store.\n+\n+The goal of this work is to allow git better handle extremely large\n+repositories.  Often in these repositories there are many files that the\n+user does not need such as ancient versions of source files, files in\n+portions of the worktree outside of the user's work area, or large binary\n+assets.  If we can avoid downloading such unneeded objects *in advance*\n+during clone and fetch operations, we can decrease download times and\n+reduce ODB disk usage.\n+\n+\n+Non-Goals\n+---------\n+\n+Partial clone is a mechanism to limit the number of blobs and trees downloaded\n+*within* a given range of commits -- and is therefore independent of and not\n+intended to conflict with existing DAG-level mechanisms to limit the set of\n+requested commits (i.e. shallow clone, single branch, or fetch '<refspec>').\n+\n+\n+Design Overview\n+---------------\n+\n+Partial clone logically consists of the following parts:\n+\n+- A mechanism for the client to describe unneeded or unwanted objects to\n+  the server.\n+\n+- A mechanism for the server to omit such unwanted objects from packfiles\n+  sent to the client.\n+\n+- A mechanism for the client to gracefully handle missing objects (that\n+  were previously omitted by the server).\n+\n+- A mechanism for the client to backfill missing objects as needed.\n+\n+\n+Design Details\n+--------------\n+\n+- A new pack-protocol capability \"filter\" is added to the fetch-pack and\n+  upload-pack negotiation.\n+\n+  This uses the existing capability discovery mechanism.\n+  See \"filter\" in Documentation/technical/pack-protocol.txt.\n+\n+- Clients pass a \"filter-spec\" to clone and fetch which is passed to the\n+  server to request filtering during packfile construction.\n+\n+  There are various filters available to accomodate different situations.\n+  See \"--filter=<filter-spec>\" in Documentation/rev-list-options.txt.\n+\n+- On the server pack-objects applies the requested filter-spec as it\n+  creates \"filtered\" packfiles for the client.\n+\n+  These filtered packfiles are incomplete in the traditional sense because\n+  they may contain trees that reference blobs that the client does not have.\n+\n+- On the client these incomplete packfiles are marked as \"promisor pacfiles\"\n+  and treated differently by various commands.\n+\n+- On the client a repository extension is added to the local config to\n+  prevent older versions of git from failing mid-operation because of\n+  missing objects that they cannot handle.\n+  See \"extensions.partialClone\" in Documentation/technical/repository-version.txt\"\n+\n+\n+Handling Missing Objects\n+------------------------\n+\n+- An object may be missing due to a partial clone or fetch, or missing due\n+  to repository corruption.  To differentiate these cases, the local\n+  repository specially indicates packfiles obtained from the promisor\n+  remote.\n+\n+  These \"promisor packfiles\" consist of a \"<name>.promisor\" file with\n+  arbitrary contents (like the \"<name>.keep\" files), in addition to\n+  their \"<name>.pack\" and \"<name>.idx\" files.\n+\n+  In the future, this ability may be extended to loose objects in case\n+  a promisor packfile is accidentally unpacked.\n+\n+- The local repository considers a \"promisor object\" to be an object that\n+  it knows (to the best of its ability) that the promisor remote has, either\n+  because the local repository has that object in one of its promisor\n+  packfiles, or because another promisor object refers to it.\n+\n+  When git encounters a missing object, Git can see if it a promisor object\n+  and handle it appropriately.  If not, Git can report a corruption.\n+\n+  This means that there is no need for the client to explicitly maintain an\n+  expensive-to-modify list of missing objects.\n+\n+- Since almost all Git code currently expects any referenced object to be\n+  present locally and because we do not want to force every command to do\n+  a dry-run first, a fallback mechanism is added to allow Git to attempt\n+  to dynamically fetch missing objects from the promisor remote.\n+\n+  When the normal object lookup fails to find an object, Git invokes\n+  fetch-object to try to get the object from the server and then retry\n+  the object lookup.  This allows objects to be \"faulted in\" without\n+  complicated prediction algorithms.\n+\n+  For efficiency reasons, no check as to whether the missing object is\n+  actually a promisor object is performed.\n+\n+  Dynamic object fetching tends to be slow as objects are fetched one at\n+  a time.\n+\n+- checkout (and any other command using unpack-trees) has been taught to\n+  bulk pre-fetch all required missing blobs in a single batch.\n+\n+- rev-list has been taught to print missing objects.\n+\n+  This can be used by other commands to bulk prefetch objects.\n+  For example, a \"git log -p A..B\" may internally want to first do\n+  something like \"git rev-list --objects --quiet --missing=print A..B\"\n+  and prefetch those objects in bulk.\n+\n+- fsck has been updated to be fully aware of promisor objects.\n+\n+- repack in GC has been updated to not touch promisor packfiles at all,\n+  and to only repack other objects.\n+\n+- The global variable fetch_if_missing is used to control whether an\n+  object lookup will attempt to dynamically fetch a missing object or\n+  report an error.\n+\n+  We are not happy with this global variable and would like to remove it,\n+  but that requires significant refactoring of the object code to pass an\n+  additional flag.  We hope that concurrent efforts to add an ODB API can\n+  encompass this.\n+\n+\n+Fetching Missing Objects\n+------------------------\n+\n+Fetching of objects is done using the existing transport mechanism using\n+transport_fetch_refs(), setting a new transport option\n+TRANS_OPT_NO_DEPENDENTS to indicate that only the objects themselves are\n+desired, not any object that they refer to.  Because some transports\n+invoke fetch_pack() in the same process, fetch_pack() has been updated\n+to not use any object flags when the corresponding argument\n+(no_dependents) is set.\n+\n+The local repository sends a request with the hashes of all requested\n+objects as \"want\" lines, and does not perform any packfile negotiation.\n+It then receives a packfile.\n+\n+Because we are reusing the existing fetch-pack mechanism, fetching\n+currently fetches all objects referred to by the requested objects, even\n+though they are not necessary.\n+\n+\n+Current Limitations\n+-------------------\n+\n+- The remote used for a partial clone (or the first partial fetch\n+  following a regular clone) is marked as the \"promisor remote\".\n+\n+  We are currently limited to a single promisor remote and only that\n+  remote may be used for subsequent partial fetches.\n+\n+- Dynamic object fetching will only ask the promisor remote for missing\n+  objects.  We assume that the promisor remote has a complete view of the\n+  repository and can satisfy all such requests.\n+\n+  Future work may lift this restriction when we figure out how to route\n+  such requests.  The current assumption is that partial clone will not be\n+  used for triangular workflows that would need that (at least initially).\n+\n+- Repack essentially treats promisor and non-promisor packfiles as 2\n+  distinct partitions and does not mix them.  Repack currently only works\n+  on non-promisor packfiles and loose objects.\n+\n+  Future work may let repack work to repack promisor packfiles (while\n+  keeping them in a different partition from the others).\n+\n+- The current object filtering mechanism does not make use of packfile\n+  bitmaps (when present).\n+\n+  We should allow this for filters that are not pathname-based.\n+\n+- Currently, dynamic object fetching invokes fetch-pack for each item\n+  because most algorithms stumble upon a missing object and need to have\n+  it resolved before continuing their work.  This may incur significant\n+  overhead -- and multiple authentication requests -- if many objects are\n+  needed.\n+\n+  We need to investigate use of a long-running process, such as proposed\n+  in [5,6] to reduce process startup and overhead costs.\n+\n+  It would be nice if pack protocol V2 could allow that long-running\n+  process to make a series of requests over a single long-running\n+  connection.\n+\n+- Dynamic object fetching currently uses the existing pack protocol V0\n+  which means that each object is requested via fetch-pack.  The server\n+  will send a full set of info/refs when the connection is established.\n+  If there are large number of refs, this may incur significant overhead.\n+\n+  We expect that protocol V2 will allow us to avoid this cost.\n+\n+\n+Non-Tasks\n+---------\n+\n+- Every time the subject of \"demand loading blobs\" comes up it seems\n+  that someone suggests that the server be allowed to \"guess\" and send\n+  additional objects that may be related to the requested objects.\n+\n+  No work has gone into actually doing that; we're just documenting that\n+  it is a common suggestion.  We're not sure how it would work and have\n+  no plans to work on it.\n+\n+  It is valid for the server to send more objects than requested (even\n+  for a dynamic object fetch), but we are not building on that.\n+\n+\n+Related Links\n+-------------\n+[0] https://bugs.chromium.org/p/git/issues/detail?id=2\n+    Chromium work item for: Partial Clone \n+\n+[1] https://public-inbox.org/git/20170113155253.1644-1-benpeart@microsoft.com/\n+    Subject: [RFC] Add support for downloading blobs on demand\n+    Date: Fri, 13 Jan 2017 10:52:53 -0500\n+\n+[2] https://public-inbox.org/git/cover.1506714999.git.jonathantanmy@google.com/\n+    Subject: [PATCH 00/18] Partial clone (from clone to lazy fetch in 18 patches)\n+    Date: Fri, 29 Sep 2017 13:11:36 -0700\n+\n+[3] https://public-inbox.org/git/20170426221346.25337-1-jonathantanmy@google.com/\n+    Subject: Proposal for missing blob support in Git repos\n+    Date: Wed, 26 Apr 2017 15:13:46 -0700\n+\n+[4] https://public-inbox.org/git/1488999039-37631-1-git-send-email-git@jeffhostetler.com/\n+    Subject: [PATCH 00/10] RFC Partial Clone and Fetch\n+    Date: Wed,  8 Mar 2017 18:50:29 +0000\n+\n+\n+[5] https://public-inbox.org/git/20170505152802.6724-1-benpeart@microsoft.com/\n+    Subject: [PATCH v7 00/10] refactor the filter process code into a reusable module\n+    Date: Fri,  5 May 2017 11:27:52 -0400\n+\n+[6] https://public-inbox.org/git/20170714132651.170708-1-benpeart@microsoft.com/\n+    Subject: [RFC/PATCH v2 0/1] Add support for downloading blobs on demand\n+    Date: Fri, 14 Jul 2017 09:26:50 -0400\n-- \n2.9.3\n\n"},{"id":"334819","messageId":"xmqq1sjxuq0a.fsf@gitster.mtv.corp.google.com","threadId":"47442","inReplyTo":"20171214152404.35708-2-git@jeffhostetler.com","subject":"Re: [PATCH v2] partial-clone: design doc","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-12-14T18:24:21Z","receivedAt":"2017-12-14T18:24:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff Hostetler <git@jeffhostetler.com> writes:\n\n> +- On the client these incomplete packfiles are marked as \"promisor pacfiles\"\n\ns/pacfiles/packfiles/\n\n> +  These \"promisor packfiles\" consist of a \"<name>.promisor\" file with\n> +  arbitrary contents (like the \"<name>.keep\" files), in addition to\n> +  their \"<name>.pack\" and \"<name>.idx\" files.\n> +\n> +  In the future, this ability may be extended to loose objects in case\n> +  a promisor packfile is accidentally unpacked.\n\nHmph.\n\nBecause we cannot assume that such an \"accidental\" unpacking would\ndo anything extra to help us tell the loose objects created out of a\npromisor pack from other loose objects, you would end up making any\nand all loose objects to serve as if they came from a promisor\nremote?  I am not sure if that makes much sense.\n\nDo we really need to write this \"in the future\" down, before we have\nthought things through enough to specify the design at a bit more\ndetailed level?\n"},{"id":"334820","messageId":"xmqqwp1ptbaw.fsf@gitster.mtv.corp.google.com","threadId":"47442","inReplyTo":"20171214152404.35708-2-git@jeffhostetler.com","subject":"Re: [PATCH v2] partial-clone: design doc","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-12-14T18:27:19Z","receivedAt":"2017-12-14T18:27:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff Hostetler <git@jeffhostetler.com> writes:\n\n> +  There are various filters available to accomodate different situations.\n\ns/accomodate/accommodate/\n\nI'll squash in this and /pacfile/packfile/ typofix while queuing.\n\nThanks.\n"},{"id":"334832","messageId":"c5d24342-e459-2a5b-6e53-69cddd948140@jeffhostetler.com","threadId":"47442","inReplyTo":"xmqq1sjxuq0a.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2] partial-clone: design doc","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-12-14T21:02:38Z","receivedAt":"2017-12-14T21:02:44Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"\n\nOn 12/14/2017 1:24 PM, Junio C Hamano wrote:\n> Jeff Hostetler <git@jeffhostetler.com> writes:\n> \n>> +- On the client these incomplete packfiles are marked as \"promisor pacfiles\"\n> \n> s/pacfiles/packfiles/\n> \n>> +  These \"promisor packfiles\" consist of a \"<name>.promisor\" file with\n>> +  arbitrary contents (like the \"<name>.keep\" files), in addition to\n>> +  their \"<name>.pack\" and \"<name>.idx\" files.\n>> +\n>> +  In the future, this ability may be extended to loose objects in case\n>> +  a promisor packfile is accidentally unpacked.\n> \n> Hmph.\n> \n> Because we cannot assume that such an \"accidental\" unpacking would\n> do anything extra to help us tell the loose objects created out of a\n> promisor pack from other loose objects, you would end up making any\n> and all loose objects to serve as if they came from a promisor\n> remote?  I am not sure if that makes much sense.\n> \n> Do we really need to write this \"in the future\" down, before we have\n> thought things through enough to specify the design at a bit more\n> detailed level?\n> \n\ngood point.  i'll move this to the bottom and elaborate on the\nproblem rather than the solution.\n\nJeff\n"}]}