All of lore.kernel.org
 help / color / mirror / Atom feed
From: Johannes Schindelin <Johannes.Schindelin@gmx.de>
To: Junio C Hamano <gitster@pobox.com>
Cc: Johannes Schindelin via GitGitGadget <gitgitgadget@gmail.com>,
	git@vger.kernel.org
Subject: Re: [PATCH v2 2/2] git_path(): handle `.lock` files correctly
Date: Mon, 21 Oct 2019 22:26:26 +0200 (CEST)	[thread overview]
Message-ID: <nycvar.QRO.7.76.6.1910212157350.46@tvgsbejvaqbjf.bet> (raw)
In-Reply-To: <xmqq1rva7sp7.fsf@gitster-ct.c.googlers.com>

Hi Junio,

On Fri, 18 Oct 2019, Junio C Hamano wrote:

> "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
> writes:
>
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> >
> > Ever since worktrees were introduced, the `git_path()` function _really_
> > needed to be called e.g. to get at the path to `logs/HEAD` (`HEAD` is
> > specific to the worktree). However, the wrong path is returned for
> > `logs/HEAD.lock`.
> >
> > This does not matter as long as the Git executable is doing the asking,
> > as the path for that `index.lock` file is constructed from
> > `git_path("index")` by appending the `.lock` suffix.
>
> Is this still git_path("index") or is it now HEAD?

Darn. It is "logs/HEAD", of course.

> > Side note: Git GUI _does_ ask for `index.lock`, but that is already
> > resolved correctly.
>
> Is that s/but/and/?

It sounds better with an "and", you're right.

