private void closeAndThrow(int id, FileChannel[] array, FileChannel o, long maxLength) throws IOException { String message = "Expected file length: " + maxLength + " got: " + o.size() + " for " + getName(id); for (FileChannel f : array) { f.close(); } throw new IOException(message); }
@Override public FileChannel open(String mode) throws IOException { ArrayList<FileChannel> list = new ArrayList<>(); list.add(getBase().open(mode)); for (int i = 1;; i++) { FilePath f = getBase(i); if (f.exists()) { list.add(f.open(mode)); long length = maxLength; if (array.length == 1) { long defaultMaxLength = getDefaultMaxLength(); if (maxLength < defaultMaxLength) { maxLength = defaultMaxLength; closeAndThrow(0, array, array[0], maxLength); length += l; if (l != maxLength) { closeAndThrow(i, array, c, maxLength); length += l; if (l > maxLength) { closeAndThrow(array.length - 1, array, c, maxLength);
@Override public ArrayList<FilePath> newDirectoryStream() { List<FilePath> list = getBase().newDirectoryStream(); ArrayList<FilePath> newList = new ArrayList<>(); for (int i = 0, size = list.size(); i < size; i++) { FilePath f = list.get(i); if (!f.getName().endsWith(PART_SUFFIX)) { newList.add(wrap(f)); } } return newList; }
private long getDefaultMaxLength() { return 1L << Integer.decode(parse(name)[0]).intValue(); }
@Override public String toString() { return file.toString(); }
@Override public OutputStream newOutputStream(boolean append) throws IOException { return new FileChannelOutputStream(open("rw"), append); }
/** * Split the file name into size and base file name. * * @param fileName the file name * @return an array with size and file name */ private String[] parse(String fileName) { if (!fileName.startsWith(getScheme())) { DbException.throwInternalError(fileName + " doesn't start with " + getScheme()); } fileName = fileName.substring(getScheme().length() + 1); String size; if (fileName.length() > 0 && Character.isDigit(fileName.charAt(0))) { int idx = fileName.indexOf(':'); size = fileName.substring(0, idx); try { fileName = fileName.substring(idx + 1); } catch (NumberFormatException e) { // ignore } } else { size = Long.toString(SysProperties.SPLIT_FILE_SIZE_SHIFT); } return new String[] { size, fileName }; }
@Override public FilePath unwrap(String fileName) { return FilePath.get(parse(fileName)[1]); }
/** * Get the file name of a part file. * * @param id the part id * @return the file name including the part id */ FilePath getBase(int id) { return FilePath.get(getName(id)); }
private FileChannel getFileChannel() throws IOException { int id = (int) (filePointer / maxLength); while (id >= list.length) { int i = list.length; FileChannel[] newList = new FileChannel[i + 1]; System.arraycopy(list, 0, newList, 0, i); FilePath f = file.getBase(i); newList[i] = f.open(mode); list = newList; } return list[id]; }
@Override public long lastModified() { long lastModified = 0; for (int i = 0;; i++) { FilePath f = getBase(i); if (f.exists()) { long l = f.lastModified(); lastModified = Math.max(lastModified, l); } else { break; } } return lastModified; }
@Override public boolean setReadOnly() { boolean result = false; for (int i = 0;; i++) { FilePath f = getBase(i); if (f.exists()) { result = f.setReadOnly(); } else { break; } } return result; }
@Override public void delete() { for (int i = 0;; i++) { FilePath f = getBase(i); if (f.exists()) { f.delete(); } else { break; } } }
@Override public long size() { long length = 0; for (int i = 0;; i++) { FilePath f = getBase(i); if (f.exists()) { length += f.size(); } else { break; } } return length; }
@Override public FileChannel truncate(long newLength) throws IOException { if (newLength >= length) { return this; } filePointer = Math.min(filePointer, newLength); int newFileCount = 1 + (int) (newLength / maxLength); if (newFileCount < list.length) { // delete some of the files FileChannel[] newList = new FileChannel[newFileCount]; // delete backwards, so that truncating is somewhat transactional for (int i = list.length - 1; i >= newFileCount; i--) { // verify the file is writable list[i].truncate(0); list[i].close(); try { file.getBase(i).delete(); } catch (DbException e) { throw DbException.convertToIOException(e); } } System.arraycopy(list, 0, newList, 0, newList.length); list = newList; } long size = newLength - maxLength * (newFileCount - 1); list[list.length - 1].truncate(size); this.length = newLength; return this; }