You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GcLog.java 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /*
  2. * Copyright (C) 2017 Two Sigma Open Source and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.internal.storage.file;
  11. import static java.nio.charset.StandardCharsets.UTF_8;
  12. import java.io.File;
  13. import java.io.IOException;
  14. import java.nio.file.Files;
  15. import java.nio.file.NoSuchFileException;
  16. import java.nio.file.attribute.FileTime;
  17. import java.text.ParseException;
  18. import java.time.Instant;
  19. import org.eclipse.jgit.api.errors.JGitInternalException;
  20. import org.eclipse.jgit.lib.ConfigConstants;
  21. import org.eclipse.jgit.util.FileUtils;
  22. import org.eclipse.jgit.util.GitDateParser;
  23. import org.eclipse.jgit.util.SystemReader;
  24. /**
  25. * This class manages the gc.log file for a {@link FileRepository}.
  26. */
  27. class GcLog {
  28. private final FileRepository repo;
  29. private final File logFile;
  30. private final LockFile lock;
  31. private Instant gcLogExpire;
  32. private static final String LOG_EXPIRY_DEFAULT = "1.day.ago"; //$NON-NLS-1$
  33. private boolean nonEmpty = false;
  34. /**
  35. * Construct a GcLog object for a {@link FileRepository}
  36. *
  37. * @param repo
  38. * the repository
  39. */
  40. GcLog(FileRepository repo) {
  41. this.repo = repo;
  42. logFile = new File(repo.getDirectory(), "gc.log"); //$NON-NLS-1$
  43. lock = new LockFile(logFile);
  44. }
  45. private Instant getLogExpiry() throws ParseException {
  46. if (gcLogExpire == null) {
  47. String logExpiryStr = repo.getConfig().getString(
  48. ConfigConstants.CONFIG_GC_SECTION, null,
  49. ConfigConstants.CONFIG_KEY_LOGEXPIRY);
  50. if (logExpiryStr == null) {
  51. logExpiryStr = LOG_EXPIRY_DEFAULT;
  52. }
  53. gcLogExpire = GitDateParser.parse(logExpiryStr, null,
  54. SystemReader.getInstance().getLocale()).toInstant();
  55. }
  56. return gcLogExpire;
  57. }
  58. private boolean autoGcBlockedByOldLockFile() {
  59. try {
  60. FileTime lastModified = Files.getLastModifiedTime(FileUtils.toPath(logFile));
  61. if (lastModified.toInstant().compareTo(getLogExpiry()) > 0) {
  62. // There is an existing log file, which is too recent to ignore
  63. return true;
  64. }
  65. } catch (NoSuchFileException e) {
  66. // No existing log file, OK.
  67. } catch (IOException | ParseException e) {
  68. throw new JGitInternalException(e.getMessage(), e);
  69. }
  70. return false;
  71. }
  72. /**
  73. * Lock the GC log file for updates
  74. *
  75. * @return {@code true} if we hold the lock
  76. */
  77. boolean lock() {
  78. try {
  79. if (!lock.lock()) {
  80. return false;
  81. }
  82. } catch (IOException e) {
  83. throw new JGitInternalException(e.getMessage(), e);
  84. }
  85. if (autoGcBlockedByOldLockFile()) {
  86. lock.unlock();
  87. return false;
  88. }
  89. return true;
  90. }
  91. /**
  92. * Unlock (roll back) the GC log lock
  93. */
  94. void unlock() {
  95. lock.unlock();
  96. }
  97. /**
  98. * Commit changes to the gc log, if there have been any writes. Otherwise,
  99. * just unlock and delete the existing file (if any)
  100. *
  101. * @return true if committing (or unlocking/deleting) succeeds.
  102. */
  103. boolean commit() {
  104. if (nonEmpty) {
  105. return lock.commit();
  106. }
  107. logFile.delete();
  108. lock.unlock();
  109. return true;
  110. }
  111. /**
  112. * Write to the pending gc log. Content will be committed upon a call to
  113. * commit()
  114. *
  115. * @param content
  116. * The content to write
  117. * @throws IOException
  118. */
  119. void write(String content) throws IOException {
  120. if (content.length() > 0) {
  121. nonEmpty = true;
  122. }
  123. lock.write(content.getBytes(UTF_8));
  124. }
  125. }