/*
* Created on 01.12.2007
* Caleido AG, All Rights Reserved
* Author: Luzius Meisser
*/
package quickbase.internal.files;
import java.io.File;
import java.io.FilenameFilter;
import quickbase.exception.AbortVisitException;
import quickbase.exception.BasicFileOperationDatabaseException;
import quickbase.exception.ClearDatabaseException;
import quickbase.exception.IExceptionHandlingStrategy;
import quickbase.exception.InvalidDataDatabaseException;
import quickbase.internal.consumer.IEntryConsumer;
import quickbase.internal.entries.Entry;
public class DataFiles {
private File path;
private String name;
private long maxFileSize;
private DataFile[] dataFiles;
public DataFiles(File path, final String name, long maxFileSize) throws BasicFileOperationDatabaseException {
this.path = path;
this.name = name;
this.maxFileSize = maxFileSize;
File[] files = path.listFiles(new FilenameFilter() {
public boolean accept(File dir, String fname) {
return fname.startsWith(name) && fname.endsWith(DataFile.SUFFIX);
}
});
this.dataFiles = new DataFile[getCount(files, name)];
for (int i = 0; i < dataFiles.length; i++) {
File file = new File(path, name + i + DataFile.SUFFIX);
if (file.exists() || (i == dataFiles.length - 1)) {
dataFiles[i] = new DataFile(file);
} else {
dataFiles[i] = new AbandonedDataFile();
}
}
}
private int getCount(File[] files, String prefix) {
int max = 0;
for (File file : files) {
String name = file.getName();
String number = name.substring(prefix.length(), name.length() - DataFile.SUFFIX.length());
try {
max = Math.max(Integer.parseInt(number), max);
} catch (NumberFormatException e) {
}
}
return max + 1;
}
public long getMaxPos() {
return getOffset() + getCurrent().getSize();
}
private long getOffset() {
return (dataFiles.length - 1) * maxFileSize;
}
private DataFile getCurrent() {
return dataFiles[dataFiles.length - 1];
}
public void visitAndClear(IExceptionHandlingStrategy strategy, IEntryConsumer consumer) throws BasicFileOperationDatabaseException, ClearDatabaseException, AbortVisitException {
for (int i = 0; i < dataFiles.length; i++) {
try {
dataFiles[i].visit(strategy, i * maxFileSize, 0, consumer);
dataFiles[i].destroy();
dataFiles[i] = new AbandonedDataFile();
} catch (DataFileAbandonedException e) {
// ignore, assume already compacted
}
}
}
public void visit(IExceptionHandlingStrategy strategy, long startPos, IEntryConsumer consumer) throws BasicFileOperationDatabaseException, ClearDatabaseException, AbortVisitException {
int number = (int) (startPos / maxFileSize);
if (number < dataFiles.length) {
boolean more = true;
for (int i = number; more && i < dataFiles.length; i++) {
try {
more = dataFiles[i].visit(strategy, i * maxFileSize, startPos, consumer);
} catch (DataFileAbandonedException e) {
strategy.handleMissingFile(e);
}
startPos = 0;
}
}
}
public long put(Entry entry) throws DataFileAbandonedException, BasicFileOperationDatabaseException {
try {
long pos = getCurrent().put(entry, maxFileSize);
return getOffset() + pos;
} catch (MaxFileLenReachedException e) {
addFile();
return put(entry);
}
}
private void addFile() throws BasicFileOperationDatabaseException {
DataFile[] newFiles = new DataFile[dataFiles.length + 1];
System.arraycopy(dataFiles, 0, newFiles, 0, dataFiles.length);
newFiles[dataFiles.length] = new DataFile(new File(path, name + dataFiles.length + DataFile.SUFFIX));
dataFiles = newFiles;
}
public Entry get(long pos) throws DataFileAbandonedException, BasicFileOperationDatabaseException, InvalidDataDatabaseException {
int number = (int) (pos / maxFileSize);
return dataFiles[number].get(pos % maxFileSize);
}
public long close() {
for (DataFile file : dataFiles) {
file.close();
}
return getOffset() + dataFiles[dataFiles.length - 1].getSize();
}
public String getName() {
return name;
}
public File getPath() {
return path;
}
public void rename(String newName) throws BasicFileOperationDatabaseException {
for (int i = 0; i < dataFiles.length; i++) {
if (dataFiles[i] != null) {
// TODO: undo rename in case of exception
dataFiles[i].rename(newName + i);
}
}
this.name = newName;
}
public void destroy() throws BasicFileOperationDatabaseException {
for (int i = 0; i < dataFiles.length; i++) {
dataFiles[i].destroy();
}
}
public long getMaxFileSize() {
return maxFileSize;
}
}