Improve directory size update performance

Use NIO Files.walkFileTree() instead of IO File.ListFiles() API.
Speed improvement was ~6.1s -> ~4.4s on my recordings list.

TODO: implement more intelligent refresh.
This commit is contained in:
ctbrec-contrib-01 2020-03-03 21:39:36 +07:00 committed by 0xboobface
parent 2eb1b17513
commit e333722522
2 changed files with 37 additions and 10 deletions

View File

@ -1,18 +1,31 @@
package ctbrec; package ctbrec;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.EnumSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.event.EventBusHolder; import ctbrec.event.EventBusHolder;
import ctbrec.event.RecordingStateChangedEvent; import ctbrec.event.RecordingStateChangedEvent;
import ctbrec.recorder.download.Download; import ctbrec.recorder.download.Download;
public class Recording implements Serializable { public class Recording implements Serializable {
private static final transient Logger LOG = LoggerFactory.getLogger(Recording.class);
private Model model; private Model model;
private transient Download download; private transient Download download;
private Instant startDate; private Instant startDate;
@ -216,17 +229,26 @@ public class Recording implements Serializable {
} }
private long getDirectorySize(File dir) { private long getDirectorySize(File dir) {
long size = 0; final long[] size = { 0 };
if (dir.exists()) { int maxDepth = 1; // Don't expect subdirs, so don't even try
File[] files = dir.listFiles(); try {
if (files == null) { Files.walkFileTree(dir.toPath(), EnumSet.noneOf(FileVisitOption.class), maxDepth, new SimpleFileVisitor<Path>() {
return 0; @Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
size[0] += attrs.size();
return FileVisitResult.CONTINUE;
} }
for (File file : files) {
size += file.length(); @Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
// Ignore file access issues
return FileVisitResult.CONTINUE;
} }
});
} catch (IOException e) {
LOG.error("Couldn't determine size of recording {}", this, e);
} }
return size; return size[0];
} }
public void refresh() { public void refresh() {

View File

@ -7,6 +7,7 @@ import static java.nio.file.StandardOpenOption.*;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -135,9 +136,13 @@ public class RecordingManager {
public List<Recording> getAll() { public List<Recording> getAll() {
recordingsLock.lock(); recordingsLock.lock();
try { try {
Instant start = Instant.now();
for (Recording recording : recordings) { for (Recording recording : recordings) {
recording.refresh(); recording.refresh();
} }
Instant finish = Instant.now();
long timeElapsed = Duration.between(start, finish).toMillis();
LOG.trace("Recordings list refreshed in {} ms", timeElapsed);
return new ArrayList<>(recordings); return new ArrayList<>(recordings);
} finally { } finally {
recordingsLock.unlock(); recordingsLock.unlock();