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

Re: [PATCH v8 4/4] cache-tree: Write updated cache-tree after commit

From
Junio C Hamano <gitster@pobox.com>
Date
Jul 14, 2014, 17:43 UTC
Message-ID
<xmqqzjgbygy3.fsf@gitster.dls.corp.google.com>
In-Reply-To
<xmqqr41oylyo.fsf@gitster.dls.corp.google.com>
Junio C Hamano <gitster@pobox.com> writes:
Show 29 quoted lines
> Duy Nguyen <pclouds@gmail.com> writes:
>
>> On Sat, Jul 12, 2014 at 11:44 AM, David Turner <dturner@twopensource.com> wrote:
>>> @@ -342,6 +342,15 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
>>>
>>>                 discard_cache();
>>>                 read_cache_from(index_lock.filename);
>>> +               if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
>>> +                       fd = open(index_lock.filename, O_WRONLY);
>>> +                       if (fd >= 0)
>>> +                               if (write_cache(fd, active_cache, active_nr) == 0) {
>>> +                                       close_lock_file(&index_lock);
>>
>> If write_cache() returns a negative value, index.lock is probably
>> corrupted. Should we die() instead of moving on and returning
>> index_lock.filename to the caller? The caller may move index.lock to
>> index later on and officially ruin "index".
>
> Perhaps true, but worse yet, this will not play nicely together with
> your split index series, no?  After taking the lock and writing and
> closing, we spawn the interactive while still holding the lock, and
> the "open" we see here is because we want to further update the same
> under the same lock.  Perhaps write_locked_index() API in the split
> index series can notice that the underlying fd in index_lock has
> been closed earlier, realize that the call is to re-update the
> index under the same lock and open the file again for writing?
>
> Then we can update the above "open() then write_cache()" sequence
> with just a call to "write_locked_index()".

Or perhaps introduce reopen_locked_file() and have these rare callers that want to re-update after they closed the file call it, in order to avoid mistake?

Perhaps something like this on top of your series?
-- >8 --
Subject: [PATCH] lockfile: allow reopening a closed but still locked file

In some code paths (e.g. giving "add -i" to prepare the contents to be committed interactively inside "commit -p") where a caller takes a lock, writes the new content, give chance for others to use it while still holding the lock, and then releases the lock when all is done. As an extension, allow the caller to re-update an already closed file while still holding the lock (i.e. not yet committed) by re-opening the file, to be followed by updating the contents and then by the usual close_lock_file() or commit_lock_file().

This is necessary if we want to add code to rebuild the cache-tree and write the resulting index out after "add -i" returns the control to "commit -p", for example.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 cache.h    |  7 ++++---
 lockfile.c | 51 +++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 41 insertions(+), 17 deletions(-)
diff --git a/cache.h b/cache.h
index c6b7770..a9344cf 100644
--- a/cache.h
+++ b/cache.h
@@ -567,12 +567,13 @@ extern NORETURN void unable_to_lock_index_die(const char *path, int err);
 extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
 extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
 extern int commit_lock_file(struct lock_file *);
-extern void update_index_if_able(struct index_state *, struct lock_file *);
+extern int reopen_lock_file(struct lock_file *);
+extern int close_lock_file(struct lock_file *);
+extern void rollback_lock_file(struct lock_file *);
 
+extern void update_index_if_able(struct index_state *, struct lock_file *);
 extern int hold_locked_index(struct lock_file *, int);
 extern void set_alternate_index_output(const char *);
-extern int close_lock_file(struct lock_file *);
-extern void rollback_lock_file(struct lock_file *);
 extern int delete_ref(const char *, const unsigned char *sha1, int delopt);
 
 /* Environment bits from configuration mechanism */
diff --git a/lockfile.c b/lockfile.c
index b706614..618a4b2 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -120,21 +120,8 @@ static char *resolve_symlink(char *p, size_t s)
 	return p;
 }
 
