git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 00/26] Sparse Index: API protections

From
Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>
Date
Apr 12, 2021, 21:07 UTC
Message-ID
<pull.906.v3.git.1618261697.gitgitgadget@gmail.com>
In-Reply-To
<pull.906.v2.git.1617241802.gitgitgadget@gmail.com>

Here is the second patch series submission coming out of the sparse-index RFC [1].

[1] https://lore.kernel.org/git/pull.847.git.1611596533.gitgitgadget@gmail.com/

This is based on ds/sparse-index.

The point of this series is to insert protections for the consumers of the in-memory index to avoid unintended behavior change when using a sparse index versus a full one.

We mark certain regions of code as needing a full index, so we call ensure_full_index() to expand a sparse index to a full one, if necessary. These protections are inserted file-by-file in every loop over all cache entries. Well, "most" loops, because some are going to be handled in the very next series so I leave them out.

Many callers use index_name_pos() to find a path by name. In these cases, we can check if that position resolves to a sparse directory instance. In those cases, we just expand to a full index and run the search again.

The last few patches deal with the name-hash hashtable for doing O(1) lookups.

These protections don't do much right now, since the previous series created the_repository->settings.command_requires_full_index to guard all index reads and writes to ensure the in-memory copy is full for commands that have not been tested with the sparse index yet.

However, after this series is complete, we now have a straight-forward plan for making commands "sparse aware" one-by-one:

 1. Disable settings.command_requires_full_index to allow an in-memory
    sparse-index.
 2. Run versions of that command under a debugger, breaking on
    ensure_full_index().
 3. Examine the call stack to determine the context of that expansion, then
    implement the proper behavior in those locations.
 4. Add tests to ensure we are checking this logic in the presence of sparse
    directory entries.

I will admit that mostly it is the writing of the test cases that takes the most time in the conversions I've done so far.

Updates in v3 =============

 * I updated based on Elijah's feedback.
 * One new patch splits out a change that Elijah (rightfully) pointed out
   did not belong with the patch it was originally in.

I gave it time to see if any other comments came in, but it looks like review stabilized. I probably waited a bit longer than I should have.

Updates in v2 =============

 * Rebased onto v5 of ds/sparse-index
 * Updated the technical doc to describe how these protections are guards to
   keep behavior consistent between a sparse-index and a full index. Whether
   or not that behavior is "correct" can be interrogated later.
 * Calls to ensure_full_index() are marked with a TODO comment saying these
   calls should be audited later (with tests).
 * Fixed an incorrectly squashed commit message.
 * Dropped the diff-lib.c commit because it was erroneously included in v2.
 * Dropped the merge-ort.c commit because of conflicts with work in flight
   and a quick audit that it is not needed.
 * I reviewed the merge of this topic with mt/add-rm-in-sparse-checkout and
   found it equivalent to what I would have done.
