You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2024/09/09 12:09:08 UTC
(jackrabbit-oak) 01/01: OAK-11099 Tree Store: support indexing from a pack file (without unpacking)
This is an automated email from the ASF dual-hosted git repository.
thomasm pushed a commit to branch OAK-11099
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 09f5ab8850233c727af5fa24b6cb7b98b52b9aba
Author: Thomas Mueller <th...@apache.org>
AuthorDate: Mon Sep 9 14:08:54 2024 +0200
OAK-11099 Tree Store: support indexing from a pack file (without unpacking)
---
.../flatfile/FlatFileNodeStoreBuilder.java | 9 +-
.../oak/index/indexer/document/tree/TreeStore.java | 34 +++--
.../indexer/document/tree/store/PackStore.java | 149 +++++++++++++++++++++
.../indexer/document/tree/store/StoreBuilder.java | 5 +-
.../document/tree/store/utils/FilePacker.java | 73 ++++++----
.../document/tree/store/PackedStoreTest.java | 87 ++++++++++++
.../document/tree/store/utils/FilePackerTest.java | 30 ++++-
7 files changed, 343 insertions(+), 44 deletions(-)
diff --git a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/flatfile/FlatFileNodeStoreBuilder.java b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/flatfile/FlatFileNodeStoreBuilder.java
index caf6cd70d8..f84aefd933 100644
--- a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/flatfile/FlatFileNodeStoreBuilder.java
+++ b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/flatfile/FlatFileNodeStoreBuilder.java
@@ -37,6 +37,7 @@ import org.apache.jackrabbit.oak.index.indexer.document.indexstore.IndexStoreSor
import org.apache.jackrabbit.oak.index.indexer.document.indexstore.IndexStoreUtils;
import org.apache.jackrabbit.oak.index.indexer.document.tree.Prefetcher;
import org.apache.jackrabbit.oak.index.indexer.document.tree.TreeStore;
+import org.apache.jackrabbit.oak.index.indexer.document.tree.store.utils.FilePacker;
import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore;
@@ -234,7 +235,7 @@ public class FlatFileNodeStoreBuilder {
File metadataFile = indexStoreFiles.metadataFile;
File file = indexStoreFiles.storeFiles.get(0);
IndexStore store;
- if (file.isDirectory()) {
+ if (file.isDirectory() || FilePacker.isPackFile(file)) {
store = buildTreeStoreForIndexing(indexHelper, file);
} else {
store = new FlatFileStore(blobStore, file, metadataFile,
@@ -362,12 +363,12 @@ public class FlatFileNodeStoreBuilder {
(dir, name) -> name.endsWith(IndexStoreUtils.getMetadataFileName(algorithm)));
if (storeFiles != null && storeFiles.length != 0) {
- // Not throwing error for backward compatibility
if (metadataFiles == null || metadataFiles.length == 0) {
- log.error("Unable to find metadata file in directory:{}", sortedDir.getAbsolutePath());
+ // the tree store doesn't need a metadata file
+ log.info("No metadata file found in directory: {}", sortedDir.getAbsolutePath());
return new IndexStoreFiles(Arrays.asList(storeFiles), null);
} else {
- checkState(metadataFiles.length == 1, "Multiple metadata files available at path:{}, metadataFiles:{}", sortedDir.getAbsolutePath(),
+ checkState(metadataFiles.length == 1, "Multiple metadata files available at path: {}, metadataFiles: {}", sortedDir.getAbsolutePath(),
Arrays.asList(metadataFiles));
return new IndexStoreFiles(Arrays.asList(storeFiles), metadataFiles[0]);
}
diff --git a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/TreeStore.java b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/TreeStore.java
index c3b4f63e50..50084c0f2e 100644
--- a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/TreeStore.java
+++ b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/TreeStore.java
@@ -36,6 +36,7 @@ import org.apache.jackrabbit.oak.index.indexer.document.tree.store.TreeSession;
import org.apache.jackrabbit.oak.index.indexer.document.tree.store.Compression;
import org.apache.jackrabbit.oak.index.indexer.document.tree.store.Store;
import org.apache.jackrabbit.oak.index.indexer.document.tree.store.StoreBuilder;
+import org.apache.jackrabbit.oak.index.indexer.document.tree.store.utils.FilePacker;
import org.apache.jackrabbit.oak.index.indexer.document.tree.store.utils.SieveCache;
import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
@@ -67,7 +68,8 @@ public class TreeStore implements IndexStore {
private final String name;
private final Store store;
private final long cacheSizeTreeStoreMB;
- private final File directory;
+ private final File fileOrDirectory;
+ private final boolean readOnly;
private final TreeSession session;
private final NodeStateEntryReader entryReader;
private final SieveCache<String, TreeStoreNodeState> nodeStateCache;
@@ -79,19 +81,30 @@ public class TreeStore implements IndexStore {
private int iterationCount;
private PathIteratorFilter filter = new PathIteratorFilter();
- public TreeStore(String name, File directory, NodeStateEntryReader entryReader, long cacheSizeFactor) {
+ public TreeStore(String name, File fileOrDirectory, NodeStateEntryReader entryReader, long cacheSizeFactor) {
this.name = name;
- this.directory = directory;
+ this.fileOrDirectory = fileOrDirectory;
this.entryReader = entryReader;
long cacheSizeNodeMB = cacheSizeFactor * CACHE_SIZE_NODE_MB;
long cacheSizeTreeStoreMB = cacheSizeFactor * CACHE_SIZE_TREE_STORE_MB;
this.cacheSizeTreeStoreMB = cacheSizeTreeStoreMB;
nodeStateCache = new SieveCache<>(cacheSizeFactor * cacheSizeNodeMB * MB);
- String storeConfig = System.getProperty(TREE_STORE_CONFIG,
- "type=file\n" +
- TreeSession.CACHE_SIZE_MB + "=" + cacheSizeTreeStoreMB + "\n" +
- Store.MAX_FILE_SIZE_BYTES + "=" + MAX_FILE_SIZE_MB * MB + "\n" +
- "dir=" + directory.getAbsolutePath());
+ String storeConfig;
+ if (FilePacker.isPackFile(fileOrDirectory)) {
+ readOnly = true;
+ storeConfig = System.getProperty(TREE_STORE_CONFIG,
+ "type=pack\n" +
+ TreeSession.CACHE_SIZE_MB + "=" + cacheSizeTreeStoreMB + "\n" +
+ Store.MAX_FILE_SIZE_BYTES + "=" + MAX_FILE_SIZE_MB * MB + "\n" +
+ "file=" + fileOrDirectory.getAbsolutePath());
+ } else {
+ readOnly = false;
+ storeConfig = System.getProperty(TREE_STORE_CONFIG,
+ "type=file\n" +
+ TreeSession.CACHE_SIZE_MB + "=" + cacheSizeTreeStoreMB + "\n" +
+ Store.MAX_FILE_SIZE_BYTES + "=" + MAX_FILE_SIZE_MB * MB + "\n" +
+ "dir=" + fileOrDirectory.getAbsolutePath());
+ }
this.store = StoreBuilder.build(storeConfig);
store.setWriteCompression(Compression.LZ4);
this.session = new TreeSession(store);
@@ -329,6 +342,9 @@ public class TreeStore implements IndexStore {
}
public void putNode(String path, String json) {
+ if (readOnly) {
+ throw new IllegalStateException("Read only store");
+ }
session.put(path, json);
if (!path.equals("/")) {
String nodeName = PathUtils.getName(path);
@@ -347,7 +363,7 @@ public class TreeStore implements IndexStore {
@Override
public String getStorePath() {
- return directory.getAbsolutePath();
+ return fileOrDirectory.getAbsolutePath();
}
@Override
diff --git a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/PackStore.java b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/PackStore.java
new file mode 100644
index 0000000000..8dc12e3e8c
--- /dev/null
+++ b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/PackStore.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.index.indexer.document.tree.store;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.jackrabbit.oak.index.indexer.document.tree.store.utils.FilePacker;
+import org.apache.jackrabbit.oak.index.indexer.document.tree.store.utils.FilePacker.FileEntry;
+
+/**
+ * A store where all the entries are stored in a "Pack File" (see @FilePacker).
+ * The store is read-only.
+ */
+public class PackStore implements Store {
+
+ private final Properties config;
+ private final String fileName;
+ private final File file;
+ private final RandomAccessFile f;
+ private final HashMap<String, FileEntry> directory = new HashMap<>();
+ private final long maxFileSizeBytes;
+ private final long start;
+ private long readCount;
+
+ public PackStore(Properties config) {
+ this.config = config;
+ this.fileName = config.getProperty("file");
+ this.maxFileSizeBytes = Long.parseLong(config.getProperty(
+ Store.MAX_FILE_SIZE_BYTES, "" + Store.DEFAULT_MAX_FILE_SIZE_BYTES));
+ try {
+ file = new File(fileName);
+ f = new RandomAccessFile(fileName, "r");
+ ArrayList<FileEntry> list = FilePacker.readDirectoryListing(file, f);
+ start = f.getFilePointer();
+ for(FileEntry e : list) {
+ directory.put(e.fileName, e);
+ }
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading file " + fileName, e);
+ }
+ }
+
+ public String toString() {
+ return "pack(" + fileName + ")";
+ }
+
+ @Override
+ public PageFile getIfExists(String key) {
+ readCount++;
+ FileEntry fe = directory.get(key);
+ if (fe == null) {
+ return null;
+ }
+ synchronized (this) {
+ try {
+ f.seek(start + fe.offset);
+ byte[] data = new byte[(int) fe.length];
+ f.readFully(data);
+ Compression c = Compression.getCompressionFromData(data[0]);
+ data = c.expand(data);
+ return PageFile.fromBytes(data, maxFileSizeBytes);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ }
+
+ @Override
+ public void put(String key, PageFile value) {
+ throw new IllegalStateException("Store is read-only");
+ }
+
+ @Override
+ public String newFileName() {
+ throw new IllegalStateException("Store is read-only");
+ }
+
+ @Override
+ public Set<String> keySet() {
+ return directory.keySet();
+ }
+
+ @Override
+ public void remove(Set<String> set) {
+ throw new IllegalStateException("Store is read-only");
+ }
+
+ @Override
+ public void removeAll() {
+ throw new IllegalStateException("Store is read-only");
+ }
+
+ @Override
+ public long getWriteCount() {
+ return 0;
+ }
+
+ @Override
+ public long getReadCount() {
+ return readCount;
+ }
+
+ @Override
+ public void setWriteCompression(Compression compression) {
+ // ignore
+ }
+
+ @Override
+ public void close() {
+ try {
+ f.close();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public Properties getConfig() {
+ return config;
+ }
+
+ @Override
+ public long getMaxFileSizeBytes() {
+ return maxFileSizeBytes;
+ }
+
+}
diff --git a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/StoreBuilder.java b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/StoreBuilder.java
index ba3b8322d4..755b8a0428 100644
--- a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/StoreBuilder.java
+++ b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/StoreBuilder.java
@@ -35,6 +35,7 @@ public class StoreBuilder {
* - "type=file": file system, with "dir" directory
* - "type=stats.another": statistics wrapper around another
* - "type=slow.another": slow wrapper around another (to simulate slowness)
+ * - "type=pack": pack file, with "file" file name
* - "type=log.another": log wrapper around another (to analyze problems)
* - "maxFileSizeBytes=16000000": the maximum file size in bytes
*
@@ -46,7 +47,7 @@ public class StoreBuilder {
if (config == null || config.isEmpty()) {
return new MemoryStore(new Properties());
}
- config = config.replace(' ', '\n').replace("\\", "\\\\");
+ config = config.replace("\\", "\\\\");
Properties prop = new Properties();
try {
prop.load(new StringReader(config));
@@ -63,6 +64,8 @@ public class StoreBuilder {
return new MemoryStore(config);
case "file":
return new FileStore(config);
+ case "pack":
+ return new PackStore(config);
}
if (type.startsWith("stats.")) {
config.put("type", type.substring("stats.".length()));
diff --git a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/utils/FilePacker.java b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/utils/FilePacker.java
index 36c2038b66..6bc145e66c 100644
--- a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/utils/FilePacker.java
+++ b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/utils/FilePacker.java
@@ -29,6 +29,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* A utility class that allows converting the files of a tree store into one
* file (pack the files), and back from a file to a list of files (unpack the
@@ -42,6 +45,8 @@ import java.util.stream.Collectors;
*/
public class FilePacker {
+ private static final Logger LOG = LoggerFactory.getLogger(FilePacker.class);
+
/**
* The header of pack files ("PACK").
*/
@@ -63,16 +68,22 @@ public class FilePacker {
/**
* Check whether the file starts with the magic header.
+ *
* @param file
- * @return
- * @throws IOException
+ * @return if this is a pack file
*/
- public static boolean isPackFile(File file) throws IOException {
- RandomAccessFile source = new RandomAccessFile(file, "rw");
- byte[] magic = new byte[4];
- source.readFully(magic);
- source.close();
- return PACK_HEADER.equals(new String(magic, StandardCharsets.UTF_8));
+ public static boolean isPackFile(File file) {
+ if (!file.exists() || !file.isFile() || file.length() < 4) {
+ return false;
+ }
+ try (RandomAccessFile source = new RandomAccessFile(file, "r")) {
+ byte[] magic = new byte[4];
+ source.readFully(magic);
+ return PACK_HEADER.equals(new String(magic, StandardCharsets.UTF_8));
+ } catch (IOException e) {
+ LOG.warn("IOException reading a possible pack file", e);
+ return false;
+ }
}
/**
@@ -136,21 +147,7 @@ public class FilePacker {
targetDirectory.mkdirs();
}
RandomAccessFile source = new RandomAccessFile(sourceFile, "rw");
- byte[] magic = new byte[4];
- source.readFully(magic);
- if (!PACK_HEADER.equals(new String(magic, StandardCharsets.UTF_8))) {
- source.close();
- throw new IOException("File header is not '" + PACK_HEADER + "': " + sourceFile.getAbsolutePath());
- }
- ArrayList<FileEntry> list = new ArrayList<>();
- long offset = 0;
- while (source.read() > 0) {
- byte[] name = new byte[source.readInt()];
- source.readFully(name);
- long length = source.readLong();
- list.add(new FileEntry(new String(name, StandardCharsets.UTF_8), length, offset));
- offset += length;
- }
+ ArrayList<FileEntry> list = readDirectoryListing(sourceFile, source);
long start = source.getFilePointer();
for (int i = list.size() - 1; i >= 0; i--) {
FileEntry f = list.get(i);
@@ -169,10 +166,29 @@ public class FilePacker {
}
}
- static class FileEntry {
- final String fileName;
- final long length;
- long offset;
+ public static ArrayList<FileEntry> readDirectoryListing(File sourceFile, RandomAccessFile source) throws IOException {
+ byte[] magic = new byte[4];
+ source.readFully(magic);
+ if (!PACK_HEADER.equals(new String(magic, StandardCharsets.UTF_8))) {
+ source.close();
+ throw new IOException("File header is not '" + PACK_HEADER + "': " + sourceFile.getAbsolutePath());
+ }
+ ArrayList<FileEntry> list = new ArrayList<>();
+ long offset = 0;
+ while (source.read() > 0) {
+ byte[] name = new byte[source.readInt()];
+ source.readFully(name);
+ long length = source.readLong();
+ list.add(new FileEntry(new String(name, StandardCharsets.UTF_8), length, offset));
+ offset += length;
+ }
+ return list;
+ }
+
+ public static class FileEntry {
+ public final String fileName;
+ public final long length;
+ public long offset;
FileEntry(String fileName, long length, long offset) {
this.fileName = fileName;
this.length = length;
@@ -182,5 +198,8 @@ public class FilePacker {
this.fileName = f.getName();
this.length = f.length();
}
+ public String toString() {
+ return fileName + "/" + length + "@" + offset;
+ }
}
}
diff --git a/oak-run-commons/src/test/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/PackedStoreTest.java b/oak-run-commons/src/test/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/PackedStoreTest.java
new file mode 100644
index 0000000000..7de3ec3860
--- /dev/null
+++ b/oak-run-commons/src/test/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/PackedStoreTest.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.index.indexer.document.tree.store;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.apache.jackrabbit.oak.index.indexer.document.tree.store.utils.FilePacker;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class PackedStoreTest {
+
+ @ClassRule
+ public static TemporaryFolder temporaryFolder = new TemporaryFolder(new File("target"));
+
+ @Test
+ public void test() throws IOException {
+ File dir = temporaryFolder.newFolder("sourceDir");
+ Store store = StoreBuilder.build(
+ "type=file\n" +
+ "dir="+dir.getAbsolutePath()+"\n" +
+ "cacheSizeMB=1\n" +
+ "maxFileSizeBytes=100");
+ store.setWriteCompression(Compression.LZ4);
+ store.removeAll();
+ TreeSession session = new TreeSession(store);
+ session.init();
+ int count = 100;
+ TreeMap<String, String> verify = new TreeMap<>();
+ for (int i = 0; i < count; i++) {
+ session.put("hello" + i, "world" + i);
+ verify.put("hello" + i, "world" + i);
+ }
+ session.checkpoint();
+ for (int i = 0; i < count; i++) {
+ if (i % 3 == 0) {
+ session.put("hello" + i, null);
+ verify.put("hello" + i, null);
+ } else if (i % 3 == 1) {
+ session.put("hello" + i, "World" + i);
+ verify.put("hello" + i, "World" + i);
+ }
+ }
+ session.flush();
+ store.close();
+
+ File pack = temporaryFolder.newFile("pack");
+ FilePacker.pack(dir, TreeSession.getFileNameRegex(), pack, true);
+ Store packStore = StoreBuilder.build(
+ "type=pack\n" +
+ "file=" + pack.getAbsolutePath() + "\n" +
+ "maxFileSizeBytes=100");
+ RandomAccessFile f = new RandomAccessFile(pack, "r");
+ ArrayList<FilePacker.FileEntry> list = FilePacker.readDirectoryListing(pack, f);
+ assertEquals(152, list.size());
+ f.close();
+ TreeSession session2 = new TreeSession(packStore);
+ for(Entry<String, String> e : verify.entrySet()) {
+ String v = session2.get(e.getKey());
+ assertEquals(v, e.getValue());
+ }
+ }
+}
diff --git a/oak-run-commons/src/test/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/utils/FilePackerTest.java b/oak-run-commons/src/test/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/utils/FilePackerTest.java
index 25fdc19b67..2013a0094f 100644
--- a/oak-run-commons/src/test/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/utils/FilePackerTest.java
+++ b/oak-run-commons/src/test/java/org/apache/jackrabbit/oak/index/indexer/document/tree/store/utils/FilePackerTest.java
@@ -46,17 +46,36 @@ public class FilePackerTest {
@ClassRule
public static TemporaryFolder temporaryFolder = new TemporaryFolder(new File("target"));
+ @Test
+ public void tinyFile() throws IOException {
+ File tiny = temporaryFolder.newFile();
+ assertFalse(FilePacker.isPackFile(tiny));
+ RandomAccessFile f = new RandomAccessFile(tiny, "rw");
+ f.write('P');
+ f.close();
+ assertFalse(FilePacker.isPackFile(tiny));
+ f = new RandomAccessFile(tiny, "rw");
+ f.write('P');
+ f.write('A');
+ f.write('C');
+ f.write('K');
+ f.close();
+ assertTrue(FilePacker.isPackFile(tiny));
+ }
+
@Test
public void headerMismatch() throws IOException {
- File pack = temporaryFolder.newFile("pack");
- File dir = temporaryFolder.newFolder("sourceDir");
+ File pack = temporaryFolder.newFile();
+ File dir = temporaryFolder.newFolder();
RandomAccessFile f = new RandomAccessFile(pack, "rw");
f.writeUTF("test");
try {
+ assertFalse(FilePacker.isPackFile(dir));
FilePacker.unpack(pack, dir, false);
fail();
} catch (IOException e) {
- assertTrue(e.getMessage().startsWith("File header is not 'PACK'"));
+ e.printStackTrace(System.out);
+ assertTrue(e.getMessage(), e.getMessage().startsWith("File header is not 'PACK'"));
}
f.close();
pack.delete();
@@ -66,6 +85,7 @@ public class FilePackerTest {
public void sourceIsDirectory() throws IOException {
File dir = temporaryFolder.newFolder("source");
try {
+ assertFalse(FilePacker.isPackFile(dir));
FilePacker.unpack(dir, dir, false);
fail();
} catch (IOException e) {
@@ -78,6 +98,8 @@ public class FilePackerTest {
public void sourceMissing() throws IOException {
File dir = temporaryFolder.newFolder("source");
try {
+ assertFalse(FilePacker.isPackFile(new File(dir, "missing")));
+ assertFalse(FilePacker.isPackFile(dir));
FilePacker.unpack(new File(dir, "missing"), dir, false);
fail();
} catch (IOException e) {
@@ -90,6 +112,7 @@ public class FilePackerTest {
public void targetDirectoryIsFile() throws IOException {
File target = temporaryFolder.newFile();
try {
+ assertFalse(FilePacker.isPackFile(target));
FilePacker.unpack(target, target, false);
fail();
} catch (IOException e) {
@@ -130,6 +153,7 @@ public class FilePackerTest {
// System.out.println(pack.getAbsolutePath());
// System.out.println(dir.getAbsolutePath());
FilePacker.pack(dir, TreeSession.getFileNameRegex(), pack, delete);
+ assertTrue(FilePacker.isPackFile(pack));
for (FileEntry f : list) {
if (delete) {