From: Junio C Hamano Date: Tue, 19 Sep 2017 01:47:56 +0000 (+0900) Subject: Merge branch 'mh/packed-ref-transactions' X-Git-Tag: v2.15.0-rc0~80 X-Git-Url: http://git.bitbasher.net/?a=commitdiff_plain;h=07f0542da32072843909b671bc60e6d913383f57;p=git.git Merge branch 'mh/packed-ref-transactions' Implement transactional update to the packed-ref representation of references. * mh/packed-ref-transactions: files_transaction_finish(): delete reflogs before references packed-backend: rip out some now-unused code files_ref_store: use a transaction to update packed refs t1404: demonstrate two problems with reference transactions files_initial_transaction_commit(): use a transaction for packed refs prune_refs(): also free the linked list files_pack_refs(): use a reference transaction to write packed refs packed_delete_refs(): implement method packed_ref_store: implement reference transactions struct ref_transaction: add a place for backends to store data packed-backend: don't adjust the reference count on lock/unlock --- 07f0542da32072843909b671bc60e6d913383f57 diff --cc refs/files-backend.c index a7cc65d0de,961424a4ea..32663a999e --- a/refs/files-backend.c +++ b/refs/files-backend.c @@@ -2418,19 -2388,20 +2434,24 @@@ static int lock_ref_for_update(struct f * the lockfile is still open. Close it to * free up the file descriptor: */ - if (close_ref(lock)) { + if (close_ref_gently(lock)) { strbuf_addf(err, "couldn't close '%s.lock'", update->refname); - return TRANSACTION_GENERIC_ERROR; + ret = TRANSACTION_GENERIC_ERROR; + goto out; } } - return 0; + +out: + strbuf_release(&referent); + return ret; } + struct files_transaction_backend_data { + struct ref_transaction *packed_transaction; + int packed_refs_locked; + }; + /* * Unlock any references in `transaction` that are still locked, and * mark the transaction closed. diff --cc refs/packed-backend.c index 321608a114,0279aeceea..3bc47ffd5e --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@@ -628,8 -586,8 +587,9 @@@ static int write_with_updates(struct pa */ packed_refs_path = get_locked_file_path(&refs->lock); strbuf_addf(&sb, "%s.new", packed_refs_path); + free(packed_refs_path); - if (create_tempfile(&refs->tempfile, sb.buf) < 0) { + refs->tempfile = create_tempfile(sb.buf); + if (!refs->tempfile) { strbuf_addf(err, "unable to create file %s: %s", sb.buf, strerror(errno)); strbuf_release(&sb); @@@ -671,83 -732,56 +734,57 @@@ goto error; } - if (rename_tempfile(&refs->tempfile, packed_refs_path)) { - strbuf_addf(err, "error replacing %s: %s", - refs->path, strerror(errno)); - goto out; - if (close_tempfile(&refs->tempfile)) { ++ if (close_tempfile_gently(refs->tempfile)) { + strbuf_addf(err, "error closing file %s: %s", - get_tempfile_path(&refs->tempfile), ++ get_tempfile_path(refs->tempfile), + strerror(errno)); + strbuf_release(&sb); ++ delete_tempfile(&refs->tempfile); + return -1; } - ret = 0; - goto out; + return 0; + + write_error: + strbuf_addf(err, "error writing to %s: %s", - get_tempfile_path(&refs->tempfile), strerror(errno)); ++ get_tempfile_path(refs->tempfile), strerror(errno)); error: - delete_tempfile(&refs->tempfile); + if (iter) + ref_iterator_abort(iter); - out: - free(packed_refs_path); - return ret; + delete_tempfile(&refs->tempfile); + return -1; } - /* - * Rewrite the packed-refs file, omitting any refs listed in - * 'refnames'. On error, leave packed-refs unchanged, write an error - * message to 'err', and return a nonzero value. The packed refs lock - * must be held when calling this function; it will still be held when - * the function returns. - * - * The refs in 'refnames' needn't be sorted. `err` must not be NULL. - */ - int repack_without_refs(struct ref_store *ref_store, - struct string_list *refnames, struct strbuf *err) + struct packed_transaction_backend_data { + /* True iff the transaction owns the packed-refs lock. */ + int own_lock; + + struct string_list updates; + }; + + static void packed_transaction_cleanup(struct packed_ref_store *refs, + struct ref_transaction *transaction) { - struct packed_ref_store *refs = - packed_downcast(ref_store, REF_STORE_WRITE | REF_STORE_MAIN, - "repack_without_refs"); - struct ref_dir *packed; - struct string_list_item *refname; - int needs_repacking = 0, removed = 0; + struct packed_transaction_backend_data *data = transaction->backend_data; - packed_assert_main_repository(refs, "repack_without_refs"); - assert(err); + if (data) { + string_list_clear(&data->updates, 0); - if (!is_lock_file_locked(&refs->lock)) - die("BUG: repack_without_refs called without holding lock"); - if (is_tempfile_active(&refs->tempfile)) ++ if (is_tempfile_active(refs->tempfile)) + delete_tempfile(&refs->tempfile); - /* Look for a packed ref */ - for_each_string_list_item(refname, refnames) { - if (get_packed_ref(refs, refname->string)) { - needs_repacking = 1; - break; + if (data->own_lock && is_lock_file_locked(&refs->lock)) { + packed_refs_unlock(&refs->base); + data->own_lock = 0; } - } - /* Avoid locking if we have nothing to do */ - if (!needs_repacking) - return 0; /* no refname exists in packed refs */ - - packed = get_packed_refs(refs); - - /* Remove refnames from the cache */ - for_each_string_list_item(refname, refnames) - if (remove_entry_from_dir(packed, refname->string) != -1) - removed = 1; - if (!removed) { - /* - * All packed entries disappeared while we were - * acquiring the lock. - */ - clear_packed_ref_cache(refs); - return 0; + free(data); + transaction->backend_data = NULL; } - /* Write what remains */ - return commit_packed_refs(&refs->base, err); - } - - static int packed_init_db(struct ref_store *ref_store, struct strbuf *err) - { - /* Nothing to do. */ - return 0; + transaction->state = REF_TRANSACTION_CLOSED; } static int packed_transaction_prepare(struct ref_store *ref_store,