Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 75e670d

Browse files
authored
Merge pull request #6874 from roberth/packbuilder-interruptible
Make packbuilder interruptible using progress callback
2 parents cb0bf67 + ab1b7ad commit 75e670d

File tree

3 files changed

+46
-17
lines changed

3 files changed

+46
-17
lines changed

include/git2/pack.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ typedef int GIT_CALLBACK(git_packbuilder_progress)(
247247
* @param progress_cb Function to call with progress information during
248248
* pack building. Be aware that this is called inline with pack building
249249
* operations, so performance may be affected.
250+
* When progress_cb returns an error, the pack building process will be
251+
* aborted and the error will be returned from the invoked function.
252+
* `pb` must then be freed.
250253
* @param progress_cb_payload Payload for progress callback.
251254
* @return 0 or an error code
252255
*/

src/libgit2/pack-objects.c

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,9 @@ static int report_delta_progress(
932932
{
933933
int ret;
934934

935+
if (pb->failure)
936+
return pb->failure;
937+
935938
if (pb->progress_cb) {
936939
uint64_t current_time = git_time_monotonic();
937940
uint64_t elapsed = current_time - pb->last_progress_report_time;
@@ -943,8 +946,10 @@ static int report_delta_progress(
943946
GIT_PACKBUILDER_DELTAFICATION,
944947
count, pb->nr_objects, pb->progress_cb_payload);
945948

946-
if (ret)
949+
if (ret) {
950+
pb->failure = ret;
947951
return git_error_set_after_callback(ret);
952+
}
948953
}
949954
}
950955

@@ -976,7 +981,10 @@ static int find_deltas(git_packbuilder *pb, git_pobject **list,
976981
}
977982

978983
pb->nr_deltified += 1;
979-
report_delta_progress(pb, pb->nr_deltified, false);
984+
if ((error = report_delta_progress(pb, pb->nr_deltified, false)) < 0) {
985+
GIT_ASSERT(git_packbuilder__progress_unlock(pb) == 0);
986+
goto on_error;
987+
}
980988

981989
po = *list++;
982990
(*list_size)--;
@@ -1124,6 +1132,10 @@ struct thread_params {
11241132
size_t depth;
11251133
size_t working;
11261134
size_t data_ready;
1135+
1136+
/* A pb->progress_cb can stop the packing process by returning an error.
1137+
When that happens, all threads observe the error and stop voluntarily. */
1138+
bool stopped;
11271139
};
11281140

11291141
static void *threaded_find_deltas(void *arg)
@@ -1133,7 +1145,12 @@ static void *threaded_find_deltas(void *arg)
11331145
while (me->remaining) {
11341146
if (find_deltas(me->pb, me->list, &me->remaining,
11351147
me->window, me->depth) < 0) {
1136-
; /* TODO */
1148+
me->stopped = true;
1149+
GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_lock(me->pb) == 0, NULL);
1150+
me->working = false;
1151+
git_cond_signal(&me->pb->progress_cond);
1152+
GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_unlock(me->pb) == 0, NULL);
1153+
return NULL;
11371154
}
11381155

11391156
GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_lock(me->pb) == 0, NULL);
@@ -1175,8 +1192,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
11751192
pb->nr_threads = git__online_cpus();
11761193

11771194
if (pb->nr_threads <= 1) {
1178-
find_deltas(pb, list, &list_size, window, depth);
1179-
return 0;
1195+
return find_deltas(pb, list, &list_size, window, depth);
11801196
}
11811197

11821198
p = git__mallocarray(pb->nr_threads, sizeof(*p));
@@ -1195,6 +1211,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
11951211
p[i].depth = depth;
11961212
p[i].working = 1;
11971213
p[i].data_ready = 0;
1214+
p[i].stopped = 0;
11981215

11991216
/* try to split chunks on "path" boundaries */
12001217
while (sub_size && sub_size < list_size &&
@@ -1262,7 +1279,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
12621279
(!victim || victim->remaining < p[i].remaining))
12631280
victim = &p[i];
12641281

