diff options
author | Matthias Sohn <matthias.sohn@sap.com> | 2019-07-03 01:07:14 +0200 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2019-07-18 03:27:52 +0200 |
commit | 95e8264cc8d2689cec10b58fbf15149856000df4 (patch) | |
tree | 02c5e1673058615c71778b436fd50855b96aed0f /org.eclipse.jgit.junit | |
parent | 4db39f50742706091ee66207526cc801db40b780 (diff) | |
download | jgit-95e8264cc8d2689cec10b58fbf15149856000df4.tar.gz jgit-95e8264cc8d2689cec10b58fbf15149856000df4.zip |
Use Instant instead of milliseconds for filesystem timestamp handling
This enables higher file timestamp resolution on filesystems like ext4,
Mac APFS (1ns) or NTFS (100ns) providing high timestamp resolution on
filesystem level.
Note:
- on some OSes Java 8,9 truncate milliseconds, see
https://bugs.openjdk.java.net/browse/JDK-8177809, fixed in Java 10
- UnixFileAttributes truncates timestamp resolution to microseconds when
converting the internal representation to FileTime exposed in the API,
see https://bugs.openjdk.java.net/browse/JDK-8181493
- WindowsFileAttributes also provides only microsecond resolution
Change-Id: I25ffff31a3c6f725fc345d4ddc2f26da3b88f6f2
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit.junit')
3 files changed, 117 insertions, 12 deletions
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java index 12b2169500..50e6f2da5a 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java @@ -51,6 +51,7 @@ import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -322,12 +323,13 @@ public abstract class LocalDiskRepositoryTestCase { throws IllegalStateException, IOException { DirCache dc = repo.readDirCache(); StringBuilder sb = new StringBuilder(); - TreeSet<Long> timeStamps = new TreeSet<>(); + TreeSet<Instant> timeStamps = new TreeSet<>(); // iterate once over the dircache just to collect all time stamps if (0 != (includedOptions & MOD_TIME)) { - for (int i=0; i<dc.getEntryCount(); ++i) - timeStamps.add(Long.valueOf(dc.getEntry(i).getLastModified())); + for (int i = 0; i < dc.getEntryCount(); ++i) { + timeStamps.add(dc.getEntry(i).getLastModifiedInstant()); + } } // iterate again, now produce the result string @@ -339,7 +341,8 @@ public abstract class LocalDiskRepositoryTestCase { sb.append(", stage:" + stage); if (0 != (includedOptions & MOD_TIME)) { sb.append(", time:t"+ - timeStamps.headSet(Long.valueOf(entry.getLastModified())).size()); + timeStamps.headSet(entry.getLastModifiedInstant()) + .size()); } if (0 != (includedOptions & SMUDGE)) if (entry.isSmudged()) diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java index 987f923b0e..49f5c5febb 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java @@ -57,7 +57,9 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.nio.file.Path; +import java.time.Instant; import java.util.Map; +import java.util.concurrent.TimeUnit; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; @@ -284,7 +286,7 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { dce = new DirCacheEntry(treeItr.getEntryPathString()); dce.setFileMode(treeItr.getEntryFileMode()); - dce.setLastModified(treeItr.getEntryLastModified()); + dce.setLastModified(treeItr.getEntryLastModifiedInstant()); dce.setLength((int) len); try (FileInputStream in = new FileInputStream( treeItr.getEntryFile())) { @@ -361,7 +363,8 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * @throws InterruptedException * @throws IOException */ - public static long fsTick(File lastFile) throws InterruptedException, + public static Instant fsTick(File lastFile) + throws InterruptedException, IOException { File tmp; FS fs = FS.DETECTED; @@ -375,15 +378,15 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { tmp = File.createTempFile("fsTickTmpFile", null, lastFile.getParentFile()); } - long res = FS.getFsTimerResolution(tmp.toPath()).toMillis(); + long res = FS.getFsTimerResolution(tmp.toPath()).toNanos(); long sleepTime = res / 10; try { - long startTime = fs.lastModified(lastFile); - long actTime = fs.lastModified(tmp); - while (actTime <= startTime) { - Thread.sleep(sleepTime); + Instant startTime = fs.lastModifiedInstant(lastFile); + Instant actTime = fs.lastModifiedInstant(tmp); + while (actTime.compareTo(startTime) <= 0) { + TimeUnit.NANOSECONDS.sleep(sleepTime); FileUtils.touch(tmp.toPath()); - actTime = fs.lastModified(tmp); + actTime = fs.lastModifiedInstant(tmp); } return actTime; } finally { diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/TimeUtil.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/TimeUtil.java new file mode 100644 index 0000000000..1f8070d919 --- /dev/null +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/TimeUtil.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2019, Matthias Sohn <matthias.sohn@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.junit.time; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileTime; +import java.time.Instant; + +import org.eclipse.jgit.util.FS; + +/** + * Utility methods for handling timestamps + */ +public class TimeUtil { + /** + * Set the lastModified time of a given file by adding a given offset to the + * current lastModified time + * + * @param path + * path of a file to set last modified + * @param offsetMillis + * offset in milliseconds, if negative the new lastModified time + * is offset before the original lastModified time, otherwise + * after the original time + * @return the new lastModified time + */ + public static Instant setLastModifiedWithOffset(Path path, + long offsetMillis) { + Instant mTime = FS.DETECTED.lastModifiedInstant(path) + .plusMillis(offsetMillis); + try { + Files.setLastModifiedTime(path, FileTime.from(mTime)); + return mTime; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Set the lastModified time of file a to the one from file b + * + * @param a + * file to set lastModified time + * @param b + * file to read lastModified time from + */ + public static void setLastModifiedOf(Path a, Path b) { + Instant mTime = FS.DETECTED.lastModifiedInstant(b); + try { + Files.setLastModifiedTime(a, FileTime.from(mTime)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + +} |