Thanks, -Stolee
Derrick Stolee (26):
  sparse-index: API protection strategy
  *: remove 'const' qualifier for struct index_state
  read-cache: expand on query into sparse-directory entry
  cache: move ensure_full_index() to cache.h
  add: ensure full index
  checkout-index: ensure full index
  checkout: ensure full index
  commit: ensure full index
  difftool: ensure full index
  fsck: ensure full index
  grep: ensure full index
  ls-files: ensure full index
  merge-index: ensure full index
  rm: ensure full index
  stash: ensure full index
  update-index: ensure full index
  dir: ensure full index
  entry: ensure full index
  merge-recursive: ensure full index
  pathspec: ensure full index
  read-cache: ensure full index
  resolve-undo: ensure full index
  revision: ensure full index
  name-hash: don't add directories to name_hash
  sparse-index: expand_to_path()
  name-hash: use expand_to_path()
 Documentation/technical/sparse-index.txt | 37 +++++++++++-
 attr.c                                   | 14 ++---
 attr.h                                   |  4 +-
 builtin/add.c                            |  2 +
 builtin/checkout-index.c                 |  2 +
 builtin/checkout.c                       |  5 ++
 builtin/commit.c                         |  4 ++
 builtin/difftool.c                       |  3 +
 builtin/fsck.c                           |  2 +
 builtin/grep.c                           |  2 +
 builtin/ls-files.c                       | 14 +++--
 builtin/merge-index.c                    |  5 ++
 builtin/rm.c                             |  2 +
 builtin/stash.c                          |  2 +
 builtin/update-index.c                   |  2 +
 cache.h                                  |  7 ++-
 convert.c                                | 26 ++++-----
 convert.h                                | 20 +++----
 dir.c                                    | 14 +++--
 dir.h                                    |  8 +--
 entry.c                                  |  2 +
 merge-recursive.c                        |  4 +-
 name-hash.c                              | 11 +++-
 pathspec.c                               |  8 ++-
 pathspec.h                               |  6 +-
 read-cache.c                             | 35 ++++++++++--
 resolve-undo.c                           |  4 ++
 revision.c                               |  2 +
 sparse-index.c                           | 73 ++++++++++++++++++++++++
 sparse-index.h                           | 14 ++++-
 submodule.c                              |  6 +-
 submodule.h                              |  6 +-
 32 files changed, 273 insertions(+), 73 deletions(-)
