package org.elasticsearch.plugin.degraphmalizer.updater;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import java.io.*;
import java.util.Arrays;
import java.util.Comparator;
import java.util.concurrent.BlockingQueue;
public class UpdaterOverflowFileManager {
private static final ESLogger LOG = Loggers.getLogger(UpdaterOverflowFileManager.class);
private static final File[] NO_FILES = {};
private final String logPath;
private final String filenamePrefix;
private final int limit;
public UpdaterOverflowFileManager(final String logPath, final String index, final int limit) {
this.logPath = logPath;
this.filenamePrefix = index + "-overflow-";
this.limit = limit;
}
private final FilenameFilter filenameFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.matches(filenamePrefix + "\\d+");
}
};
private final Comparator<File> fileComparator = new Comparator<File>() {
@Override
public int compare(File file1, File file2) {
return Long.valueOf(file1.lastModified()).compareTo(file2.lastModified());
}
};
/**
* Number of records in overflow files.
*/
public int size() {
int count = 0;
for (File file : getOverflowFiles()) {
count += countLines(file);
}
return count;
}
public int countLines(File file) {
LineNumberReader lnr = null;
try {
lnr = new LineNumberReader(new FileReader(file));
while(lnr.skip(Long.MAX_VALUE)>0);
lnr.getLineNumber();
lnr.close();
} catch (IOException e) {
LOG.error("Can't read from file {} " + file.getPath());
} finally {
closeQuietly(lnr);
}
return 0;
}
public boolean isEmpty() {
return getOverflowFiles().length == 0;
}
public void clear() {
for (File file : getOverflowFiles()) {
if (!file.delete()) {
try {
LOG.error("Error deleting file {}", file.getCanonicalPath());
} catch (IOException e) {
LOG.error("Error deleting file {}", file.getName());
}
}
}
}
/**
* Saves the contents of the input queue to disk.
*/
public void save(final BlockingQueue<DelayedImpl<Change>> queue) {
File file;
do {
file = new File(logPath, filenamePrefix + System.currentTimeMillis());
} while (file.exists());
try {
final PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")));
int count = 0;
while (!queue.isEmpty() && count < limit) {
try {
final DelayedImpl<Change> delayed = queue.take();
writer.println(delayed.toValue());
count++;
} catch (InterruptedException e) {
LOG.warn("Take from input queue interrupted: " + e.getMessage());
}
}
writer.flush();
writer.close();
} catch (IOException e) {
LOG.error("Error saving overflow file {}: {}", file, e.getMessage());
}
}
/**
* Load the contents of the 'first in line' overflow file into the output queue.
*/
public void load(final BlockingQueue<DelayedImpl<Change>> queue) {
final File[] files = getOverflowFiles();
final DelayedImpl<Change> delayedFactory = new DelayedImpl<Change>(new Change(), 0);
BufferedReader reader = null;
if (files.length > 0) {
final File file = files[0];
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
String line = reader.readLine();
do {
try {
final DelayedImpl<Change> delayed = delayedFactory.fromValue(line);
queue.put(delayed);
} catch (InterruptedException e) {
LOG.warn("Put into queue was interrupted: {}", e.getMessage());
} catch (Exception e) {
LOG.error("Unparsable overflow line " + line);
}
line = reader.readLine();
} while (line != null);
reader.close();
if (!file.delete()) {
LOG.error("Can not remove file {}", file.getCanonicalPath());
}
} catch (IOException e) {
LOG.error("Error loading overflow file {}: {}", file, e.getMessage());
} finally {
closeQuietly(reader);
}
}
}
/**
* Array of overflow files sorted by last modified date.
*/
private File[] getOverflowFiles() {
final File[] files = new File(logPath).listFiles(filenameFilter);
if (files != null) {
Arrays.sort(files, fileComparator);
} else {
return NO_FILES;
}
return files;
}
private void closeQuietly(Reader input) {
if (input == null) {
return;
}
try {
input.close();
} catch (IOException ioe) {
}
}
}