|
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"
|
@@ -1345,6 +1346,155 @@ static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts
|
1345 | 1346 | return 0;
|
1346 | 1347 | }
|
1347 | 1348 |
|
| 1349 | + |
| 1350 | +static void copy_file(const char *srcdir, const char *dstdir, const char *name) |
| 1351 | +{ |
| 1352 | + int ret = 0; |
| 1353 | + struct strbuf src = STRBUF_INIT, dst = STRBUF_INIT; |
| 1354 | + int srcfd = -1, dstfd = -1; |
| 1355 | + char buf[1024]; |
| 1356 | + ssize_t nr; |
| 1357 | + |
| 1358 | + strbuf_addf(&src, "%s/%s", srcdir, name); |
| 1359 | + strbuf_addf(&dst, "%s/%s", dstdir, name); |
| 1360 | + |
| 1361 | + srcfd = open(src.buf, O_RDONLY); |
| 1362 | + if (srcfd < 0) { |
| 1363 | + error("failed to open source file"); |
| 1364 | + ret = 1; |
| 1365 | + goto cleanup; |
| 1366 | + } |
| 1367 | + |
| 1368 | + dstfd = open(dst.buf, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
| 1369 | + if (dstfd < 0) { |
| 1370 | + error("failed to open destination file"); |
| 1371 | + ret = 1; |
| 1372 | + goto cleanup; |
| 1373 | + } |
| 1374 | + |
| 1375 | + while ((nr = read(srcfd, buf, sizeof(buf))) > 0) { |
| 1376 | + if (write(dstfd, buf, nr) < 0) { |
| 1377 | + error("failed to write to destination file"); |
| 1378 | + ret = 1; |
| 1379 | + } |
| 1380 | + } |
| 1381 | + |
| 1382 | +cleanup: |
| 1383 | + if (srcfd >= 0) close(srcfd); |
| 1384 | + if (dstfd >= 0) close(dstfd); |
| 1385 | + |
| 1386 | + if (ret) |
| 1387 | + die_errno(_("failed to copy '%s' to '%s'"), src.buf, dst.buf); |
| 1388 | + |
| 1389 | + strbuf_release(&src); |
| 1390 | + strbuf_release(&dst); |
| 1391 | +} |
| 1392 | + |
| 1393 | +static void move_file(const char *srcdir, const char *dstdir, const char *name) |
| 1394 | +{ |
| 1395 | + struct strbuf src = STRBUF_INIT, dst = STRBUF_INIT; |
| 1396 | + |
| 1397 | + strbuf_addf(&src, "%s/%s", srcdir, name); |
| 1398 | + strbuf_addf(&dst, "%s/%s", dstdir, name); |
| 1399 | + |
| 1400 | + if (rename(src.buf, dst.buf)) |
| 1401 | + die_errno(_("failed to move '%s' to '%s'"), src.buf, dst.buf); |
| 1402 | + |
| 1403 | + strbuf_release(&src); |
| 1404 | + strbuf_release(&dst); |
| 1405 | +} |
| 1406 | + |
| 1407 | +static void delete_file(const char *dir, const char *name) |
| 1408 | +{ |
| 1409 | + struct strbuf path = STRBUF_INIT; |
| 1410 | + |
| 1411 | + strbuf_addf(&path, "%s/%s", dir, name); |
| 1412 | + |
| 1413 | + if (unlink(path.buf)) |
| 1414 | + warning_errno(_("failed to delete '%s'"), path.buf); |
| 1415 | + |
| 1416 | + strbuf_release(&path); |
| 1417 | +} |
| 1418 | + |
| 1419 | +static void migrate_pack(const char *srcdir, const char *dstdir, |
| 1420 | + const char *pack_filename) |
| 1421 | +{ |
| 1422 | + struct strbuf path = STRBUF_INIT; |
| 1423 | + struct stat st; |
| 1424 | + char *basename, *keep_filename, *rev_filename, *idx_filename; |
| 1425 | + int has_keep, has_rev; |
| 1426 | + |
| 1427 | + basename = xstrndup(pack_filename, strlen(pack_filename) - 5 /*.pack*/); |
| 1428 | + keep_filename = xstrfmt("%s.keep", basename); |
| 1429 | + rev_filename = xstrfmt("%s.rev", basename); |
| 1430 | + idx_filename = xstrfmt("%s.idx", basename); |
| 1431 | + |
| 1432 | + strbuf_addf(&path, "%s/%s", srcdir, keep_filename); |
| 1433 | + has_keep = !stat(path.buf, &st); |
| 1434 | + strbuf_reset(&path); |
| 1435 | + strbuf_addf(&path, "%s/%s", srcdir, rev_filename); |
| 1436 | + has_rev = !stat(path.buf, &st); |
| 1437 | + strbuf_release(&path); |
| 1438 | + |
| 1439 | + /* Copy all but the index file, which we will *move* atomically */ |
| 1440 | + copy_file(srcdir, dstdir, pack_filename); |
| 1441 | + if (has_keep) copy_file(srcdir, dstdir, keep_filename); |
| 1442 | + if (has_rev) copy_file(srcdir, dstdir, rev_filename); |
| 1443 | + move_file(srcdir, dstdir, idx_filename); |
| 1444 | + |
| 1445 | + /* |
| 1446 | + * Now the pack and associated files exist at the destination we |
| 1447 | + * we can now clean up files in the source directory. |
| 1448 | + */ |
| 1449 | + delete_file(srcdir, pack_filename); |
| 1450 | + if (has_keep) delete_file(srcdir, keep_filename); |
| 1451 | + if (has_rev) delete_file(srcdir, rev_filename); |
| 1452 | + |
| 1453 | + free(idx_filename); |
| 1454 | + free(keep_filename); |
| 1455 | + free(rev_filename); |
| 1456 | +} |
| 1457 | + |
| 1458 | +static void move_pack_to_vfs_cache(const char *full_path, size_t full_path_len, |
| 1459 | + const char *file_name, UNUSED void *data) |
| 1460 | +{ |
| 1461 | + char *srcdir; |
| 1462 | + struct strbuf dstdir = STRBUF_INIT; |
| 1463 | + |
| 1464 | + /* We only care about the actual pack files here. |
| 1465 | + * The associated .idx, .keep, .rev files will be copied in tandem |
| 1466 | + * with the pack file, with the index file being moved last. |
| 1467 | + * The original locations of the non-index files will only deleted |
| 1468 | + * once all other files have been copied/moved. |
| 1469 | + */ |
| 1470 | + if (!ends_with(file_name, ".pack")) |
| 1471 | + return; |
| 1472 | + |
| 1473 | + srcdir = xstrndup(full_path, full_path_len - strlen(file_name) - 1); |
| 1474 | + |
| 1475 | + /* No cache or same source + desintation means there's no work to do. */ |
| 1476 | + if (!object_dir || !fspathcmp(srcdir, object_dir)) |
| 1477 | + return; |
| 1478 | + |
| 1479 | + strbuf_addf(&dstdir, "%s/pack", object_dir); |
| 1480 | + |
| 1481 | + migrate_pack(srcdir, dstdir.buf, file_name); |
| 1482 | + |
| 1483 | + free(srcdir); |
| 1484 | + strbuf_release(&dstdir); |
| 1485 | +} |
| 1486 | + |
| 1487 | +static int maintenance_task_vfs_cache_move(UNUSED struct maintenance_run_opts *opts, |
| 1488 | + UNUSED struct gc_config *cfg) |
| 1489 | +{ |
| 1490 | + struct repository *r = the_repository; |
| 1491 | + |
| 1492 | + for_each_file_in_pack_dir(r->objects->odb->path, move_pack_to_vfs_cache, |
| 1493 | + NULL); |
| 1494 | + |
| 1495 | + return 0; |
| 1496 | +} |
| 1497 | + |
1348 | 1498 | typedef int maintenance_task_fn(struct maintenance_run_opts *opts,
|
1349 | 1499 | struct gc_config *cfg);
|
1350 | 1500 |
|
@@ -1374,6 +1524,7 @@ enum maintenance_task_label {
|
1374 | 1524 | TASK_GC,
|
1375 | 1525 | TASK_COMMIT_GRAPH,
|
1376 | 1526 | TASK_PACK_REFS,
|
| 1527 | + TASK_VFS_CACHE_MOVE, |
1377 | 1528 |
|
1378 | 1529 | /* Leave as final value */
|
1379 | 1530 | TASK__COUNT
|
@@ -1410,6 +1561,10 @@ static struct maintenance_task tasks[] = {
|
1410 | 1561 | maintenance_task_pack_refs,
|
1411 | 1562 | pack_refs_condition,
|
1412 | 1563 | },
|
| 1564 | + [TASK_VFS_CACHE_MOVE] = { |
| 1565 | + "vfs-cache-move", |
| 1566 | + maintenance_task_vfs_cache_move, |
| 1567 | + }, |
1413 | 1568 | };
|
1414 | 1569 |
|
1415 | 1570 | static int compare_tasks_by_selection(const void *a_, const void *b_)
|
@@ -1504,6 +1659,8 @@ static void initialize_maintenance_strategy(void)
|
1504 | 1659 | tasks[TASK_LOOSE_OBJECTS].schedule = SCHEDULE_DAILY;
|
1505 | 1660 | tasks[TASK_PACK_REFS].enabled = 1;
|
1506 | 1661 | tasks[TASK_PACK_REFS].schedule = SCHEDULE_WEEKLY;
|
| 1662 | + tasks[TASK_VFS_CACHE_MOVE].enabled = 1; |
| 1663 | + tasks[TASK_VFS_CACHE_MOVE].schedule = SCHEDULE_WEEKLY; |
1507 | 1664 | }
|
1508 | 1665 | }
|
1509 | 1666 |
|
|
0 commit comments