package io.fathom.cloud.storage;
import io.fathom.cloud.server.model.Project;
import java.util.concurrent.LinkedBlockingQueue;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fathomdb.TimeSpan;
@Singleton
public class FilesystemCompactor {
private static final Logger log = LoggerFactory.getLogger(FilesystemCompactor.class);
@Inject
FileServiceInternal fileService;
final LinkedBlockingQueue<CompactOperation> queue = new LinkedBlockingQueue<>();
public void enqueue(Project project, String bucketName, String name) {
// TODO: Don't enqueue if already in queue?
CompactOperation key = new CompactOperation(project, bucketName, name);
try {
queue.put(key);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.warn("Error while adding to change queue", e);
}
}
public void start() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
poll();
} catch (Exception e) {
log.error("Error during polling", e);
}
TimeSpan.FIVE_SECONDS.doSafeSleep();
}
}
});
thread.start();
}
protected void poll() throws InterruptedException {
while (true) {
// TODO: Figure out how this should work when distributed to avoid
// repeating work
CompactOperation compaction = queue.take();
try {
if (!fileService.compact(compaction)) {
// TODO: Don't enqueue if already in queue?
log.debug("Compaction was not needed: {}", compaction);
} else {
log.debug("Compaction successful: {}", compaction);
}
} catch (Exception e) {
// TODO: Auto-retry on concurrent modification?
// TODO: So we can re-use the compacted data
// TODO: We probably want a worker pool
log.warn("Ignoring error while compacting: " + compaction, e);
}
}
}
}