-
-static int lock_file(struct lock_file *lk, const char *path, int flags)
+static int lock_file_open(struct lock_file *lk)
 {
-	/*
-	 * subtract 5 from size to make sure there's room for adding
-	 * ".lock" for the lock file name
-	 */
-	static const size_t max_path_len = sizeof(lk->filename) - 5;
-
-	if (strlen(path) >= max_path_len)
-		return -1;
-	strcpy(lk->filename, path);
-	if (!(flags & LOCK_NODEREF))
-		resolve_symlink(lk->filename, max_path_len);
-	strcat(lk->filename, ".lock");
 	lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
 	if (0 <= lk->fd) {
 		if (!lock_file_list) {
@@ -156,6 +143,23 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
 	return lk->fd;
 }
 
+static int lock_file(struct lock_file *lk, const char *path, int flags)
+{
+	/*
+	 * subtract 5 from size to make sure there's room for adding
+	 * ".lock" for the lock file name
+	 */
+	static const size_t max_path_len = sizeof(lk->filename) - 5;
+
+	if (strlen(path) >= max_path_len)
+		return -1;
+	strcpy(lk->filename, path);
+	if (!(flags & LOCK_NODEREF))
+		resolve_symlink(lk->filename, max_path_len);
+	strcat(lk->filename, ".lock");
+	return lock_file_open(lk);
+}
+
 static char *unable_to_lock_message(const char *path, int err)
 {
 	struct strbuf buf = STRBUF_INIT;
@@ -221,6 +225,25 @@ int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
 	return fd;
 }
 
+/*
+ * After calling close_lock_file() to flush the contents to the
+ * disk, without releasing the lock, this can be called to reopen
+ * to update the contents of the file.  An expected calling sequence
+ * is
+ *
+ * hold_lock_file(lk), write(lk->fd), close_lock_file(lk),
+ * reopen_lock_file(lk), write(lk->fd), close_lock_file(lk),
+ * commit_lock_file(lk).
+ */
+int reopen_lock_file(struct lock_file *lk)
+{
+	if (0 <= lk->fd)
+		die(_("BUG: attempt to reopen an unclosed lockfile"));
+	if (!lk->filename[0])
+		die(_("BUG: attempt to reopen a committed lockfile"));
+	return lock_file_open(lk);
+}
+
 int close_lock_file(struct lock_file *lk)
 {
 	int fd = lk->fd;
-- 
2.0.1-812-g56968e3
Previous: Junio C HamanoNext: Junio C Hamano
Message 18 of 28 in “cache-tree: Create/update cache-tree on checkout”
  1. 1/4 cache-tree: Create/update cache-tree on checkoutDavid Turner, Jul 12, 2014
  2. 2/4 test-dump-cache-tree: invalid trees are not errorsDavid Turner, Jul 12, 2014
  3. 3/4 cache-tree: subdirectory testsDavid Turner, Jul 12, 2014
  4. 4/4 cache-tree: Write updated cache-tree after commitDavid Turner, Jul 12, 2014
  5. Duy NguyenJul 13, 2014
  6. Junio C HamanoJul 14, 2014
  7. Ramsay JonesJul 14, 2014
  8. Junio C HamanoJul 14, 2014
  9. Ramsay JonesJul 14, 2014
  10. Junio C HamanoJul 14, 2014
  11. David TurnerJul 14, 2014
  12. Duy NguyenJul 15, 2014
  13. Junio C HamanoJul 15, 2014
  14. Duy NguyenJul 15, 2014
  15. Junio C HamanoJul 15, 2014
  16. Duy NguyenJul 16, 2014
  17. Junio C HamanoJul 16, 2014
  18. Junio C HamanoJul 14, 2014
  19. lockfile: allow reopening a closed but still locked fileJunio C Hamano, Jul 14, 2014
  20. John KeepingAug 31, 2014
  21. David TurnerSep 1, 2014
  22. John KeepingSep 1, 2014
  23. Junio C HamanoSep 2, 2014
  24. Junio C HamanoSep 2, 2014
  25. cache-tree: propagate invalidation up when puntingJunio C Hamano, Sep 2, 2014
  26. cache-tree: do not try to use an invalidated subtree info to build a treeJunio C Hamano, Sep 2, 2014
  27. David TurnerSep 3, 2014
  28. Eric SunshineSep 3, 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.