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

[PATCH v3 11/23] untracked cache: load from UNTR index extension

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Dec 8, 2014, 14:04 UTC
Message-ID
<1418047507-22892-13-git-send-email-pclouds@gmail.com>
In-Reply-To
<1418047507-22892-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 dir.c        | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 dir.h        |   2 +
 read-cache.c |   5 ++
 3 files changed, 227 insertions(+)
diff --git a/dir.c b/dir.c
index a0a7330..0126a0d 100644
--- a/dir.c
+++ b/dir.c
@@ -2273,3 +2273,223 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
 	strbuf_release(&wd.sb_stat);
 	strbuf_release(&wd.sb_sha1);
 }
+
+static void free_untracked(struct untracked_cache_dir *ucd)
+{
+	int i;
+	if (!ucd)
+		return;
+	for (i = 0; i < ucd->dirs_nr; i++)
+		free_untracked(ucd->dirs[i]);
+	for (i = 0; i < ucd->untracked_nr; i++)
+		free(ucd->untracked[i]);
+	free(ucd->untracked);
+	free(ucd->dirs);
+	free(ucd);
+}
+
+void free_untracked_cache(struct untracked_cache *uc)
+{
+	if (uc)
+		free_untracked(uc->root);
+	free(uc);
+}
+
+struct read_data {
+	int index;
+	struct untracked_cache_dir **ucd;
+	struct ewah_bitmap *check_only;
+	struct ewah_bitmap *valid;
+	struct ewah_bitmap *sha1_valid;
+	const unsigned char *data;
+	const unsigned char *end;
+};
+
+static void stat_data_from_disk(struct stat_data *to, const struct stat_data *from)
+{
+	to->sd_ctime.sec  = get_be32(&from->sd_ctime.sec);
+	to->sd_ctime.nsec = get_be32(&from->sd_ctime.nsec);
+	to->sd_mtime.sec  = get_be32(&from->sd_mtime.sec);
+	to->sd_mtime.nsec = get_be32(&from->sd_mtime.nsec);
+	to->sd_dev	  = get_be32(&from->sd_dev);
+	to->sd_ino	  = get_be32(&from->sd_ino);
+	to->sd_uid	  = get_be32(&from->sd_uid);
+	to->sd_gid	  = get_be32(&from->sd_gid);
+	to->sd_size	  = get_be32(&from->sd_size);
+}
+
+static int read_one_dir(struct untracked_cache_dir **untracked_,
+			struct read_data *rd)
+{
+#define NEXT(x) \
+	next = data + (x); \
+	if (next > rd->end) \
+		return -1;
+
+	struct untracked_cache_dir ud, *untracked;
+	const unsigned char *next, *data = rd->data, *end = rd->end;
+	unsigned int value;
+	int i, len;
+
+	memset(&ud, 0, sizeof(ud));
+
+	next = data;
+	value = decode_varint(&next);
+	if (next > end)
+		return -1;
+	ud.recurse	   = 1;
+	ud.untracked_alloc = value;
+	ud.untracked_nr	   = value;
+	if (ud.untracked_nr)
+		ud.untracked = xmalloc(sizeof(*ud.untracked) * ud.untracked_nr);
+	data = next;
+
+	next = data;
+	ud.dirs_alloc = ud.dirs_nr = decode_varint(&next);
+	if (next > end)
+		return -1;
+	ud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr);
+	data = next;
+
+	len = strlen((const char *)data);
+	NEXT(len + 1);
+	*untracked_ = untracked = xmalloc(sizeof(*untracked) + len);
+	memcpy(untracked, &ud, sizeof(ud));
+	memcpy(untracked->name, data, len + 1);
+	data = next;
+
+	for (i = 0; i < untracked->untracked_nr; i++) {
+		len = strlen((const char *)data);
+		NEXT(len + 1);
+		untracked->untracked[i] = xstrdup((const char*)data);
+		data = next;
+	}
+
+	rd->ucd[rd->index++] = untracked;
+	rd->data = data;
+
+	for (i = 0; i < untracked->dirs_nr; i++) {
+		len = read_one_dir(untracked->dirs + i, rd);
+		if (len < 0)
+			return -1;
+	}
+	return 0;
+}
+
+static void set_check_only(size_t pos, void *cb)
+{
+	struct read_data *rd = cb;
+	struct untracked_cache_dir *ud = rd->ucd[pos];
+	ud->check_only = 1;
+}
+
+static void read_stat(size_t pos, void *cb)
+{
+	struct read_data *rd = cb;
+	struct untracked_cache_dir *ud = rd->ucd[pos];
+	if (rd->data + sizeof(struct stat_data) > rd->end) {
+		rd->data = rd->end + 1;
+		return;
+	}
+	stat_data_from_disk(&ud->stat_data, (struct stat_data *)rd->data);
+	rd->data += sizeof(struct stat_data);
+	ud->valid = 1;
+}
+
+static void read_sha1(size_t pos, void *cb)
+{
+	struct read_data *rd = cb;
+	struct untracked_cache_dir *ud = rd->ucd[pos];
+	if (rd->data + 20 > rd->end) {
+		rd->data = rd->end + 1;
+		return;
+	}
+	hashcpy(ud->exclude_sha1, rd->data);
+	rd->data += 20;
+}
+
+static void load_sha1_stat(struct sha1_stat *sha1_stat,
+			   const struct stat_data *stat,
+			   const unsigned char *sha1)
+{
+	stat_data_from_disk(&sha1_stat->stat, stat);
+	hashcpy(sha1_stat->sha1, sha1);
+	sha1_stat->valid = 1;
+}
+
+struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz)
+{
+	const struct ondisk_untracked_cache *ouc;
+	struct untracked_cache *uc;
+	struct read_data rd;
+	const unsigned char *next = data, *end = data + sz;
+	int len;
+
+	if (sz <= 1 || end[-1] != '\0')
+		return NULL;
+	end--;
+
+	ouc = (const struct ondisk_untracked_cache *)next;
+	if (next + sizeof(*ouc) > end)
+		return NULL;
+
+	uc = xcalloc(1, sizeof(*uc));
+	load_sha1_stat(&uc->ss_info_exclude, &ouc->info_exclude_stat,
+		       ouc->info_exclude_sha1);
+	load_sha1_stat(&uc->ss_excludes_file, &ouc->excludes_file_stat,
+		       ouc->excludes_file_sha1);
+	uc->dir_flags = get_be32(&ouc->dir_flags);
+	uc->exclude_per_dir = xstrdup(ouc->exclude_per_dir);
+	/* NUL after exclude_per_dir is covered by sizeof(*ouc) */
+	next += sizeof(*ouc) + strlen(ouc->exclude_per_dir);
+	if (next >= end)
+		goto done2;
+
+	len = decode_varint(&next);
+	if (next > end || len == 0)
+		goto done2;
+
+	rd.valid      = ewah_new();
+	rd.check_only = ewah_new();
+	rd.sha1_valid = ewah_new();
+	rd.data	      = next;
+	rd.end	      = end;
+	rd.index      = 0;
+	rd.ucd        = xmalloc(sizeof(*rd.ucd) * len);
+
+	if (read_one_dir(&uc->root, &rd) || rd.index != len)
+		goto done;
+
+	next = rd.data;
+	len = ewah_read_mmap(rd.valid, next, end - next);
+	if (len < 0)
+		goto done;
+
+	next += len;
+	len = ewah_read_mmap(rd.check_only, next, end - next);
+	if (len < 0)
+		goto done;
+
+	next += len;
+	len = ewah_read_mmap(rd.sha1_valid, next, end - next);
+	if (len < 0)
+		goto done;
+
+	ewah_each_bit(rd.check_only, set_check_only, &rd);
+	rd.data = next + len;
+	ewah_each_bit(rd.valid, read_stat, &rd);
+	ewah_each_bit(rd.sha1_valid, read_sha1, &rd);
+	next = rd.data;
+
+done:
+	free(rd.ucd);
+	ewah_free(rd.valid);
+	ewah_free(rd.check_only);
+	ewah_free(rd.sha1_valid);
+done2:
+	if (next != end) {
+		free_untracked_cache(uc);
+		uc = NULL;
+	}
+	return uc;
+}
diff --git a/dir.h b/dir.h
index dc3ee0b..40a679a 100644
--- a/dir.h
+++ b/dir.h
@@ -298,5 +298,7 @@ static inline int dir_path_match(const struct dir_entry *ent,
 			      has_trailing_dir);
 }
 