1265-
if (victim) {
1282+
if (victim && !target->stopped) {
12661283
sub_size = victim->remaining / 2;
12671284
list = victim->list + victim->list_size - sub_size;
12681285
while (sub_size && list[0]->hash &&
@@ -1286,7 +1303,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
12861303
}
12871304
target->list_size = sub_size;
12881305
target->remaining = sub_size;
1289-
target->working = 1;
1306+
target->working = 1; /* even when target->stopped, so that we don't process this thread again */
12901307
GIT_ASSERT(git_packbuilder__progress_unlock(pb) == 0);
12911308

12921309
if (git_mutex_lock(&target->mutex)) {
@@ -1299,7 +1316,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
12991316
git_cond_signal(&target->cond);
13001317
git_mutex_unlock(&target->mutex);
13011318

1302-
if (!sub_size) {
1319+
if (target->stopped || !sub_size) {
13031320
git_thread_join(&target->thread, NULL);
13041321
git_cond_free(&target->cond);
13051322
git_mutex_free(&target->mutex);
@@ -1308,7 +1325,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
13081325
}
13091326

13101327
git__free(p);
1311-
return 0;
1328+
return pb->failure;
13121329
}
13131330

13141331
#else
@@ -1319,6 +1336,7 @@ int git_packbuilder__prepare(git_packbuilder *pb)
13191336
{
13201337
git_pobject **delta_list;
13211338
size_t i, n = 0;
1339+
int error;
13221340

13231341
if (pb->nr_objects == 0 || pb->done)
13241342
return 0; /* nothing to do */
@@ -1327,8 +1345,10 @@ int git_packbuilder__prepare(git_packbuilder *pb)
13271345
* Although we do not report progress during deltafication, we
13281346
* at least report that we are in the deltafication stage
13291347
*/
1330-
if (pb->progress_cb)
1331-
pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload);
1348+
if (pb->progress_cb) {
1349+
if ((error = pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload)) < 0)
1350+
return git_error_set_after_callback(error);
1351+
}
13321352

13331353
delta_list = git__mallocarray(pb->nr_objects, sizeof(*delta_list));
13341354
GIT_ERROR_CHECK_ALLOC(delta_list);
@@ -1345,31 +1365,33 @@ int git_packbuilder__prepare(git_packbuilder *pb)
13451365

13461366
if (n > 1) {
13471367
git__tsort((void **)delta_list, n, type_size_sort);
1348-
if (ll_find_deltas(pb, delta_list, n,
1368+
if ((error = ll_find_deltas(pb, delta_list, n,
13491369
GIT_PACK_WINDOW + 1,
1350-
GIT_PACK_DEPTH) < 0) {
1370+
GIT_PACK_DEPTH)) < 0) {
13511371
git__free(delta_list);
1352-
return -1;
1372+
return error;
13531373
}
13541374
}
13551375

1356-
report_delta_progress(pb, pb->nr_objects, true);
1376+
error = report_delta_progress(pb, pb->nr_objects, true);
13571377

13581378
pb->done = true;
13591379
git__free(delta_list);
1360-
return 0;
1380+
return error;
13611381
}
13621382

1363-
#define PREPARE_PACK if (git_packbuilder__prepare(pb) < 0) { return -1; }
1383+
#define PREPARE_PACK error = git_packbuilder__prepare(pb); if (error < 0) { return error; }
13641384

13651385
int git_packbuilder_foreach(git_packbuilder *pb, int (*cb)(void *buf, size_t size, void *payload), void *payload)
13661386
{
1387+
int error;
13671388
PREPARE_PACK;
13681389
return write_pack(pb, cb, payload);
13691390
}
13701391

13711392
int git_packbuilder__write_buf(git_str *buf, git_packbuilder *pb)
13721393
{
1394+
int error;
13731395
PREPARE_PACK;
13741396

13751397
return write_pack(pb, &write_pack_buf, buf);

src/libgit2/pack-objects.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ struct git_packbuilder {
100100
uint64_t last_progress_report_time;
101101

102102
bool done;
103+
104+
/* A non-zero error code in failure causes all threads to shut themselves
105+
down. Some functions will return this error code. */
106+
volatile int failure;
103107
};
104108

105109
int git_packbuilder__write_buf(git_str *buf, git_packbuilder *pb);

0 commit comments

Comments
 (0)