base-commit: c9e40ae8ec41c5566e5849a87c969fa81ef49fcd
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-906%2Fderrickstolee%2Fsparse-index%2Fprotections-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-906/derrickstolee/sparse-index/protections-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/906
Range-diff vs v2:
  1:  7484e085e342 =  1:  4731f610ba6e sparse-index: API protection strategy
  2:  098b2c9ef352 =  2:  d3a92538edb6 *: remove 'const' qualifier for struct index_state
  3:  737d27e18d64 =  3:  f4b77aa18b93 read-cache: expand on query into sparse-directory entry
  4:  db5c100f3e2b =  4:  da17774a53c5 cache: move ensure_full_index() to cache.h
  5:  4a5fc2eb5a9f =  5:  b59c9f482828 add: ensure full index
  6:  11c38f7277c5 =  6:  0082855b5961 checkout-index: ensure full index
  7:  fd04adbb3f79 =  7:  e2ac527143ff checkout: ensure full index
  8:  65704f39edc9 =  8:  1a3b51fd3c4b commit: ensure full index
  9:  739f3fe9edf2 =  9:  8c61d40dfe01 difftool: ensure full index
 10:  779a86ad1ec4 = 10:  45b603379422 fsck: ensure full index
 11:  8c0d377054fa = 11:  97124e9fdc7f grep: ensure full index
 12:  beaa1467cabb = 12:  b00e214515e8 ls-files: ensure full index
 13:  73684141fcff = 13:  6497f2ce225b merge-index: ensure full index
 14:  6ea81a49c6b5 = 14:  175f3bc6b336 rm: ensure full index
 15:  49ca5ed05c8d = 15:  daa77e84e0e2 stash: ensure full index
 16:  9c4bb187c15d = 16:  8c5336964d9b update-index: ensure full index
 17:  fae4c078c3ef = 17:  08a62c23c8f7 dir: ensure full index
 18:  2b9180ee77d3 = 18:  825ebceee508 entry: ensure full index
 19:  1e3f6085a405 = 19:  3673db517235 merge-recursive: ensure full index
 20:  e62a597a9725 = 20:  4d3f6de29a63 pathspec: ensure full index
 21:  ebfffdbdd6ad = 21:  bda9cab15966 read-cache: ensure full index
 22:  495b07a87973 = 22:  38f295a41ec1 resolve-undo: ensure full index
 23:  3144114d1a75 = 23:  f928e104f0d3 revision: ensure full index
  -:  ------------ > 24:  5fd83dcf2747 name-hash: don't add directories to name_hash
 24:  d52c72b4a7b9 ! 25:  335fec3676a0 sparse-index: expand_to_path()
     @@ sparse-index.c: void ensure_full_index(struct index_state *istate)
      +				      path_mutable.len, icase)) {
      +			/*
      +			 * We found a parent directory in the name-hash
     -+			 * hashtable, which means that this entry could
     -+			 * exist within a sparse-directory entry. Expand
     -+			 * accordingly.
     ++			 * hashtable, because only sparse directory entries
     ++			 * have a trailing '/' character.  Since "path" wasn't
     ++			 * in the index, perhaps it exists within this
     ++			 * sparse-directory.  Expand accordingly.
      +			 */
      +			ensure_full_index(istate);
      +			break;
 25:  7e2d3fae9a2a ! 26:  1f3af8a886e5 name-hash: use expand_to_path()
     @@ name-hash.c
       
       struct dir_entry {
       	struct hashmap_entry ent;
     -@@ name-hash.c: static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
     - 	if (ce->ce_flags & CE_HASHED)
     - 		return;
     - 	ce->ce_flags |= CE_HASHED;
     -+
     -+	if (S_ISSPARSEDIR(ce->ce_mode)) {
     -+		add_dir_entry(istate, ce);
     -+		return;
     -+	}
     -+
     - 	hashmap_entry_init(&ce->ent, memihash(ce->name, ce_namelen(ce)));
     - 	hashmap_add(&istate->name_hash, &ce->ent);
     - 
      @@ name-hash.c: int index_dir_exists(struct index_state *istate, const char *name, int namelen)
       	struct dir_entry *dir;
       
-- 
gitgitgadget
Previous: Elijah NewrenNext: Derrick Stolee via GitGitGadget
Message 82 of 111 in “Sparse Index: API protections”
  1. 00/27 Sparse Index: API protectionsDerrick Stolee via GitGitGadget, Mar 16, 2021
  2. 02/27 read-cache: expand on query into sparse-directory entryDerrick Stolee via GitGitGadget, Mar 16, 2021
  3. 03/27 sparse-index: API protection strategyDerrick Stolee via GitGitGadget, Mar 16, 2021
  4. 04/27 cache: move ensure_full_index() to cache.hDerrick Stolee via GitGitGadget, Mar 16, 2021
  5. 01/27 *: remove 'const' qualifier for struct index_stateDerrick Stolee via GitGitGadget, Mar 16, 2021
  6. Junio C HamanoMar 19, 2021
  7. Derrick StoleeMar 20, 2021
  8. Junio C HamanoMar 20, 2021
  9. Derrick StoleeMar 30, 2021
  10. 13/27 merge-index: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  11. 12/27 ls-files: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  12. 08/27 commit: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  13. 05/27 add: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  14. Elijah NewrenMar 17, 2021
  15. Matheus Tavares BernardinoMar 17, 2021
  16. Derrick StoleeMar 17, 2021
  17. 07/27 checkout: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  18. 09/27 difftool: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  19. 15/27 sparse-checkout: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  20. Elijah NewrenMar 18, 2021
  21. Derrick StoleeMar 23, 2021
  22. 14/27 rm: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  23. 10/27 fsck: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  24. 11/27 grep: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  25. 27/27 name-hash: use expand_to_path()Derrick Stolee via GitGitGadget, Mar 16, 2021
  26. 16/27 update-index: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  27. 06/27 checkout-index: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  28. Elijah NewrenMar 17, 2021
  29. Derrick StoleeMar 17, 2021
  30. Elijah NewrenMar 17, 2021
  31. Derrick StoleeMar 17, 2021
  32. Elijah NewrenMar 17, 2021
  33. Derrick StoleeMar 18, 2021
  34. 18/27 dir: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  35. 17/27 diff-lib: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  36. Elijah NewrenMar 18, 2021
  37. Derrick StoleeMar 23, 2021
  38. 26/27 sparse-index: expand_to_path()Derrick Stolee via GitGitGadget, Mar 16, 2021
  39. 23/27 read-cache: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  40. 24/27 resolve-undo: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  41. 21/27 merge-recursive: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  42. 19/27 entry: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  43. 25/27 revision: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  44. 20/27 merge-ort: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  45. Elijah NewrenMar 18, 2021
  46. Derrick StoleeMar 23, 2021
  47. 22/27 pathspec: ensure full indexDerrick Stolee via GitGitGadget, Mar 16, 2021
  48. Elijah NewrenMar 17, 2021
  49. Elijah NewrenMar 18, 2021
  50. 00/25 Sparse Index: API protectionsDerrick Stolee via GitGitGadget, Apr 1, 2021
  51. 01/25 sparse-index: API protection strategyDerrick Stolee via GitGitGadget, Apr 1, 2021
  52. 03/25 read-cache: expand on query into sparse-directory entryDerrick Stolee via GitGitGadget, Apr 1, 2021
  53. 04/25 cache: move ensure_full_index() to cache.hDerrick Stolee via GitGitGadget, Apr 1, 2021
  54. 05/25 add: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  55. 02/25 *: remove 'const' qualifier for struct index_stateDerrick Stolee via GitGitGadget, Apr 1, 2021
  56. 10/25 fsck: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  57. 06/25 checkout-index: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  58. 08/25 commit: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  59. 11/25 grep: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  60. 07/25 checkout: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  61. 17/25 dir: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  62. 12/25 ls-files: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  63. 15/25 stash: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  64. 14/25 rm: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  65. 09/25 difftool: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  66. 19/25 merge-recursive: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  67. 20/25 pathspec: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  68. 18/25 entry: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  69. 13/25 merge-index: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  70. 21/25 read-cache: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  71. 23/25 revision: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  72. 22/25 resolve-undo: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  73. 24/25 sparse-index: expand_to_path()Derrick Stolee via GitGitGadget, Apr 1, 2021
  74. Elijah NewrenApr 5, 2021
  75. Derrick StoleeApr 6, 2021
  76. 25/25 name-hash: use expand_to_path()Derrick Stolee via GitGitGadget, Apr 1, 2021
  77. Elijah NewrenApr 5, 2021
  78. 16/25 update-index: ensure full indexDerrick Stolee via GitGitGadget, Apr 1, 2021
  79. Junio C HamanoApr 1, 2021
  80. Derrick StoleeApr 1, 2021
  81. Elijah NewrenApr 5, 2021
  82. 00/26 Sparse Index: API protectionsDerrick Stolee via GitGitGadget, Apr 12, 2021
  83. 01/26 sparse-index: API protection strategyDerrick Stolee via GitGitGadget, Apr 12, 2021
  84. 03/26 read-cache: expand on query into sparse-directory entryDerrick Stolee via GitGitGadget, Apr 12, 2021
  85. 02/26 *: remove 'const' qualifier for struct index_stateDerrick Stolee via GitGitGadget, Apr 12, 2021
  86. 08/26 commit: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  87. 06/26 checkout-index: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  88. 07/26 checkout: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  89. 05/26 add: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  90. 04/26 cache: move ensure_full_index() to cache.hDerrick Stolee via GitGitGadget, Apr 12, 2021
  91. 09/26 difftool: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  92. 12/26 ls-files: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  93. 13/26 merge-index: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  94. 14/26 rm: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  95. 15/26 stash: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  96. 16/26 update-index: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  97. 17/26 dir: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  98. 18/26 entry: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  99. 19/26 merge-recursive: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  100. 24/26 name-hash: don't add directories to name_hashDerrick Stolee via GitGitGadget, Apr 12, 2021
  101. 23/26 revision: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  102. 22/26 resolve-undo: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  103. 21/26 read-cache: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  104. 20/26 pathspec: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  105. 26/26 name-hash: use expand_to_path()Derrick Stolee via GitGitGadget, Apr 12, 2021
  106. 25/26 sparse-index: expand_to_path()Derrick Stolee via GitGitGadget, Apr 12, 2021
  107. 10/26 fsck: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  108. 11/26 grep: ensure full indexDerrick Stolee via GitGitGadget, Apr 12, 2021
  109. Elijah NewrenApr 13, 2021
  110. Junio C HamanoApr 14, 2021
  111. Derrick StoleeApr 15, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.