+void free_untracked_cache(struct untracked_cache *);
+struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz);
 void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked);
 #endif
diff --git a/read-cache.c b/read-cache.c
index baf3057..3736a56 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1366,6 +1366,9 @@ static int read_index_extension(struct index_state *istate,
 		if (read_link_extension(istate, data, sz))
 			return -1;
 		break;
+	case CACHE_EXT_UNTRACKED:
+		istate->untracked = read_untracked_extension(data, sz);
+		break;
 	default:
 		if (*ext < 'A' || 'Z' < *ext)
 			return error("index uses %.4s extension, which we do not understand",
@@ -1631,6 +1634,8 @@ int discard_index(struct index_state *istate)
 	istate->cache = NULL;
 	istate->cache_alloc = 0;
 	discard_split_index(istate);
+	free_untracked_cache(istate->untracked);
+	istate->untracked = NULL;
 	return 0;
 }
 
-- 
2.2.0.60.gb7b3c64
Previous: Duy NguyenNext: Junio C Hamano
Message 16 of 35 in “nd/untracked-cache updates”
  1. 00/23 nd/untracked-cache updatesNguyễn Thái Ngọc Duy, Dec 8, 2014
  2. checkout: add --ignore-other-wortreesNguyễn Thái Ngọc Duy, Dec 8, 2014
  3. Duy NguyenDec 8, 2014
  4. 01/23 dir.c: optionally compute sha-1 of a .gitignore fileNguyễn Thái Ngọc Duy, Dec 8, 2014
  5. 02/23 untracked cache: record .gitignore information and dir hierarchyNguyễn Thái Ngọc Duy, Dec 8, 2014
  6. 03/23 untracked cache: initial untracked cache validationNguyễn Thái Ngọc Duy, Dec 8, 2014
  7. 04/23 untracked cache: invalidate dirs recursively if .gitignore changesNguyễn Thái Ngọc Duy, Dec 8, 2014
  8. 05/23 untracked cache: make a wrapper around {open,read,close}dir()Nguyễn Thái Ngọc Duy, Dec 8, 2014
  9. 06/23 untracked cache: record/validate dir mtime and reuse cached outputNguyễn Thái Ngọc Duy, Dec 8, 2014
  10. 07/23 untracked cache: mark what dirs should be recursed/savedNguyễn Thái Ngọc Duy, Dec 8, 2014
  11. 08/23 untracked cache: don't open non-existent .gitignoreNguyễn Thái Ngọc Duy, Dec 8, 2014
  12. 09/23 ewah: add convenient wrapper ewah_serialize_strbuf()Nguyễn Thái Ngọc Duy, Dec 8, 2014
  13. 10/23 untracked cache: save to an index extensionNguyễn Thái Ngọc Duy, Dec 8, 2014
  14. Eric SunshineDec 9, 2014
  15. Duy NguyenDec 10, 2014
  16. 11/23 untracked cache: load from UNTR index extensionNguyễn Thái Ngọc Duy, Dec 8, 2014
  17. Junio C HamanoDec 15, 2014
  18. 12/23 untracked cache: invalidate at index addition or removalNguyễn Thái Ngọc Duy, Dec 8, 2014
  19. 13/23 read-cache.c: split racy stat test to a separate functionNguyễn Thái Ngọc Duy, Dec 8, 2014
  20. 14/23 untracked cache: avoid racy timestampsNguyễn Thái Ngọc Duy, Dec 8, 2014
  21. 15/23 untracked cache: print stats with $GIT_TRACE_UNTRACKED_STATSNguyễn Thái Ngọc Duy, Dec 8, 2014
  22. 16/23 untracked cache: mark index dirty if untracked cache is updatedNguyễn Thái Ngọc Duy, Dec 8, 2014
  23. 17/23 untracked-cache: temporarily disable with $GIT_DISABLE_UNTRACKED_CACHENguyễn Thái Ngọc Duy, Dec 8, 2014
  24. 18/23 status: enable untracked cacheNguyễn Thái Ngọc Duy, Dec 8, 2014
  25. 19/23 update-index: manually enable or disable untracked cacheNguyễn Thái Ngọc Duy, Dec 8, 2014
  26. 20/23 update-index: test the system before enabling untracked cacheNguyễn Thái Ngọc Duy, Dec 8, 2014
  27. 21/23 t7063: tests for untracked cacheNguyễn Thái Ngọc Duy, Dec 8, 2014
  28. 22/23 mingw32: add uname()Nguyễn Thái Ngọc Duy, Dec 8, 2014
  29. 23/23 untracked cache: guard and disable on system changesNguyễn Thái Ngọc Duy, Dec 8, 2014
  30. brian m. carlsonDec 9, 2014
  31. Duy NguyenDec 9, 2014
  32. Torsten BögershausenDec 10, 2014
  33. Duy NguyenDec 10, 2014
  34. Torsten BögershausenDec 11, 2014
  35. Duy NguyenDec 15, 2014

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.