|
10 | 10 | * Copyright (c) 2006 Shawn O. Pearce
|
11 | 11 | */
|
12 | 12 | #define USE_THE_REPOSITORY_VARIABLE
|
| 13 | +#include "git-compat-util.h" |
13 | 14 | #include "builtin.h"
|
14 | 15 | #include "abspath.h"
|
15 | 16 | #include "date.h"
|
|
41 | 42 | #include "hook.h"
|
42 | 43 | #include "setup.h"
|
43 | 44 | #include "trace2.h"
|
| 45 | +#include "copy.h" |
| 46 | +#include "dir.h" |
44 | 47 |
|
45 | 48 | #define FAILED_RUN "failed to run %s"
|
46 | 49 |
|
| 50 | +#define DEBUG_WAIT { \ |
| 51 | + struct stat st; \ |
| 52 | + while (!stat("D:/tmp/debug", &st)) { \ |
| 53 | + fprintf(stderr, "[%d] Waiting to attach...\n", getpid()); \ |
| 54 | + sleep(5); \ |
| 55 | + } \ |
| 56 | +} |
| 57 | + |
47 | 58 | static const char * const builtin_gc_usage[] = {
|
48 | 59 | N_("git gc [<options>]"),
|
49 | 60 | NULL
|
@@ -1347,6 +1358,132 @@ static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts
|
1347 | 1358 | return 0;
|
1348 | 1359 | }
|
1349 | 1360 |
|
| 1361 | +static void link_or_copy_or_die(const char *src, const char *dst) |
| 1362 | +{ |
| 1363 | + if (!link(src, dst)) |
| 1364 | + return; |
| 1365 | + |
| 1366 | + warning_errno(_("failed to link '%s' to '%s'"), src, dst); |
| 1367 | + |
| 1368 | + if (!copy_file(dst, src, 0644)) |
| 1369 | + return; |
| 1370 | + |
| 1371 | + die_errno(_("failed to copy '%s' to '%s'"), src, dst); |
| 1372 | +} |
| 1373 | + |
| 1374 | +static void migrate_pack(const char *srcdir, const char *dstdir, |
| 1375 | + const char *pack_filename) |
| 1376 | +{ |
| 1377 | + struct stat st; |
| 1378 | + int has_keep, has_rev, has_idx; |
| 1379 | + char *basename, *pack_src, *keep_src, *rev_src, *idx_src, |
| 1380 | + *pack_dst, *keep_dst, *rev_dst, *idx_dst; |
| 1381 | + |
| 1382 | + trace2_region_enter("maintenance", "migrate_pack", the_repository); |
| 1383 | + |
| 1384 | + basename = xstrndup(pack_filename, strlen(pack_filename) - 5 /*.pack*/); |
| 1385 | + pack_src = xstrfmt("%s/%s", srcdir, pack_filename); |
| 1386 | + pack_dst = xstrfmt("%s/%s", dstdir, pack_filename); |
| 1387 | + keep_src = xstrfmt("%s/%s.keep", srcdir, basename); |
| 1388 | + keep_dst = xstrfmt("%s/%s.keep", dstdir, basename); |
| 1389 | + rev_src = xstrfmt("%s/%s.rev", srcdir, basename); |
| 1390 | + rev_dst = xstrfmt("%s/%s.rev", dstdir, basename); |
| 1391 | + idx_src = xstrfmt("%s/%s.idx", srcdir, basename); |
| 1392 | + idx_dst = xstrfmt("%s/%s.idx", dstdir, basename); |
| 1393 | + |
| 1394 | + has_keep = !stat(keep_src, &st); |
| 1395 | + has_rev = !stat(rev_src, &st); |
| 1396 | + has_idx = !stat(idx_src, &st); |
| 1397 | + |
| 1398 | + /* A pack without an index file is not yet ready to be migrated. */ |
| 1399 | + if (!has_idx) |
| 1400 | + goto cleanup; |
| 1401 | + |
| 1402 | + /* |
| 1403 | + * Hard link (or copy if that fails) all but the index file so that |
| 1404 | + * other Git processes don't attempt to use the pack file from the new |
| 1405 | + * location yet. |
| 1406 | + */ |
| 1407 | + link_or_copy_or_die(pack_src, pack_dst); |
| 1408 | + if (has_keep) |
| 1409 | + link_or_copy_or_die(keep_src, keep_dst); |
| 1410 | + if (has_rev) |
| 1411 | + link_or_copy_or_die(rev_src, rev_dst); |
| 1412 | + |
| 1413 | + /* |
| 1414 | + * Move the index file atomically now that the other files can be found |
| 1415 | + * at the destination. |
| 1416 | + */ |
| 1417 | + if (rename(idx_src, idx_dst)) |
| 1418 | + die_errno(_("failed to move '%s' to '%s'"), idx_src, idx_dst); |
| 1419 | + |
| 1420 | + /* |
| 1421 | + * Now the pack and all associated files exist at the destination we can |
| 1422 | + * now clean up the files in the source directory. |
| 1423 | + */ |
| 1424 | + if (unlink(pack_src)) |
| 1425 | + warning_errno(_("failed to delete '%s'"), pack_src); |
| 1426 | + if (has_keep && unlink(keep_src)) |
| 1427 | + warning_errno(_("failed to delete '%s'"), keep_src); |
| 1428 | + if (has_rev & unlink(rev_src)) |
| 1429 | + warning_errno(_("failed to delete '%s'"), rev_src); |
| 1430 | + |
| 1431 | +cleanup: |
| 1432 | + free(idx_src); |
| 1433 | + free(idx_dst); |
| 1434 | + free(rev_src); |
| 1435 | + free(rev_dst); |
| 1436 | + free(keep_src); |
| 1437 | + free(keep_dst); |
| 1438 | + free(pack_src); |
| 1439 | + free(pack_dst); |
| 1440 | + free(basename); |
| 1441 | + |
| 1442 | + trace2_region_leave("maintenance", "migrate_pack", the_repository); |
| 1443 | +} |
| 1444 | + |
| 1445 | +static void move_pack_to_vfs_cache(const char *full_path, size_t full_path_len, |
| 1446 | + const char *file_name, UNUSED void *data) |
| 1447 | +{ |
| 1448 | + char *srcdir; |
| 1449 | + struct strbuf dstdir = STRBUF_INIT; |
| 1450 | + |
| 1451 | + /* We only care about the actual pack files here. |
| 1452 | + * The associated .idx, .keep, .rev files will be copied in tandem |
| 1453 | + * with the pack file, with the index file being moved last. |
| 1454 | + * The original locations of the non-index files will only deleted |
| 1455 | + * once all other files have been copied/moved. |
| 1456 | + */ |
| 1457 | + if (!ends_with(file_name, ".pack")) |
| 1458 | + return; |
| 1459 | + |
| 1460 | + srcdir = xstrndup(full_path, full_path_len - strlen(file_name) - 1); |
| 1461 | + |
| 1462 | + /* No cache or same source + desintation means there's no work to do. */ |
| 1463 | + if (!vfs_object_dir || !fspathcmp(srcdir, vfs_object_dir)) |
| 1464 | + return; |
| 1465 | + |
| 1466 | + strbuf_addf(&dstdir, "%s/pack", vfs_object_dir); |
| 1467 | + |
| 1468 | + migrate_pack(srcdir, dstdir.buf, file_name); |
| 1469 | + |
| 1470 | + free(srcdir); |
| 1471 | + strbuf_release(&dstdir); |
| 1472 | +} |
| 1473 | + |
| 1474 | +static int maintenance_task_vfs_cache_move(UNUSED struct maintenance_run_opts *opts, |
| 1475 | + UNUSED struct gc_config *cfg) |
| 1476 | +{ |
| 1477 | + struct repository *r = the_repository; |
| 1478 | + |
| 1479 | + DEBUG_WAIT |
| 1480 | + |
| 1481 | + for_each_file_in_pack_dir(r->objects->odb->path, move_pack_to_vfs_cache, |
| 1482 | + NULL); |
| 1483 | + |
| 1484 | + return 0; |
| 1485 | +} |
| 1486 | + |
1350 | 1487 | typedef int maintenance_task_fn(struct maintenance_run_opts *opts,
|
1351 | 1488 | struct gc_config *cfg);
|
1352 | 1489 |
|
@@ -1376,6 +1513,7 @@ enum maintenance_task_label {
|
1376 | 1513 | TASK_GC,
|
1377 | 1514 | TASK_COMMIT_GRAPH,
|
1378 | 1515 | TASK_PACK_REFS,
|
| 1516 | + TASK_VFS_CACHE_MOVE, |
1379 | 1517 |
|
1380 | 1518 | /* Leave as final value */
|
1381 | 1519 | TASK__COUNT
|
@@ -1412,6 +1550,10 @@ static struct maintenance_task tasks[] = {
|
1412 | 1550 | maintenance_task_pack_refs,
|
1413 | 1551 | pack_refs_condition,
|
1414 | 1552 | },
|
| 1553 | + [TASK_VFS_CACHE_MOVE] = { |
| 1554 | + "vfs-cache-move", |
| 1555 | + maintenance_task_vfs_cache_move, |
| 1556 | + }, |
1415 | 1557 | };
|
1416 | 1558 |
|
1417 | 1559 | static int compare_tasks_by_selection(const void *a_, const void *b_)
|
@@ -1506,6 +1648,8 @@ static void initialize_maintenance_strategy(void)
|
1506 | 1648 | tasks[TASK_LOOSE_OBJECTS].schedule = SCHEDULE_DAILY;
|
1507 | 1649 | tasks[TASK_PACK_REFS].enabled = 1;
|
1508 | 1650 | tasks[TASK_PACK_REFS].schedule = SCHEDULE_WEEKLY;
|
| 1651 | + tasks[TASK_VFS_CACHE_MOVE].enabled = 1; |
| 1652 | + tasks[TASK_VFS_CACHE_MOVE].schedule = SCHEDULE_WEEKLY; |
1509 | 1653 | }
|
1510 | 1654 | }
|
1511 | 1655 |
|
|
0 commit comments