1866
const char *reported_error = NULL;
1867
struct strmap failed_refs = STRMAP_INIT;
1868
1869
- transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
1870
- REF_TRANSACTION_ALLOW_FAILURE, &err);
1871
- if (!transaction) {
1872
- rp_error("%s", err.buf);
1873
- strbuf_reset(&err);
1874
- reported_error = "transaction failed to start";
1875
- goto failure;
1876
- }
1869
+ /*
1870
+ * Reference updates, where D/F conflicts shouldn't arise due to
1871
+ * one reference being deleted, while the other being created
1872
+ * are treated as conflicts in batched updates. This is because
1873
+ * we don't do conflict resolution inside a transaction. To
1874
+ * mitigate this, delete references in a separate batch.
1875
+ *
1876
+ * NEEDSWORK: Add conflict resolution between deletion and creation
1877
+ * of reference updates within a transaction. With that, we can
1878
+ * combine the two phases.
1879
+ */
1880
+ enum processing_phase {
1881
+ PHASE_DELETIONS,
1882
+ PHASE_OTHERS
1883
+ };
1884
1878
- for (cmd = commands; cmd; cmd = cmd->next) {
1879
- if (!should_process_cmd(cmd) || cmd->run_proc_receive)
1880
- continue;
1885
+ for (enum processing_phase phase = PHASE_DELETIONS; phase <= PHASE_OTHERS; phase++) {
1886
+ for (cmd = commands; cmd; cmd = cmd->next) {
1887
+ if (!should_process_cmd(cmd) || cmd->run_proc_receive)
1888
+ continue;
1889
1882
- cmd->error_string = update(cmd, si);
1883
- }
1890
+ if (phase == PHASE_DELETIONS && !is_null_oid(&cmd->new_oid))
1891
+ continue;
1892
+ else if (phase == PHASE_OTHERS && is_null_oid(&cmd->new_oid))
1893
+ continue;
1894
1885
- if (ref_transaction_commit(transaction, &err)) {
1886
- rp_error("%s", err.buf);
1887
- reported_error = "failed to update refs";
1888
- goto failure;
1889
- }
1895
+ /*
1896
+ * Lazily create a transaction only when we know there are
1897
+ * updates to be added.
1898
+ */
1899
+ if (!transaction) {
1900
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
1901
+ REF_TRANSACTION_ALLOW_FAILURE, &err);
1902
+ if (!transaction) {
1903
+ rp_error("%s", err.buf);
1904
+ strbuf_reset(&err);
1905
+ reported_error = "transaction failed to start";
1906
+ goto failure;
1907
+ }
1908
+ }
1909
1891
- ref_transaction_for_each_rejected_update(transaction,
1892
- ref_transaction_rejection_handler,
1893
- &failed_refs);
1910
+ cmd->error_string = update(cmd, si);
1911
+ }
1912
1895
- if (strmap_empty(&failed_refs))
1896
- goto cleanup;
1913
+ /* No transaction, so nothing to commit */
1914
+ if (!transaction)
1915
+ goto cleanup;
1916
1898
-failure:
1899
- for (cmd = commands; cmd; cmd = cmd->next) {
1900
- if (reported_error)
1901
- cmd->error_string = reported_error;
1902
- else if (strmap_contains(&failed_refs, cmd->ref_name))
1903
- cmd->error_string = strmap_get(&failed_refs, cmd->ref_name);
1904
- }
1917
+ if (ref_transaction_commit(transaction, &err)) {
1918
+ rp_error("%s", err.buf);
1919
+ reported_error = "failed to update refs";
1920
+ goto failure;
1921
+ }
1922
1906
-cleanup:
1907
- ref_transaction_free(transaction);
1908
- strmap_clear(&failed_refs, 0);
1909
- strbuf_release(&err);
1923
+ ref_transaction_for_each_rejected_update(transaction,
1924
+ ref_transaction_rejection_handler,
1925
+ &failed_refs);
1926
+
1927
+ if (strmap_empty(&failed_refs))
1928
+ goto cleanup;
1929
+
1930
+ failure:
1931
+ for (cmd = commands; cmd; cmd = cmd->next) {
1932
+ if (reported_error)
1933
+ cmd->error_string = reported_error;
1934
+ else if (strmap_contains(&failed_refs, cmd->ref_name))
1935
+ cmd->error_string = strmap_get(&failed_refs, cmd->ref_name);
1936
+ }
1937
+
1938
+ cleanup:
1939
+ ref_transaction_free(transaction);
1940
+ transaction = NULL;
1941
+ strmap_clear(&failed_refs, 0);
1942
+ strbuf_release(&err);
1943
+ }
1944
}
1945
1946
static void execute_commands_atomic(struct command *commands,