Skip to content

Commit 80b3824

Browse files
authored
Merge pull request #56 from zonkyio/binary-consistency
#50 implement self-repairing mechanism for cases where binary data is corrupted
2 parents df44535 + 9e493ef commit 80b3824

File tree

2 files changed

+39
-10
lines changed

2 files changed

+39
-10
lines changed

src/main/java/io/zonky/test/db/postgres/embedded/EmbeddedPostgres.java

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,20 @@
4343
import java.util.ArrayList;
4444
import java.util.Arrays;
4545
import java.util.HashMap;
46+
import java.util.HashSet;
4647
import java.util.List;
4748
import java.util.Map;
4849
import java.util.Map.Entry;
4950
import java.util.Objects;
5051
import java.util.Optional;
52+
import java.util.Set;
5153
import java.util.UUID;
5254
import java.util.concurrent.Phaser;
5355
import java.util.concurrent.TimeUnit;
5456
import java.util.concurrent.atomic.AtomicBoolean;
5557
import java.util.concurrent.locks.Lock;
5658
import java.util.concurrent.locks.ReentrantLock;
59+
import java.util.stream.Stream;
5760

5861
import javax.sql.DataSource;
5962

@@ -681,19 +684,31 @@ private static String getArchitecture()
681684
* @param stream A stream with the postgres binaries.
682685
* @param targetDir The directory to extract the content to.
683686
*/
684-
private static void extractTxz(InputStream stream, String targetDir) throws IOException {
687+
private static void extractTxz(InputStream stream, File targetDir) throws IOException {
685688
try (
686689
XZInputStream xzIn = new XZInputStream(stream);
687690
TarArchiveInputStream tarIn = new TarArchiveInputStream(xzIn)
688691
) {
692+
final Set<File> dirsToUpdate = new HashSet<>();
689693
final Phaser phaser = new Phaser(1);
690694
TarArchiveEntry entry;
691695

692696
while ((entry = tarIn.getNextTarEntry()) != null) {
693697
final String individualFile = entry.getName();
694698
final File fsObject = new File(targetDir, individualFile);
695699

696-
if (entry.isSymbolicLink() || entry.isLink()) {
700+
if (fsObject.exists()) {
701+
fsObject.setLastModified(System.currentTimeMillis());
702+
703+
File parentDir = fsObject.getParentFile();
704+
while (parentDir != null) {
705+
dirsToUpdate.add(parentDir);
706+
if (targetDir.equals(parentDir)) {
707+
break;
708+
}
709+
parentDir = parentDir.getParentFile();
710+
}
711+
} else if (entry.isSymbolicLink() || entry.isLink()) {
697712
Path target = FileSystems.getDefault().getPath(entry.getLinkName());
698713
Files.createSymbolicLink(fsObject.toPath(), target);
699714
} else if (entry.isFile()) {
@@ -743,6 +758,10 @@ private void closeChannel(Channel channel) {
743758
}
744759
}
745760

761+
for (File updatedDir : dirsToUpdate) {
762+
updatedDir.setLastModified(System.currentTimeMillis());
763+
}
764+
746765
phaser.arriveAndAwaitAdvance();
747766
}
748767
}
@@ -786,31 +805,28 @@ private static File prepareBinaries(PgBinaryResolver pgBinaryResolver, File over
786805
final File unpackLockFile = new File(pgDir, LOCK_FILE_NAME);
787806
final File pgDirExists = new File(pgDir, ".exists");
788807

789-
if (!pgDirExists.exists()) {
808+
if (!isPgBinReady(pgDirExists)) {
790809
try (FileOutputStream lockStream = new FileOutputStream(unpackLockFile);
791810
FileLock unpackLock = lockStream.getChannel().tryLock()) {
792811
if (unpackLock != null) {
793812
try {
794-
if (pgDirExists.exists()) {
795-
throw new IllegalStateException("unpack lock acquired but .exists file is present " + pgDirExists);
796-
}
797813
LOG.info("Extracting Postgres...");
798814
try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray())) {
799-
extractTxz(bais, pgDir.getPath());
815+
extractTxz(bais, pgDir);
800816
}
801817
if (!pgDirExists.createNewFile()) {
802-
throw new IllegalStateException("couldn't make .exists file " + pgDirExists);
818+
pgDirExists.setLastModified(System.currentTimeMillis());
803819
}
804820
} catch (Exception e) {
805821
LOG.error("while unpacking Postgres", e);
806822
}
807823
} else {
808824
// the other guy is unpacking for us.
809825
int maxAttempts = 60;
810-
while (!pgDirExists.exists() && --maxAttempts > 0) {
826+
while (!isPgBinReady(pgDirExists) && --maxAttempts > 0) {
811827
Thread.sleep(1000L);
812828
}
813-
if (!pgDirExists.exists()) {
829+
if (!isPgBinReady(pgDirExists)) {
814830
throw new IllegalStateException("Waited 60 seconds for postgres to be unpacked but it never finished!");
815831
}
816832
}
@@ -834,6 +850,18 @@ private static File prepareBinaries(PgBinaryResolver pgBinaryResolver, File over
834850
}
835851
}
836852

853+
public static boolean isPgBinReady(File pgDirExists) {
854+
if (!pgDirExists.exists()) {
855+
return false;
856+
}
857+
858+
File parentDir = pgDirExists.getParentFile();
859+
File[] otherFiles = Optional.ofNullable(parentDir.listFiles(file -> !file.equals(pgDirExists))).orElseGet(() -> new File[0]);
860+
861+
long contentLastModified = Stream.of(otherFiles).mapToLong(File::lastModified).max().orElse(Long.MAX_VALUE);
862+
return parentDir.lastModified() <= pgDirExists.lastModified() && contentLastModified <= pgDirExists.lastModified();
863+
}
864+
837865
@Override
838866
public String toString()
839867
{
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.slf4j.simpleLogger.showDateTime=true

0 commit comments

Comments
 (0)