> > diff --git a/path.c b/path.c
> > index e3da1f3c4e..ff85692b45 100644
> > --- a/path.c
> > +++ b/path.c
> > @@ -268,7 +268,7 @@ static int trie_find(struct trie *root, const char *key, match_fn fn,
> >  	int result;
> >  	struct trie *child;
> >
> > -	if (!*key) {
> > +	if (!*key || !strcmp(key, ".lock")) {
>
> We only do strcmp for the tail part at the end of the path, so this
> should probably OK from performance point of view but semantically
> it is not very satisfying to see a special case for a single .suffix
> this deep in the callchain.  I wonder if it is nicer to have the
> higher level callers notice ".lock" or whatever other suffixes they
> care about and ask the lower layer for a key with the suffix
> stripped?

Hmm. The parameter is provided as a `const char *`, so I cannot just
edit it. My first attempt at fixing this resulted in this commit:

-- snip --
    path: switch `trie_find()` to a counted string

    Before this patch, the `trie_find()` function would be fed a regular,
    NUL-terminated string.

    However, in the next commit, we want to strip any `.lock` suffix from
    the argument, and the argument is provided as a `const char *` (i.e. we
    do not want to modify it).

    Let's use a string + length pair of parameters instead of a single
    NUL-terminated string to open the door for this kind of manipulation.

    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

diff --git a/path.c b/path.c
index e3da1f3c4e2..b18d552c890 100644
--- a/path.c
+++ b/path.c
@@ -236,7 +236,8 @@ static void *add_to_trie(struct trie *root, const char *key, void *value)
 	return old;
 }

-typedef int (*match_fn)(const char *unmatched, void *data, void *baton);
+typedef int (*match_fn)(const char *unmatched, size_t unmatched_len,
+			void *data, void *baton);

 /*
  * Search a trie for some key.  Find the longest /-or-\0-terminated
@@ -261,22 +262,22 @@ typedef int (*match_fn)(const char *unmatched, void *data, void *baton);
  * |-----------------|------------|---------------|--------------|
  *
  */
-static int trie_find(struct trie *root, const char *key, match_fn fn,
-		     void *baton)
+static int trie_find(struct trie *root, const char *key, size_t key_len,
+		     match_fn fn, void *baton)
 {
 	int i;
 	int result;
 	struct trie *child;

-	if (!*key) {
+	if (!key_len) {
 		/* we have reached the end of the key */
 		if (root->value && !root->len)
-			return fn(key, root->value, baton);
+			return fn(key, key_len, root->value, baton);
 		else
 			return -1;
 	}

-	for (i = 0; i < root->len; i++) {
+	for (i = 0; i < key_len && i < root->len; i++) {
 		/* Partial path normalization: skip consecutive slashes. */
 		if (key[i] == '/' && key[i+1] == '/') {
 			key++;
@@ -288,24 +289,26 @@ static int trie_find(struct trie *root, const char *key, match_fn fn,

 	/* Matched the entire compressed section */
 	key += i;
-	if (!*key)
+	key_len -= i;
+
+	if (!key_len)
 		/* End of key */
-		return fn(key, root->value, baton);
+		return fn(key, key_len, root->value, baton);

 	/* Partial path normalization: skip consecutive slashes */
-	while (key[0] == '/' && key[1] == '/')
-		key++;
+	while (key_len > 0 && key[0] == '/' && key[1] == '/')
+		key++, key_len--;

-	child = root->children[(unsigned char)*key];
+	child = root->children[!key_len ? '0' : (unsigned char)*key];
 	if (child)
-		result = trie_find(child, key + 1, fn, baton);
+		result = trie_find(child, key + 1, key_len - 1, fn, baton);
 	else
 		result = -1;

-	if (result >= 0 || (*key != '/' && *key != 0))
+	if (result >= 0 || (key_len && *key != '/'))
 		return result;
 	if (root->value)
-		return fn(key, root->value, baton);
+		return fn(key, key_len, root->value, baton);
 	else
 		return -1;
 }
@@ -330,17 +333,18 @@ static void init_common_trie(void)
  * Helper function for update_common_dir: returns 1 if the dir
  * prefix is common.
  */
-static int check_common(const char *unmatched, void *value, void *baton)
+static int check_common(const char *unmatched, size_t unmatched_len,
+			void *value, void *baton)
 {
 	struct common_dir *dir = value;

 	if (!dir)
 		return 0;

-	if (dir->is_dir && (unmatched[0] == 0 || unmatched[0] == '/'))
+	if (dir->is_dir && (!unmatched_len || unmatched[0] == '/'))
 		return !dir->exclude;

-	if (!dir->is_dir && unmatched[0] == 0)
+	if (!dir->is_dir && !unmatched_len)
 		return !dir->exclude;

 	return 0;
@@ -350,8 +354,10 @@ static void update_common_dir(struct strbuf *buf, int git_dir_len,
 			      const char *common_dir)
 {
 	char *base = buf->buf + git_dir_len;
+	size_t len = strlen(base);
+
 	init_common_trie();
-	if (trie_find(&common_trie, base, check_common, NULL) > 0)
+	if (trie_find(&common_trie, base, len, check_common, NULL) > 0)
 		replace_dir(buf, git_dir_len, common_dir);
 }
-- snap --

However, I think this is _really_ ugly and intrusive. The opposite of
what my goals were.

So I think I'll just bite the bullet and use a temporary copy if the
argument ends in `.lock`.

Ciao,
Dscho

  parent reply	other threads:[~2019-10-21 20:26 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-16  7:07 [PATCH 0/2] Handle git_path() with lock files correctly in worktrees Johannes Schindelin via GitGitGadget
2019-10-16  7:07 ` [PATCH 1/2] t1400: wrap setup code in test case Johannes Schindelin via GitGitGadget
2019-10-16  7:07 ` [PATCH 2/2] git_path(): handle `.lock` files correctly Johannes Schindelin via GitGitGadget
2019-10-16 11:04   ` SZEDER Gábor
2019-10-17  7:15     ` Junio C Hamano
2019-10-17 22:05     ` Johannes Schindelin
2019-10-18 11:06       ` SZEDER Gábor
2019-10-18 11:35         ` SZEDER Gábor
2019-10-21 16:00           ` [PATCH 0/5] path.c: a couple of common dir/trie fixes SZEDER Gábor
2019-10-21 16:00             ` [PATCH 1/5] Documentation: mention more worktree-specific exceptions SZEDER Gábor
2019-10-21 16:00             ` [PATCH 2/5] path.c: clarify trie_find()'s in-code comment SZEDER Gábor
2019-10-21 16:00             ` [PATCH 3/5] path.c: mark 'logs/HEAD' in 'common_list' as file SZEDER Gábor
2019-10-21 16:00             ` [PATCH 4/5] path.c: clarify two field names in 'struct common_dir' SZEDER Gábor
2019-10-21 16:00             ` [PATCH 5/5] path.c: don't call the match function without value in trie_find() SZEDER Gábor
2019-10-21 17:39               ` David Turner
2019-10-21 20:57               ` SZEDER Gábor
2019-10-23  4:01                 ` Junio C Hamano
2019-10-23 16:20                   ` SZEDER Gábor
2019-10-24  3:29                     ` Junio C Hamano
2019-10-28 10:57               ` Johannes Schindelin
2019-10-28 12:00                 ` SZEDER Gábor
2019-10-28 21:30                   ` Johannes Schindelin
2019-10-18 11:42         ` [PATCH 0/2] path.c: minor common_list fixes SZEDER Gábor
2019-10-18 11:42           ` [PATCH 1/2] path.c: fix field name in 'struct common_dir' SZEDER Gábor
2019-10-18 11:42           ` [PATCH 2/2] path.c: mark 'logs/HEAD' in 'common_list' as file SZEDER Gábor
2019-10-21 19:35           ` [PATCH 0/2] path.c: minor common_list fixes Johannes Schindelin
2019-10-17 22:07 ` [PATCH v2 0/2] Handle git_path() with lock files correctly in worktrees Johannes Schindelin via GitGitGadget
2019-10-17 22:07   ` [PATCH v2 1/2] t1400: wrap setup code in test case Johannes Schindelin via GitGitGadget
2019-10-17 22:07   ` [PATCH v2 2/2] git_path(): handle `.lock` files correctly Johannes Schindelin via GitGitGadget
2019-10-18  1:23     ` Junio C Hamano
2019-10-18 12:35       ` SZEDER Gábor
2019-10-21 20:26       ` Johannes Schindelin [this message]
2019-10-23  2:12         ` Junio C Hamano
2019-10-21 21:54   ` [PATCH v3 0/2] Handle git_path() with lock files correctly in worktrees Johannes Schindelin via GitGitGadget
2019-10-21 21:54     ` [PATCH v3 1/2] t1400: wrap setup code in test case Johannes Schindelin via GitGitGadget
2019-10-21 21:54     ` [PATCH v3 2/2] git_path(): handle `.lock` files correctly Johannes Schindelin via GitGitGadget
2019-10-22 16:01       ` SZEDER Gábor
2019-10-23  3:38         ` Junio C Hamano
2019-10-28 12:01         ` Johannes Schindelin
2019-10-28 12:32           ` SZEDER Gábor
2019-10-28 17:30           ` Junio C Hamano
2019-10-28 12:57     ` [PATCH v4 0/2] Handle git_path() with lock files correctly in worktrees Johannes Schindelin via GitGitGadget
2019-10-28 12:57       ` [PATCH v4 1/2] t1400: wrap setup code in test case Johannes Schindelin via GitGitGadget
2019-10-28 12:57       ` [PATCH v4 2/2] git_path(): handle `.lock` files correctly Johannes Schindelin via GitGitGadget
2019-10-29  3:39       ` [PATCH v4 0/2] Handle git_path() with lock files correctly in worktrees Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=nycvar.QRO.7.76.6.1910212157350.46@tvgsbejvaqbjf.bet \
    --to=johannes.schindelin@gmx.de \
    --cc=git@vger.kernel.org \
    --cc=gitgitgadget@gmail.com \
    --cc=gitster@pobox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.