@@ -1041,11 +1041,17 @@ static void prune_ref(struct files_ref_store *refs, struct ref_to_prune *r)
1041
1041
strbuf_release (& err );
1042
1042
}
1043
1043
1044
- static void prune_refs (struct files_ref_store * refs , struct ref_to_prune * r )
1044
+ /*
1045
+ * Prune the loose versions of the references in the linked list
1046
+ * `*refs_to_prune`, freeing the entries in the list as we go.
1047
+ */
1048
+ static void prune_refs (struct files_ref_store * refs , struct ref_to_prune * * refs_to_prune )
1045
1049
{
1046
- while (r ) {
1050
+ while (* refs_to_prune ) {
1051
+ struct ref_to_prune * r = * refs_to_prune ;
1052
+ * refs_to_prune = r -> next ;
1047
1053
prune_ref (refs , r );
1048
- r = r -> next ;
1054
+ free ( r ) ;
1049
1055
}
1050
1056
}
1051
1057
@@ -1084,6 +1090,11 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
1084
1090
int ok ;
1085
1091
struct ref_to_prune * refs_to_prune = NULL ;
1086
1092
struct strbuf err = STRBUF_INIT ;
1093
+ struct ref_transaction * transaction ;
1094
+
1095
+ transaction = ref_store_transaction_begin (refs -> packed_ref_store , & err );
1096
+ if (!transaction )
1097
+ return -1 ;
1087
1098
1088
1099
packed_refs_lock (refs -> packed_ref_store , LOCK_DIE_ON_ERROR , & err );
1089
1100
@@ -1099,12 +1110,14 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
1099
1110
continue ;
1100
1111
1101
1112
/*
1102
- * Create an entry in the packed-refs cache equivalent
1103
- * to the one from the loose ref cache, except that
1104
- * we don't copy the peeled status, because we want it
1105
- * to be re-peeled.
1113
+ * Add a reference creation for this reference to the
1114
+ * packed-refs transaction:
1106
1115
*/
1107
- add_packed_ref (refs -> packed_ref_store , iter -> refname , iter -> oid );
1116
+ if (ref_transaction_update (transaction , iter -> refname ,
1117
+ iter -> oid -> hash , NULL ,
1118
+ REF_NODEREF , NULL , & err ))
1119
+ die ("failure preparing to create packed reference %s: %s" ,
1120
+ iter -> refname , err .buf );
1108
1121
1109
1122
/* Schedule the loose reference for pruning if requested. */
1110
1123
if ((flags & PACK_REFS_PRUNE )) {
@@ -1118,11 +1131,14 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
1118
1131
if (ok != ITER_DONE )
1119
1132
die ("error while iterating over references" );
1120
1133
1121
- if (commit_packed_refs (refs -> packed_ref_store , & err ))
1122
- die ("unable to overwrite old ref-pack file: %s" , err .buf );
1134
+ if (ref_transaction_commit (transaction , & err ))
1135
+ die ("unable to write new packed-refs: %s" , err .buf );
1136
+
1137
+ ref_transaction_free (transaction );
1138
+
1123
1139
packed_refs_unlock (refs -> packed_ref_store );
1124
1140
1125
- prune_refs (refs , refs_to_prune );
1141
+ prune_refs (refs , & refs_to_prune );
1126
1142
strbuf_release (& err );
1127
1143
return 0 ;
1128
1144
}
@@ -1141,7 +1157,7 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
1141
1157
if (packed_refs_lock (refs -> packed_ref_store , 0 , & err ))
1142
1158
goto error ;
1143
1159
1144
- if (repack_without_refs (refs -> packed_ref_store , refnames , & err )) {
1160
+ if (refs_delete_refs (refs -> packed_ref_store , msg , refnames , flags )) {
1145
1161
packed_refs_unlock (refs -> packed_ref_store );
1146
1162
goto error ;
1147
1163
}
@@ -2431,13 +2447,22 @@ static int lock_ref_for_update(struct files_ref_store *refs,
2431
2447
return ret ;
2432
2448
}
2433
2449
2450
+ struct files_transaction_backend_data {
2451
+ struct ref_transaction * packed_transaction ;
2452
+ int packed_refs_locked ;
2453
+ };
2454
+
2434
2455
/*
2435
2456
* Unlock any references in `transaction` that are still locked, and
2436
2457
* mark the transaction closed.
2437
2458
*/
2438
- static void files_transaction_cleanup (struct ref_transaction * transaction )
2459
+ static void files_transaction_cleanup (struct files_ref_store * refs ,
2460
+ struct ref_transaction * transaction )
2439
2461
{
2440
2462
size_t i ;
2463
+ struct files_transaction_backend_data * backend_data =
2464
+ transaction -> backend_data ;
2465
+ struct strbuf err = STRBUF_INIT ;
2441
2466
2442
2467
for (i = 0 ; i < transaction -> nr ; i ++ ) {
2443
2468
struct ref_update * update = transaction -> updates [i ];
@@ -2449,6 +2474,17 @@ static void files_transaction_cleanup(struct ref_transaction *transaction)
2449
2474
}
2450
2475
}
2451
2476
2477
+ if (backend_data -> packed_transaction &&
2478
+ ref_transaction_abort (backend_data -> packed_transaction , & err )) {
2479
+ error ("error aborting transaction: %s" , err .buf );
2480
+ strbuf_release (& err );
2481
+ }
2482
+
2483
+ if (backend_data -> packed_refs_locked )
2484
+ packed_refs_unlock (refs -> packed_ref_store );
2485
+
2486
+ free (backend_data );
2487
+
2452
2488
transaction -> state = REF_TRANSACTION_CLOSED ;
2453
2489
}
2454
2490
@@ -2465,12 +2501,17 @@ static int files_transaction_prepare(struct ref_store *ref_store,
2465
2501
char * head_ref = NULL ;
2466
2502
int head_type ;
2467
2503
struct object_id head_oid ;
2504
+ struct files_transaction_backend_data * backend_data ;
2505
+ struct ref_transaction * packed_transaction = NULL ;
2468
2506
2469
2507
assert (err );
2470
2508
2471
2509
if (!transaction -> nr )
2472
2510
goto cleanup ;
2473
2511
2512
+ backend_data = xcalloc (1 , sizeof (* backend_data ));
2513
+ transaction -> backend_data = backend_data ;
2514
+
2474
2515
/*
2475
2516
* Fail if a refname appears more than once in the
2476
2517
* transaction. (If we end up splitting up any updates using
@@ -2537,14 +2578,49 @@ static int files_transaction_prepare(struct ref_store *ref_store,
2537
2578
head_ref , & affected_refnames , err );
2538
2579
if (ret )
2539
2580
break ;
2581
+
2582
+ if (update -> flags & REF_DELETING &&
2583
+ !(update -> flags & REF_LOG_ONLY ) &&
2584
+ !(update -> flags & REF_ISPRUNING )) {
2585
+ /*
2586
+ * This reference has to be deleted from
2587
+ * packed-refs if it exists there.
2588
+ */
2589
+ if (!packed_transaction ) {
2590
+ packed_transaction = ref_store_transaction_begin (
2591
+ refs -> packed_ref_store , err );
2592
+ if (!packed_transaction ) {
2593
+ ret = TRANSACTION_GENERIC_ERROR ;
2594
+ goto cleanup ;
2595
+ }
2596
+
2597
+ backend_data -> packed_transaction =
2598
+ packed_transaction ;
2599
+ }
2600
+
2601
+ ref_transaction_add_update (
2602
+ packed_transaction , update -> refname ,
2603
+ update -> flags & ~REF_HAVE_OLD ,
2604
+ update -> new_oid .hash , update -> old_oid .hash ,
2605
+ NULL );
2606
+ }
2607
+ }
2608
+
2609
+ if (packed_transaction ) {
2610
+ if (packed_refs_lock (refs -> packed_ref_store , 0 , err )) {
2611
+ ret = TRANSACTION_GENERIC_ERROR ;
2612
+ goto cleanup ;
2613
+ }
2614
+ backend_data -> packed_refs_locked = 1 ;
2615
+ ret = ref_transaction_prepare (packed_transaction , err );
2540
2616
}
2541
2617
2542
2618
cleanup :
2543
2619
free (head_ref );
2544
2620
string_list_clear (& affected_refnames , 0 );
2545
2621
2546
2622
if (ret )
2547
- files_transaction_cleanup (transaction );
2623
+ files_transaction_cleanup (refs , transaction );
2548
2624
else
2549
2625
transaction -> state = REF_TRANSACTION_PREPARED ;
2550
2626
@@ -2559,9 +2635,10 @@ static int files_transaction_finish(struct ref_store *ref_store,
2559
2635
files_downcast (ref_store , 0 , "ref_transaction_finish" );
2560
2636
size_t i ;
2561
2637
int ret = 0 ;
2562
- struct string_list refs_to_delete = STRING_LIST_INIT_NODUP ;
2563
- struct string_list_item * ref_to_delete ;
2564
2638
struct strbuf sb = STRBUF_INIT ;
2639
+ struct files_transaction_backend_data * backend_data ;
2640
+ struct ref_transaction * packed_transaction ;
2641
+
2565
2642
2566
2643
assert (err );
2567
2644
@@ -2570,6 +2647,9 @@ static int files_transaction_finish(struct ref_store *ref_store,
2570
2647
return 0 ;
2571
2648
}
2572
2649
2650
+ backend_data = transaction -> backend_data ;
2651
+ packed_transaction = backend_data -> packed_transaction ;
2652
+
2573
2653
/* Perform updates first so live commits remain referenced */
2574
2654
for (i = 0 ; i < transaction -> nr ; i ++ ) {
2575
2655
struct ref_update * update = transaction -> updates [i ];
@@ -2605,7 +2685,44 @@ static int files_transaction_finish(struct ref_store *ref_store,
2605
2685
}
2606
2686
}
2607
2687
}
2608
- /* Perform deletes now that updates are safely completed */
2688
+
2689
+ /*
2690
+ * Now that updates are safely completed, we can perform
2691
+ * deletes. First delete the reflogs of any references that
2692
+ * will be deleted, since (in the unexpected event of an
2693
+ * error) leaving a reference without a reflog is less bad
2694
+ * than leaving a reflog without a reference (the latter is a
2695
+ * mildly invalid repository state):
2696
+ */
2697
+ for (i = 0 ; i < transaction -> nr ; i ++ ) {
2698
+ struct ref_update * update = transaction -> updates [i ];
2699
+ if (update -> flags & REF_DELETING &&
2700
+ !(update -> flags & REF_LOG_ONLY ) &&
2701
+ !(update -> flags & REF_ISPRUNING )) {
2702
+ strbuf_reset (& sb );
2703
+ files_reflog_path (refs , & sb , update -> refname );
2704
+ if (!unlink_or_warn (sb .buf ))
2705
+ try_remove_empty_parents (refs , update -> refname ,
2706
+ REMOVE_EMPTY_PARENTS_REFLOG );
2707
+ }
2708
+ }
2709
+
2710
+ /*
2711
+ * Perform deletes now that updates are safely completed.
2712
+ *
2713
+ * First delete any packed versions of the references, while
2714
+ * retaining the packed-refs lock:
2715
+ */
2716
+ if (packed_transaction ) {
2717
+ ret = ref_transaction_commit (packed_transaction , err );
2718
+ ref_transaction_free (packed_transaction );
2719
+ packed_transaction = NULL ;
2720
+ backend_data -> packed_transaction = NULL ;
2721
+ if (ret )
2722
+ goto cleanup ;
2723
+ }
2724
+
2725
+ /* Now delete the loose versions of the references: */
2609
2726
for (i = 0 ; i < transaction -> nr ; i ++ ) {
2610
2727
struct ref_update * update = transaction -> updates [i ];
2611
2728
struct ref_lock * lock = update -> backend_data ;
@@ -2623,39 +2740,13 @@ static int files_transaction_finish(struct ref_store *ref_store,
2623
2740
}
2624
2741
update -> flags |= REF_DELETED_LOOSE ;
2625
2742
}
2626
-
2627
- if (!(update -> flags & REF_ISPRUNING ))
2628
- string_list_append (& refs_to_delete ,
2629
- lock -> ref_name );
2630
2743
}
2631
2744
}
2632
2745
2633
- if (packed_refs_lock (refs -> packed_ref_store , 0 , err )) {
2634
- ret = TRANSACTION_GENERIC_ERROR ;
2635
- goto cleanup ;
2636
- }
2637
-
2638
- if (repack_without_refs (refs -> packed_ref_store , & refs_to_delete , err )) {
2639
- ret = TRANSACTION_GENERIC_ERROR ;
2640
- packed_refs_unlock (refs -> packed_ref_store );
2641
- goto cleanup ;
2642
- }
2643
-
2644
- packed_refs_unlock (refs -> packed_ref_store );
2645
-
2646
- /* Delete the reflogs of any references that were deleted: */
2647
- for_each_string_list_item (ref_to_delete , & refs_to_delete ) {
2648
- strbuf_reset (& sb );
2649
- files_reflog_path (refs , & sb , ref_to_delete -> string );
2650
- if (!unlink_or_warn (sb .buf ))
2651
- try_remove_empty_parents (refs , ref_to_delete -> string ,
2652
- REMOVE_EMPTY_PARENTS_REFLOG );
2653
- }
2654
-
2655
2746
clear_loose_ref_cache (refs );
2656
2747
2657
2748
cleanup :
2658
- files_transaction_cleanup (transaction );
2749
+ files_transaction_cleanup (refs , transaction );
2659
2750
2660
2751
for (i = 0 ; i < transaction -> nr ; i ++ ) {
2661
2752
struct ref_update * update = transaction -> updates [i ];
@@ -2673,15 +2764,17 @@ static int files_transaction_finish(struct ref_store *ref_store,
2673
2764
}
2674
2765
2675
2766
strbuf_release (& sb );
2676
- string_list_clear (& refs_to_delete , 0 );
2677
2767
return ret ;
2678
2768
}
2679
2769
2680
2770
static int files_transaction_abort (struct ref_store * ref_store ,
2681
2771
struct ref_transaction * transaction ,
2682
2772
struct strbuf * err )
2683
2773
{
2684
- files_transaction_cleanup (transaction );
2774
+ struct files_ref_store * refs =
2775
+ files_downcast (ref_store , 0 , "ref_transaction_abort" );
2776
+
2777
+ files_transaction_cleanup (refs , transaction );
2685
2778
return 0 ;
2686
2779
}
2687
2780
@@ -2703,6 +2796,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
2703
2796
size_t i ;
2704
2797
int ret = 0 ;
2705
2798
struct string_list affected_refnames = STRING_LIST_INIT_NODUP ;
2799
+ struct ref_transaction * packed_transaction = NULL ;
2706
2800
2707
2801
assert (err );
2708
2802
@@ -2735,6 +2829,12 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
2735
2829
& affected_refnames ))
2736
2830
die ("BUG: initial ref transaction called with existing refs" );
2737
2831
2832
+ packed_transaction = ref_store_transaction_begin (refs -> packed_ref_store , err );
2833
+ if (!packed_transaction ) {
2834
+ ret = TRANSACTION_GENERIC_ERROR ;
2835
+ goto cleanup ;
2836
+ }
2837
+
2738
2838
for (i = 0 ; i < transaction -> nr ; i ++ ) {
2739
2839
struct ref_update * update = transaction -> updates [i ];
2740
2840
@@ -2747,28 +2847,30 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
2747
2847
ret = TRANSACTION_NAME_CONFLICT ;
2748
2848
goto cleanup ;
2749
2849
}
2850
+
2851
+ /*
2852
+ * Add a reference creation for this reference to the
2853
+ * packed-refs transaction:
2854
+ */
2855
+ ref_transaction_add_update (packed_transaction , update -> refname ,
2856
+ update -> flags & ~REF_HAVE_OLD ,
2857
+ update -> new_oid .hash , update -> old_oid .hash ,
2858
+ NULL );
2750
2859
}
2751
2860
2752
2861
if (packed_refs_lock (refs -> packed_ref_store , 0 , err )) {
2753
2862
ret = TRANSACTION_GENERIC_ERROR ;
2754
2863
goto cleanup ;
2755
2864
}
2756
2865
2757
- for (i = 0 ; i < transaction -> nr ; i ++ ) {
2758
- struct ref_update * update = transaction -> updates [i ];
2759
-
2760
- if ((update -> flags & REF_HAVE_NEW ) &&
2761
- !is_null_oid (& update -> new_oid ))
2762
- add_packed_ref (refs -> packed_ref_store , update -> refname ,
2763
- & update -> new_oid );
2764
- }
2765
-
2766
- if (commit_packed_refs (refs -> packed_ref_store , err )) {
2866
+ if (initial_ref_transaction_commit (packed_transaction , err )) {
2767
2867
ret = TRANSACTION_GENERIC_ERROR ;
2768
2868
goto cleanup ;
2769
2869
}
2770
2870
2771
2871
cleanup :
2872
+ if (packed_transaction )
2873
+ ref_transaction_free (packed_transaction );
2772
2874
packed_refs_unlock (refs -> packed_ref_store );
2773
2875
transaction -> state = REF_TRANSACTION_CLOSED ;
2774
2876
string_list_clear (& affected_refnames , 0 );
0 commit comments