Skip to content

Commit 1f140f0

Browse files
committed
Tested FileCache
1 parent 18f28ef commit 1f140f0

File tree

3 files changed

+88
-16
lines changed

3 files changed

+88
-16
lines changed

src/main/java/org/radarcns/RestructureAvroRecords.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.apache.hadoop.fs.LocatedFileStatus;
2020
import org.apache.hadoop.fs.Path;
2121
import org.apache.hadoop.fs.RemoteIterator;
22+
import org.radarcns.util.FileCache;
2223
import org.slf4j.Logger;
2324
import org.slf4j.LoggerFactory;
2425

src/main/java/org/radarcns/FileCache.java renamed to src/main/java/org/radarcns/util/FileCache.java

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.radarcns;
1+
package org.radarcns.util;
22

33
import java.io.BufferedWriter;
44
import java.io.Closeable;
@@ -14,6 +14,10 @@
1414
import org.slf4j.Logger;
1515
import org.slf4j.LoggerFactory;
1616

17+
/**
18+
* Caches open file handles. If more than the limit is cached, the half of the files that were used
19+
* the longest ago cache are evicted from cache.
20+
*/
1721
public class FileCache implements Flushable, Closeable {
1822
private static final Logger logger = LoggerFactory.getLogger(FileCache.class);
1923

@@ -22,35 +26,56 @@ public class FileCache implements Flushable, Closeable {
2226

2327
public FileCache(int maxFiles) {
2428
this.maxFiles = maxFiles;
25-
this.caches = new HashMap<>();
29+
this.caches = new HashMap<>(maxFiles * 4 / 3 + 1);
2630
}
2731

28-
public void appendLine(File file, String data) throws IOException {
32+
/**
33+
* Append a line to given file. This will append a line ending to given data.
34+
* If the file handle and writer are already open in this cache,
35+
* those will be used. Otherwise, the file will be opened and the file handle cached.
36+
*
37+
* @param file file to append data to
38+
* @param data data without line ending
39+
* @return true if the cache was used, false if a new file was opened.
40+
* @throws IOException when failing to open a file or writing to it.
41+
*/
42+
public boolean appendLine(File file, String data) throws IOException {
2943
SingleFileCache cache = caches.get(file);
30-
if (cache == null) {
31-
if (caches.size() == maxFiles) {
32-
ArrayList<SingleFileCache> cacheList = new ArrayList<>(caches.values());
33-
Collections.sort(cacheList);
34-
for (int i = 0; i < cacheList.size() / 2; i++) {
35-
SingleFileCache rmCache = cacheList.get(i);
36-
caches.remove(rmCache.getFile());
37-
rmCache.close();
38-
}
39-
}
44+
if (cache != null) {
45+
cache.appendLine(data);
46+
return true;
47+
} else {
48+
ensureCapacity();
4049

4150
File dir = file.getParentFile();
4251
if (!file.getParentFile().exists()){
4352
if (dir.mkdirs()) {
44-
logger.info("Created directory: {}", dir.getAbsolutePath());
53+
logger.debug("Created directory: {}", dir.getAbsolutePath());
4554
} else {
46-
logger.warn("FAILED to create directory: " + dir.getAbsolutePath());
55+
logger.warn("FAILED to create directory: {}", dir.getAbsolutePath());
4756
}
4857
}
4958

5059
cache = new SingleFileCache(file);
5160
caches.put(file, cache);
61+
cache.appendLine(data);
62+
return false;
63+
}
64+
}
65+
66+
/**
67+
* Ensure that a new filecache can be added. Evict files used longest ago from cache if needed.
68+
*/
69+
private void ensureCapacity() throws IOException {
70+
if (caches.size() == maxFiles) {
71+
ArrayList<SingleFileCache> cacheList = new ArrayList<>(caches.values());
72+
Collections.sort(cacheList);
73+
for (int i = 0; i < cacheList.size() / 2; i++) {
74+
SingleFileCache rmCache = cacheList.get(i);
75+
caches.remove(rmCache.getFile());
76+
rmCache.close();
77+
}
5278
}
53-
cache.appendLine(data);
5479
}
5580

5681
@Override
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.radarcns.util;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertFalse;
5+
import static org.junit.Assert.assertTrue;
6+
7+
import java.io.File;
8+
import java.io.IOException;
9+
import java.nio.file.Files;
10+
import org.junit.Rule;
11+
import org.junit.Test;
12+
import org.junit.rules.TemporaryFolder;
13+
14+
public class FileCacheTest {
15+
@Rule
16+
public TemporaryFolder folder = new TemporaryFolder();
17+
18+
@Test
19+
public void appendLine() throws IOException {
20+
File f1 = folder.newFile();
21+
File f2 = folder.newFile();
22+
File f3 = folder.newFile();
23+
File d4 = folder.newFolder();
24+
File f4 = new File(d4, "f4.txt");
25+
26+
assertTrue(f1.delete());
27+
assertTrue(d4.delete());
28+
29+
try (FileCache cache = new FileCache(2)) {
30+
assertFalse(cache.appendLine(f1, "something"));
31+
assertTrue(cache.appendLine(f1, "somethingElse"));
32+
assertFalse(cache.appendLine(f2, "something"));
33+
assertTrue(cache.appendLine(f1, "third"));
34+
assertFalse(cache.appendLine(f3, "f3"));
35+
assertFalse(cache.appendLine(f2, "f2"));
36+
assertTrue(cache.appendLine(f3, "f3"));
37+
assertFalse(cache.appendLine(f4, "f4"));
38+
assertTrue(cache.appendLine(f3, "f3"));
39+
}
40+
41+
assertEquals("something\nsomethingElse\nthird\n", new String(Files.readAllBytes(f1.toPath())));
42+
assertEquals("something\nf2\n", new String(Files.readAllBytes(f2.toPath())));
43+
assertEquals("f3\nf3\nf3\n", new String(Files.readAllBytes(f3.toPath())));
44+
assertEquals("f4\n", new String(Files.readAllBytes(f4.toPath())));
45+
}
46+
}

0 commit comments

Comments
 (0)